Skip to content

Commit fd3eff7

Browse files
committed
[LLDB] Add CPU feature check support to Darwin
Add new `CPUFeature` class as an abstraction to hide the platform-specific implementations to check for CPU features. Unify local (on host) and remote (on device) test execution by always going through `test.Base.run_platform_command()` which uses LLDB's `platform shell <cmd>` command.
1 parent ef50227 commit fd3eff7

File tree

3 files changed

+73
-64
lines changed

3 files changed

+73
-64
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
Platform-agnostic helper to query for CPU features.
3+
"""
4+
5+
import re
6+
7+
8+
class CPUFeature:
9+
def __init__(self, linux_cpu_info_flag: str, darwin_sysctl_key: str):
10+
self.cpu_info_flag = linux_cpu_info_flag
11+
self.sysctl_key = darwin_sysctl_key
12+
13+
def is_supported(self, triple, cmd_runner):
14+
if re.match(".*-.*-linux", triple):
15+
err_msg, res = self._is_supported_linux(cmd_runner)
16+
elif re.match(".*-apple-.*", triple):
17+
err_msg, res = self._is_supported_darwin(cmd_runner)
18+
else:
19+
err_msg, res = None, False
20+
21+
if err_msg:
22+
print(f"CPU feature check failed: {err_msg}")
23+
24+
return res
25+
26+
def _is_supported_linux(self, cmd_runner):
27+
cmd = "cat /proc/cpuinfo"
28+
err, retcode, output = cmd_runner(cmd)
29+
if err.Fail() or retcode != 0:
30+
err_msg = f"cat /proc/cpuinfo failed: {output}"
31+
return err_msg, False
32+
33+
return None, (self.cpu_info_flag in output)
34+
35+
def _is_supported_darwin(self, cmd_runner):
36+
cmd = f"sysctl -n {self.sysctl_key}"
37+
err, retcode, output = cmd_runner(cmd)
38+
if err.Fail() or retcode != 0:
39+
return output, False
40+
41+
return None, (output.strip() == "1")
42+
43+
44+
# List of CPU features
45+
FPMR = CPUFeature("fpmr", "???")
46+
GCS = CPUFeature("gcs", "???")
47+
LASX = CPUFeature("lasx", "???")
48+
LSX = CPUFeature("lsx", "???")
49+
MTE = CPUFeature("mte", "???")
50+
MTE_STORE_ONLY = CPUFeature("mtestoreonly", "???")
51+
PTR_AUTH = CPUFeature("paca", "hw.optional.arm.FEAT_PAuth2")
52+
SME = CPUFeature("sme", "hw.optional.arm.FEAT_SME")
53+
SME_FA64 = CPUFeature("smefa64", "???")
54+
SME2 = CPUFeature("sme2", "hw.optional.arm.FEAT_SME2")
55+
SVE = CPUFeature("sve", "???")

lldb/packages/Python/lldbsuite/test/lldbtest.py

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
# LLDB modules
4949
import lldb
5050
from . import configuration
51+
from . import cpu_feature
5152
from . import decorators
5253
from . import lldbplatformutil
5354
from . import lldbtest_config
@@ -1315,39 +1316,6 @@ def isPPC64le(self):
13151316
return True
13161317
return False
13171318

1318-
def getCPUInfo(self):
1319-
triple = self.dbg.GetSelectedPlatform().GetTriple()
1320-
1321-
# TODO other platforms, please implement this function
1322-
if not re.match(".*-.*-linux", triple):
1323-
return ""
1324-
1325-
# Need to do something different for non-Linux/Android targets
1326-
cpuinfo_path = self.getBuildArtifact("cpuinfo")
1327-
if configuration.lldb_platform_name:
1328-
self.runCmd(
1329-
'platform get-file "/proc/cpuinfo" ' + cpuinfo_path, check=False
1330-
)
1331-
if not self.res.Succeeded():
1332-
if self.TraceOn():
1333-
print(
1334-
'Failed to get /proc/cpuinfo from remote: "{}"'.format(
1335-
self.res.GetOutput().strip()
1336-
)
1337-
)
1338-
print("All cpuinfo feature checks will fail.")
1339-
return ""
1340-
else:
1341-
cpuinfo_path = "/proc/cpuinfo"
1342-
1343-
try:
1344-
with open(cpuinfo_path, "r") as f:
1345-
cpuinfo = f.read()
1346-
except:
1347-
return ""
1348-
1349-
return cpuinfo
1350-
13511319
def isAArch64(self):
13521320
"""Returns true if the architecture is AArch64."""
13531321
arch = self.getArchitecture().lower()
@@ -1360,39 +1328,43 @@ def isARM(self):
13601328
self.getArchitecture().lower().startswith("arm")
13611329
)
13621330

1331+
def isSupported(self, cpu_feature: cpu_feature.CPUFeature):
1332+
triple = self.dbg.GetSelectedPlatform().GetTriple()
1333+
cmd_runner = self.run_platform_command
1334+
return cpu_feature.is_supported(triple, cmd_runner)
1335+
13631336
def isAArch64SVE(self):
1364-
return self.isAArch64() and "sve" in self.getCPUInfo()
1337+
return self.isAArch64() and self.isSupported(cpu_feature.SVE)
13651338

13661339
def isAArch64SME(self):
1367-
return self.isAArch64() and "sme" in self.getCPUInfo()
1340+
return self.isAArch64() and self.isSupported(cpu_feature.SME)
13681341

13691342
def isAArch64SME2(self):
13701343
# If you have sme2, you also have sme.
1371-
return self.isAArch64() and "sme2" in self.getCPUInfo()
1344+
return self.isAArch64() and self.isSupported(cpu_feature.SME2)
13721345

13731346
def isAArch64SMEFA64(self):
13741347
# smefa64 allows the use of the full A64 instruction set in streaming
13751348
# mode. This is required by certain test programs to setup register
13761349
# state.
1377-
cpuinfo = self.getCPUInfo()
1378-
return self.isAArch64() and "sme" in cpuinfo and "smefa64" in cpuinfo
1350+
return self.isAArch64() and self.isSupported(cpu_feature.SME) and self.isSupported(cpu_feature.SME_FA64)
13791351

13801352
def isAArch64MTE(self):
1381-
return self.isAArch64() and "mte" in self.getCPUInfo()
1353+
return self.isAArch64() and self.isSupported(cpu_feature.MTE)
13821354

13831355
def isAArch64MTEStoreOnly(self):
1384-
return self.isAArch64() and "mtestoreonly" in self.getCPUInfo()
1356+
return self.isAArch64() and self.isSupported(cpu_feature.MTE_STORE_ONLY)
13851357

13861358
def isAArch64GCS(self):
1387-
return self.isAArch64() and "gcs" in self.getCPUInfo()
1359+
return self.isAArch64() and self.isSupported(cpu_feature.GCS)
13881360

13891361
def isAArch64PAuth(self):
13901362
if self.getArchitecture() == "arm64e":
13911363
return True
1392-
return self.isAArch64() and "paca" in self.getCPUInfo()
1364+
return self.isAArch64() and self.isSupported(cpu_feature.PTR_AUTH)
13931365

13941366
def isAArch64FPMR(self):
1395-
return self.isAArch64() and "fpmr" in self.getCPUInfo()
1367+
return self.isAArch64() and self.isSupported(cpu_feature.FPMR)
13961368

13971369
def isAArch64Windows(self):
13981370
"""Returns true if the architecture is AArch64 and platform windows."""
@@ -1407,10 +1379,10 @@ def isLoongArch(self):
14071379
return arch in ["loongarch64", "loongarch32"]
14081380

14091381
def isLoongArchLSX(self):
1410-
return self.isLoongArch() and "lsx" in self.getCPUInfo()
1382+
return self.isLoongArch() and self.isSupported(cpu_feature.LSX)
14111383

14121384
def isLoongArchLASX(self):
1413-
return self.isLoongArch() and "lasx" in self.getCPUInfo()
1385+
return self.isLoongArch() and self.isSupported(cpu_feature.LASX)
14141386

14151387
def isRISCV(self):
14161388
"""Returns true if the architecture is RISCV64 or RISCV32."""

lldb/test/API/commands/register/register/register_command/TestRegisters.py

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,6 @@ def tearDown(self):
2121
self.dbg.GetSelectedTarget().GetProcess().Destroy()
2222
TestBase.tearDown(self)
2323

24-
# on macOS, detect if the current machine is arm64 and supports SME
25-
def get_sme_available(self):
26-
if self.getArchitecture() != "arm64":
27-
return None
28-
try:
29-
sysctl_output = subprocess.check_output(
30-
["sysctl", "hw.optional.arm.FEAT_SME"]
31-
).decode("utf-8")
32-
except subprocess.CalledProcessError:
33-
return None
34-
m = re.match(r"hw\.optional\.arm\.FEAT_SME: (\w+)", sysctl_output)
35-
if m:
36-
if int(m.group(1)) == 1:
37-
return True
38-
else:
39-
return False
40-
return None
41-
4224
@skipIfiOSSimulator
4325
@skipIf(archs=no_match(["amd64", "arm$", "i386", "x86_64"]))
4426
@expectedFailureAll(oslist=["freebsd", "netbsd"], bugnumber="llvm.org/pr48371")
@@ -51,7 +33,7 @@ def test_register_commands(self):
5133
self.log_enable("registers")
5234

5335
error_str_matched = False
54-
if self.get_sme_available() and self.platformIsDarwin():
36+
if self.isAArch64SME() and self.platformIsDarwin():
5537
# On Darwin AArch64 SME machines, we will have unavailable
5638
# registers when not in Streaming SVE Mode/SME, so
5739
# `register read -a` will report that some registers

0 commit comments

Comments
 (0)