================
@@ -0,0 +1,553 @@
+"""
+Check handling of registers on an AArch64 Linux system that only has SME. As
+opposed to SVE and SME. Check register access and restoration after expression
+evaluation.
+"""
+
+from enum import Enum
+from pprint import pprint
+from functools import lru_cache
+from itertools import permutations
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from itertools import cycle
+
+
+class Mode(Enum):
+ SIMD = 0
+ SSVE = 2
+
+ def __str__(self):
+ return "streaming" if self == Mode.SSVE else "simd"
+
+
+class ZA(Enum):
+ ON = 1
+ OFF = 2
+
+ def __str__(self):
+ return "on" if self == ZA.ON else "off"
+
+
+class ByteVector(object):
+ def __init__(self, data):
+ self.data = data
+
+ def __repr__(self):
+ return "{" + " ".join([f"0x{b:02x}" for b in self.data]) + "}"
+
+ def as_bytes(self):
+ return self.data
+
+
+class HexValue(object):
+ # Assume all values are 64-bit, but some display as 32-bit, like fpcr.
+ def __init__(self, value, repr_size=8):
+ self.value = value
+ # In bytes
+ self.repr_size = repr_size
+
+ def __repr__(self):
+ return f"0x{self.value:0{self.repr_size*2}x}"
+
+ def as_bytes(self):
+ data = []
+ v = self.value
+ # Little endian order.
+ for i in range(8):
+ data.append(v & 0xFF)
+ v >>= 8
+
+ return data
+
+
+class SVESIMDRegistersTestCase(TestBase):
+ def reg_names(self, prefix, count):
+ return [f"{prefix}{n}" for n in range(count)]
+
+ def expected_registers(self, svl_b, mode, za):
+ register_values = []
+
+ if mode == Mode.SIMD:
+ # In streaming mode we have real V registers and no Z registers.
+
+ # V regs are {N <7 0s> N <7 0s>} because we set the bottom element
to N
+ # where N is 1 + the register index.
+ v_values = [
+ ByteVector([n + 1] + [0] * 7 + [n + 1] + [0] * 7) for n in
range(32)
+ ]
+
+ # Z regs are {N <7 0s> N <7 0s> <16 more 0s}. First half overlaps
a V
+ # register, the second half we fake 0s for as there is no real Z
register
+ # in non-streaming mode.
+ z_values = [
+ ByteVector([n + 1] + [0] * 7 + [n + 1] + [0] * 7 + [0] *
(svl_b - 16))
+ for n in range(32)
+ ]
+
+ # P regs are {<4 0s>}, we fake the value.
+ p_values = [ByteVector([0] * (svl_b // 8)) for _ in range(16)]
+ else:
+ # In streaming mode, Z registers are real and V are the bottom 128
+ # bits of the Z registers.
+
+ # Streaming SVE registers have their elements set to their number
plus 1.
+ # So z0 has elements of 0x01, z1 is 0x02 and so on.
+ v_values = [ByteVector([n + 1] * 16) for n in range(32)]
+
+ z_values = [ByteVector([n + 1] * svl_b) for n in range(32)]
+
+ # P registers have all emlements set to the same value and that
value
+ # cycles between 0xff, 0x55, 0x11, 0x01 and 0x00.
+ p_values = []
+ for i, v in zip(range(16), cycle([0xFF, 0x55, 0x11, 0x01, 0x00])):
+ p_values.append(ByteVector([v] * (svl_b // 8)))
+
+ # Would use strict=True here but it requires Python 3.10.
+ register_values += list(zip(self.reg_names("v", 32), v_values))
+ register_values += [
+ ("fpsr", HexValue(0x50000015, repr_size=4)),
+ ("fpcr", HexValue(0x05551505, repr_size=4)),
+ ]
+ register_values += list(zip(self.reg_names("z", 32), z_values))
+ register_values += list(zip(self.reg_names("p", 16), p_values))
+
+ # ffr is all 0s. In SIMD mode we're faking the value, in streaming
mode,
+ # use of ffr is illegal so the kernel tells us it's 0s.
+ register_values += [("ffr", ByteVector([0] * (svl_b // 8)))]
+
+ svcr_value = 1 if mode == Mode.SSVE else 0
+ if za == ZA.ON:
+ svcr_value += 2
+
+ register_values += [
+ ("svcr", HexValue(svcr_value)),
+ # SVG is the streaming vector length in granules.
+ ("svg", HexValue(svl_b // 8)),
+ ]
+
+ # ZA and ZTO may be enabled or disabled regardless of streaming mode.
+ # ZA is a square of vector length * vector length.
+ # ZT0 is 512 bits regardless of streaming vector length.
+ if za == ZA.ON:
+ register_values += [("za", ByteVector(list(range(1, svl_b + 1)) *
svl_b))]
+ if self.isAArch64SME2():
+ register_values += [("zt0", ByteVector(list(range(1, (512 //
8) + 1))))]
+ else:
+ # ZA is fake.
+ register_values += [("za", ByteVector([0x0] * (svl_b * svl_b)))]
+ # ZT0 is also fake.
+ if self.isAArch64SME2():
+ register_values += [("zt0", ByteVector([0x00] * (512 // 8)))]
+
+ return dict(register_values)
+
+ def check_expected_regs_fn(self, expected_registers):
+ def check_expected_regs():
+ self.expect(
+ f'register read {" ".join(expected_registers.keys())}',
+ substrs=[f"{n} = {v}" for n, v in expected_registers.items()],
+ )
+
+ return check_expected_regs
+
+ def skip_if_not_sme_only(self):
+ if self.isAArch64SVE():
+ self.skipTest("SVE must not be present outside of streaming mode.")
+
+ if not self.isAArch64SME():
+ self.skipTest("SSVE registers must be supported.")
+
+ def setup_test(self, mode, za, svl):
+ self.build()
+ self.line = line_number("main.c", "// Set a break point here.")
+
+ exe = self.getBuildArtifact("a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ self.runCmd(f"settings set target.run-args {mode} {za} {svl}")
+
+ lldbutil.run_break_set_by_file_and_line(
+ self, "main.c", self.line, num_expected_locations=1
+ )
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ self.expect(
+ "thread backtrace",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stop reason = breakpoint 1."],
+ )
+
+ def write_expected_reg_data(self, reg_data):
+ # Write expected register values into program memory so it can be
+ # verified in-process.
+ # This must be done via. memory write instead of expressions because
----------------
jasonmolenda wrote:
silly thing, but no period after via.
https://github.com/llvm/llvm-project/pull/165414
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits