David Spickett 8c122e5d3b
[lldb][test] Make Linux cpuinfo check more robust (#160675)
We were looking for any mention of the feature name in cpuinfo, which
could have hit anything including features with common prefixes like
sme, sme2, smefa64.

Luckily this was not a problem but I'm changing this to find the
features line and split the features into a list. Then we are only
looking for exact matches.

Here's the information for one core as an example:
```
processor	: 7
BogoMIPS	: 200.00
Features	: fp asimd evtstrm crc32 atomics fphp asimdhp cpuid <...>
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd0f
CPU revision	: 0
```
(and to avoid any doubt, this is from a CPU simulated in Arm's FVP, it's
not real)

Note that the layout of the label, colon, values is sometimes aligned
but not always. So I trim whitespace a few times to normalise that.

This repeats once for each core so we only need to find one features
line.
2025-09-26 08:33:50 +00:00

80 lines
2.4 KiB
Python

"""
Platform-agnostic helper to query for CPU features.
"""
import re
class CPUFeature:
def __init__(self, linux_cpu_info_flag: str = None, darwin_sysctl_key: str = None):
self.cpu_info_flag = linux_cpu_info_flag
self.sysctl_key = darwin_sysctl_key
def __str__(self):
for arch_class in ALL_ARCHS:
for feat_var in dir(arch_class):
if self == getattr(arch_class, feat_var):
return f"{arch_class.__name__}.{feat_var}"
raise AssertionError("unreachable")
def is_supported(self, triple, cmd_runner):
if re.match(".*-.*-linux", triple):
err_msg, res = self._is_supported_linux(cmd_runner)
elif re.match(".*-apple-.*", triple):
err_msg, res = self._is_supported_darwin(cmd_runner)
else:
err_msg, res = None, False
if err_msg:
print(f"CPU feature check failed: {err_msg}")
return res
def _is_supported_linux(self, cmd_runner):
if not self.cpu_info_flag:
return f"Unspecified cpuinfo flag for {self}", False
cmd = "cat /proc/cpuinfo"
err, retcode, output = cmd_runner(cmd)
if err.Fail() or retcode != 0:
return output, False
# Assume that every processor presents the same features.
# Look for the first "Features: ...." line. Features are space separated.
if m := re.search(r"Features\s*: (.*)\n", output):
features = m.group(1).split()
return None, (self.cpu_info_flag in features)
return 'No "Features:" line found in /proc/cpuinfo', False
def _is_supported_darwin(self, cmd_runner):
if not self.sysctl_key:
return f"Unspecified sysctl key for {self}", False
cmd = f"sysctl -n {self.sysctl_key}"
err, retcode, output = cmd_runner(cmd)
if err.Fail() or retcode != 0:
return output, False
return None, (output.strip() == "1")
class AArch64:
FPMR = CPUFeature("fpmr")
GCS = CPUFeature("gcs")
MTE = CPUFeature("mte")
MTE_STORE_ONLY = CPUFeature("mtestoreonly")
PTR_AUTH = CPUFeature("paca", "hw.optional.arm.FEAT_PAuth2")
SME = CPUFeature("sme", "hw.optional.arm.FEAT_SME")
SME_FA64 = CPUFeature("smefa64")
SME2 = CPUFeature("sme2", "hw.optional.arm.FEAT_SME2")
SVE = CPUFeature("sve")
class Loong:
LASX = CPUFeature("lasx")
LSX = CPUFeature("lsx")
ALL_ARCHS = [AArch64, Loong]