From 4d3081331ad854e0bff5032c818ec6414fb974c0 Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid Date: Tue, 19 Jan 2021 14:52:23 +0500 Subject: [PATCH] [LLDB] Test SVE dynamic resize with multiple threads This patch adds a new test case which depends on AArch64 SVE support and dynamic resize capability enabled. It created two seperate threads which have different values of sve registers and SVE vector granule at various points during execution. We test that LLDB is doing the size and offset updates properly for all of the threads including the main thread and when we VG is updated using prctl call or by 'register write vg' command the appropriate changes are also update in register infos. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D82866 --- .../rw_access_dynamic_resize/Makefile | 5 + .../TestSVEThreadedDynamic.py | 138 +++++++++++++++++++++ .../rw_access_dynamic_resize/main.c | 96 ++++++++++++++ 3 files changed, 239 insertions(+) create mode 100644 lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/Makefile create mode 100644 lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/TestSVEThreadedDynamic.py create mode 100644 lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_dynamic_resize/main.c 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 index 00000000000..efa5ca913f6 --- /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 index 00000000000..4d9cb686818 --- /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 index 00000000000..b14ba280bb7 --- /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; +} -- 2.11.0