| Message ID | 20260110161159.1073435-3-stefansf@linux.ibm.com |
|---|---|
| State | New |
| Headers |
Return-Path: <gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 90C774BA2E1F for <patchwork@sourceware.org>; Sat, 10 Jan 2026 16:13:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 90C774BA2E1F Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Ydpo9t3D X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 61A874BA2E26 for <gcc-patches@gcc.gnu.org>; Sat, 10 Jan 2026 16:12:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 61A874BA2E26 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.ibm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 61A874BA2E26 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768061541; cv=none; b=d0vqXfpoVV8H/FUK5VsBgC5puuO8Ju+cRf6eKimmS6fSoMwVV0ddeNso8sGKJ8lmtMnCJkCQXB0Scz3vm2Qhzf1ZskISk6yeisba22D2h2F1GdcGq0yP0z6mJxoBKA8ZInffun45TQk1DGX6agBu4u/I9wkhF73r7vlKt3ZBb7g= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768061541; c=relaxed/simple; bh=gbOc4kPAnyQ22eyNskvSNqgnAuwHyrPzd1UhzdbglaQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=q5UpBXAL1sOA7+68QgtFvEXMmnr8dy/5hd/aeNMAAl0wUObI4sg6oNGBQ/OjNISmpW6tyW0n79K0TXaMDC9UHpqfVQeu+HgGaJy7JR0zshS9wm+Gdw8dYmYEXkIozqO7r3/RQZuXyuVUDRLA8qmipQ3TdSaVKHgvNrubAwQkrbo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 61A874BA2E26 Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60ABgI6A012673 for <gcc-patches@gcc.gnu.org>; Sat, 10 Jan 2026 16:12:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=ZM31UrHtG/QmNU6Z6 avp4R8UiOlD+rNrUL7gTm+1gz4=; b=Ydpo9t3DC2tsVgDb1UM4Vc8+FOmnUdso1 EFD8KnQAzp9PPUCaz57CzU9Atgv53A1El/nWoScpBKaso7z0HWoRC6befV8rp/+i 8L0QcbhZefRLGKkFKX3y/B95PXzUcPAQGexpgXqUYY/3XZKrJJvodl2CDFArlquT Mv0gAO5pEy9xQLVf+eU5u8+BcEg5jclMZhNfGTcNcVhpro1n0/cWUIT+Teva4xJK /z9q3Sv17WxhA67XjMzMEKQJ6321pnA+L6ruHrUyNLbxEsWaDHpB8JVgjuXSJ8mU aagX5Xymemw2xuaovvS/AXYT5NPWvE3Up9b1kok4Yvenni0AG10Pg== Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkedshdrx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for <gcc-patches@gcc.gnu.org>; Sat, 10 Jan 2026 16:12:20 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60AFCUvn004091 for <gcc-patches@gcc.gnu.org>; Sat, 10 Jan 2026 16:12:20 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bkavbtr3n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for <gcc-patches@gcc.gnu.org>; Sat, 10 Jan 2026 16:12:19 +0000 Received: from smtpav06.fra02v.mail.ibm.com (smtpav06.fra02v.mail.ibm.com [10.20.54.105]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60AGCGqr42205526 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 10 Jan 2026 16:12:16 GMT Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 106C220049; Sat, 10 Jan 2026 16:12:16 +0000 (GMT) Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EFE7720040; Sat, 10 Jan 2026 16:12:15 +0000 (GMT) Received: from a8345010.lnxne.boe (unknown [9.152.108.100]) by smtpav06.fra02v.mail.ibm.com (Postfix) with ESMTPS; Sat, 10 Jan 2026 16:12:15 +0000 (GMT) From: Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> To: gcc-patches@gcc.gnu.org Cc: Stefan Schulze Frielinghaus <stefansf@linux.ibm.com> Subject: [PATCH 2/3] cse: Take single register constraints into account Date: Sat, 10 Jan 2026 17:11:58 +0100 Message-ID: <20260110161159.1073435-3-stefansf@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260110161159.1073435-1-stefansf@linux.ibm.com> References: <20260110161159.1073435-1-stefansf@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTEwMDEzOSBTYWx0ZWRfX1qucvMDhatRx gPA2vbQxs3iIs/DURKwEHQdkGiHtWseulRc85uXTwgIBNL1R5pU+RoRl9HV2zj4e79zCi7LsAr6 BywphJV2r3ovaN3P9TjkK1kbwWesLA2gY7XajvYvf7f5s2AyAcKcklXJKbuvF2AQ6VDmeCSRalk bEoVNAisc7t5MLftF3+itQbWYpaBz9B7TL7BZLkZnmJsOe1o8m0LZGMw6137hCNX3uF83PLaTO2 jCOH8c6yA0bK8iDAa9W6NzyV5hZAGI+tr1DtIp/GA/9w9YgSjzYKXRtGMrtLXYraMoYQQhB5pCq /kMd9KGvEi9oLSGshke6I+gjqoAjPtkDGvbK9b1DOZXn5iV4LoeJGzDINQBDNbR7v2pvFfuk0ip MIbT5/Kfn/EbO/ODwwocMfZ347of2rjyB9NSZKswPIvfLa+TPa3lq2vAdQiIgcMF1EIFo5LlA5n E/CnYyTSgKcnUNdg74w== X-Proofpoint-GUID: Gi44pb5cmUAUpyHizgLPBipNlsuprLjS X-Authority-Analysis: v=2.4 cv=WLJyn3sR c=1 sm=1 tr=0 ts=69627a64 cx=c_pps a=5BHTudwdYE3Te8bg5FgnPg==:117 a=5BHTudwdYE3Te8bg5FgnPg==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=mDV3o1hIAAAA:8 a=3WxvHUeLdPRF0WQvEOQA:9 a=3ZKOabzyN94A:10 X-Proofpoint-ORIG-GUID: Gi44pb5cmUAUpyHizgLPBipNlsuprLjS X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-10_05,2026-01-09_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 adultscore=0 malwarescore=0 phishscore=0 suspectscore=0 priorityscore=1501 bulkscore=0 clxscore=1015 impostorscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601100139 X-Spam-Status: No, score=-8.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_PASS, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org |
| Series |
Take single register constraints into account
|
|
Commit Message
Stefan Schulze Frielinghaus
Jan. 10, 2026, 4:11 p.m. UTC
From: Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
This fixes
t.c:17:3: error: 'asm' operand has impossible constraints or there are not enough registers
17 | __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d));
| ^~~~~~~
on powerpc64le-unknown-linux-gnu for the attached test. Prior cse1 we have
(insn 2 4 3 2 (set (reg/v:TF 120 [ c ])
(reg:TF 33 1 [ c ])) "t.c":14:26 614 {*movtf_64bit_dm}
(nil))
...
(insn 10 9 6 2 (parallel [
(set (reg:DF 121)
(asm_operands:DF ("") ("=f") 0 [
(reg:TF 124)
]
[
(asm_input:TF ("{fr1}") t.c:17)
]
[] t.c:17))
(set (reg:DF 123 [ e ])
(asm_operands:DF ("") ("={fr2}") 1 [
(reg:TF 124)
]
[
(asm_input:TF ("{fr1}") t.c:17)
]
[] t.c:17))
(clobber (reg:SI 98 ca))
]) "t.c":17:3 -1
(nil))
...
(insn 12 11 13 2 (set (reg:TF 33 1)
(reg/v:TF 120 [ c ])) "t.c":18:12 614 {*movtf_64bit_dm}
(nil))
During cse1, in insn 12 pseudo 120 is substituted with hard register 33
rendering the resulting insn trivial which is why the insn gets removed
afterwards. Since hard register 33 has a use after insn 12, the
register is live before and after insn 10. This leaves us with the
non-trivial problem, during LRA, to also assign hard register 33 to
pseudo 124 which is coming from the constraint of insn 10. Since hard
registers are not tracked, except for liveness, this cannot be solved by
reloads which is why we end up with an error.
Therefore, treat single register constraints as clobbers of the
respective hard registers. This includes constraints associated a
single register class as well as hard register constraints.
gcc/ChangeLog:
* cse.cc (invalidate_from_sets_and_clobbers): Consider any hard
register referred to by any single register constraint
potentially being clobbered.
gcc/testsuite/ChangeLog:
* gcc.target/powerpc/asm-hard-reg-2.c: New test.
---
Bootstrapped and regtested on aarch64, powerpc64le, s390, x86_64. Ok
for mainline?
gcc/cse.cc | 42 +++++++++++++++++++
.../gcc.target/powerpc/asm-hard-reg-2.c | 9 ++++
2 files changed, 51 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c
Comments
On 1/10/2026 9:11 AM, Stefan Schulze Frielinghaus wrote: > From: Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> > > This fixes > > t.c:17:3: error: 'asm' operand has impossible constraints or there are not enough registers > 17 | __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d)); > | ^~~~~~~ > > on powerpc64le-unknown-linux-gnu for the attached test. Prior cse1 we have > > (insn 2 4 3 2 (set (reg/v:TF 120 [ c ]) > (reg:TF 33 1 [ c ])) "t.c":14:26 614 {*movtf_64bit_dm} > (nil)) > ... > (insn 10 9 6 2 (parallel [ > (set (reg:DF 121) > (asm_operands:DF ("") ("=f") 0 [ > (reg:TF 124) > ] > [ > (asm_input:TF ("{fr1}") t.c:17) > ] > [] t.c:17)) > (set (reg:DF 123 [ e ]) > (asm_operands:DF ("") ("={fr2}") 1 [ > (reg:TF 124) > ] > [ > (asm_input:TF ("{fr1}") t.c:17) > ] > [] t.c:17)) > (clobber (reg:SI 98 ca)) > ]) "t.c":17:3 -1 > (nil)) > ... > (insn 12 11 13 2 (set (reg:TF 33 1) > (reg/v:TF 120 [ c ])) "t.c":18:12 614 {*movtf_64bit_dm} > (nil)) > > During cse1, in insn 12 pseudo 120 is substituted with hard register 33 > rendering the resulting insn trivial which is why the insn gets removed > afterwards. Since hard register 33 has a use after insn 12, the > register is live before and after insn 10. This leaves us with the > non-trivial problem, during LRA, to also assign hard register 33 to > pseudo 124 which is coming from the constraint of insn 10. Since hard > registers are not tracked, except for liveness, this cannot be solved by > reloads which is why we end up with an error. > > Therefore, treat single register constraints as clobbers of the > respective hard registers. This includes constraints associated a > single register class as well as hard register constraints. > > gcc/ChangeLog: > > * cse.cc (invalidate_from_sets_and_clobbers): Consider any hard > register referred to by any single register constraint > potentially being clobbered. > > gcc/testsuite/ChangeLog: > > * gcc.target/powerpc/asm-hard-reg-2.c: New test. Can we really get at the register classes while in CSE? That's a bit of a surprise. My recollection is these kinds of cases a handled by the likely-spilled hooks. Look in hash_rtx, where that code is lying around. Jeff jeff
On Tue, Jan 13, 2026 at 08:20:49AM -0700, Jeffrey Law wrote: > > > On 1/10/2026 9:11 AM, Stefan Schulze Frielinghaus wrote: > > From: Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> > > > > This fixes > > > > t.c:17:3: error: 'asm' operand has impossible constraints or there are not enough registers > > 17 | __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d)); > > | ^~~~~~~ > > > > on powerpc64le-unknown-linux-gnu for the attached test. Prior cse1 we have > > > > (insn 2 4 3 2 (set (reg/v:TF 120 [ c ]) > > (reg:TF 33 1 [ c ])) "t.c":14:26 614 {*movtf_64bit_dm} > > (nil)) > > ... > > (insn 10 9 6 2 (parallel [ > > (set (reg:DF 121) > > (asm_operands:DF ("") ("=f") 0 [ > > (reg:TF 124) > > ] > > [ > > (asm_input:TF ("{fr1}") t.c:17) > > ] > > [] t.c:17)) > > (set (reg:DF 123 [ e ]) > > (asm_operands:DF ("") ("={fr2}") 1 [ > > (reg:TF 124) > > ] > > [ > > (asm_input:TF ("{fr1}") t.c:17) > > ] > > [] t.c:17)) > > (clobber (reg:SI 98 ca)) > > ]) "t.c":17:3 -1 > > (nil)) > > ... > > (insn 12 11 13 2 (set (reg:TF 33 1) > > (reg/v:TF 120 [ c ])) "t.c":18:12 614 {*movtf_64bit_dm} > > (nil)) > > > > During cse1, in insn 12 pseudo 120 is substituted with hard register 33 > > rendering the resulting insn trivial which is why the insn gets removed > > afterwards. Since hard register 33 has a use after insn 12, the > > register is live before and after insn 10. This leaves us with the > > non-trivial problem, during LRA, to also assign hard register 33 to > > pseudo 124 which is coming from the constraint of insn 10. Since hard > > registers are not tracked, except for liveness, this cannot be solved by > > reloads which is why we end up with an error. > > > > Therefore, treat single register constraints as clobbers of the > > respective hard registers. This includes constraints associated a > > single register class as well as hard register constraints. > > > > gcc/ChangeLog: > > > > * cse.cc (invalidate_from_sets_and_clobbers): Consider any hard > > register referred to by any single register constraint > > potentially being clobbered. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.target/powerpc/asm-hard-reg-2.c: New test. > Can we really get at the register classes while in CSE? That's a bit of a > surprise. My recollection is these kinds of cases a handled by the > likely-spilled hooks. Look in hash_rtx, where that code is lying around. ira_class_singleton is setup in setup_prohibited_and_exclude_class_mode_regs() which is called during ira_init() which itself is called during backend_init_target(). So my reading is that it should be save to access during CSE. On the other hand I'm wondering why this is not in ira_init_once(). Maybe I'm overlooking something here. Let me double check. The likely-spilled hook seems to be precisely what I was looking for. Thanks for the pointer! Cheers, Stefan
On Tue, Jan 13, 2026 at 05:50:47PM +0100, Stefan Schulze Frielinghaus wrote: > On Tue, Jan 13, 2026 at 08:20:49AM -0700, Jeffrey Law wrote: > > > > > > On 1/10/2026 9:11 AM, Stefan Schulze Frielinghaus wrote: > > > From: Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org> > > > > > > This fixes > > > > > > t.c:17:3: error: 'asm' operand has impossible constraints or there are not enough registers > > > 17 | __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d)); > > > | ^~~~~~~ > > > > > > on powerpc64le-unknown-linux-gnu for the attached test. Prior cse1 we have > > > > > > (insn 2 4 3 2 (set (reg/v:TF 120 [ c ]) > > > (reg:TF 33 1 [ c ])) "t.c":14:26 614 {*movtf_64bit_dm} > > > (nil)) > > > ... > > > (insn 10 9 6 2 (parallel [ > > > (set (reg:DF 121) > > > (asm_operands:DF ("") ("=f") 0 [ > > > (reg:TF 124) > > > ] > > > [ > > > (asm_input:TF ("{fr1}") t.c:17) > > > ] > > > [] t.c:17)) > > > (set (reg:DF 123 [ e ]) > > > (asm_operands:DF ("") ("={fr2}") 1 [ > > > (reg:TF 124) > > > ] > > > [ > > > (asm_input:TF ("{fr1}") t.c:17) > > > ] > > > [] t.c:17)) > > > (clobber (reg:SI 98 ca)) > > > ]) "t.c":17:3 -1 > > > (nil)) > > > ... > > > (insn 12 11 13 2 (set (reg:TF 33 1) > > > (reg/v:TF 120 [ c ])) "t.c":18:12 614 {*movtf_64bit_dm} > > > (nil)) > > > > > > During cse1, in insn 12 pseudo 120 is substituted with hard register 33 > > > rendering the resulting insn trivial which is why the insn gets removed > > > afterwards. Since hard register 33 has a use after insn 12, the > > > register is live before and after insn 10. This leaves us with the > > > non-trivial problem, during LRA, to also assign hard register 33 to > > > pseudo 124 which is coming from the constraint of insn 10. Since hard > > > registers are not tracked, except for liveness, this cannot be solved by > > > reloads which is why we end up with an error. > > > > > > Therefore, treat single register constraints as clobbers of the > > > respective hard registers. This includes constraints associated a > > > single register class as well as hard register constraints. > > > > > > gcc/ChangeLog: > > > > > > * cse.cc (invalidate_from_sets_and_clobbers): Consider any hard > > > register referred to by any single register constraint > > > potentially being clobbered. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * gcc.target/powerpc/asm-hard-reg-2.c: New test. > > Can we really get at the register classes while in CSE? That's a bit of a > > surprise. My recollection is these kinds of cases a handled by the > > likely-spilled hooks. Look in hash_rtx, where that code is lying around. > > ira_class_singleton is setup in > setup_prohibited_and_exclude_class_mode_regs() which is called during > ira_init() which itself is called during backend_init_target(). So my > reading is that it should be save to access during CSE. On the other > hand I'm wondering why this is not in ira_init_once(). Maybe I'm > overlooking something here. Let me double check. Hmm even after giving it a second thought I still don't see a reason not to access ira_class_singleton since it is set during initialize_rtl(). Maybe I'm overlooking something fundamental here? Anyhow, I added else { enum reg_class cl = reg_class_for_constraint (lookup_constraint (p)); if (cl == NO_REGS) continue; machine_mode mode = recog_data.operand_mode[nop]; int regno = ira_class_singleton[cl][mode]; if (regno >= 0) invalidate_reg (gen_rtx_REG (mode, regno)); } for the sake of completeness and symmetry of hard register constraints and constraints associated a single register class. Maybe the stage4 interrupt should be applied here, too, i.e., I don't want to risk it and introduce hiccups. Would the patch be ok if I remove the else clause and the include statement of ira.h? Cheers, Stefan
On 1/14/2026 8:13 AM, Stefan Schulze Frielinghaus wrote: >>>> gcc/ChangeLog: >>>> >>>> * cse.cc (invalidate_from_sets_and_clobbers): Consider any hard >>>> register referred to by any single register constraint >>>> potentially being clobbered. >>>> >>>> gcc/testsuite/ChangeLog: >>>> >>>> * gcc.target/powerpc/asm-hard-reg-2.c: New test. >>> Can we really get at the register classes while in CSE? That's a bit of a >>> surprise. My recollection is these kinds of cases a handled by the >>> likely-spilled hooks. Look in hash_rtx, where that code is lying around. >> ira_class_singleton is setup in >> setup_prohibited_and_exclude_class_mode_regs() which is called during >> ira_init() which itself is called during backend_init_target(). So my >> reading is that it should be save to access during CSE. On the other >> hand I'm wondering why this is not in ira_init_once(). Maybe I'm >> overlooking something here. Let me double check. > Hmm even after giving it a second thought I still don't see a reason not > to access ira_class_singleton since it is set during initialize_rtl(). > Maybe I'm overlooking something fundamental here? > > Anyhow, I added > > else > { > enum reg_class cl > = reg_class_for_constraint (lookup_constraint (p)); > if (cl == NO_REGS) > continue; > machine_mode mode = recog_data.operand_mode[nop]; > int regno = ira_class_singleton[cl][mode]; > if (regno >= 0) > invalidate_reg (gen_rtx_REG (mode, regno)); > } > > for the sake of completeness and symmetry of hard register constraints > and constraints associated a single register class. Maybe the stage4 > interrupt should be applied here, too, i.e., I don't want to risk it and > introduce hiccups. Would the patch be ok if I remove the else clause > and the include statement of ira.h? It was more "I didn't realize we could do that" and "we should tie this into the existing mechansisms to avoid CSE in some cases if possible". The likely-spilled classes machinery can't be used as-is since the decision for your case is dependent upon context (ie, the insn itself and its constraints). So perhaps what we want is your code to peek at the constraints, but bolted onto the code that's checking for the likely-spilled classes? Jeff
On Thu, Jan 15, 2026 at 09:01:41AM -0700, Jeffrey Law wrote: > > > On 1/14/2026 8:13 AM, Stefan Schulze Frielinghaus wrote: > > > > > gcc/ChangeLog: > > > > > > > > > > * cse.cc (invalidate_from_sets_and_clobbers): Consider any hard > > > > > register referred to by any single register constraint > > > > > potentially being clobbered. > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > * gcc.target/powerpc/asm-hard-reg-2.c: New test. > > > > Can we really get at the register classes while in CSE? That's a bit of a > > > > surprise. My recollection is these kinds of cases a handled by the > > > > likely-spilled hooks. Look in hash_rtx, where that code is lying around. > > > ira_class_singleton is setup in > > > setup_prohibited_and_exclude_class_mode_regs() which is called during > > > ira_init() which itself is called during backend_init_target(). So my > > > reading is that it should be save to access during CSE. On the other > > > hand I'm wondering why this is not in ira_init_once(). Maybe I'm > > > overlooking something here. Let me double check. > > Hmm even after giving it a second thought I still don't see a reason not > > to access ira_class_singleton since it is set during initialize_rtl(). > > Maybe I'm overlooking something fundamental here? > > > > Anyhow, I added > > > > else > > { > > enum reg_class cl > > = reg_class_for_constraint (lookup_constraint (p)); > > if (cl == NO_REGS) > > continue; > > machine_mode mode = recog_data.operand_mode[nop]; > > int regno = ira_class_singleton[cl][mode]; > > if (regno >= 0) > > invalidate_reg (gen_rtx_REG (mode, regno)); > > } > > > > for the sake of completeness and symmetry of hard register constraints > > and constraints associated a single register class. Maybe the stage4 > > interrupt should be applied here, too, i.e., I don't want to risk it and > > introduce hiccups. Would the patch be ok if I remove the else clause > > and the include statement of ira.h? > It was more "I didn't realize we could do that" and "we should tie this into > the existing mechansisms to avoid CSE in some cases if possible". Understood. Thanks for clarification. > > > The likely-spilled classes machinery can't be used as-is since the decision > for your case is dependent upon context (ie, the insn itself and its > constraints). So perhaps what we want is your code to peek at the > constraints, but bolted onto the code that's checking for the likely-spilled > classes? My knowledge about cse is very thin and so far I don't see how to implement this in hash_rtx() or tight this with likely-spilled classes. For example, having 1: r100=%1 2: r101=... 3: r102=exp_a(r100) 4: r103=exp_b(r101) 5: r104=exp_c(r100) Assume that insn 3 has no hard register constraint, but insn 4 does which is referring to hard register %1. Then I would still like to keep track that r100 and %1 hold the same value, while analyzing insn 1, which enables me to substitute r100 by %1 in insn 3. For insn 4, however, I would like to invalidate this relation, since operand r101 is potentially loaded into %1 and would clobber the register. Explicitly clobbering/invalidating register %1 while analyzing insn 4 ensures that r100 is not substituted by %1 in insn 5. Thus, at first encounter I still want to hash a hard register and at some later point once I encounter a hard register constraint referring to the same hard register, I want to invalidate it. To be conservative here, I do this irrespective whether an alternative is likely, unlikely, or whatsoever. Basically I'm treating a hard register constraint as a possible load. In that regard hard register constraints may not be as restrictive as single register classes, since for the latter even a substitution into insn 3 wouldn't be done if I read the current implementation correctly. Cheers, Stefan
On 1/16/2026 7:29 AM, Stefan Schulze Frielinghaus wrote: >> >> The likely-spilled classes machinery can't be used as-is since the decision >> for your case is dependent upon context (ie, the insn itself and its >> constraints). So perhaps what we want is your code to peek at the >> constraints, but bolted onto the code that's checking for the likely-spilled >> classes? > My knowledge about cse is very thin and so far I don't see how to > implement this in hash_rtx() or tight this with likely-spilled classes. > For example, having > > 1: r100=%1 > 2: r101=... > 3: r102=exp_a(r100) > 4: r103=exp_b(r101) > 5: r104=exp_c(r100) > > Assume that insn 3 has no hard register constraint, but insn 4 does > which is referring to hard register %1. Then I would still like to keep > track that r100 and %1 hold the same value, while analyzing insn 1, > which enables me to substitute r100 by %1 in insn 3. For insn 4, > however, I would like to invalidate this relation, since operand r101 is > potentially loaded into %1 and would clobber the register. Explicitly > clobbering/invalidating register %1 while analyzing insn 4 ensures that > r100 is not substituted by %1 in insn 5. > > Thus, at first encounter I still want to hash a hard register and at > some later point once I encounter a hard register constraint referring to > the same hard register, I want to invalidate it. To be conservative > here, I do this irrespective whether an alternative is likely, unlikely, > or whatsoever. Basically I'm treating a hard register constraint as a > possible load. > > In that regard hard register constraints may not be as restrictive as > single register classes, since for the latter even a substitution into > insn 3 wouldn't be done if I read the current implementation correctly. The basic idea is that by setting "record" to false, the value won't be kept in the hash table and it won't be subject to CSE going forward. For your scenario I think we still have a problem; but I don't see a great solution. Essentially at 1, you don't know if %1 is safe to have its lifetime extended. That's the key difference -- more context is needed for the single register constraint issues. ISTM that you have to invalidate the relevant hash table entries at 4. Not sure the best way to do that, most of CSE has fallen out of my brain through the years. jeff > > Cheers, > Stefan
On Thu, Jan 22, 2026 at 09:55:42AM -0700, Jeffrey Law wrote: > > > On 1/16/2026 7:29 AM, Stefan Schulze Frielinghaus wrote: > > > > > > The likely-spilled classes machinery can't be used as-is since the decision > > > for your case is dependent upon context (ie, the insn itself and its > > > constraints). So perhaps what we want is your code to peek at the > > > constraints, but bolted onto the code that's checking for the likely-spilled > > > classes? > > My knowledge about cse is very thin and so far I don't see how to > > implement this in hash_rtx() or tight this with likely-spilled classes. > > For example, having > > > > 1: r100=%1 > > 2: r101=... > > 3: r102=exp_a(r100) > > 4: r103=exp_b(r101) > > 5: r104=exp_c(r100) > > > > Assume that insn 3 has no hard register constraint, but insn 4 does > > which is referring to hard register %1. Then I would still like to keep > > track that r100 and %1 hold the same value, while analyzing insn 1, > > which enables me to substitute r100 by %1 in insn 3. For insn 4, > > however, I would like to invalidate this relation, since operand r101 is > > potentially loaded into %1 and would clobber the register. Explicitly > > clobbering/invalidating register %1 while analyzing insn 4 ensures that > > r100 is not substituted by %1 in insn 5. > > > > Thus, at first encounter I still want to hash a hard register and at > > some later point once I encounter a hard register constraint referring to > > the same hard register, I want to invalidate it. To be conservative > > here, I do this irrespective whether an alternative is likely, unlikely, > > or whatsoever. Basically I'm treating a hard register constraint as a > > possible load. > > > > In that regard hard register constraints may not be as restrictive as > > single register classes, since for the latter even a substitution into > > insn 3 wouldn't be done if I read the current implementation correctly. > The basic idea is that by setting "record" to false, the value won't be kept > in the hash table and it won't be subject to CSE going forward. For your > scenario I think we still have a problem; but I don't see a great solution. > Essentially at 1, you don't know if %1 is safe to have its lifetime > extended. That's the key difference -- more context is needed for the > single register constraint issues. Yes, there is basically one contract which has to be fulfilled at the moment: A hard register N must not be live at an insn which constraints an operand to hard register N via a hard register constraint or a constraint referring to a single register class. That would be a bug coming either from an optimization or if the target emits a sequence of instructions where we have assignments to hard registers and usages of hard register constraints referring to the same hard register. Assume that in the following r100 is constraint to hard register %1 in insn 1 and 3. Furthermore, assume that hard register %1 becomes dead between insn 2 and 3. 1: r101=exp_a(r100) ... 2: %r1=... ... 3: r102=exp_b(r100) Then r100 would be assigned %r1 for insn 1 and spilled prior insn 2 and reloaded just after insn 2 as soon as %1 becomes dead. Thus, between insn 2 and 3 the lifetime of %1 may be extended assuming that no other insn has a single register constraint referring to %1. The important part is that %1 becomes dead somewhere before insn 3, i.e., I have to prevent CSE to extend the lifetime of register %1 across insn 3. > > ISTM that you have to invalidate the relevant hash table entries at 4. Not > sure the best way to do that, most of CSE has fallen out of my brain through > the years. Isn't this what is happening by this patch during invalidate_from_sets_and_clobbers() where we have the context in form of the insn? I'm basically removing all hash table entries which are related to a register which is referred by any hard register constraint. That should prevent CSE to propagate a hard register any further. Cheers, Stefan
On 1/23/2026 7:49 AM, Stefan Schulze Frielinghaus wrote: > On Thu, Jan 22, 2026 at 09:55:42AM -0700, Jeffrey Law wrote: >> >> On 1/16/2026 7:29 AM, Stefan Schulze Frielinghaus wrote: >>>> The likely-spilled classes machinery can't be used as-is since the decision >>>> for your case is dependent upon context (ie, the insn itself and its >>>> constraints). So perhaps what we want is your code to peek at the >>>> constraints, but bolted onto the code that's checking for the likely-spilled >>>> classes? >>> My knowledge about cse is very thin and so far I don't see how to >>> implement this in hash_rtx() or tight this with likely-spilled classes. >>> For example, having >>> >>> 1: r100=%1 >>> 2: r101=... >>> 3: r102=exp_a(r100) >>> 4: r103=exp_b(r101) >>> 5: r104=exp_c(r100) >>> >>> Assume that insn 3 has no hard register constraint, but insn 4 does >>> which is referring to hard register %1. Then I would still like to keep >>> track that r100 and %1 hold the same value, while analyzing insn 1, >>> which enables me to substitute r100 by %1 in insn 3. For insn 4, >>> however, I would like to invalidate this relation, since operand r101 is >>> potentially loaded into %1 and would clobber the register. Explicitly >>> clobbering/invalidating register %1 while analyzing insn 4 ensures that >>> r100 is not substituted by %1 in insn 5. >>> >>> Thus, at first encounter I still want to hash a hard register and at >>> some later point once I encounter a hard register constraint referring to >>> the same hard register, I want to invalidate it. To be conservative >>> here, I do this irrespective whether an alternative is likely, unlikely, >>> or whatsoever. Basically I'm treating a hard register constraint as a >>> possible load. >>> >>> In that regard hard register constraints may not be as restrictive as >>> single register classes, since for the latter even a substitution into >>> insn 3 wouldn't be done if I read the current implementation correctly. >> The basic idea is that by setting "record" to false, the value won't be kept >> in the hash table and it won't be subject to CSE going forward. For your >> scenario I think we still have a problem; but I don't see a great solution. >> Essentially at 1, you don't know if %1 is safe to have its lifetime >> extended. That's the key difference -- more context is needed for the >> single register constraint issues. > Yes, there is basically one contract which has to be fulfilled at the > moment: A hard register N must not be live at an insn which constraints > an operand to hard register N via a hard register constraint or a > constraint referring to a single register class. That would be a bug > coming either from an optimization or if the target emits a sequence of > instructions where we have assignments to hard registers and usages of > hard register constraints referring to the same hard register. > > Assume that in the following r100 is constraint to hard register %1 in > insn 1 and 3. Furthermore, assume that hard register %1 becomes dead > between insn 2 and 3. > > 1: r101=exp_a(r100) > ... > 2: %r1=... > ... > 3: r102=exp_b(r100) > > Then r100 would be assigned %r1 for insn 1 and spilled prior insn 2 and > reloaded just after insn 2 as soon as %1 becomes dead. Thus, between > insn 2 and 3 the lifetime of %1 may be extended assuming that no other > insn has a single register constraint referring to %1. The important > part is that %1 becomes dead somewhere before insn 3, i.e., I have to > prevent CSE to extend the lifetime of register %1 across insn 3. > >> ISTM that you have to invalidate the relevant hash table entries at 4. Not >> sure the best way to do that, most of CSE has fallen out of my brain through >> the years. > Isn't this what is happening by this patch during > invalidate_from_sets_and_clobbers() where we have the context in form of > the insn? I'm basically removing all hash table entries which are > related to a register which is referred by any hard register constraint. > That should prevent CSE to propagate a hard register any further. Yea, it just took me a little time to reach the conclusion that this has to be handled as an invalidation problem, not as a "avoid putting something into the hash table" problem. Now that I'm on board with that key concept, it's obvious to me that your patch is a reasonable solution. OK for the trunk. Thanks for your patience. Jeff > > Cheers, > Stefan
diff --git a/gcc/cse.cc b/gcc/cse.cc index a86fe307819..28175e2732b 100644 --- a/gcc/cse.cc +++ b/gcc/cse.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "backend.h" #include "target.h" #include "rtl.h" +#include "stmt.h" #include "tree.h" #include "cfghooks.h" #include "df.h" @@ -31,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "insn-config.h" #include "regs.h" #include "emit-rtl.h" +#include "ira.h" #include "recog.h" #include "cfgrtl.h" #include "cfganal.h" @@ -6217,6 +6219,46 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn) invalidate (SET_DEST (y), VOIDmode); } } + + /* Any single register constraint may introduce a conflict, if the associated + hard register is live. For example: + + r100=%1 + r101=42 + r102=exp(r101) + + If the first operand r101 of exp is constrained to hard register %1, then + r100 cannot be trivially substituted by %1 in the following since %1 got + clobbered. Such conflicts may stem from single register classes as well + as hard register constraints. Since prior RA we do not know which + alternative will be chosen, be conservative and consider any such hard + register from any alternative as a potential clobber. */ + extract_insn (insn); + for (int nop = recog_data.n_operands - 1; nop >= 0; --nop) + { + int c; + const char *p = recog_data.constraints[nop]; + for (; (c = *p); p += CONSTRAINT_LEN (c, p)) + if (c == ',') + ; + else if (c == '{') + { + int regno = decode_hard_reg_constraint (p); + machine_mode mode = recog_data.operand_mode[nop]; + invalidate_reg (gen_rtx_REG (mode, regno)); + } + else + { + enum reg_class cl + = reg_class_for_constraint (lookup_constraint (p)); + if (cl == NO_REGS) + continue; + machine_mode mode = recog_data.operand_mode[nop]; + int regno = ira_class_singleton[cl][mode]; + if (regno >= 0) + invalidate_reg (gen_rtx_REG (mode, regno)); + } + } } static rtx cse_process_note (rtx); diff --git a/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c b/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c new file mode 100644 index 00000000000..c0aad292acb --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +double a; +double b (long double c) { + long double d = 0; + double e; + __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d)); + return c + c; +}