mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[A64/Vector] Gate pack ordering on Windows ARM64
- Swap src ordering for XT(N)/UQXTN/SQXTN/SQXTUN on _WIN32 - Add UMIN saturation before 32->16 unsigned packing - Keep non-Windows path matching existing macOS/Linux ordering
This commit is contained in:
@@ -1702,18 +1702,31 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
if (i.src2.is_constant) {
|
||||
e.LoadConstantV(src2, i.src2.constant());
|
||||
}
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
// macOS works with src1->src2 without EXT
|
||||
#ifdef _WIN32
|
||||
e.UQXTN(i.dest.reg().toD().B8(), src2.H8());
|
||||
e.UQXTN2(i.dest.reg().B16(), src1.H8());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.UQXTN(i.dest.reg().toD().B8(), src1.H8());
|
||||
e.UQXTN2(i.dest.reg().B16(), src2.H8());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// unsigned -> unsigned
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.XTN(i.dest.reg().toD().B8(), i.src2.reg().H8());
|
||||
e.XTN2(i.dest.reg().B16(), i.src1.reg().H8());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.XTN(i.dest.reg().toD().B8(), i.src1.reg().H8());
|
||||
e.XTN2(i.dest.reg().B16(), i.src2.reg().H8());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (IsPackOutSaturate(flags)) {
|
||||
@@ -1738,11 +1751,17 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
e.LoadConstantV(src2, i.src2.constant());
|
||||
}
|
||||
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.SQXTUN(i.dest.reg().toD().B8(), src2.H8());
|
||||
e.SQXTUN2(i.dest.reg().B16(), src1.H8());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.SQXTUN(i.dest.reg().toD().B8(), src1.H8());
|
||||
e.SQXTUN2(i.dest.reg().B16(), src2.H8());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// signed -> unsigned
|
||||
assert_always();
|
||||
@@ -1750,11 +1769,17 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
} else {
|
||||
if (IsPackOutSaturate(flags)) {
|
||||
// signed -> signed + saturate
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.SQXTN(i.dest.reg().toD().B8(), i.src2.reg().H8());
|
||||
e.SQXTN2(i.dest.reg().B16(), i.src1.reg().H8());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.SQXTN(i.dest.reg().toD().B8(), i.src1.reg().H8());
|
||||
e.SQXTN2(i.dest.reg().B16(), i.src2.reg().H8());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// signed -> signed
|
||||
assert_always();
|
||||
@@ -1780,18 +1805,40 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
e.LoadConstantV(src2, i.src2.constant());
|
||||
}
|
||||
|
||||
e.UQXTN(i.dest.reg().toD().H4(), src2.S4());
|
||||
e.UQXTN2(i.dest.reg().H8(), src1.S4());
|
||||
// Create saturation limit: 0xFFFF in all lanes
|
||||
e.MOV(W0, 0xFFFF);
|
||||
e.DUP(Q2.S4(), W0);
|
||||
|
||||
// Saturate both sources
|
||||
e.UMIN(Q0.S4(), src1.S4(), Q2.S4()); // Saturate src1 (v3)
|
||||
e.UMIN(Q1.S4(), src2.S4(), Q2.S4()); // Saturate src2 (v4)
|
||||
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.UQXTN(i.dest.reg().toD().H4(),
|
||||
Q1.S4()); // Pack src2 to lower 64 bits
|
||||
e.UQXTN2(i.dest.reg().H8(), Q0.S4()); // Pack src1 to upper 64 bits
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.UQXTN(i.dest.reg().toD().H4(),
|
||||
Q0.S4()); // Pack src1 to lower 64 bits
|
||||
e.UQXTN2(i.dest.reg().H8(), Q1.S4()); // Pack src2 to upper 64 bits
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// unsigned -> unsigned
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.XTN(i.dest.reg().toD().H4(), i.src2.reg().S4());
|
||||
e.XTN2(i.dest.reg().H8(), i.src1.reg().S4());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.XTN(i.dest.reg().toD().H4(), i.src1.reg().S4());
|
||||
e.XTN2(i.dest.reg().H8(), i.src2.reg().S4());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (IsPackOutSaturate(flags)) {
|
||||
@@ -1806,11 +1853,17 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
if (IsPackOutUnsigned(flags)) {
|
||||
if (IsPackOutSaturate(flags)) {
|
||||
// signed -> unsigned + saturate
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.SQXTUN(i.dest.reg().toD().H4(), i.src2.reg().S4());
|
||||
e.SQXTUN2(i.dest.reg().H8(), i.src1.reg().S4());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.SQXTUN(i.dest.reg().toD().H4(), i.src1.reg().S4());
|
||||
e.SQXTUN2(i.dest.reg().H8(), i.src2.reg().S4());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// signed -> unsigned
|
||||
assert_always();
|
||||
@@ -1827,11 +1880,17 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
|
||||
if (i.src2.is_constant) {
|
||||
e.LoadConstantV(src2, i.src2.constant());
|
||||
}
|
||||
// Windows ARM64 requires src2->src1 ordering with EXT swap
|
||||
#ifdef _WIN32
|
||||
e.SQXTN(i.dest.reg().toD().H4(), src2.S4());
|
||||
e.SQXTN2(i.dest.reg().H8(), src1.S4());
|
||||
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
e.EXT(i.dest.reg().B16(), i.dest.reg().B16(), i.dest.reg().B16(), 8);
|
||||
#else
|
||||
e.SQXTN(i.dest.reg().toD().H4(), src1.S4());
|
||||
e.SQXTN2(i.dest.reg().H8(), src2.S4());
|
||||
e.REV32(i.dest.reg().H8(), i.dest.reg().H8());
|
||||
#endif
|
||||
} else {
|
||||
// signed -> signed
|
||||
assert_always();
|
||||
|
||||
Reference in New Issue
Block a user