Fixing totally broken vpkd3d128 and adding new pack instructions.

This commit is contained in:
Ben Vanik
2014-11-02 21:49:39 -08:00
parent 32f42cd5ae
commit 96c203699d
21 changed files with 643 additions and 126 deletions

View File

@@ -801,6 +801,7 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
1.0f / 32767.0f, 1.0f / (32767.0f * 65536.0f), 0.0f, 0.0f),
/* XMM0001 */ vec128f(0.0f, 0.0f, 0.0f, 1.0f),
/* XMM3301 */ vec128f(3.0f, 3.0f, 0.0f, 1.0f),
/* XMM3333 */ vec128f(3.0f, 3.0f, 3.0f, 3.0f),
/* XMMSignMaskPS */ vec128i(0x80000000u, 0x80000000u,
0x80000000u, 0x80000000u),
/* XMMSignMaskPD */ vec128i(0x00000000u, 0x80000000u,
@@ -811,7 +812,10 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
0xFFFFFFFFu, 0x7FFFFFFFu),
/* XMMByteSwapMask */ vec128i(0x00010203u, 0x04050607u,
0x08090A0Bu, 0x0C0D0E0Fu),
/* XMMByteOrderMask */ vec128i(0x01000302u, 0x05040706u,
0x09080B0Au, 0x0D0C0F0Eu),
/* XMMPermuteControl15 */ vec128b(15),
/* XMMPackD3DCOLORSat */ vec128i(0x404000FFu),
/* XMMPackD3DCOLOR */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
0xFFFFFFFFu, 0x0C000408u),
/* XMMUnpackD3DCOLOR */ vec128i(0xFFFFFF0Eu, 0xFFFFFF0Du,
@@ -824,6 +828,8 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
0x05040706u, 0x01000302u),
/* XMMUnpackFLOAT16_4 */ vec128i(0x09080B0Au, 0x0D0C0F0Eu,
0xFFFFFFFFu, 0xFFFFFFFFu),
/* XMMPackSHORT_2Min */ vec128i(0x403F8001u),
/* XMMPackSHORT_2Max */ vec128i(0x40407FFFu),
/* XMMPackSHORT_2 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
0xFFFFFFFFu, 0x01000504u),
/* XMMUnpackSHORT_2 */ vec128i(0xFFFF0F0Eu, 0xFFFF0D0Cu,

View File

@@ -49,18 +49,23 @@ enum XmmConst {
XMMNormalizeX16Y16,
XMM0001,
XMM3301,
XMM3333,
XMMSignMaskPS,
XMMSignMaskPD,
XMMAbsMaskPS,
XMMAbsMaskPD,
XMMByteSwapMask,
XMMByteOrderMask,
XMMPermuteControl15,
XMMPackD3DCOLORSat,
XMMPackD3DCOLOR,
XMMUnpackD3DCOLOR,
XMMPackFLOAT16_2,
XMMUnpackFLOAT16_2,
XMMPackFLOAT16_4,
XMMUnpackFLOAT16_4,
XMMPackSHORT_2Min,
XMMPackSHORT_2Max,
XMMPackSHORT_2,
XMMUnpackSHORT_2,
XMMOneOver255,

View File

@@ -5080,9 +5080,9 @@ EMITTER_OPCODE_TABLE(
// ============================================================================
// OPCODE_PACK
// ============================================================================
EMITTER(PACK, MATCH(I<OPCODE_PACK, V128<>, V128<>>)) {
EMITTER(PACK, MATCH(I<OPCODE_PACK, V128<>, V128<>, V128<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
switch (i.instr->flags) {
switch (i.instr->flags & PACK_TYPE_MODE) {
case PACK_TYPE_D3DCOLOR:
EmitD3DCOLOR(e, i);
break;
@@ -5095,33 +5095,34 @@ EMITTER(PACK, MATCH(I<OPCODE_PACK, V128<>, V128<>>)) {
case PACK_TYPE_SHORT_2:
EmitSHORT_2(e, i);
break;
case PACK_TYPE_S8_IN_16_LO:
EmitS8_IN_16_LO(e, i);
case PACK_TYPE_8_IN_16:
Emit8_IN_16(e, i, i.instr->flags);
break;
case PACK_TYPE_S8_IN_16_HI:
EmitS8_IN_16_HI(e, i);
break;
case PACK_TYPE_S16_IN_32_LO:
EmitS16_IN_32_LO(e, i);
break;
case PACK_TYPE_S16_IN_32_HI:
EmitS16_IN_32_HI(e, i);
case PACK_TYPE_16_IN_32:
Emit16_IN_32(e, i, i.instr->flags);
break;
default: assert_unhandled_case(i.instr->flags); break;
}
}
static void EmitD3DCOLOR(X64Emitter& e, const EmitArgType& i) {
assert_true(i.src2.value->IsConstantZero());
// Saturate to [3,3....] so that only values between 3...[00] and 3...[FF]
// are valid.
if (i.src1.is_constant) {
e.LoadConstantXmm(i.dest, i.src1.constant());
e.vminps(i.dest, i.dest, e.GetXmmConstPtr(XMMPackD3DCOLORSat));
} else {
e.vminps(i.dest, i.src1, e.GetXmmConstPtr(XMMPackD3DCOLORSat));
}
e.vmaxps(i.dest, i.dest, e.GetXmmConstPtr(XMM3333));
// Extract bytes.
// RGBA (XYZW) -> ARGB (WXYZ)
// w = ((src1.uw & 0xFF) << 24) | ((src1.ux & 0xFF) << 16) |
// ((src1.uy & 0xFF) << 8) | (src1.uz & 0xFF)
if (i.src1.is_constant) {
e.LoadConstantXmm(i.dest, i.src1.constant());
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackD3DCOLOR));
} else {
e.vpshufb(i.dest, i.src1, e.GetXmmConstPtr(XMMPackD3DCOLOR));
}
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackD3DCOLOR));
}
static void EmitFLOAT16_2(X64Emitter& e, const EmitArgType& i) {
assert_true(i.src2.value->IsConstantZero());
// http://blogs.msdn.com/b/chuckw/archive/2012/09/11/directxmath-f16c-and-fma.aspx
// dest = [(src1.x | src1.y), 0, 0, 0]
// 0|0|0|0|W|Z|Y|X
@@ -5130,34 +5131,112 @@ EMITTER(PACK, MATCH(I<OPCODE_PACK, V128<>, V128<>>)) {
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackFLOAT16_2));
}
static void EmitFLOAT16_4(X64Emitter& e, const EmitArgType& i) {
assert_true(i.src2.value->IsConstantZero());
// dest = [(src1.x | src1.y), (src1.z | src1.w), 0, 0]
// 0|0|0|0|W|Z|Y|X
e.vcvtps2ph(e.xmm0, i.src1, B00000011);
e.vcvtps2ph(i.dest, i.src1, B00000011);
// Shuffle to X|Y|Z|W|0|0|0|0
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackFLOAT16_4));
}
static void EmitSHORT_2(X64Emitter& e, const EmitArgType& i) {
assert_true(i.src2.value->IsConstantZero());
// Saturate.
e.vmaxps(i.dest, i.src1, e.GetXmmConstPtr(XMMNegativeOne));
e.vminps(i.dest, i.dest, e.GetXmmConstPtr(XMMOne));
// Multiply by SHRT_MAX.
e.vmulps(i.dest, i.dest, e.GetXmmConstPtr(XMMShortMaxPS));
// Convert to int32.
e.vcvtps2dq(i.dest, i.dest);
e.vmaxps(i.dest, i.src1, e.GetXmmConstPtr(XMMPackSHORT_2Min));
e.vminps(i.dest, i.dest, e.GetXmmConstPtr(XMMPackSHORT_2Max));
// Pack.
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackSHORT_2));
}
static void EmitS8_IN_16_LO(X64Emitter& e, const EmitArgType& i) {
assert_always();
static void Emit8_IN_16(X64Emitter& e, const EmitArgType& i, uint32_t flags) {
// TODO(benvanik): handle src2 (or src1) being constant zero
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
if (IsPackOutSaturate(flags)) {
// unsigned -> unsigned + saturate
assert_always();
} else {
// unsigned -> unsigned
assert_always();
}
} else {
if (IsPackOutSaturate(flags)) {
// unsigned -> signed + saturate
assert_always();
} else {
// unsigned -> signed
assert_always();
}
}
} else {
if (IsPackOutUnsigned(flags)) {
if (IsPackOutSaturate(flags)) {
// signed -> unsigned + saturate
// PACKUSWB / SaturateSignedWordToUnsignedByte
e.vpackuswb(i.dest, i.src1, i.src2);
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMByteOrderMask));
} else {
// signed -> unsigned
assert_always();
}
} else {
if (IsPackOutSaturate(flags)) {
// signed -> signed + saturate
// PACKSSWB / SaturateSignedWordToSignedByte
e.vpacksswb(i.dest, i.src1, i.src2);
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMByteOrderMask));
} else {
// signed -> signed
assert_always();
}
}
}
}
static void EmitS8_IN_16_HI(X64Emitter& e, const EmitArgType& i) {
assert_always();
}
static void EmitS16_IN_32_LO(X64Emitter& e, const EmitArgType& i) {
assert_always();
}
static void EmitS16_IN_32_HI(X64Emitter& e, const EmitArgType& i) {
assert_always();
static void Emit16_IN_32(X64Emitter& e, const EmitArgType& i, uint32_t flags) {
// TODO(benvanik): handle src2 (or src1) being constant zero
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
if (IsPackOutSaturate(flags)) {
// unsigned -> unsigned + saturate
assert_always();
} else {
// unsigned -> unsigned
assert_always();
}
} else {
if (IsPackOutSaturate(flags)) {
// unsigned -> signed + saturate
assert_always();
} else {
// unsigned -> signed
assert_always();
}
}
} else {
if (IsPackOutUnsigned(flags)) {
if (IsPackOutSaturate(flags)) {
// signed -> unsigned + saturate
// PACKUSDW
// TMP[15:0] <- (DEST[31:0] < 0) ? 0 : DEST[15:0];
// DEST[15:0] <- (DEST[31:0] > FFFFH) ? FFFFH : TMP[15:0];
e.vpackusdw(i.dest, i.src1, i.src2);
e.vpshuflw(i.dest, i.dest, B10110001);
e.vpshufhw(i.dest, i.dest, B10110001);
} else {
// signed -> unsigned
assert_always();
}
} else {
if (IsPackOutSaturate(flags)) {
// signed -> signed + saturate
// PACKSSDW / SaturateSignedDwordToSignedWord
e.vpackssdw(i.dest, i.src1, i.src2);
e.vpshuflw(i.dest, i.dest, B10110001);
e.vpshufhw(i.dest, i.dest, B10110001);
} else {
// signed -> signed
assert_always();
}
}
}
}
};
EMITTER_OPCODE_TABLE(
@@ -5170,7 +5249,7 @@ EMITTER_OPCODE_TABLE(
// ============================================================================
EMITTER(UNPACK, MATCH(I<OPCODE_UNPACK, V128<>, V128<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {
switch (i.instr->flags) {
switch (i.instr->flags & PACK_TYPE_MODE) {
case PACK_TYPE_D3DCOLOR:
EmitD3DCOLOR(e, i);
break;
@@ -5183,17 +5262,11 @@ EMITTER(UNPACK, MATCH(I<OPCODE_UNPACK, V128<>, V128<>>)) {
case PACK_TYPE_SHORT_2:
EmitSHORT_2(e, i);
break;
case PACK_TYPE_S8_IN_16_LO:
EmitS8_IN_16_LO(e, i);
case PACK_TYPE_8_IN_16:
Emit8_IN_16(e, i, i.instr->flags);
break;
case PACK_TYPE_S8_IN_16_HI:
EmitS8_IN_16_HI(e, i);
break;
case PACK_TYPE_S16_IN_32_LO:
EmitS16_IN_32_LO(e, i);
break;
case PACK_TYPE_S16_IN_32_HI:
EmitS16_IN_32_HI(e, i);
case PACK_TYPE_16_IN_32:
Emit16_IN_32(e, i, i.instr->flags);
break;
default: assert_unhandled_case(i.instr->flags); break;
}
@@ -5271,21 +5344,93 @@ EMITTER(UNPACK, MATCH(I<OPCODE_UNPACK, V128<>, V128<>>)) {
// Add 3,3,0,1.
e.vpor(i.dest, e.GetXmmConstPtr(XMM3301));
}
static void EmitS8_IN_16_LO(X64Emitter& e, const EmitArgType& i) {
e.vpunpckhbw(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 8);
static void Emit8_IN_16(X64Emitter& e, const EmitArgType& i, uint32_t flags) {
assert_false(IsPackOutSaturate(flags));
if (IsPackToLo(flags)) {
// Unpack to LO.
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
// unsigned -> unsigned
assert_always();
} else {
// unsigned -> signed
assert_always();
}
} else {
if (IsPackOutUnsigned(flags)) {
// signed -> unsigned
assert_always();
} else {
// signed -> signed
e.vpunpckhbw(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 8);
}
}
} else {
// Unpack to HI.
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
// unsigned -> unsigned
assert_always();
} else {
// unsigned -> signed
assert_always();
}
} else {
if (IsPackOutUnsigned(flags)) {
// signed -> unsigned
assert_always();
} else {
// signed -> signed
e.vpunpcklbw(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 8);
}
}
}
}
static void EmitS8_IN_16_HI(X64Emitter& e, const EmitArgType& i) {
e.vpunpcklbw(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 8);
}
static void EmitS16_IN_32_LO(X64Emitter& e, const EmitArgType& i) {
e.vpunpckhwd(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 16);
}
static void EmitS16_IN_32_HI(X64Emitter& e, const EmitArgType& i) {
e.vpunpcklwd(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 16);
static void Emit16_IN_32(X64Emitter& e, const EmitArgType& i, uint32_t flags) {
assert_false(IsPackOutSaturate(flags));
if (IsPackToLo(flags)) {
// Unpack to LO.
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
// unsigned -> unsigned
assert_always();
} else {
// unsigned -> signed
assert_always();
}
} else {
if (IsPackOutUnsigned(flags)) {
// signed -> unsigned
assert_always();
} else {
// signed -> signed
e.vpunpckhwd(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 16);
}
}
} else {
// Unpack to HI.
if (IsPackInUnsigned(flags)) {
if (IsPackOutUnsigned(flags)) {
// unsigned -> unsigned
assert_always();
} else {
// unsigned -> signed
assert_always();
}
} else {
if (IsPackOutUnsigned(flags)) {
// signed -> unsigned
assert_always();
} else {
// signed -> signed
e.vpunpcklwd(i.dest, i.src1, i.src1);
e.vpsrad(i.dest, 16);
}
}
}
}
};
EMITTER_OPCODE_TABLE(