From: <Ezra.Sitorus@arm.com>
To: <gdb-patches@sourceware.org>
Cc: <luis.machado.foss@gmail.com>, <thiago.bauermann@linaro.org>,
Ezra Sitorus <ezra.sitorus@arm.com>
Subject: [PATCH 1/4] gdb/aarch64: record/replay support for LRCPC3
Date: Mon, 20 Apr 2026 22:52:29 +0100 [thread overview]
Message-ID: <20260420215232.68675-2-Ezra.Sitorus@arm.com> (raw)
In-Reply-To: <20260420215232.68675-1-Ezra.Sitorus@arm.com>
From: Ezra Sitorus <ezra.sitorus@arm.com>
FEAT_LRCPC3 introduces various load/store instructions with release
consistency for cases where ordering is required. This patch teaches GDB
to decode these instructions for recording and reversing.
The gdb.reverse/aarch64-lrcpc3.exp testcase verifies that the
instructions are recorded and correctly reversed. In particular, there
are some interesting cases to note:
* ldapur/stlur are SIMD instructions, but are not decoded in the simd
function.
* There are writeback cases to cover too. These were taken from the
binutils testcases: gas/testsuite/gas/aarch64/rcpc3.s.
The full testsuite was done on aarch64-none-linux-gnu without LRCPC3.
The gdb.arch and gdb.reverse tests were run on Shrinkwrap with LRCPC3
support.
Please note:
1) There is no support for LRCPC and LRCPC2 instructions
2) LRCPC3 is gated with +rcpc3 in GCC/binutils.
---
gdb/aarch64-tdep.c | 87 +++++
gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c | 319 +++++++++++++++++++
gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp | 203 ++++++++++++
gdb/testsuite/lib/gdb.exp | 63 ++++
4 files changed, 672 insertions(+)
create mode 100644 gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
create mode 100644 gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 4befaa2720d..81d4f160f8f 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -5812,6 +5812,93 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r)
aarch64_insn_r->reg_rec_count = 1;
}
}
+ /* LRCPC3 instructions. This covers ldiapp/stilp, ldapur/stlur (FP/SIMD),
+ ldapr/stlr. */
+ else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x01
+ && insn_bits10_11 == 0x02 && !insn_bit21)
+ {
+ /* ldapur/stlur (FP/SIMD), ldapr/stlr. We can differentiate between the
+ 2 types by checking the vector flag. */
+ if (insn_bit23 || vector_flag)
+ {
+ /* For the vector instruction, the offset comes from the imm9
+ bitfield, whereas the other can only take possible values from the
+ size bitfield. */
+ int16_t imm9_off = sbits (aarch64_insn_r->aarch64_insn, 12, 20);
+ offset = vector_flag ? imm9_off : -(1 << size_bits);
+ uint32_t regnum_offset = vector_flag ? AARCH64_V0_REGNUM : 0;
+ if (ld_flag)
+ {
+ record_buf[0] = reg_rt + regnum_offset;
+ aarch64_insn_r->reg_rec_count = 1;
+ if (!vector_flag)
+ {
+ /* The Rn register always has writeback in LRCPC3. This is
+ not the case in LRCPC. */
+ record_buf[1] = reg_rn;
+ aarch64_insn_r->reg_rec_count = 2;
+ }
+ }
+ else
+ {
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ /* (vector_flag && insn_bit23) is the STLUR instruction with Q
+ register. */
+ datasize = (vector_flag && insn_bit23) ? 128 : (8 << size_bits);
+ /* LRCPC3 adds STLR with a pre-indexed offset. There is another
+ STLR variant without offset but this has a different encoding. */
+ if (!vector_flag)
+ {
+ record_buf[0] = reg_rn;
+ aarch64_insn_r->reg_rec_count = 1;
+ }
+ record_buf_mem[0] = datasize >> 3;
+ record_buf_mem[1] = address + offset;
+ aarch64_insn_r->mem_rec_count = 1;
+ }
+ }
+ else
+ {
+ /* ldiapp/stilp. */
+ uint8_t opc2 = bits (aarch64_insn_r->aarch64_insn, 12, 15);
+ reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 16, 20);
+ if (ld_flag)
+ {
+ record_buf[0] = reg_rt;
+ record_buf[1] = reg_rt2;
+ aarch64_insn_r->reg_rec_count = 2;
+
+ /* If the registers don't match and there's no offset then
+ there's WB. */
+ if (reg_rn != reg_rt && reg_rn != reg_rt2 && opc2 == 0)
+ {
+ record_buf[2] = reg_rn;
+ aarch64_insn_r->reg_rec_count = 3;
+ }
+ }
+ else
+ {
+ datasize = 8 << size_bits;
+ regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
+ &address);
+ offset = (opc2 == 0) ? (2 << size_bits) : 0;
+ address -= offset;
+
+ record_buf_mem[0] = datasize >> 3;
+ record_buf_mem[1] = address;
+ record_buf_mem[2] = datasize >> 3;
+ record_buf_mem[3] = address + (datasize >> 3);
+ aarch64_insn_r->mem_rec_count = 2;
+
+ if (offset != 0)
+ {
+ record_buf[0] = reg_rn;
+ aarch64_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+ }
/* Load/store register (register offset) instructions. */
else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
&& insn_bits10_11 == 0x02 && insn_bit21)
diff --git a/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
new file mode 100644
index 00000000000..9265489ff70
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
@@ -0,0 +1,319 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 2024-2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdalign.h>
+#include <string.h>
+
+#define INITIAL_STRING "This is just some string."
+#define BUF_SIZE sizeof (INITIAL_STRING)
+
+#define PREPARE_FOR_LOAD(OFFSET) \
+ __asm__ volatile ("mov %0, #0\n" : "=r"(xa)::); \
+ __asm__ volatile ("mov %0, #0\n" : "=r"(xb)::); \
+ strcpy (src, INITIAL_STRING); \
+ ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
+
+#define PREPARE_FOR_VECTOR_LOAD(OFFSET) \
+ __asm__ volatile ("movi %0.2d, #0\n" : "=w"(va)::); \
+ strcpy (src, INITIAL_STRING); \
+ ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
+
+#define PREPARE_FOR_STORE(OFFSET) \
+ __asm__ volatile ("mov %0, #0\n" : "=r"(xa)::); \
+ __asm__ volatile ("mov %0, #0\n" : "=r"(xb)::); \
+ strcpy (src, INITIAL_STRING); \
+ ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
+
+#define PREPARE_FOR_VECTOR_STORE(OFFSET) \
+ __asm__ volatile ("movi %0.2d, #0\n" : "=w"(va)::); \
+ strcpy (src, INITIAL_STRING); \
+ ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
+
+typedef uint64_t uint64x2_t __attribute__((vector_size(16)));
+
+int
+main (void)
+{
+ alignas(16) char src[BUF_SIZE];
+
+ register uint64_t xa asm ("x19");
+ register uint32_t xb asm ("x20");
+ register uint64_t *ptr asm ("x21");
+ register uint64x2_t va asm ("v22");
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-0. */
+ __asm__ volatile ("ldiapp %0, %1, [%2]\n"
+ : "=r"(xa), "=r"(xb)
+ : "r"(ptr)
+ : "memory");
+ /* After ldiapp-0. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-1. */
+ __asm__ volatile ("ldiapp %w0, %w1, [%2]\n"
+ : "=r"(xa), "=r"(xb)
+ : "r"(ptr)
+ : "memory");
+ /* After ldiapp-1. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-2. */
+ __asm__ volatile ("ldiapp %0, %1, [%2], #16\n"
+ : "=r"(xa), "=r"(xb)
+ : "r"(ptr)
+ : "memory");
+ /* After ldiapp-2. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-3. */
+ __asm__ volatile ("ldiapp %w0, %w1, [%2], #8\n"
+ : "=r"(xa), "=r"(xb)
+ : "r"(ptr)
+ : "memory");
+ /* After ldiapp-3. */
+ /* Register overlap between source and destination registers. Since there is
+ no offset, writeback is disabled. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-4. */
+ __asm__ volatile ("ldiapp %0, %1, [%0]\n"
+ : "+r"(ptr), "=r"(xb)
+ :
+ : "memory");
+ /* After ldiapp-4. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldiapp-5. */
+ __asm__ volatile ("ldiapp %w0, %w1, [%0]\n"
+ : "+r"(ptr), "=r"(xb)
+ :
+ : "memory");
+ /* After ldiapp-5. */
+
+ PREPARE_FOR_STORE (0);
+ /* Before stilp-0. */
+ __asm__ volatile ("stilp %0, %1, [%2]\n"
+ :
+ : "r"(xa), "r"(xb), "r"(ptr)
+ : "memory");
+ /* After stilp-0. */
+
+ PREPARE_FOR_STORE (0);
+ /* Before stilp-1. */
+ __asm__ volatile ("stilp %w0, %w1, [%2]\n"
+ :
+ : "r"(xa), "r"(xb), "r"(ptr)
+ : "memory");
+ /* After stilp-1. */
+
+ PREPARE_FOR_STORE (16);
+ /* Before stilp-2. */
+ __asm__ volatile ("stilp %1, %2, [%0, #-16]!\n"
+ : "+r"(ptr)
+ : "r"(xa), "r"(xb)
+ : "memory");
+ /* After stilp-2. */
+
+ PREPARE_FOR_STORE (8);
+ /* Before stilp-3. */
+ __asm__ volatile ("stilp %w1, %w2, [%0, #-8]!\n"
+ : "+r"(ptr)
+ : "r"(xa), "r"(xb)
+ : "memory");
+ /* After stilp-3. */
+ /* Register overlap. Since there is no offset, writeback is disabled. */
+
+ PREPARE_FOR_STORE (0);
+ /* Before stilp-4. */
+ __asm__ volatile ("stilp %0, %1, [%0]\n"
+ :
+ : "r"(ptr), "r"(xb)
+ : "memory");
+ /* After stilp-4. */
+
+ PREPARE_FOR_STORE (0);
+ /* Before stilp-5. */
+ __asm__ volatile ("stilp %w0, %w1, [%0]\n"
+ :
+ : "r"(ptr), "r"(xb)
+ : "memory");
+ /* After stilp-5. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldapr-0. */
+ __asm__ volatile ("ldapr %0, [%1], #8\n"
+ : "+r"(xa), "+r"(ptr)
+ :
+ : "memory");
+ /* After ldapr-0. */
+
+ PREPARE_FOR_LOAD (0);
+ /* Before ldapr-1. */
+ __asm__ volatile ("ldapr %w0, [%1], #4\n"
+ : "+r"(xa), "+r"(ptr)
+ :
+ : "memory");
+ /* After ldapr-1. */
+
+ PREPARE_FOR_STORE (8);
+ /* Before stlr-0. */
+ __asm__ volatile ("stlr %1, [%0, #-8]!\n"
+ : "+r"(ptr)
+ : "r"(xa)
+ : "memory");
+ /* After stlr-0. */
+
+ PREPARE_FOR_STORE (4);
+ /* Before stlr-1. */
+ __asm__ volatile ("stlr %w1, [%0, #-4]!\n"
+ : "+r"(ptr)
+ : "r"(xa)
+ : "memory");
+ /* After stlr-1. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldap1-0. */
+ __asm__ volatile ("ldap1 {%0.d}[0], [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldap1-0. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stl1-0. */
+ __asm__ volatile ("stl1 {%0.d}[0], [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stl1-0. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldapur-0. */
+ __asm__ volatile ("ldapur %d0, [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-0. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stlur-0. */
+ __asm__ volatile ("stlur %d0, [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-0. */
+
+ PREPARE_FOR_VECTOR_LOAD (256);
+ /* Before ldapur-1. */
+ __asm__ volatile ("ldapur %d0, [%1, #-256]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-1. */
+
+ PREPARE_FOR_VECTOR_STORE (256);
+ /* Before stlur-1. */
+ __asm__ volatile ("stlur %d0, [%1, #-256]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-1. */
+
+ PREPARE_FOR_VECTOR_LOAD (-255);
+ /* Before ldapur-2. */
+ __asm__ volatile ("ldapur %d0, [%1, #255]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-2. */
+
+ PREPARE_FOR_VECTOR_STORE (-255);
+ /* Before stlur-2. */
+ __asm__ volatile ("stlur %d0, [%1, #255]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-2. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldapur-3. */
+ __asm__ volatile ("ldapur %h0, [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-3. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stlur-3. */
+ __asm__ volatile ("stlur %h0, [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-3. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldapur-4. */
+ __asm__ volatile ("ldapur %s0, [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-4. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stlur-4. */
+ __asm__ volatile ("stlur %s0, [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-4. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldapur-5. */
+ __asm__ volatile ("ldapur %d0, [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-5. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stlur-5. */
+ __asm__ volatile ("stlur %d0, [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-5. */
+
+ PREPARE_FOR_VECTOR_LOAD (0);
+ /* Before ldapur-6. */
+ __asm__ volatile ("ldapur %q0, [%1]\n"
+ : "=w"(va)
+ : "r"(ptr)
+ : "memory");
+ /* After ldapur-6. */
+
+ PREPARE_FOR_VECTOR_STORE (0);
+ /* Before stlur-6. */
+ __asm__ volatile ("stlur %q0, [%1]\n"
+ :
+ : "w"(va), "r"(ptr)
+ : "memory");
+ /* After stlur-6. */
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
new file mode 100644
index 00000000000..7d7a8c45445
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
@@ -0,0 +1,203 @@
+# Copyright 2024-2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test instruction record for AArch64 FEAT_LRCPC3 instructions.
+# Based on gdb.reverse/aarch64-mops.exp
+#
+# The basic flow of the record tests are:
+# 1) Stop before executing the instructions of interest. Record
+# the initial value of the registers that the instruction will
+# change, i.e. the destination register.
+# 2) Execute the instructions. Record the new value of the
+# registers that changed.
+# 3) Reverse the direction of the execution and execute back to
+# just before the instructions of interest. Record the final
+# value of the registers of interest.
+# 4) Check that the initial and new values of the registers are
+# different, i.e. the instruction changed the registers as expected.
+# 5) Check that the initial and final values of the registers are
+# the same, i.e. GDB record restored the registers to their
+# original values.
+
+require allow_aarch64_lrcpc3_tests
+
+standard_testfile
+
+if {
+ [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ [list debug additional_flags=-march=armv8-a+rcpc3]]
+} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+gdb_test_no_output "record full"
+
+proc test_single_asm {name diff_reg diff_var diff_mem same_reg same_var same_mem} {
+ global decimal hex
+
+ set before_seq [gdb_get_line_number "Before ${name}"]
+ set after_seq [gdb_get_line_number "After ${name}"]
+
+ set insn [lindex [split $name "-"] 0]
+
+ gdb_test "break $before_seq" \
+ "Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
+ "$name: break before instruction sequence"
+ gdb_continue_to_breakpoint "$name: about to execute instruction sequence" \
+ [multi_line ".*/aarch64-lrcpc3.c:$decimal" \
+ "$decimal\[ \t\]+__asm__ volatile \\(\"${insn} \[^\r\n\]+\""]
+
+ # Depending on the compiler, the line number information may put GDB a few
+ # instructions before the beginning of the asm statement.
+ arrive_at_instruction $insn
+ # Add a breakpoint that we're sure is at the prologue instruction.
+ gdb_test "break *\$pc" \
+ "Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
+ "$name: break at prologue instruction"
+
+ # Record the initial memory and register values.
+ set regs [concat $diff_reg $same_reg]
+ set vars [concat $diff_var $same_var]
+ set mem [concat $diff_mem $same_mem]
+ foreach r $regs {
+ set ${r}_initial [capture_command_output "info register $r" ""]
+ }
+ foreach v $vars {
+ set ${v}_initial [get_valueof "/x" "$v" "unable to read $v" \
+ "$name: get $v initial value"]
+ }
+ foreach m $mem {
+ set ${m}_initial [capture_command_output "x/x $m" ""]
+ }
+
+ gdb_test "break $after_seq" \
+ "Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
+ "$name: break after instruction sequence"
+ gdb_continue_to_breakpoint "$name: executed instruction sequence" \
+ [multi_line ".*/aarch64-lrcpc3.c:$decimal" ".*"]
+
+ # Record the new memory and register values.
+ foreach r $regs {
+ set ${r}_new [capture_command_output "info register $r" ""]
+ }
+ foreach v $vars {
+ set ${v}_new [get_valueof "/x" "$v" "unable to read $v" \
+ "$name: get $v new value"]
+ }
+ foreach m $mem {
+ set ${m}_new [capture_command_output "x/x $m" ""]
+ }
+
+ # Execute in reverse to before the instruction sequence.
+ gdb_test_no_output "set exec-direction reverse"
+
+ gdb_continue_to_breakpoint "reversed execution of instruction sequence" \
+ [multi_line ".*/aarch64-lrcpc3.c:$decimal" \
+ "$decimal\[ \t\]+__asm__ volatile \\(\"${insn} \[^\r\n\]+\""]
+
+ # Record the final memory and register values.
+ foreach r $regs {
+ set ${r}_final [capture_command_output "info register $r" ""]
+ }
+ foreach v $vars {
+ set ${v}_final [get_valueof "/x" "$v" "unable to read $v" \
+ "$name: get $v final value"]
+ }
+ foreach m $mem {
+ set ${m}_final [capture_command_output "x/x $m" ""]
+ }
+
+ foreach v [concat $same_reg $same_var $same_mem] {
+ gdb_assert ![string compare [set ${v}_initial] [set ${v}_new]] \
+ "$name: check $v initial value versus $v new value"
+ gdb_assert ![string compare [set ${v}_initial] [set ${v}_final]] \
+ "$name: check $v initial value versus $v final value"
+ }
+
+ foreach v [concat $diff_reg $diff_var $diff_mem] {
+ gdb_assert [string compare [set ${v}_initial] [set ${v}_new]] \
+ "$name: check $v initial value versus $v new value"
+ gdb_assert ![string compare [set ${v}_initial] [set ${v}_final]] \
+ "$name: check $v initial value versus $v final value"
+ }
+
+ # Restore forward execution and go to end of recording.
+ gdb_test_no_output "set exec-direction forward"
+ gdb_test "record goto end" \
+ [multi_line \
+ "Go forward to insn number $decimal" \
+ "#0 main \\(\\) at .*/aarch64-lrcpc3.c:$decimal" \
+ ".*"]
+}
+
+set ldiapp_cases {
+ { ldiapp-0 { x19 x20 } { } { } { } { ptr } { src } }
+ { ldiapp-1 { w19 w20 } { } { } { } { ptr } { src } }
+ { ldiapp-2 { x19 x20 } { ptr } { } { } { } { src } }
+ { ldiapp-3 { w19 w20 } { ptr } { } { } { } { src } }
+ { ldiapp-4 { x21 x20 } { } { } { } { } { src } }
+ { ldiapp-5 { w21 w20 } { } { } { } { } { src } }
+}
+
+set stilp_cases {
+ { stilp-0 { } { } { src } { x19 x20 } { ptr } { } }
+ { stilp-1 { } { } { src } { w19 w20 } { ptr } { } }
+ { stilp-2 { } { ptr } { src } { x19 x20 } { } { } }
+ { stilp-3 { } { ptr } { src } { x19 x20 } { } { } }
+ { stilp-4 { } { } { src } { x20 } { ptr } { } }
+ { stilp-5 { } { } { src } { w20 } { ptr } { } }
+}
+
+set ldapr_stlr_cases {
+ { ldapr-0 { x19 } { ptr } { } { } { } { src } }
+ { ldapr-1 { w19 } { ptr } { } { } { } { src } }
+ { stlr-0 { } { ptr } { src } { x19 } { } { } }
+ { stlr-1 { } { ptr } { src } { w19 } { } { } }
+}
+
+set ldap1_stl1_cases {
+ { ldap1-0 { v22 } { } { } { ptr } { } { src } }
+ { stl1-0 { } { } { src } { v22 } { } { } }
+}
+
+set ldapur_stlur_cases {
+ { ldapur-0 { v22 } { } { } { ptr } { } { src } }
+ { stlur-0 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-1 { v22 } { } { } { ptr } { } { src } }
+ { stlur-1 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-2 { v22 } { } { } { ptr } { } { src } }
+ { stlur-2 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-3 { v22 } { } { } { ptr } { } { src } }
+ { stlur-3 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-4 { v22 } { } { } { ptr } { } { src } }
+ { stlur-4 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-5 { v22 } { } { } { ptr } { } { src } }
+ { stlur-5 { } { } { src } { v22 } { ptr } { } }
+ { ldapur-6 { v22 } { } { } { ptr } { } { src } }
+ { stlur-6 { } { } { src } { v22 } { ptr } { } }
+}
+
+set all_cases [concat \
+ $ldiapp_cases $stilp_cases $ldapr_stlr_cases \
+ $ldap1_stl1_cases $ldapur_stlur_cases]
+
+foreach c $all_cases {
+ lassign $c name diff_reg diff_var diff_mem same_reg same_var same_mem
+ test_single_asm $name $diff_reg $diff_var $diff_mem $same_reg $same_var $same_mem
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 28709004570..c6afc556548 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5287,6 +5287,69 @@ gdb_caching_proc allow_aarch64_fpmr_tests {} {
return $allow_fpmr_tests
}
+# Run a test on the target to see if it supports AArch64 LRCPC3 (Load-Acquire
+# RCpc instructions) extensions. Return 1 if so, 0 if it does not. Note this
+# causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_lrcpc3_tests {} {
+ global srcdir subdir gdb_prompt inferior_exited_re
+
+ set me "allow_aarch64_lrcpc3_tests"
+
+ if { ![is_aarch64_target] } {
+ return 0
+ }
+
+ # Take the opportunity to check whether the toolchain knows about LRCPC3.
+ set compile_flags "{additional_flags=-march=armv8-a+rcpc3}"
+
+ # Compile a program that tests the LRCPC3 feature.
+ set src {
+ #include <stdint.h>
+
+ int main() {
+ uint64_t a, b = 0;
+ uint64_t *ptr;
+ *ptr = 0xdeadbeef;
+
+ __asm__ volatile ("ldiapp %0, %1, [%2]\n"
+ : "=r"(a), "=r"(b)
+ : "r"(ptr)
+ : "memory");
+
+ return 0;
+ }
+ }
+
+ if {![gdb_simple_compile $me $src executable $compile_flags]} {
+ return 0
+ }
+
+ # Compilation succeeded so now run it via gdb.
+ clean_restart
+ gdb_load $obj
+ gdb_run_cmd
+ gdb_expect {
+ -re ".*Illegal instruction.*${gdb_prompt} $" {
+ verbose -log "\n$me lrcpc3 support not detected"
+ set allow_lrcpc3_tests 0
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ verbose -log "\n$me: lrcpc3 support detected"
+ set allow_lrcpc3_tests 1
+ }
+ default {
+ warning "\n$me: default case taken"
+ set allow_lrcpc3_tests 0
+ }
+ }
+ gdb_exit
+ remote_file build delete $obj
+
+ verbose "$me: returning $allow_lrcpc3_tests" 2
+ return $allow_lrcpc3_tests
+}
+
# Run a test on the target to see if it supports AArch64 MOPS (Memory
# Operations) extensions. Return 1 if so, 0 if it does not. Note this
# causes a restart of GDB.
--
2.43.0
next prev parent reply other threads:[~2026-04-20 21:54 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-20 21:52 [PATCH 0/4] gdb/aarch64: record/replay support for AArch64 Ezra.Sitorus
2026-04-20 21:52 ` Ezra.Sitorus [this message]
2026-04-24 7:00 ` [PATCH 1/4] gdb/aarch64: record/replay support for LRCPC3 Luis
2026-04-24 15:09 ` Guinevere Larsen
2026-04-25 5:08 ` Thiago Jung Bauermann
2026-04-25 7:21 ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 2/4] gdb/aarch64: Test record/replay support for CSSC Ezra.Sitorus
2026-04-24 7:07 ` Luis
2026-04-24 16:53 ` Guinevere Larsen
2026-04-25 6:10 ` Thiago Jung Bauermann
2026-04-25 7:28 ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 3/4] gdb/aarch64: record/replay support for RPRFM and PRFM (reg) Ezra.Sitorus
2026-04-24 7:08 ` Luis
2026-04-24 16:56 ` Guinevere Larsen
2026-04-25 8:12 ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 4/4] gdb/aarch64: record/replay support for LSE128 Ezra.Sitorus
2026-04-24 7:11 ` Luis
2026-04-24 17:12 ` Guinevere Larsen
2026-04-25 8:38 ` Thiago Jung Bauermann
2026-04-23 17:31 ` [PATCH 0/4] gdb/aarch64: record/replay support for AArch64 Guinevere Larsen
2026-04-23 22:20 ` Ezra Sitorus
2026-04-24 5:33 ` Thiago Jung Bauermann
2026-04-24 7:16 ` Luis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260420215232.68675-2-Ezra.Sitorus@arm.com \
--to=ezra.sitorus@arm.com \
--cc=gdb-patches@sourceware.org \
--cc=luis.machado.foss@gmail.com \
--cc=thiago.bauermann@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox