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:
Ryan Houdek committed 2025-07-17 15:09:27 -07:00
1 parent b7ac641aa0
commit 7e1ee5bb07
5 files changed
+102 -29

No files matched your search

+47 -26
View File
@@ -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": {