From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 34z9Cv+H62mR4TgAWB0awg (envelope-from ) for ; Fri, 24 Apr 2026 11:10:55 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ISSllApc; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 18D421E0BA; Fri, 24 Apr 2026 11:10:55 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 433EE1E067 for ; Fri, 24 Apr 2026 11:10:53 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id B3D214BB58CD for ; Fri, 24 Apr 2026 15:10:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B3D214BB58CD Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ISSllApc Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 13B1E4BB588F for ; Fri, 24 Apr 2026 15:10:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 13B1E4BB588F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 13B1E4BB588F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777043403; cv=none; b=CvrhRTpDwruuc3mcJE413w9Wz+QznsM0FbTL79GvH1x6Hcm7fXKAAxNzw84mj12GROAbw6e2mNPER0qHkDPXSC9AfmI96aK+EX2rbRJAYWL6IXM80Yf99z9onkbp4lpwMVYb12FbrDo4OH7jvmjjCpa0DAlFMHdyFKEEXfgHF38= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777043403; c=relaxed/simple; bh=p30+cCspRyiDVzujNDVfy3UMbGgcGAoIy45hmiOlp/Y=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=FHSncW3fNRvxAw3PBVb0Jg0aa8JYn5FPuVvcyDEmELpXTBnq9rR5fsXXakPIfFb8i2o37Fqhjnvshhe2rOOpPKLzy+bXDTOlvWnFt5vK0t+Qd8XRhJPz4Q2PbX8bJHA9vSoYf81c9uzRH+WeSwH8kfDplgJC5SRngAHdzCXRcyo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 13B1E4BB588F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777043402; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DbrQIiELS2T6xE+yepoJ2l4gsG4TgeYiTqP7LBZUeiY=; b=ISSllApc9aREHA1uYw3TW1wjqVM6T7/PQ6J9cUGkv0NmRx68jC3iErtRjO5vv7jdOik8mO WEHXYMwIyZDSacijYI7lTEPJcFRVCs49/evANOdUvjg+Mc19ZTHsJYwogOweLwkwoyMK+d XfQLHnrA/d5ObC3mEHqIsFyoteljh9M= Received: from mail-vk1-f200.google.com (mail-vk1-f200.google.com [209.85.221.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-605-zkzkz8q3NiSoEqfNK5jtFQ-1; Fri, 24 Apr 2026 11:10:01 -0400 X-MC-Unique: zkzkz8q3NiSoEqfNK5jtFQ-1 X-Mimecast-MFC-AGG-ID: zkzkz8q3NiSoEqfNK5jtFQ_1777043401 Received: by mail-vk1-f200.google.com with SMTP id 71dfb90a1353d-56f71e90581so6645784e0c.3 for ; Fri, 24 Apr 2026 08:10:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777043401; x=1777648201; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=DbrQIiELS2T6xE+yepoJ2l4gsG4TgeYiTqP7LBZUeiY=; b=p34yNbvesLXUlSmEMVuQBuPfkbCS9xpKIIbkcJIygly0SLBEfSiBokh6Y5jqiXKzNu RoZzY0zX5w1Q1HDStXj2fRGSVQ5Rfy/2AqVHwmnGEjYfjsdSMADP4kVTR0ziC8APJ0FV 0T+FlGeW6iwV4NQOe60czEPkdDjge2X2vMf0X8HwBqpWbt1mimVh9QSW7vElAJyy0Ouc WOUrkUJsCXUSxU+n3xL4vnbEkJXlYLCZm/jp38GVPfVCsF345bdClZnBPFhAF0KmW4XW kUnUzI3QM9HsJGnKkzY6jKLT2cXVlzPhcruiETgLJhSROmjIFgylCTbVXXiHIm5EQRCu MNUg== X-Forwarded-Encrypted: i=1; AFNElJ/0Pjrpxg1f8OFyXPOoyFxptX7PnXsIphkblT/GY9eNKZ8EZkaTods3fi74n8JJeGvuakvn4G/AvmczPw==@sourceware.org X-Gm-Message-State: AOJu0YyZSYTQPYT33NnVKlJ3r6JrQQqoNTB8CkWhNHNiKwuIValcnk6i FHJk/x4hqJtEDFqaJo2KE3BOfYo2UMwoo5UWxyeFXOXiV6+U4QzQZL+plLMvJewsCFUSa71EOti YxGnmUMPehhF0M71MmkquQT9gTUbcwIDN6mX3QAPklQPWfFlMCD9eUmBPZ8OC79Y= X-Gm-Gg: AeBDiet96H4zNdGFYFusdl2fPgXMsmAyarysWGXBSqH02YtFFNnQMvKXX/cZCRv9cZb QmF7s2HOH2xhLpoKv5FGLokB2pPv4QZpxIMgN0JQdlaYwnffDaIxpaKh7d69s3exBjpsk2BlVKg pq3pVvIO5aM+C7RaScbCBO6q5H2G1JazDRtLx+g4cG+Dknj6UpFDI5lBqZJU4Y2WAp+Wia7TCGM 9wR0lcXejhxrDa1ovfA00e/wIf7BbWwSUXq7RsPNdqfvwjC0DUytkR0lZqnGeJdhnq0NYednc4z Z3NvxtCtxIldrl8TM7stLXJG1Om02gav7nzOw4a0G0Jx3zNM9yliix55tbPHSZwxWH8Jip6IRqd A0hWhsaHnMz47G+FgjELXarpax1SquJ61p0QlNFJ5Lg== X-Received: by 2002:a05:6122:a20f:b0:56f:1c32:bcfa with SMTP id 71dfb90a1353d-56fa59dcc4dmr13083110e0c.11.1777043400539; Fri, 24 Apr 2026 08:10:00 -0700 (PDT) X-Received: by 2002:a05:6122:a20f:b0:56f:1c32:bcfa with SMTP id 71dfb90a1353d-56fa59dcc4dmr13083046e0c.11.1777043399854; Fri, 24 Apr 2026 08:09:59 -0700 (PDT) Received: from ?IPV6:2804:14d:8084:993e::75d? ([2804:14d:8084:993e::75d]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-56fa92f25acsm13601630e0c.9.2026.04.24.08.09.56 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 24 Apr 2026 08:09:59 -0700 (PDT) Message-ID: <76af2403-c565-418d-b730-10b0490565db@redhat.com> Date: Fri, 24 Apr 2026 12:09:53 -0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH 1/4] gdb/aarch64: record/replay support for LRCPC3 To: Ezra.Sitorus@arm.com, gdb-patches@sourceware.org Cc: luis.machado.foss@gmail.com, thiago.bauermann@linaro.org References: <20260420215232.68675-1-Ezra.Sitorus@arm.com> <20260420215232.68675-2-Ezra.Sitorus@arm.com> From: Guinevere Larsen In-Reply-To: <20260420215232.68675-2-Ezra.Sitorus@arm.com> X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: wg9ClIO09fzzjcg8wGd4Hfxm8C5okWsupteFG_2igHc_1777043401 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org On 4/20/26 6:52 PM, Ezra.Sitorus@arm.com wrote: > From: Ezra Sitorus > > 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. > --- Hi! Thanks for working on this! I can't really comment on the aarch64-tdep bits, but I did notice a few minor things in the test that could be improved. > 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 . */ > + > +#include > +#include > +#include > + > +#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); \ All of these macros have the same strcpy and ptr assignment code in them. I think it would be more clear if you made one macro for that part and the rest either have that macro, or just be in the code directly. > + > +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"); The register keyword is a hint for the compiler, and has been deprecated since c++11. I know that clang always ignores the keyword and I think GCC is free to do so under some circumstances. Considering that the rest of the test doesn't access the variables in any way that isn't assembly code, you're free to write the registers directly there. I did see that in the exp file you check for the value of the variable, however, if you're already checking the register, there isn't anything special that checking the variable would do, it is in fact closer to double checking that the compiler actually did what you told it to do. You can just drop the variable and examine only the registers. > + > + PREPARE_FOR_LOAD (0); > + /* Before ldiapp-0. */ > + __asm__ volatile ("ldiapp %0, %1, [%2]\n" > + : "=r"(xa), "=r"(xb) > + : "r"(ptr) > + : "memory"); For example, writing __asm__ volatile ("ldiapp x19, x20, [%0]", : : "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 . > + > +# 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 > + > + 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. -- Cheers, Guinevere Larsen It/she