#include "emit.h"
#include "codegen.h"
-bool IsSSE2Instruction(instruction ins)
+bool IsSSEInstruction(instruction ins)
{
- return (ins >= INS_FIRST_SSE2_INSTRUCTION) && (ins <= INS_LAST_SSE2_INSTRUCTION);
-}
-
-bool IsSSE4Instruction(instruction ins)
-{
- return (ins >= INS_FIRST_SSE4_INSTRUCTION) && (ins <= INS_LAST_SSE4_INSTRUCTION);
+ return (ins >= INS_FIRST_SSE_INSTRUCTION) && (ins <= INS_LAST_SSE_INSTRUCTION);
}
bool IsSSEOrAVXInstruction(instruction ins)
{
- return (ins >= INS_FIRST_SSE2_INSTRUCTION) && (ins <= INS_LAST_AVX_INSTRUCTION);
+ return (ins >= INS_FIRST_SSE_INSTRUCTION) && (ins <= INS_LAST_AVX_INSTRUCTION);
}
bool IsAVXOnlyInstruction(instruction ins)
#endif // FEATURE_HW_INTRINSICS
// -------------------------------------------------------------------
-// Is4ByteSSE4Instruction: Returns true if the SSE4 instruction
-// is a 4-byte opcode.
+// Is4ByteSSEInstruction: Returns true if the SSE instruction is a 4-byte opcode.
//
// Arguments:
// ins - instruction
//
// Note that this should be true for any of the instructions in instrsXArch.h
-// that use the SSE38 or SSE3A macro.
-bool emitter::Is4ByteSSE4Instruction(instruction ins)
+// that use the SSE38 or SSE3A macro but returns false if the VEX encoding is
+// in use, since that encoding does not require an additional byte.
+bool emitter::Is4ByteSSEInstruction(instruction ins)
{
- return UseSSE4() && IsSSE4Instruction(ins) && EncodedBySSE38orSSE3A(ins);
-}
-
-// ------------------------------------------------------------------------------
-// Is4ByteSSE4OrAVXInstruction: Returns true if the SSE4 or AVX instruction is a 4-byte opcode.
-//
-// Arguments:
-// ins - instructions
-//
-// Note that this should be true for any of the instructions in instrsXArch.h
-// that use the SSE38 or SSE3A macro.
-bool emitter::Is4ByteSSE4OrAVXInstruction(instruction ins)
-{
- return ((UseVEXEncoding() && (IsSSE4Instruction(ins) || IsAVXOnlyInstruction(ins))) ||
- (UseSSE4() && IsSSE4Instruction(ins))) &&
- EncodedBySSE38orSSE3A(ins);
+ return !UseVEXEncoding() && EncodedBySSE38orSSE3A(ins);
}
// Returns true if this instruction requires a VEX prefix
size_t insCode = 0;
+ if (!IsSSEOrAVXInstruction(ins))
+ {
+ return false;
+ }
+
if (hasCodeRM(ins))
{
insCode = insCodeRM(ins);
UNATIVE_OFFSET sz = emitInsSizeRR(ins, reg1, reg2, attr);
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require one additional byte
+ // The 4-Byte SSE instructions require one additional byte
sz += 1;
}
void emitter::emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int ival)
{
- // SSE2 version requires 5 bytes and SSE4/AVX version 6 bytes
+ // SSE2 version requires 5 bytes and some SSE/AVX version 6 bytes
UNATIVE_OFFSET sz = 4;
if (IsSSEOrAVXInstruction(ins))
{
// AVX: 3 byte VEX prefix + 1 byte opcode + 1 byte ModR/M + 1 byte immediate
- // SSE4: 4 byte opcode + 1 byte ModR/M + 1 byte immediate
- // SSE2: 3 byte opcode + 1 byte ModR/M + 1 byte immediate
- sz = (UseVEXEncoding() || UseSSE4()) ? 6 : 5;
+ // SSE: 4 byte opcode + 1 byte ModR/M + 1 byte immediate
+ // SSE: 3 byte opcode + 1 byte ModR/M + 1 byte immediate
+ sz = (UseVEXEncoding() || Is4ByteSSEInstruction(ins)) ? 6 : 5;
}
#ifdef _TARGET_AMD64_
if ((ins == INS_pextrq || ins == INS_pinsrq) && !UseVEXEncoding())
{
- assert(UseSSE4());
sz += 1;
}
UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins), ival);
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require two additional bytes
+ // The 4-Byte SSE instructions require two additional bytes
sz += 2;
}
UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins), ival);
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require two additional bytes
+ // The 4-Byte SSE instructions require two additional bytes
sz += 2;
}
UNATIVE_OFFSET sz = emitInsSizeCV(id, insCodeRM(ins), ival);
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require two additional bytes
+ // The 4-Byte SSE instructions require two additional bytes
sz += 2;
}
UNATIVE_OFFSET sz = emitInsSizeSV(id, insCodeRM(ins), varx, offs, ival);
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require two additional bytes
+ // The 4-Byte SSE instructions require two additional bytes
sz += 2;
}
sz = emitInsSizeAM(id, insCodeRM(ins));
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
- // The 4-Byte SSE4 instructions require two additional bytes
+ // The 4-Byte SSE instructions require two additional bytes
sz += 2;
}
}
// Special case emitting AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if ((ins == INS_crc32) && (size > EA_1BYTE))
{
// Use the large version if this is not a byte. This trick will not
// work in case of SSE2 and AVX instructions.
- if ((size != EA_1BYTE) && (ins != INS_imul) && !IsSSE2Instruction(ins) && !IsAVXInstruction(ins))
+ if ((size != EA_1BYTE) && (ins != INS_imul) && !IsSSEInstruction(ins) && !IsAVXInstruction(ins))
{
code++;
}
code += 4;
}
}
- else if (!IsSSE2Instruction(ins) && !IsAVXInstruction(ins))
+ else if (!IsSSEInstruction(ins) && !IsAVXInstruction(ins))
{
/* Is the operand size larger than a byte? */
// The address is of the form "[disp]"
// On x86 - disp is relative to zero
// On Amd64 - disp is relative to RIP
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst += emitOutputByte(dst, code | 0x05);
}
else
{
#ifdef _TARGET_X86_
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst += emitOutputByte(dst, code | 0x05);
}
noway_assert((int)dsp == dsp);
// This requires, specifying a SIB byte after ModRM byte.
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst += emitOutputByte(dst, code | 0x04);
}
case REG_EBP:
{
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
// Does the offset fit in a byte?
if (dspInByte)
case REG_ESP:
{
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
// Is the offset 0 or does it at least fit in a byte?
if (dspIsZero)
default:
{
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
// Put the register in the opcode
code |= insEncodeReg012(ins, reg, EA_PTRSIZE, nullptr);
regByte = insEncodeReg012(ins, reg, EA_PTRSIZE, nullptr) |
insEncodeReg345(ins, rgx, EA_PTRSIZE, nullptr) | insSSval(mul);
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
// Emit [ebp + {2/4/8} * rgz] as [ebp + {2/4/8} * rgx + 0]
if (dspIsZero && reg != REG_EBP)
regByte = insEncodeReg012(ins, REG_EBP, EA_PTRSIZE, nullptr) |
insEncodeReg345(ins, rgx, EA_PTRSIZE, nullptr) | insSSval(mul);
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst += emitOutputByte(dst, code | 0x04);
}
// The address is "[reg+rgx+dsp]"
regByte = insEncodeReg012(ins, reg, EA_PTRSIZE, nullptr) | insEncodeReg345(ins, rgx, EA_PTRSIZE, nullptr);
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if (dspIsZero && reg != REG_EBP)
{
}
// Special case emitting AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if ((ins == INS_crc32) && (size > EA_1BYTE))
{
}
// Use the large version if this is not a byte
- if ((size != EA_1BYTE) && (ins != INS_imul) && (!insIsCMOV(ins)) && !IsSSE2Instruction(ins) &&
+ if ((size != EA_1BYTE) && (ins != INS_imul) && (!insIsCMOV(ins)) && !IsSSEInstruction(ins) &&
!IsAVXInstruction(ins))
{
code |= 0x1;
code += 4;
}
}
- else if (!IsSSE2Instruction(ins) && !IsAVXInstruction(ins))
+ else if (!IsSSEInstruction(ins) && !IsAVXInstruction(ins))
{
// Is the operand size larger than a byte?
switch (size)
if (EBPbased)
{
// EBP-based variable: does the offset fit in a byte?
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if (dspInByte)
{
dspIsZero = (dsp == 0);
// Does the offset fit in a byte?
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if (dspInByte)
{
#endif //_TARGET_X86_
// Special case emitting AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
if ((ins == INS_crc32) && (size > EA_1BYTE))
{
emitAttr size = id->idOpSize();
// We would to update GC info correctly
- assert(!IsSSE2Instruction(ins));
+ assert(!IsSSEInstruction(ins));
assert(!IsAVXInstruction(ins));
// Get the 'base' opcode
dst += emitOutputWord(dst, code >> 16);
code &= 0x0000FFFF;
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
// Output 3rd byte of the opcode
dst += emitOutputByte(dst, code);
}
else if ((code & 0xFF) == 0x00)
{
- // This case happens for SSE4/AVX instructions only
- assert(IsAVXInstruction(ins) || IsSSE4Instruction(ins));
+ // This case happens for some SSE/AVX instructions only
+ assert(IsAVXInstruction(ins) || Is4ByteSSEInstruction(ins));
dst += emitOutputByte(dst, (code >> 8) & 0xFF);
dst += emitOutputByte(dst, (0xC0 | regCode));
bool valInByte = ((signed char)val == val);
// We would to update GC info correctly
- assert(!IsSSE2Instruction(ins));
+ assert(!IsSSEInstruction(ins));
assert(!IsAVXInstruction(ins));
#ifdef _TARGET_AMD64_
bool jmp;
bool relAddr = true; // does the instruction use relative-addressing?
- // SSE2 doesnt make any sense here
- assert(!IsSSE2Instruction(ins));
+ // SSE/AVX doesnt make any sense here
+ assert(!IsSSEInstruction(ins));
assert(!IsAVXInstruction(ins));
size_t ssz;
dst += emitOutputWord(dst, code >> 16);
code &= 0x0000FFFF;
- if (Is4ByteSSE4Instruction(ins))
+ if (Is4ByteSSEInstruction(ins))
{
// Output 3rd byte of the opcode
dst += emitOutputByte(dst, code);
}
else if ((code & 0xFF) == 0x00)
{
- // This case happens for SSE4/AVX instructions only
- assert(IsAVXInstruction(ins) || IsSSE4Instruction(ins));
+ // This case happens for some SSE/AVX instructions only
+ assert(IsAVXInstruction(ins) || Is4ByteSSEInstruction(ins));
dst += emitOutputByte(dst, (code >> 8) & 0xFF);
dst += emitOutputByte(dst, (0xC0 | regcode));
code = insCodeRM(ins);
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputAM(dst, id, code, &cnsVal);
}
case IF_RWR_RRD_ARD:
{
code = insCodeRM(ins);
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst = emitOutputAM(dst, id, code);
}
{
emitGetInsAmdCns(id, &cnsVal);
code = insCodeRM(ins);
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputAM(dst, id, code, &cnsVal);
}
code = insCodeRM(ins);
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputSV(dst, id, code, &cnsVal);
}
// 4-byte AVX instructions are special cased inside emitOutputSV
// since they do not have space to encode ModRM byte.
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst = emitOutputSV(dst, id, code);
}
// 4-byte AVX instructions are special cased inside emitOutputSV
// since they do not have space to encode ModRM byte.
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputSV(dst, id, code);
}
// 4-byte AVX instructions are special cased inside emitOutputSV
// since they do not have space to encode ModRM byte.
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputSV(dst, id, code, &cnsVal);
}
code = insCodeRM(ins);
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputCV(dst, id, code, &cnsVal);
}
code = insCodeRM(ins);
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins) || (ins == INS_crc32))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst = emitOutputCV(dst, id, code);
}
code); // encode source operand reg in 'vvvv' bits in 1's complement form
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputCV(dst, id, code);
}
code); // encode source operand reg in 'vvvv' bits in 1's complement form
// Special case 4-byte AVX instructions
- if (Is4ByteSSE4OrAVXInstruction(ins))
+ if (EncodedBySSE38orSSE3A(ins))
{
dst = emitOutputCV(dst, id, code, &cnsVal);
}
#define VEX3INT(c1,c2) PACK4(c1, 0xc5, 0x02, c2)
#define VEX3FLT(c1,c2) PACK4(c1, 0xc5, 0x02, c2)
-INST3(FIRST_SSE2_INSTRUCTION, "FIRST_SSE2_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
+INST3(FIRST_SSE_INSTRUCTION, "FIRST_SSE_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
// These are the SSE instructions used on x86
INST3(mov_i2xmm, "movd", IUM_WR, BAD_CODE, BAD_CODE, PCKDBL(0x6E), INS_FLAGS_None) // Move int reg to a xmm reg. reg1=xmm reg, reg2=int reg
INST3(mov_xmm2i, "movd", IUM_WR, BAD_CODE, BAD_CODE, PCKDBL(0x7E), INS_FLAGS_None) // Move xmm reg to an int reg. reg1=xmm reg, reg2=int reg
INST3(packssdw, "packssdw", IUM_WR, BAD_CODE, BAD_CODE, PCKDBL(0x6B), INS_Flags_IsDstDstSrcAVXInstruction) // Pack (narrow) int to short with saturation
INST3(packsswb, "packsswb", IUM_WR, BAD_CODE, BAD_CODE, PCKDBL(0x63), INS_Flags_IsDstDstSrcAVXInstruction) // Pack (narrow) short to byte with saturation
INST3(packuswb, "packuswb", IUM_WR, BAD_CODE, BAD_CODE, PCKDBL(0x67), INS_Flags_IsDstDstSrcAVXInstruction) // Pack (narrow) short to unsigned byte with saturation
-INST3(LAST_SSE2_INSTRUCTION, "LAST_SSE2_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
-INST3(FIRST_SSE4_INSTRUCTION, "FIRST_SSE4_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
// id nm um mr mi rm flags
INST3(dpps, "dpps", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x40), INS_Flags_IsDstDstSrcAVXInstruction) // Packed dot product of two float vector regs
INST3(dppd, "dppd", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0x41), INS_Flags_IsDstDstSrcAVXInstruction) // Packed dot product of two double vector regs
INST3(aesenclast, "aesenclast", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xDD), INS_Flags_IsDstDstSrcAVXInstruction) // Perform last round of an AES encryption flow
INST3(aesimc, "aesimc", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xDB), INS_FLAGS_None) // Perform the AES InvMixColumn Transformation
INST3(aeskeygenassist, "aeskeygenassist", IUM_WR, BAD_CODE, BAD_CODE, SSE3A(0xDF), INS_FLAGS_None) // AES Round Key Generation Assist
-INST3(LAST_SSE4_INSTRUCTION, "LAST_SSE4_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
+INST3(LAST_SSE_INSTRUCTION, "LAST_SSE_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
INST3(FIRST_AVX_INSTRUCTION, "FIRST_AVX_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None)
// AVX only instructions