diff --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/Makefile b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/Makefile @@ -0,0 +1,5 @@ +C_SOURCES := main.c + +CFLAGS_EXTRAS := -march=armv8-a+sve -lpthread + +include Makefile.rules diff --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py @@ -0,0 +1,138 @@ +""" +Test the AArch64 SVE registers dynamic resize with multiple threads. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class RegisterCommandsTestCase(TestBase): + + def check_sve_registers(self, vg_test_value): + z_reg_size = vg_test_value * 8 + p_reg_size = int(z_reg_size / 8) + + p_value_bytes = ['0xff', '0x55', '0x11', '0x01', '0x00'] + + for i in range(32): + s_reg_value = 's%i = 0x' % (i) + \ + ''.join('{:02x}'.format(i + 1) for _ in range(4)) + + d_reg_value = 'd%i = 0x' % (i) + \ + ''.join('{:02x}'.format(i + 1) for _ in range(8)) + + v_reg_value = 'v%i = 0x' % (i) + \ + ''.join('{:02x}'.format(i + 1) for _ in range(16)) + + z_reg_value = '{' + \ + ' '.join('0x{:02x}'.format(i + 1) + for _ in range(z_reg_size)) + '}' + + self.expect("register read -f hex " + 's%i' % + (i), substrs=[s_reg_value]) + + self.expect("register read -f hex " + 'd%i' % + (i), substrs=[d_reg_value]) + + self.expect("register read -f hex " + 'v%i' % + (i), substrs=[v_reg_value]) + + self.expect("register read " + 'z%i' % + (i), substrs=[z_reg_value]) + + for i in range(16): + p_regs_value = '{' + \ + ' '.join(p_value_bytes[i % 5] for _ in range(p_reg_size)) + '}' + self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value]) + + self.expect("register read ffr", substrs=[p_regs_value]) + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + @skipIf(archs=no_match(["aarch64"])) + @skipIf(oslist=no_match(['linux'])) + def test_sve_registers_dynamic_config(self): + """Test AArch64 SVE registers multi-threaded dynamic resize. """ + + self.build() + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + if not self.isAArch64SVE(): + self.skipTest('SVE registers must be supported.') + + main_thread_stop_line = line_number( + "main.c", "// Break in main thread") + lldbutil.run_break_set_by_file_and_line( + self, "main.c", main_thread_stop_line) + + thX_break_line1 = line_number("main.c", "// Thread X breakpoint 1") + lldbutil.run_break_set_by_file_and_line( + self, "main.c", thX_break_line1) + + thX_break_line2 = line_number("main.c", "// Thread X breakpoint 2") + lldbutil.run_break_set_by_file_and_line( + self, "main.c", thX_break_line2) + + thY_break_line1 = line_number("main.c", "// Thread Y breakpoint 1") + lldbutil.run_break_set_by_file_and_line( + self, "main.c", thY_break_line1) + + thY_break_line2 = line_number("main.c", "// Thread Y breakpoint 2") + lldbutil.run_break_set_by_file_and_line( + self, "main.c", thY_break_line2) + + self.runCmd("run", RUN_SUCCEEDED) + + process = self.dbg.GetSelectedTarget().GetProcess() + + thread1 = process.GetThreadAtIndex(0) + + self.expect("thread info 1", STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint"]) + + self.check_sve_registers(8) + + self.runCmd("process continue", RUN_SUCCEEDED) + + for idx in range(1, process.GetNumThreads()): + thread = process.GetThreadAtIndex(idx) + if thread.GetStopReason() != lldb.eStopReasonBreakpoint: + self.runCmd("thread continue %d" % (idx + 1)) + self.assertEqual(thread.GetStopReason(), + lldb.eStopReasonBreakpoint) + + stopped_at_line_number = thread.GetFrameAtIndex( + 0).GetLineEntry().GetLine() + + if stopped_at_line_number == thX_break_line1: + self.runCmd("thread select %d" % (idx + 1)) + self.check_sve_registers(4) + self.runCmd('register write vg 2') + + elif stopped_at_line_number == thY_break_line1: + self.runCmd("thread select %d" % (idx + 1)) + self.check_sve_registers(2) + self.runCmd('register write vg 4') + + self.runCmd("thread continue 2") + self.runCmd("thread continue 3") + + for idx in range(1, process.GetNumThreads()): + thread = process.GetThreadAtIndex(idx) + self.assertEqual(thread.GetStopReason(), + lldb.eStopReasonBreakpoint) + + stopped_at_line_number = thread.GetFrameAtIndex( + 0).GetLineEntry().GetLine() + + if stopped_at_line_number == thX_break_line2: + self.runCmd("thread select %d" % (idx + 1)) + self.check_sve_registers(2) + + elif stopped_at_line_number == thY_break_line2: + self.runCmd("thread select %d" % (idx + 1)) + self.check_sve_registers(4) diff --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c @@ -0,0 +1,96 @@ +#include +#include + +static inline void write_sve_registers() { + asm volatile("setffr\n\t"); + asm volatile("ptrue p0.b\n\t"); + asm volatile("ptrue p1.h\n\t"); + asm volatile("ptrue p2.s\n\t"); + asm volatile("ptrue p3.d\n\t"); + asm volatile("pfalse p4.b\n\t"); + asm volatile("ptrue p5.b\n\t"); + asm volatile("ptrue p6.h\n\t"); + asm volatile("ptrue p7.s\n\t"); + asm volatile("ptrue p8.d\n\t"); + asm volatile("pfalse p9.b\n\t"); + asm volatile("ptrue p10.b\n\t"); + asm volatile("ptrue p11.h\n\t"); + asm volatile("ptrue p12.s\n\t"); + asm volatile("ptrue p13.d\n\t"); + asm volatile("pfalse p14.b\n\t"); + asm volatile("ptrue p15.b\n\t"); + + asm volatile("cpy z0.b, p0/z, #1\n\t"); + asm volatile("cpy z1.b, p5/z, #2\n\t"); + asm volatile("cpy z2.b, p10/z, #3\n\t"); + asm volatile("cpy z3.b, p15/z, #4\n\t"); + asm volatile("cpy z4.b, p0/z, #5\n\t"); + asm volatile("cpy z5.b, p5/z, #6\n\t"); + asm volatile("cpy z6.b, p10/z, #7\n\t"); + asm volatile("cpy z7.b, p15/z, #8\n\t"); + asm volatile("cpy z8.b, p0/z, #9\n\t"); + asm volatile("cpy z9.b, p5/z, #10\n\t"); + asm volatile("cpy z10.b, p10/z, #11\n\t"); + asm volatile("cpy z11.b, p15/z, #12\n\t"); + asm volatile("cpy z12.b, p0/z, #13\n\t"); + asm volatile("cpy z13.b, p5/z, #14\n\t"); + asm volatile("cpy z14.b, p10/z, #15\n\t"); + asm volatile("cpy z15.b, p15/z, #16\n\t"); + asm volatile("cpy z16.b, p0/z, #17\n\t"); + asm volatile("cpy z17.b, p5/z, #18\n\t"); + asm volatile("cpy z18.b, p10/z, #19\n\t"); + asm volatile("cpy z19.b, p15/z, #20\n\t"); + asm volatile("cpy z20.b, p0/z, #21\n\t"); + asm volatile("cpy z21.b, p5/z, #22\n\t"); + asm volatile("cpy z22.b, p10/z, #23\n\t"); + asm volatile("cpy z23.b, p15/z, #24\n\t"); + asm volatile("cpy z24.b, p0/z, #25\n\t"); + asm volatile("cpy z25.b, p5/z, #26\n\t"); + asm volatile("cpy z26.b, p10/z, #27\n\t"); + asm volatile("cpy z27.b, p15/z, #28\n\t"); + asm volatile("cpy z28.b, p0/z, #29\n\t"); + asm volatile("cpy z29.b, p5/z, #30\n\t"); + asm volatile("cpy z30.b, p10/z, #31\n\t"); + asm volatile("cpy z31.b, p15/z, #32\n\t"); +} + +void *threadX_func(void *x_arg) { + prctl(PR_SVE_SET_VL, 8 * 4); + write_sve_registers(); + write_sve_registers(); // Thread X breakpoint 1 + return NULL; // Thread X breakpoint 2 +} + +void *threadY_func(void *y_arg) { + prctl(PR_SVE_SET_VL, 8 * 2); + write_sve_registers(); + write_sve_registers(); // Thread Y breakpoint 1 + return NULL; // Thread Y breakpoint 2 +} + +int main() { + /* this variable is our reference to the second thread */ + pthread_t x_thread, y_thread; + + /* Set vector length to 8 and write SVE registers values */ + prctl(PR_SVE_SET_VL, 8 * 8); + write_sve_registers(); + + /* create a second thread which executes with argument x */ + if (pthread_create(&x_thread, NULL, threadX_func, 0)) // Break in main thread + return 1; + + /* create a second thread which executes with argument y */ + if (pthread_create(&y_thread, NULL, threadY_func, 0)) + return 1; + + /* wait for the first thread to finish */ + if (pthread_join(x_thread, NULL)) + return 2; + + /* wait for the second thread to finish */ + if (pthread_join(y_thread, NULL)) + return 2; + + return 0; +}