mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
Merge pull request #2074 from lioncash/vuxtl
IR: Handle 256-bit VUXTL/VUXTL2
This commit is contained in:
4 files changed
+191
-58
No files matched your search
@@ -1784,40 +1784,46 @@ DEF_OP(VSXTL2) {
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
void *Src = GetSrc<void*>(Data->SSAData, Op->Vector);
|
||||
uint8_t Tmp[16]{};
|
||||
uint8_t Tmp[Core::CPUState::XMM_AVX_REG_SIZE]{};
|
||||
|
||||
const uint8_t Elements = OpSize / Op->Header.ElementSize;
|
||||
const uint8_t ElementSize = Op->Header.ElementSize;
|
||||
const uint8_t Elements = OpSize / ElementSize;
|
||||
const auto Func = [](auto a, auto min, auto max) { return a; };
|
||||
|
||||
switch (Op->Header.ElementSize) {
|
||||
switch (ElementSize) {
|
||||
DO_VECTOR_1SRC_2TYPE_OP(2, uint16_t, uint8_t, Func, 0, 0)
|
||||
DO_VECTOR_1SRC_2TYPE_OP(4, uint32_t, uint16_t, Func, 0, 0)
|
||||
DO_VECTOR_1SRC_2TYPE_OP(8, uint64_t, uint32_t, Func, 0, 0)
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize); break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
memcpy(GDP, Tmp, OpSize);
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL2) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
void *Src = GetSrc<void*>(Data->SSAData, Op->Vector);
|
||||
|
||||
uint8_t Tmp[16];
|
||||
uint8_t Tmp[Core::CPUState::XMM_AVX_REG_SIZE]{};
|
||||
|
||||
const uint8_t Elements = OpSize / Op->Header.ElementSize;
|
||||
const uint8_t ElementSize = Op->Header.ElementSize;
|
||||
const uint8_t Elements = OpSize / ElementSize;
|
||||
const auto Func = [](auto a, auto min, auto max) { return a; };
|
||||
|
||||
switch (Op->Header.ElementSize) {
|
||||
switch (ElementSize) {
|
||||
DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(2, uint16_t, uint8_t, Func, 0, 0)
|
||||
DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(4, uint32_t, uint16_t, Func, 0, 0)
|
||||
DO_VECTOR_1SRC_2TYPE_OP_TOP_SRC(8, uint64_t, uint32_t, Func, 0, 0)
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize); break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
memcpy(GDP, Tmp, OpSize);
|
||||
}
|
||||
|
||||
+101
-24
@@ -4155,34 +4155,111 @@ DEF_OP(VSXTL2) {
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 2:
|
||||
uxtl(GetDst(Node).V8H(), GetSrc(Op->Vector.ID()).V8B());
|
||||
break;
|
||||
case 4:
|
||||
uxtl(GetDst(Node).V4S(), GetSrc(Op->Vector.ID()).V4H());
|
||||
break;
|
||||
case 8:
|
||||
uxtl(GetDst(Node).V2D(), GetSrc(Op->Vector.ID()).V2S());
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize);
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
const auto ElementSize = Op->Header.ElementSize;
|
||||
const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
|
||||
const auto Dst = GetDst(Node);
|
||||
const auto Vector = GetSrc(Op->Vector.ID());
|
||||
|
||||
if (HostSupportsSVE && Is256Bit) {
|
||||
// NOTE: See VSXTL implementation for an explanation on why
|
||||
// UXTB/UXTH/UXTW aren't used, since the same behavior
|
||||
// concerns applies here, but with zero-extension
|
||||
// instead of sign-extension.
|
||||
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
ushllb(VTMP1.Z().VnH(), Vector.Z().VnB(), 0);
|
||||
ushllt(VTMP2.Z().VnH(), Vector.Z().VnB(), 0);
|
||||
zip1(Dst.Z().VnH(), VTMP1.Z().VnH(), VTMP2.Z().VnH());
|
||||
break;
|
||||
case 4:
|
||||
ushllb(VTMP1.Z().VnS(), Vector.Z().VnH(), 0);
|
||||
ushllt(VTMP2.Z().VnS(), Vector.Z().VnH(), 0);
|
||||
zip1(Dst.Z().VnS(), VTMP1.Z().VnS(), VTMP2.Z().VnS());
|
||||
break;
|
||||
case 8:
|
||||
ushllb(VTMP1.Z().VnD(), Vector.Z().VnS(), 0);
|
||||
ushllt(VTMP2.Z().VnD(), Vector.Z().VnS(), 0);
|
||||
zip1(Dst.Z().VnD(), VTMP1.Z().VnD(), VTMP2.Z().VnD());
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
uxtl(Dst.V8H(), Vector.V8B());
|
||||
break;
|
||||
case 4:
|
||||
uxtl(Dst.V4S(), Vector.V4H());
|
||||
break;
|
||||
case 8:
|
||||
uxtl(Dst.V2D(), Vector.V2S());
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL2) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 2:
|
||||
uxtl2(GetDst(Node).V8H(), GetSrc(Op->Vector.ID()).V16B());
|
||||
break;
|
||||
case 4:
|
||||
uxtl2(GetDst(Node).V4S(), GetSrc(Op->Vector.ID()).V8H());
|
||||
break;
|
||||
case 8:
|
||||
uxtl2(GetDst(Node).V2D(), GetSrc(Op->Vector.ID()).V4S());
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize);
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
const auto ElementSize = Op->Header.ElementSize;
|
||||
const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
|
||||
const auto Dst = GetDst(Node);
|
||||
const auto Vector = GetSrc(Op->Vector.ID());
|
||||
|
||||
if (HostSupportsSVE && Is256Bit) {
|
||||
// NOTE: See VSXTL implementation for an explanation on why
|
||||
// UXTB/UXTH/UXTW aren't used, since the same behavior
|
||||
// concerns applies here, but with zero-extension
|
||||
// instead of sign-extension.
|
||||
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
ushllb(VTMP1.Z().VnH(), Vector.Z().VnB(), 0);
|
||||
ushllt(VTMP2.Z().VnH(), Vector.Z().VnB(), 0);
|
||||
zip2(Dst.Z().VnH(), VTMP1.Z().VnH(), VTMP2.Z().VnH());
|
||||
break;
|
||||
case 4:
|
||||
ushllb(VTMP1.Z().VnS(), Vector.Z().VnH(), 0);
|
||||
ushllt(VTMP2.Z().VnS(), Vector.Z().VnH(), 0);
|
||||
zip2(Dst.Z().VnS(), VTMP1.Z().VnS(), VTMP2.Z().VnS());
|
||||
break;
|
||||
case 8:
|
||||
ushllb(VTMP1.Z().VnD(), Vector.Z().VnS(), 0);
|
||||
ushllt(VTMP2.Z().VnD(), Vector.Z().VnS(), 0);
|
||||
zip2(Dst.Z().VnD(), VTMP1.Z().VnD(), VTMP2.Z().VnD());
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
uxtl2(Dst.V8H(), Vector.V16B());
|
||||
break;
|
||||
case 4:
|
||||
uxtl2(Dst.V4S(), Vector.V8H());
|
||||
break;
|
||||
case 8:
|
||||
uxtl2(Dst.V2D(), Vector.V4S());
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+73
-23
@@ -2353,37 +2353,87 @@ DEF_OP(VSXTL2) {
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
switch (Op->Header.ElementSize) {
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
const auto ElementSize = Op->Header.ElementSize;
|
||||
const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
|
||||
const auto Dst = GetDst(Node);
|
||||
const auto Vector = GetSrc(Op->Vector.ID());
|
||||
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
pmovzxbw(GetDst(Node), GetSrc(Op->Vector.ID()));
|
||||
break;
|
||||
if (Is256Bit) {
|
||||
vpmovzxbw(ToYMM(Dst), Vector);
|
||||
} else {
|
||||
vpmovzxbw(Dst, Vector);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
pmovzxwd(GetDst(Node), GetSrc(Op->Vector.ID()));
|
||||
break;
|
||||
if (Is256Bit) {
|
||||
vpmovzxwd(ToYMM(Dst), Vector);
|
||||
} else {
|
||||
vpmovzxwd(Dst, Vector);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
pmovzxdq(GetDst(Node), GetSrc(Op->Vector.ID()));
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize);
|
||||
if (Is256Bit) {
|
||||
vpmovzxdq(ToYMM(Dst), Vector);
|
||||
} else {
|
||||
vpmovzxdq(Dst, Vector);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VUXTL2) {
|
||||
auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
uint8_t OpSize = IROp->Size;
|
||||
const auto Op = IROp->C<IR::IROp_VUXTL2>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
vpsrldq(GetDst(Node), GetSrc(Op->Vector.ID()), OpSize / 2);
|
||||
switch (Op->Header.ElementSize) {
|
||||
case 2:
|
||||
pmovzxbw(GetDst(Node), GetDst(Node));
|
||||
break;
|
||||
case 4:
|
||||
pmovzxwd(GetDst(Node), GetDst(Node));
|
||||
break;
|
||||
case 8:
|
||||
pmovzxdq(GetDst(Node), GetDst(Node));
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unknown Element Size: {}", Op->Header.ElementSize);
|
||||
const auto ElementSize = Op->Header.ElementSize;
|
||||
const auto Is256Bit = OpSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
|
||||
const auto Dst = GetDst(Node);
|
||||
const auto Vector = GetSrc(Op->Vector.ID());
|
||||
|
||||
if (Is256Bit) {
|
||||
const auto DstYMM = ToYMM(Dst);
|
||||
|
||||
vextracti128(Dst, ToYMM(Vector), 1);
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
vpmovzxbw(DstYMM, Dst);
|
||||
break;
|
||||
case 4:
|
||||
vpmovzxwd(DstYMM, Dst);
|
||||
break;
|
||||
case 8:
|
||||
vpmovzxdq(DstYMM, Dst);
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
vpsrldq(Dst, Vector, OpSize / 2);
|
||||
switch (ElementSize) {
|
||||
case 2:
|
||||
vpmovzxbw(Dst, Dst);
|
||||
break;
|
||||
case 4:
|
||||
vpmovzxwd(Dst, Dst);
|
||||
break;
|
||||
case 8:
|
||||
vpmovzxdq(Dst, Dst);
|
||||
break;
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Element Size: {}", ElementSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1077,7 +1077,7 @@
|
||||
},
|
||||
"FPR = VUXTL2 u8:#RegisterSize, u8:#ElementSize, FPR:$Vector": {
|
||||
"Desc": ["Zero extends elements from the source element size to the next size up",
|
||||
"Source elements come from the upper 64bits of the register"
|
||||
"Source elements come from the upper half of the register"
|
||||
],
|
||||
"DestSize": "RegisterSize",
|
||||
"NumElements": "RegisterSize / (ElementSize << 1)"
|
||||
|
||||
Reference in new issue
Block a user