mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
FEXCore: Reintroduce support for CSSC
Now that the PF flag isn't using popcount, this is a win across the board if the hardware supports it. Been a while since I last looked at this, added a new instcountci file to show the improvement.
This commit is contained in:
5 files changed
+102
-29
No files matched your search
@@ -1038,34 +1038,55 @@ DEF_OP(Popcount) {
|
||||
const auto Dst = GetReg(Node);
|
||||
const auto Src = GetReg(Op->Src);
|
||||
|
||||
switch (OpSize) {
|
||||
case IR::OpSize::i8Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
// only use lowest byte
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i16Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// only count two lowest bytes
|
||||
addp(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i32Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// fmov has zero extended, unused bytes are zero
|
||||
addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i64Bit:
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// fmov has zero extended, unused bytes are zero
|
||||
addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unsupported Popcount size: {}", OpSize);
|
||||
if (CTX->HostFeatures.SupportsCSSC) {
|
||||
switch (OpSize) {
|
||||
case IR::OpSize::i8Bit:
|
||||
uxtb(ARMEmitter::Size::i32Bit, Dst, Src);
|
||||
cnt(ARMEmitter::Size::i32Bit, Dst, Dst);
|
||||
break;
|
||||
case IR::OpSize::i16Bit:
|
||||
uxth(ARMEmitter::Size::i32Bit, Dst, Src);
|
||||
cnt(ARMEmitter::Size::i32Bit, Dst, Dst);
|
||||
break;
|
||||
case IR::OpSize::i32Bit:
|
||||
cnt(ARMEmitter::Size::i32Bit, Dst, Src);
|
||||
break;
|
||||
case IR::OpSize::i64Bit:
|
||||
cnt(ARMEmitter::Size::i64Bit, Dst, Src);
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unsupported Popcount size: {}", OpSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (OpSize) {
|
||||
case IR::OpSize::i8Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
// only use lowest byte
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i16Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// only count two lowest bytes
|
||||
addp(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i32Bit:
|
||||
fmov(ARMEmitter::Size::i32Bit, VTMP1.S(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// fmov has zero extended, unused bytes are zero
|
||||
addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
case IR::OpSize::i64Bit:
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), Src);
|
||||
cnt(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
// fmov has zero extended, unused bytes are zero
|
||||
addv(ARMEmitter::SubRegSize::i8Bit, VTMP1.D(), VTMP1.D());
|
||||
break;
|
||||
default: LOGMAN_MSG_A_FMT("Unsupported Popcount size: {}", OpSize);
|
||||
}
|
||||
|
||||
umov<ARMEmitter::SubRegSize::i8Bit>(Dst, VTMP1, 0);
|
||||
umov<ARMEmitter::SubRegSize::i8Bit>(Dst, VTMP1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(FindLSB) {
|
||||
|
||||
@@ -2747,7 +2747,7 @@ void OpDispatchBuilder::XADDOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PopcountOp(OpcodeArgs) {
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = GetSrcSize(Op) >= 4});
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = CTX->HostFeatures.SupportsCSSC || GetSrcSize(Op) >= 4});
|
||||
Src = _Popcount(OpSizeFromSrc(Op), Src);
|
||||
StoreResult(GPRClass, Op, Src, OpSize::iInvalid);
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"SVE128",
|
||||
"SVE256",
|
||||
"RPRES",
|
||||
"AFP"
|
||||
"AFP",
|
||||
"CSSC"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"Features": {
|
||||
"Bitness": 64,
|
||||
"EnabledHostFeatures": [
|
||||
"FLAGM",
|
||||
"FLAGM2",
|
||||
"CSSC"
|
||||
],
|
||||
"DisabledHostFeatures": [
|
||||
"SVE128",
|
||||
"SVE256",
|
||||
"RPRES",
|
||||
"AFP"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
"popcnt ax, bx": {
|
||||
"ExpectedInstructionCount": 6,
|
||||
"Comment": "0xf3 0x0f 0xb8",
|
||||
"ExpectedArm64ASM": [
|
||||
"uxth w20, w6",
|
||||
"cnt w20, w20",
|
||||
"bfxil x4, x20, #0, #16",
|
||||
"mov w27, #0x0",
|
||||
"cmp w20, #0x0 (0)",
|
||||
"mov w26, #0x1"
|
||||
]
|
||||
},
|
||||
"popcnt eax, ebx": {
|
||||
"ExpectedInstructionCount": 4,
|
||||
"Comment": "0xf3 0x0f 0xb8",
|
||||
"ExpectedArm64ASM": [
|
||||
"cnt w4, w6",
|
||||
"mov w27, #0x0",
|
||||
"cmp w4, #0x0 (0)",
|
||||
"mov w26, #0x1"
|
||||
]
|
||||
},
|
||||
"popcnt rax, rbx": {
|
||||
"ExpectedInstructionCount": 4,
|
||||
"Comment": "0xf3 0x0f 0xb8",
|
||||
"ExpectedArm64ASM": [
|
||||
"cnt x4, x6",
|
||||
"mov w27, #0x0",
|
||||
"cmp w4, #0x0 (0)",
|
||||
"mov w26, #0x1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
"AFP",
|
||||
"FLAGM",
|
||||
"FLAGM2",
|
||||
"FRINTTS"
|
||||
"FRINTTS",
|
||||
"CSSC"
|
||||
]
|
||||
},
|
||||
"Instructions": {
|
||||
|
||||
Reference in new issue
Block a user