From patchwork Sat Jul 13 15:09:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1960178 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WLsMc3C0jz1xqx for ; Sun, 14 Jul 2024 01:10:02 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B0E5D386103A for ; Sat, 13 Jul 2024 15:09:59 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 489A53858C66 for ; Sat, 13 Jul 2024 15:09:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 489A53858C66 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=arm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 489A53858C66 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720883380; cv=none; b=pPDG1v36vZ9j/NIsG3CTbcSdz4nGrm1dB2DSI5OZRfSzXXL9JuhrXOsMHJ6Hbm7Qygj0CmBgpaPhJKPrrIbBg8nVcDK+45ZH5KIiIoqgp3ysv4/nJPTGgJ6FrOPpnoASUTp6tnme7Vcb3VYxw9lGUrQLMs+Y/IP1OlblWYqPppA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720883380; c=relaxed/simple; bh=tF3gDMha0YkH1eXgKFybiZF+UlzU4EnU9aY2wNylV4Y=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=QJ+g10brgnDMN+u3Lj0KXa5tXNv9tF3k2KEx7LQThgzf7i7M/GWAQzvGmL/dVu5KxFtqiT8KyB1Km5fLxWQP5aIyjL6qAHBpIDyXZirYbK2LaPWJIn+Bt2UllrNabVBden+vTBDnIiIQSjhZm7Qi0TvsZKc6HbIERv6ZW6DkVe8= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4B20C1007 for ; Sat, 13 Jul 2024 08:10:02 -0700 (PDT) Received: from localhost (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A58BB3F762 for ; Sat, 13 Jul 2024 08:09:36 -0700 (PDT) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [PATCH] rtl-ssa: Enforce earlyclobbers on hard-coded clobbers [PR115891] Date: Sat, 13 Jul 2024 16:09:35 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Spam-Status: No, score=-19.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org The asm in the testcase has a memory operand and also clobbers ax. The clobber means that ax cannot be used to hold inputs, which extends to the address of the memory. I think I had an implicit assumption that constrain_operands would enforce this, but in hindsight, that clearly wasn't going to be true. constrain_operands only looks at constraints, and these clobbers are by definition outside the constraint system. (And that's why they have to be handled conservatively, since there's no way to distinguish the earlyclobber and non-earlyclobber cases.) The semantics of hard-coded clobbers are generic enough that I think they should be handled directly by rtl-ssa, rather than by consumers. And in the context of rtl-ssa, the easiest way to check for a clash is to walk the list of input registers, which we already have to hand. It therefore seemed better not to push this down to a more generic rtl helper. The patch detects hard-coded clobbers in the same way as regrename: by temporarily stubbing out the operands with pc_rtx. Tested on aarch64-linux-gnu & x86_64-linux-gnu. OK to install? Richard gcc/ PR rtl-optimization/115891 * rtl-ssa/changes.cc (find_clobbered_access): New function. (recog_level2): Use it to check for overlap between input registers and hard-coded clobbers. Conditionally reset recog_data.insn after changing the insn code. gcc/testsuite/ PR rtl-optimization/115891 * gcc.target/i386/pr115891.c: New test. --- gcc/rtl-ssa/changes.cc | 60 +++++++++++++++++++++++- gcc/testsuite/gcc.target/i386/pr115891.c | 10 ++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr115891.c diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc index 6b6f7cd5d3a..a163c6d3bec 100644 --- a/gcc/rtl-ssa/changes.cc +++ b/gcc/rtl-ssa/changes.cc @@ -944,6 +944,25 @@ add_clobber (insn_change &change, add_regno_clobber_fn add_regno_clobber, return true; } +// See if PARALLEL pattern PAT clobbers any of the registers in ACCESSES. +// Return one such access if so, otherwise return null. +static access_info * +find_clobbered_access (access_array accesses, rtx pat) +{ + rtx subpat; + for (int i = 0; i < XVECLEN (pat, 0); ++i) + if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER) + { + rtx x = XEXP (subpat, 0); + if (REG_P (x)) + for (auto *access : accesses) + if (access->regno () >= REGNO (x) + && access->regno () < END_REGNO (x)) + return access; + } + return nullptr; +} + // Try to recognize the new form of the insn associated with CHANGE, // adding any clobbers that are necessary to make the instruction match // an .md pattern. Return true on success. @@ -1035,9 +1054,48 @@ recog_level2 (insn_change &change, add_regno_clobber_fn add_regno_clobber) pat = newpat; } + INSN_CODE (rtl) = icode; + if (recog_data.insn == rtl) + recog_data.insn = nullptr; + + // See if the pattern contains any hard-coded clobbers of registers + // that are also inputs to the instruction. The standard rtl semantics + // treat such clobbers as earlyclobbers, since there is no way of proving + // which clobbers conflict with the inputs and which don't. + // + // (Non-hard-coded clobbers are handled by constraint satisfaction instead.) + rtx subpat; + if (GET_CODE (pat) == PARALLEL) + for (int i = 0; i < XVECLEN (pat, 0); ++i) + if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER + && REG_P (XEXP (subpat, 0))) + { + // Stub out all operands, so that can tell which registers + // are hard-coded. + extract_insn (rtl); + for (int j = 0; j < recog_data.n_operands; ++j) + *recog_data.operand_loc[j] = pc_rtx; + + auto *use = find_clobbered_access (change.new_uses, pat); + + // Restore the operands. + for (int j = 0; j < recog_data.n_operands; ++j) + *recog_data.operand_loc[j] = recog_data.operand[j]; + + if (use) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "register %d is both clobbered" + " and used as an input:\n", use->regno ()); + print_rtl_single (dump_file, pat); + } + return false; + } + } + // check_asm_operands checks the constraints after RA, so we don't // need to do it again. - INSN_CODE (rtl) = icode; if (reload_completed && !asm_p) { extract_insn (rtl); diff --git a/gcc/testsuite/gcc.target/i386/pr115891.c b/gcc/testsuite/gcc.target/i386/pr115891.c new file mode 100644 index 00000000000..b1a1b159c5d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr115891.c @@ -0,0 +1,10 @@ +/* { dg-require-effective-target ia32 } */ +/* { dg-options "-O2" } */ + +void __attribute__((regparm(1))) +f (int *ptr) +{ + asm volatile ("mem = %0" : "=m" (*ptr) :: "ax"); +} + +/* { dg-final { scan-assembler-not {mem = [^\n]*%eax} } } */