Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/Makefile =================================================================== --- /dev/null +++ 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 Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py =================================================================== --- /dev/null +++ lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py @@ -0,0 +1,142 @@ +""" +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_register_size_and_offset(self, set, name, expected_size, + expected_offset): + reg_value = set.GetChildMemberWithName(name) + + self.assertTrue(reg_value.IsValid(), + 'Verify we have a register named "%s"' % (name)) + self.assertEqual(reg_value.GetByteSize(), expected_size, + 'Verify "%s" size == %i' % (name, expected_size)) + self.assertEqual(reg_value.GetByteOffset(), expected_offset, + 'Verify "%s" == %i' % (name, expected_offset)) + + def check_sve_registers_config(self, set, vg_test_value): + vg_reg_value = set.GetChildMemberWithName("vg").GetValueAsUnsigned() + offset = set.GetChildMemberWithName("z0").GetByteOffset() + + z_reg_size = vg_reg_value * 8 + p_reg_size = z_reg_size / 8 + + for i in range(32): + self.check_sve_register_size_and_offset( + set, 's%i' % (i), 4, offset) + self.check_sve_register_size_and_offset( + set, 'd%i' % (i), 8, offset) + self.check_sve_register_size_and_offset( + set, 'v%i' % (i), 16, offset) + self.check_sve_register_size_and_offset( + set, 'z%i' % (i), z_reg_size, offset) + offset = offset + z_reg_size + + for i in range(16): + self.check_sve_register_size_and_offset( + set, 'p%i' % (i), p_reg_size, offset) + offset = offset + p_reg_size + + self.check_sve_register_size_and_offset(set, 'ffr', p_reg_size, offset) + + mydir = TestBase.compute_mydir(__file__) + # @skipIf + + def test_sve_registers_configuration(self): + """Test AArch64 SVE registers multi-threaded dynamic resize. """ + + self.build() + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + 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"]) + + has_sve = False + for registerSet in thread1.GetFrameAtIndex(0).GetRegisters(): + if 'sve registers' in registerSet.GetName().lower(): + has_sve = True + self.check_sve_registers_config(registerSet, 8) + + if not has_sve: + self.skipTest('SVE registers must be supported.') + + 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() + + sve_registers = thread.GetFrameAtIndex( + 0).GetRegisters().GetValueAtIndex(2) + + if stopped_at_line_number == thX_break_line1: + self.check_sve_registers_config(sve_registers, 2) + self.runCmd("thread select %d" % (idx + 1)) + self.runCmd('register write vg 4') + + elif stopped_at_line_number == thY_break_line1: + self.check_sve_registers_config(sve_registers, 4) + self.runCmd("thread select %d" % (idx + 1)) + self.runCmd('register write vg 2') + + 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() + + sve_registers = thread.GetFrameAtIndex( + 0).GetRegisters().GetValueAtIndex(2) + + if stopped_at_line_number == thX_break_line2: + self.check_sve_registers_config(sve_registers, 4) + + elif stopped_at_line_number == thY_break_line2: + self.check_sve_registers_config(sve_registers, 2) Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c =================================================================== --- /dev/null +++ lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c @@ -0,0 +1,59 @@ +#include +#include + +void *thread_func(void *x_void_ptr) +{ + void * return_ptr = NULL; + if (*((int *)x_void_ptr) == 0) { + prctl(PR_SVE_SET_VL, 8 * 4); + asm volatile("ptrue p0.s\n\t"); + asm volatile("fcpy z30.s, p0/m, #1.00000000\n\t"); + asm volatile("fcpy z31.s, p0/m, #5.00000000\n\t"); + return_ptr = (void *)x_void_ptr; // Thread X breakpoint 1 + asm volatile("ptrue p0.s\n\t"); + asm volatile("fcpy z0.s, p0/m, #1.00000000\n\t"); + asm volatile("fcpy z1.s, p0/m, #5.00000000\n\t"); + return return_ptr; // Thread X breakpoint 2 + } + + if (*((int *)x_void_ptr) == 1) { + prctl(PR_SVE_SET_VL, 8 * 2); + asm volatile("ptrue p0.s\n\t"); + asm volatile("fcpy z30.s, p0/m, #5.00000000\n\t"); + asm volatile("fcpy z31.s, p0/m, #1.00000000\n\t"); + return_ptr = x_void_ptr; // Thread Y breakpoint 1 + asm volatile("ptrue p0.s\n\t"); + asm volatile("fcpy z1.s, p0/m, #1.00000000\n\t"); + asm volatile("fcpy z0.s, p0/m, #5.00000000\n\t"); + return return_ptr; // Thread Y breakpoint 2 + } + return return_ptr; +} + +int main() +{ + prctl(PR_SVE_SET_VL, 8); + + /* this variable is our reference to the second thread */ + pthread_t x_thread, y_thread; + + int x = 0, y = 1; + + /* create a second thread which executes with argument x */ + if(pthread_create(&x_thread, NULL, thread_func, &x)) // Break in main thread + return 1; + + /* create a second thread which executes with argument y */ + if(pthread_create(&y_thread, NULL, thread_func, &y)) + 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; +}