https://gcc.gnu.org/g:aebcf71b7a50bb6e72c539d4e8aae0c96c732a44

commit r16-9197-gaebcf71b7a50bb6e72c539d4e8aae0c96c732a44
Author: Stefan Schulze Frielinghaus <[email protected]>
Date:   Fri Jun 12 11:15:14 2026 +0200

    ira: Allow multiple uses within an insn [PR125173]
    
    For the attached test we end up during IRA with
    
    6: r99:DI=`s'
      REG_EQUIV `s'
    7: {[`b']=asm_operands;
        [const(`s'+0x4)]=asm_operands;
        [`a']=asm_operands;clobber flags:CC;}
      REG_DEAD r99:DI
      REG_UNUSED flags:CC
    
    where r99 is used in each asm_operands
    
    (mem/c:SI (plus:DI (reg/f:DI 99)
                       (const_int 4 [0x4])) [2 s.d+0 S4 A32])
    
    This in turn means that we hit multiple times the very same insn while
    iterating over all uses of r99 which in the end triggers the assert.
    
    This patch relaxes the assert since what we want to ensure here is that
    a register is not used by multiple insns since otherwise we cannot
    trivially move or delete the definition.
    
            PR rtl-optimization/125173
    
    gcc/ChangeLog:
    
            * ira.cc (combine_and_move_insns): Allow multiple uses within
            an insn.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/pr125173-1.c: New test.
    
    (cherry picked from commit 107d2ad166d09883b43ec1a5cf1e37c68b134a93)

Diff:
---
 gcc/ira.cc                        | 12 +++++++++++-
 gcc/testsuite/gcc.dg/pr125173-1.c | 17 +++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/gcc/ira.cc b/gcc/ira.cc
index d65e1b97ed84..3936fa0fbc16 100644
--- a/gcc/ira.cc
+++ b/gcc/ira.cc
@@ -3982,6 +3982,7 @@ combine_and_move_insns (void)
        continue;
 
       rtx_insn *use_insn = 0;
+      bool multiple_insns = false;
       for (df_ref use = DF_REG_USE_CHAIN (regno);
           use;
           use = DF_REF_NEXT_REG (use))
@@ -3989,11 +3990,20 @@ combine_and_move_insns (void)
          {
            if (DEBUG_INSN_P (DF_REF_INSN (use)))
              continue;
-           gcc_assert (!use_insn);
+           if (use_insn && DF_REF_INSN (use) != use_insn)
+             {
+               multiple_insns = true;
+               break;
+             }
            use_insn = DF_REF_INSN (use);
          }
       gcc_assert (use_insn);
 
+      /* If a register is used by more than one insn, we cannot trivially move
+        or delete the definition anymore.  */
+      if (multiple_insns)
+       continue;
+
       /* Don't substitute into jumps.  indirect_jump_optimize does
         this for anything we are prepared to handle.  */
       if (JUMP_P (use_insn))
diff --git a/gcc/testsuite/gcc.dg/pr125173-1.c 
b/gcc/testsuite/gcc.dg/pr125173-1.c
new file mode 100644
index 000000000000..5f66b24fcb00
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr125173-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fno-fuse-ops-with-volatile-access -fno-forward-propagate 
--param=max-cse-insns=0" } */
+
+int a;
+volatile short b;
+
+struct
+{
+  char c;
+  int d;
+} s;
+
+void
+foo ()
+{
+  __asm__ ("":"+m" (b), "+m" (s.d), "+m" (a));
+}

Reply via email to