Swapping around vec128 to match AVX order.
Was really hoping all this would fix some bugs, but no luck :(
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@ using alloy::runtime::ThreadState;
|
||||
static const size_t MAX_CODE_SIZE = 1 * 1024 * 1024;
|
||||
|
||||
static const size_t STASH_OFFSET = 32;
|
||||
static const size_t STASH_OFFSET_HIGH = 32 + 16;
|
||||
|
||||
// If we are running with tracing on we have to store the EFLAGS in the stack,
|
||||
// otherwise our calls out to C to print will clear it before DID_CARRY/etc
|
||||
@@ -786,8 +787,8 @@ void X64Emitter::MovMem64(const RegExp& addr, uint64_t v) {
|
||||
|
||||
Address X64Emitter::GetXmmConstPtr(XmmConst id) {
|
||||
static const vec128_t xmm_consts[] = {
|
||||
/* XMMZero */ vec128f(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
/* XMMOne */ vec128f(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
/* XMMZero */ vec128f(0.0f),
|
||||
/* XMMOne */ vec128f(1.0f),
|
||||
/* XMMNegativeOne */ vec128f(-1.0f, -1.0f, -1.0f, -1.0f),
|
||||
/* XMMMaskX16Y16 */ vec128i(0x0000FFFFu, 0xFFFF0000u,
|
||||
0x00000000u, 0x00000000u),
|
||||
@@ -808,14 +809,24 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
|
||||
0xFFFFFFFFu, 0x7FFFFFFFu),
|
||||
/* XMMByteSwapMask */ vec128i(0x00010203u, 0x04050607u,
|
||||
0x08090A0Bu, 0x0C0D0E0Fu),
|
||||
/* XMMPermuteControl15 */ vec128b(15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15),
|
||||
/* XMMPermuteControl15 */ vec128b(15),
|
||||
/* XMMPackD3DCOLOR */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
|
||||
0xFFFFFFFFu, 0x0C000408u),
|
||||
/* XMMUnpackD3DCOLOR */ vec128i(0xFFFFFF0Eu, 0xFFFFFF0Du,
|
||||
0xFFFFFF0Cu, 0xFFFFFF0Fu),
|
||||
/* XMMOneOver255 */ vec128f(1.0f / 255.0f, 1.0f / 255.0f,
|
||||
1.0f / 255.0f, 1.0f / 255.0f),
|
||||
/* XMMPackFLOAT16_2 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
|
||||
0xFFFFFFFFu, 0x01000302u),
|
||||
/* XMMUnpackFLOAT16_2 */ vec128i(0x0D0C0F0Eu, 0xFFFFFFFFu,
|
||||
0xFFFFFFFFu, 0xFFFFFFFFu),
|
||||
/* XMMPackFLOAT16_4 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
|
||||
0x05040706u, 0x01000302u),
|
||||
/* XMMUnpackFLOAT16_4 */ vec128i(0x09080B0Au, 0x0D0C0F0Eu,
|
||||
0xFFFFFFFFu, 0xFFFFFFFFu),
|
||||
/* XMMPackSHORT_2 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu,
|
||||
0xFFFFFFFFu, 0x01000504u),
|
||||
/* XMMUnpackSHORT_2 */ vec128i(0xFFFF0F0Eu, 0xFFFF0D0Cu,
|
||||
0xFFFFFFFFu, 0xFFFFFFFFu),
|
||||
/* XMMOneOver255 */ vec128f(1.0f / 255.0f),
|
||||
/* XMMMaskEvenPI16 */ vec128i(0x0000FFFFu, 0x0000FFFFu,
|
||||
0x0000FFFFu, 0x0000FFFFu),
|
||||
/* XMMShiftMaskEvenPI16 */ vec128i(0x0000000Fu, 0x0000000Fu,
|
||||
@@ -826,8 +837,8 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
|
||||
0x000000FFu, 0x000000FFu),
|
||||
/* XMMUnsignedDwordMax */ vec128i(0xFFFFFFFFu, 0x00000000u,
|
||||
0xFFFFFFFFu, 0x00000000u),
|
||||
/* XMM255 */ vec128f(255.0f, 255.0f, 255.0f, 255.0f),
|
||||
/* XMMPI32 */ vec128i(32, 32, 32, 32),
|
||||
/* XMM255 */ vec128f(255.0f),
|
||||
/* XMMPI32 */ vec128i(32),
|
||||
/* XMMSignMaskI8 */ vec128i(0x80808080u, 0x80808080u,
|
||||
0x80808080u, 0x80808080u),
|
||||
/* XMMSignMaskI16 */ vec128i(0x80008000u, 0x80008000u,
|
||||
@@ -836,6 +847,8 @@ Address X64Emitter::GetXmmConstPtr(XmmConst id) {
|
||||
0x80000000u, 0x80000000u),
|
||||
/* XMMSignMaskF32 */ vec128i(0x80000000u, 0x80000000u,
|
||||
0x80000000u, 0x80000000u),
|
||||
/* XMMShortMinPS */ vec128f(SHRT_MIN),
|
||||
/* XMMShortMaxPS */ vec128f(SHRT_MAX),
|
||||
};
|
||||
// TODO(benvanik): cache base pointer somewhere? stack? It'd be nice to
|
||||
// prevent this move.
|
||||
@@ -901,19 +914,12 @@ void X64Emitter::LoadConstantXmm(Xbyak::Xmm dest, double v) {
|
||||
}
|
||||
}
|
||||
|
||||
Address X64Emitter::StashXmm(const Xmm& r) {
|
||||
auto addr = ptr[rsp + STASH_OFFSET];
|
||||
Address X64Emitter::StashXmm(int index, const Xmm& r) {
|
||||
auto addr = ptr[rsp + STASH_OFFSET + (index * 16)];
|
||||
vmovups(addr, r);
|
||||
return addr;
|
||||
}
|
||||
|
||||
Address X64Emitter::StashXmm(const vec128_t& v) {
|
||||
auto addr = ptr[rsp + STASH_OFFSET];
|
||||
LoadConstantXmm(xmm0, v);
|
||||
vmovups(addr, xmm0);
|
||||
return addr;
|
||||
}
|
||||
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
@@ -56,6 +56,12 @@ enum XmmConst {
|
||||
XMMPermuteControl15,
|
||||
XMMPackD3DCOLOR,
|
||||
XMMUnpackD3DCOLOR,
|
||||
XMMPackFLOAT16_2,
|
||||
XMMUnpackFLOAT16_2,
|
||||
XMMPackFLOAT16_4,
|
||||
XMMUnpackFLOAT16_4,
|
||||
XMMPackSHORT_2,
|
||||
XMMUnpackSHORT_2,
|
||||
XMMOneOver255,
|
||||
XMMMaskEvenPI16,
|
||||
XMMShiftMaskEvenPI16,
|
||||
@@ -68,6 +74,8 @@ enum XmmConst {
|
||||
XMMSignMaskI16,
|
||||
XMMSignMaskI32,
|
||||
XMMSignMaskF32,
|
||||
XMMShortMinPS,
|
||||
XMMShortMaxPS,
|
||||
};
|
||||
|
||||
// Unfortunately due to the design of xbyak we have to pass this to the ctor.
|
||||
@@ -158,8 +166,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, float v);
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, double v);
|
||||
void LoadConstantXmm(Xbyak::Xmm dest, const vec128_t& v);
|
||||
Xbyak::Address StashXmm(const Xbyak::Xmm& r);
|
||||
Xbyak::Address StashXmm(const vec128_t& v);
|
||||
Xbyak::Address StashXmm(int index, const Xbyak::Xmm& r);
|
||||
|
||||
size_t stack_size() const { return stack_size_; }
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@ Value* CalculateEA_0(PPCHIRBuilder& f, uint32_t ra, uint32_t rb);
|
||||
// Most of this file comes from:
|
||||
// http://biallas.net/doc/vmx128/vmx128.txt
|
||||
// https://github.com/kakaroto/ps3ida/blob/master/plugins/PPCAltivec/src/main.cpp
|
||||
// http://sannybuilder.com/forums/viewtopic.php?id=190
|
||||
|
||||
#define OP(x) ((((uint32_t)(x)) & 0x3f) << 26)
|
||||
#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0))
|
||||
@@ -154,7 +155,7 @@ XEEMITTER(lvxl128, VX128_1(4, 707), VX128_1)(PPCHIRBuilder& f, InstrData& i) {
|
||||
|
||||
XEEMITTER(stvebx, 0x7C00010E, X)(PPCHIRBuilder& f, InstrData& i) {
|
||||
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
||||
Value* el = f.And(ea, f.LoadConstant(0xFull));
|
||||
Value* el = f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstant(uint8_t(0xF)));
|
||||
Value* v = f.Extract(f.LoadVR(i.X.RT), el, INT8_TYPE);
|
||||
f.Store(ea, v);
|
||||
return 0;
|
||||
@@ -163,7 +164,8 @@ XEEMITTER(stvebx, 0x7C00010E, X)(PPCHIRBuilder& f, InstrData& i) {
|
||||
XEEMITTER(stvehx, 0x7C00014E, X)(PPCHIRBuilder& f, InstrData& i) {
|
||||
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
||||
ea = f.And(ea, f.LoadConstant(~0x1ull));
|
||||
Value* el = f.Shr(f.And(ea, f.LoadConstant(0xFull)), 1);
|
||||
Value* el =
|
||||
f.Shr(f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstant(uint8_t(0xF))), 1);
|
||||
Value* v = f.Extract(f.LoadVR(i.X.RT), el, INT16_TYPE);
|
||||
f.Store(ea, f.ByteSwap(v));
|
||||
return 0;
|
||||
@@ -173,7 +175,8 @@ int InstrEmit_stvewx_(PPCHIRBuilder& f, InstrData& i, uint32_t vd, uint32_t ra,
|
||||
uint32_t rb) {
|
||||
Value* ea = CalculateEA_0(f, ra, rb);
|
||||
ea = f.And(ea, f.LoadConstant(~0x3ull));
|
||||
Value* el = f.Shr(f.And(ea, f.LoadConstant(0xFull)), 2);
|
||||
Value* el =
|
||||
f.Shr(f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstant(uint8_t(0xF))), 2);
|
||||
Value* v = f.Extract(f.LoadVR(vd), el, INT32_TYPE);
|
||||
f.Store(ea, f.ByteSwap(v));
|
||||
return 0;
|
||||
@@ -239,8 +242,8 @@ int InstrEmit_lvrx_(PPCHIRBuilder& f, InstrData& i, uint32_t vd, uint32_t ra,
|
||||
ea = f.And(ea, f.LoadConstant(~0xFull));
|
||||
// v = (new >> (16 - eb))
|
||||
Value* v = f.Permute(f.LoadVectorShr(f.Sub(f.LoadConstant((int8_t)16), eb)),
|
||||
f.LoadZero(VEC128_TYPE),
|
||||
f.ByteSwap(f.Load(ea, VEC128_TYPE)), INT8_TYPE);
|
||||
f.ByteSwap(f.Load(ea, VEC128_TYPE)),
|
||||
f.LoadZero(VEC128_TYPE), INT8_TYPE);
|
||||
f.StoreVR(vd, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -935,8 +938,8 @@ int InstrEmit_vmrghw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) {
|
||||
// (VD.y) = (VB.x)
|
||||
// (VD.z) = (VA.y)
|
||||
// (VD.w) = (VB.y)
|
||||
Value* v = f.Permute(f.LoadConstant(0x00040105), f.LoadVR(va), f.LoadVR(vb),
|
||||
INT32_TYPE);
|
||||
Value* v = f.Permute(f.LoadConstant(PERMUTE_MASK(0, 0, 1, 0, 0, 1, 1, 1)),
|
||||
f.LoadVR(va), f.LoadVR(vb), INT32_TYPE);
|
||||
f.StoreVR(vd, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -962,8 +965,8 @@ int InstrEmit_vmrglw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) {
|
||||
// (VD.y) = (VB.z)
|
||||
// (VD.z) = (VA.w)
|
||||
// (VD.w) = (VB.w)
|
||||
Value* v = f.Permute(f.LoadConstant(0x02060307), f.LoadVR(va), f.LoadVR(vb),
|
||||
INT32_TYPE);
|
||||
Value* v = f.Permute(f.LoadConstant(PERMUTE_MASK(0, 2, 1, 2, 0, 3, 1, 3)),
|
||||
f.LoadVR(va), f.LoadVR(vb), INT32_TYPE);
|
||||
f.StoreVR(vd, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -1140,7 +1143,8 @@ XEEMITTER(vpermwi128, VX128_P(6, 528), VX128_P)(PPCHIRBuilder& f,
|
||||
const uint32_t vd = i.VX128_P.VD128l | (i.VX128_P.VD128h << 5);
|
||||
const uint32_t vb = i.VX128_P.VB128l | (i.VX128_P.VB128h << 5);
|
||||
uint32_t uimm = i.VX128_P.PERMl | (i.VX128_P.PERMh << 5);
|
||||
Value* v = f.Swizzle(f.LoadVR(vb), INT32_TYPE, uimm);
|
||||
uint32_t mask = SWIZZLE_MASK(uimm >> 6, uimm >> 4, uimm >> 2, uimm >> 0);
|
||||
Value* v = f.Swizzle(f.LoadVR(vb), INT32_TYPE, mask);
|
||||
f.StoreVR(vd, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -1213,14 +1217,16 @@ XEEMITTER(vrfiz128, VX128_3(6, 1008), VX128_3)(PPCHIRBuilder& f, InstrData& i) {
|
||||
|
||||
XEEMITTER(vrlb, 0x10000004, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
// (VD) <- ROTL((VA), (VB)&0x3)
|
||||
Value* v = f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE);
|
||||
Value* v =
|
||||
f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE);
|
||||
f.StoreVR(i.VX.VD, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
XEEMITTER(vrlh, 0x10000044, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
// (VD) <- ROTL((VA), (VB)&0xF)
|
||||
Value* v = f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE);
|
||||
Value* v =
|
||||
f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE);
|
||||
f.StoreVR(i.VX.VD, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -1244,10 +1250,10 @@ XEEMITTER(vrlimi128, VX128_4(6, 1808), VX128_4)(PPCHIRBuilder& f,
|
||||
const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5);
|
||||
uint32_t blend_mask_src = i.VX128_4.IMM;
|
||||
uint32_t blend_mask = 0;
|
||||
for (int n = 3; n >= 0; n--) {
|
||||
blend_mask |= ((blend_mask_src & 0x1) ? n : (4 + n)) << ((3 - n) * 8);
|
||||
blend_mask_src >>= 1;
|
||||
}
|
||||
blend_mask |= (((blend_mask_src >> 3) & 0x1) ? 0 : 4) << 0;
|
||||
blend_mask |= (((blend_mask_src >> 2) & 0x1) ? 1 : 5) << 8;
|
||||
blend_mask |= (((blend_mask_src >> 1) & 0x1) ? 2 : 6) << 16;
|
||||
blend_mask |= (((blend_mask_src >> 0) & 0x1) ? 3 : 7) << 24;
|
||||
uint32_t rotate = i.VX128_4.z;
|
||||
// This is just a fancy permute.
|
||||
// X Y Z W, rotated left by 2 = Z W X Y
|
||||
@@ -1278,7 +1284,7 @@ XEEMITTER(vrlimi128, VX128_4(6, 1808), VX128_4)(PPCHIRBuilder& f,
|
||||
} else {
|
||||
v = f.LoadVR(vb);
|
||||
}
|
||||
if (blend_mask != 0x00010203) {
|
||||
if (blend_mask != PERMUTE_IDENTITY) {
|
||||
v = f.Permute(f.LoadConstant(blend_mask), v, f.LoadVR(vd), INT32_TYPE);
|
||||
}
|
||||
f.StoreVR(vd, v);
|
||||
@@ -1382,7 +1388,7 @@ int InstrEmit_vsldoi_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb,
|
||||
// (VA << SH) OR (VB >> (16 - SH))
|
||||
vec128_t shift = *((vec128_t*)(__vsldoi_table[sh]));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
shift.i4[i] = poly::byte_swap(shift.i4[i]);
|
||||
shift.u32[i] = poly::byte_swap(shift.u32[i]);
|
||||
}
|
||||
Value* control = f.LoadConstant(shift);
|
||||
Value* v = f.Permute(control, f.LoadVR(va), f.LoadVR(vb), INT8_TYPE);
|
||||
@@ -1410,7 +1416,7 @@ XEEMITTER(vspltb, 0x1000020C, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
// b <- UIMM*8
|
||||
// do i = 0 to 127 by 8
|
||||
// (VD)[i:i+7] <- (VB)[b:b+7]
|
||||
Value* b = f.Extract(f.LoadVR(i.VX.VB), (i.VX.VA & 0xF), INT8_TYPE);
|
||||
Value* b = f.Extract(f.LoadVR(i.VX.VB), i.VX.VA & 0xF, INT8_TYPE);
|
||||
Value* v = f.Splat(b, VEC128_TYPE);
|
||||
f.StoreVR(i.VX.VD, v);
|
||||
return 0;
|
||||
@@ -1418,7 +1424,7 @@ XEEMITTER(vspltb, 0x1000020C, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
|
||||
XEEMITTER(vsplth, 0x1000024C, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
// (VD.xyzw) <- (VB.uimm)
|
||||
Value* h = f.Extract(f.LoadVR(i.VX.VB), (i.VX.VA & 0x7), INT16_TYPE);
|
||||
Value* h = f.Extract(f.LoadVR(i.VX.VB), i.VX.VA & 0x7, INT16_TYPE);
|
||||
Value* v = f.Splat(h, VEC128_TYPE);
|
||||
f.StoreVR(i.VX.VD, v);
|
||||
return 0;
|
||||
@@ -1427,7 +1433,7 @@ XEEMITTER(vsplth, 0x1000024C, VX)(PPCHIRBuilder& f, InstrData& i) {
|
||||
int InstrEmit_vspltw_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb,
|
||||
uint32_t uimm) {
|
||||
// (VD.xyzw) <- (VB.uimm)
|
||||
Value* w = f.Extract(f.LoadVR(vb), (uimm & 0x3), INT32_TYPE);
|
||||
Value* w = f.Extract(f.LoadVR(vb), uimm & 0x3, INT32_TYPE);
|
||||
Value* v = f.Splat(w, VEC128_TYPE);
|
||||
f.StoreVR(vd, v);
|
||||
return 0;
|
||||
@@ -1856,8 +1862,8 @@ XEEMITTER(vpkd3d128, VX128_4(6, 1552), VX128_4)(PPCHIRBuilder& f,
|
||||
}
|
||||
// http://hlssmod.net/he_code/public/pixelwriter.h
|
||||
// control = prev:0123 | new:4567
|
||||
uint32_t control = 0x00010203; // original
|
||||
uint32_t src = xerotl(0x04050607, shift * 8);
|
||||
uint32_t control = PERMUTE_IDENTITY; // original
|
||||
uint32_t src = xerotl(0x07060504, shift * 8);
|
||||
uint32_t mask = 0;
|
||||
switch (pack) {
|
||||
case 1: // VPACK_32
|
||||
@@ -1870,8 +1876,8 @@ XEEMITTER(vpkd3d128, VX128_4(6, 1552), VX128_4)(PPCHIRBuilder& f,
|
||||
mask = 0x0000FFFF << (shift * 8);
|
||||
} else {
|
||||
// w
|
||||
src = 0x00000007;
|
||||
mask = 0x000000FF;
|
||||
src = 0x07000000;
|
||||
mask = 0xFF000000;
|
||||
}
|
||||
control = (control & ~mask) | (src & mask);
|
||||
break;
|
||||
@@ -1880,7 +1886,7 @@ XEEMITTER(vpkd3d128, VX128_4(6, 1552), VX128_4)(PPCHIRBuilder& f,
|
||||
mask = 0x0000FFFF << (shift * 8);
|
||||
} else {
|
||||
// z
|
||||
src = 0x00000006;
|
||||
src = 0x00000004;
|
||||
mask = 0x000000FF;
|
||||
}
|
||||
control = (control & ~mask) | (src & mask);
|
||||
|
||||
@@ -1072,7 +1072,7 @@ XEEMITTER(sradx, 0x7C000634, X)(PPCHIRBuilder& f, InstrData& i) {
|
||||
|
||||
Value* v = f.LoadGPR(i.X.RT);
|
||||
Value* sh = f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE),
|
||||
f.LoadConstant((int8_t)0x7F));
|
||||
f.LoadConstant((int8_t)0x3F));
|
||||
|
||||
// CA is set if any bits are shifted out of the right and if the result
|
||||
// is negative. Start tracking that here.
|
||||
@@ -1137,14 +1137,15 @@ XEEMITTER(srawx, 0x7C000630, X)(PPCHIRBuilder& f, InstrData& i) {
|
||||
// if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS)
|
||||
Value* v = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE);
|
||||
Value* sh =
|
||||
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE), f.LoadConstant(0x7F));
|
||||
f.And(f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE), f.LoadConstant(0x1F));
|
||||
// CA is set if any bits are shifted out of the right and if the result
|
||||
// is negative.
|
||||
Value* mask = f.Not(f.Shl(f.LoadConstant(-1), sh));
|
||||
Value* ca =
|
||||
f.And(f.Truncate(f.Shr(v, 31), INT8_TYPE), f.IsTrue(f.And(v, mask)));
|
||||
f.StoreCA(ca);
|
||||
v = f.Sha(v, sh), v = f.SignExtend(v, INT64_TYPE);
|
||||
v = f.Sha(v, sh);
|
||||
v = f.SignExtend(v, INT64_TYPE);
|
||||
f.StoreGPR(i.X.RA, v);
|
||||
if (i.X.Rc) {
|
||||
f.UpdateCR(0, v);
|
||||
|
||||
@@ -51,11 +51,14 @@ enum ArithmeticFlags {
|
||||
ARITHMETIC_UNSIGNED = (1 << 2),
|
||||
ARITHMETIC_SATURATE = (1 << 3),
|
||||
};
|
||||
#define PERMUTE_MASK(sel_x, x, sel_y, y, sel_z, z, sel_w, w) \
|
||||
((((x)&0x3) << 0) | (sel_x << 2) | (((y)&0x3) << 8) | (sel_y << 10) | \
|
||||
(((z)&0x3) << 16) | (sel_z << 18) | (((w)&0x3) << 24) | (sel_w << 26))
|
||||
enum Permutes {
|
||||
PERMUTE_XY_ZW = 0x00010405,
|
||||
PERMUTE_IDENTITY = PERMUTE_MASK(0, 0, 0, 1, 0, 2, 0, 3),
|
||||
};
|
||||
#define SWIZZLE_MASK(x, y, z, w) \
|
||||
((((x)&0x3) << 6) | (((y)&0x3) << 4) | (((z)&0x3) << 2) | (((w)&0x3)))
|
||||
((((x)&0x3) << 0) | (((y)&0x3) << 2) | (((z)&0x3) << 4) | (((w)&0x3) << 6))
|
||||
enum Swizzles {
|
||||
SWIZZLE_XYZW_TO_XYZW = SWIZZLE_MASK(0, 1, 2, 3),
|
||||
SWIZZLE_XYZW_TO_YZWX = SWIZZLE_MASK(1, 2, 3, 0),
|
||||
|
||||
@@ -582,7 +582,7 @@ void Value::ByteSwap() {
|
||||
break;
|
||||
case VEC128_TYPE:
|
||||
for (int n = 0; n < 4; n++) {
|
||||
constant.v128.i4[n] = poly::byte_swap(constant.v128.i4[n]);
|
||||
constant.v128.u32[n] = poly::byte_swap(constant.v128.u32[n]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -14,6 +14,58 @@
|
||||
|
||||
namespace alloy {
|
||||
|
||||
// The first rule of vector programming is to only rely on exact positions
|
||||
// when absolutely required - prefer dumb loops to exact offsets.
|
||||
// Vectors in memory are laid out as in AVX registers on little endian
|
||||
// machines. Note that little endian is dumb, so the byte at index 0 in
|
||||
// the vector is is really byte 15 (or the high byte of short 7 or int 3).
|
||||
// Because of this, all byte access should be via the accessors instead of
|
||||
// the direct array.
|
||||
|
||||
// Altivec big endian layout: AVX little endian layout:
|
||||
// +---------+---------+---------+ +---------+---------+---------+
|
||||
// | int32 0 | int16 0 | int8 0 | | int32 3 | int16 7 | int8 15 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 1 | | | | int8 14 |
|
||||
// | +---------+---------+ | +---------+---------+
|
||||
// | | int16 1 | int8 2 | | | int16 6 | int8 13 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 3 | | | | int8 12 |
|
||||
// +---------+---------+---------+ +---------+---------+---------+
|
||||
// | int32 1 | int16 2 | int8 4 | | int32 2 | int16 5 | int8 11 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 5 | | | | int8 10 |
|
||||
// | +---------+---------+ | +---------+---------+
|
||||
// | | int16 3 | int8 6 | | | int16 4 | int8 9 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 7 | | | | int8 8 |
|
||||
// +---------+---------+---------+ +---------+---------+---------+
|
||||
// | int32 2 | int16 4 | int8 8 | | int32 1 | int16 3 | int8 7 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 9 | | | | int8 6 |
|
||||
// | +---------+---------+ | +---------+---------+
|
||||
// | | int16 5 | int8 10 | | | int16 2 | int8 5 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 11 | | | | int8 4 |
|
||||
// +---------+---------+---------+ +---------+---------+---------+
|
||||
// | int32 3 | int16 6 | int8 12 | | int32 0 | int16 1 | int8 3 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 13 | | | | int8 2 |
|
||||
// | +---------+---------+ | +---------+---------+
|
||||
// | | int16 7 | int8 14 | | | int16 0 | int8 1 |
|
||||
// | | +---------+ | | +---------+
|
||||
// | | | int8 15 | | | | int8 0 |
|
||||
// +---------+---------+---------+ +---------+---------+---------+
|
||||
//
|
||||
// Logical order:
|
||||
// +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
// | X | Y | Z | W | | W | Z | Y | X |
|
||||
// +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
//
|
||||
// Mapping indices is easy:
|
||||
// int32[i ^ 0x3]
|
||||
// int16[i ^ 0x7]
|
||||
// int8[i ^ 0xF]
|
||||
typedef struct alignas(16) vec128_s {
|
||||
union {
|
||||
struct {
|
||||
@@ -23,15 +75,26 @@ typedef struct alignas(16) vec128_s {
|
||||
float w;
|
||||
};
|
||||
struct {
|
||||
uint32_t ix;
|
||||
uint32_t iy;
|
||||
uint32_t iz;
|
||||
uint32_t iw;
|
||||
int32_t ix;
|
||||
int32_t iy;
|
||||
int32_t iz;
|
||||
int32_t iw;
|
||||
};
|
||||
float f4[4];
|
||||
uint32_t i4[4];
|
||||
uint16_t s8[8];
|
||||
uint8_t b16[16];
|
||||
struct {
|
||||
uint32_t ux;
|
||||
uint32_t uy;
|
||||
uint32_t uz;
|
||||
uint32_t uw;
|
||||
};
|
||||
float f32[4];
|
||||
int8_t i8[16];
|
||||
uint8_t u8[16];
|
||||
int16_t i16[8];
|
||||
uint16_t u16[8];
|
||||
int32_t i32[4];
|
||||
uint32_t u32[4];
|
||||
int64_t i64[2];
|
||||
uint64_t u64[2];
|
||||
struct {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
@@ -42,40 +105,41 @@ typedef struct alignas(16) vec128_s {
|
||||
return low == b.low && high == b.high;
|
||||
}
|
||||
} vec128_t;
|
||||
|
||||
static inline vec128_t vec128i(uint32_t src) {
|
||||
vec128_t v;
|
||||
for (auto i = 0; i < 4; ++i) {
|
||||
v.i4[i] = src;
|
||||
v.u32[i] = src;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
static inline vec128_t vec128i(uint32_t x, uint32_t y, uint32_t z, uint32_t w) {
|
||||
vec128_t v;
|
||||
v.i4[0] = x;
|
||||
v.i4[1] = y;
|
||||
v.i4[2] = z;
|
||||
v.i4[3] = w;
|
||||
v.u32[0] = x;
|
||||
v.u32[1] = y;
|
||||
v.u32[2] = z;
|
||||
v.u32[3] = w;
|
||||
return v;
|
||||
}
|
||||
static inline vec128_t vec128f(float src) {
|
||||
vec128_t v;
|
||||
for (auto i = 0; i < 4; ++i) {
|
||||
v.f4[i] = src;
|
||||
v.f32[i] = src;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
static inline vec128_t vec128f(float x, float y, float z, float w) {
|
||||
vec128_t v;
|
||||
v.f4[0] = x;
|
||||
v.f4[1] = y;
|
||||
v.f4[2] = z;
|
||||
v.f4[3] = w;
|
||||
v.f32[0] = x;
|
||||
v.f32[1] = y;
|
||||
v.f32[2] = z;
|
||||
v.f32[3] = w;
|
||||
return v;
|
||||
}
|
||||
static inline vec128_t vec128s(uint16_t src) {
|
||||
vec128_t v;
|
||||
for (auto i = 0; i < 8; ++i) {
|
||||
v.s8[i] = src;
|
||||
v.u16[i] = src;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -83,20 +147,20 @@ static inline vec128_t vec128s(uint16_t x0, uint16_t x1, uint16_t y0,
|
||||
uint16_t y1, uint16_t z0, uint16_t z1,
|
||||
uint16_t w0, uint16_t w1) {
|
||||
vec128_t v;
|
||||
v.s8[0] = x0;
|
||||
v.s8[1] = x1;
|
||||
v.s8[2] = y0;
|
||||
v.s8[3] = y1;
|
||||
v.s8[4] = z0;
|
||||
v.s8[5] = z1;
|
||||
v.s8[6] = w0;
|
||||
v.s8[7] = w1;
|
||||
v.u16[0] = x1;
|
||||
v.u16[1] = x0;
|
||||
v.u16[2] = y1;
|
||||
v.u16[3] = y0;
|
||||
v.u16[4] = z1;
|
||||
v.u16[5] = z0;
|
||||
v.u16[6] = w1;
|
||||
v.u16[7] = w0;
|
||||
return v;
|
||||
}
|
||||
static inline vec128_t vec128b(uint8_t src) {
|
||||
vec128_t v;
|
||||
for (auto i = 0; i < 16; ++i) {
|
||||
v.b16[i] = src;
|
||||
v.u8[i] = src;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -105,22 +169,22 @@ static inline vec128_t vec128b(uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3,
|
||||
uint8_t z0, uint8_t z1, uint8_t z2, uint8_t z3,
|
||||
uint8_t w0, uint8_t w1, uint8_t w2, uint8_t w3) {
|
||||
vec128_t v;
|
||||
v.b16[0] = x3;
|
||||
v.b16[1] = x2;
|
||||
v.b16[2] = x1;
|
||||
v.b16[3] = x0;
|
||||
v.b16[4] = y3;
|
||||
v.b16[5] = y2;
|
||||
v.b16[6] = y1;
|
||||
v.b16[7] = y0;
|
||||
v.b16[8] = z3;
|
||||
v.b16[9] = z2;
|
||||
v.b16[10] = z1;
|
||||
v.b16[11] = z0;
|
||||
v.b16[12] = w3;
|
||||
v.b16[13] = w2;
|
||||
v.b16[14] = w1;
|
||||
v.b16[15] = w0;
|
||||
v.u8[0] = x3;
|
||||
v.u8[1] = x2;
|
||||
v.u8[2] = x1;
|
||||
v.u8[3] = x0;
|
||||
v.u8[4] = y3;
|
||||
v.u8[5] = y2;
|
||||
v.u8[6] = y1;
|
||||
v.u8[7] = y0;
|
||||
v.u8[8] = z3;
|
||||
v.u8[9] = z2;
|
||||
v.u8[10] = z1;
|
||||
v.u8[11] = z0;
|
||||
v.u8[12] = w3;
|
||||
v.u8[13] = w2;
|
||||
v.u8[14] = w1;
|
||||
v.u8[15] = w0;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
@@ -38,6 +39,10 @@ T round_up(T value, V multiple) {
|
||||
return value + multiple - 1 - (value - 1) % multiple;
|
||||
}
|
||||
|
||||
inline float saturate(float value) {
|
||||
return std::max(std::min(1.0f, value), -1.0f);
|
||||
}
|
||||
|
||||
// Gets the next power of two value that is greater than or equal to the given
|
||||
// value.
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user