On Mon, Jun 22, 2026 at 1:59 PM Uros Bizjak <[email protected]> wrote:
>
> -ENOPATCH

Oops.  Here it is.

> On Sun, Jun 21, 2026 at 11:44 PM H.J. Lu <[email protected]> wrote:
> >
> > Since LCP stall peepholes are added after register allocation, each
> > peephole may use a different scratch register.  For input:
> >
> > extern void bar (void);
> >
> > void
> > foo (short *dst)
> > {
> >   dst[0] = 3;
> >   asm volatile ("" : : : "memory");
> >   dst[2] = 3;
> >   bar ();
> >   dst[1] = 3;
> >   asm volatile ("" : : : "memory");
> >   dst[4] = 3;
> > }
> >
> > with LCP stall peepholes, GCC generates:
> >
> > movl $3, %eax
> > pushq %rbx
> > movq %rdi, %rbx
> > movw %ax, (%rdi)
> > movl $3, %edx
> > movw %dx, 4(%rdi)
> > call bar
> > movl $3, %ecx
> > movw %cx, 2(%rbx)
> > movl $3, %esi
> > movw %si, 8(%rbx)
> > popq %rbx
> >
> > using 4 different scratch registers vs without LCP stall peepholes:
> >
> > pushq %rbx
> > movq %rdi, %rbx
> > movw $3, (%rdi)
> > movw $3, 4(%rdi)
> > call bar
> > movw $3, 2(%rbx)
> > movw $3, 8(%rbx)
> > popq %rbx
> >
> > Add ix86_output_lcp_stall_peephole to generate LCP stall peepholes with
> > the previous scratch register:
> >
> > 1. Scan backward for the previous scratch register definition with
> > the same immediate operand in the same basic block.
> > 2. The previous scratch register is unusable if it is set between the
> > previous scratch register definition and the current instruction.
> > 3. If a usable previous scratch register is found, ignore the allocated
> > scratch register and use the previous scratch register.  Otherwise, use
> > the allocated scratch register.
> >
> > so that the same scratch register can be reused if possible:
> >
> > movl $3, %eax
> > pushq %rbx
> > movq %rdi, %rbx
> > movw %ax, (%rdi)
> > movw %ax, 4(%rdi)
> > call bar
> > movl $3, %ecx
> > movw %cx, 2(%rbx)
> > movw %cx, 8(%rbx)
> > popq %rbx
> >
> > I backported this patch to GCC 16:
> >
> > 1. When bootstrapping GCC 16 with only C and C++ enabled, this optimization
> > triggers 54 times.  No regressions.
> > 2. When building glibc 2.44, this optimization triggers 33 times.  No
> > regressions.
> > 3. When building Linux kernel 7.1.1, this optimization triggers 2099 times.
> > Kernel boots correctly.
> >
> > gcc/
> >
> > PR target/125893
> > * config/i386/i386-protos.h (ix86_output_lcp_stall_peephole):
> > New.
> > * config/i386/i386.cc (ix86_output_lcp_stall_peephole): Likewise.
> > * config/i386/i386.md (TARGET_LCP_STALL peepholes): Call
> > ix86_output_lcp_stall_peephole.
> >
> > gcc/testsuite/
> >
> > PR target/125893
> > * gcc.target/i386/pr125893-1.c: New test.
> > * gcc.target/i386/pr125893-2.c: Likewise.
> > * gcc.target/i386/pr125893-3.c: Likewise.
> > * gcc.target/i386/pr125893-4.c: Likewise.
> > * gcc.target/i386/pr125893-5.c: Likewise.
> > * gcc.target/i386/pr125893-6.c: Likewise.
> > * gcc.target/i386/pr125893-7.c: Likewise.
> > * gcc.target/i386/pr125893-8.c: Likewise.
> > * gcc.target/i386/pr125893-9.c: Likewise.
> > * gcc.target/i386/pr125893-10.c: Likewise.
> >
> >
> > --
> > H.J.



-- 
H.J.
From 1f5f76994de747415fe0e783c02bcdee8358c20c Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Sun, 21 Jun 2026 07:13:38 +0800
Subject: [PATCH] x86: Use previous scratch register in LCP stall peepholes

Since LCP stall peepholes are added after register allocation, each
peephole may use a different scratch register.  For input:

extern void bar (void);

void
foo (short *dst)
{
  dst[0] = 3;
  asm volatile ("" : : : "memory");
  dst[2] = 3;
  bar ();
  dst[1] = 3;
  asm volatile ("" : : : "memory");
  dst[4] = 3;
}

with LCP stall peepholes, GCC generates:

	movl	$3, %eax
	pushq	%rbx
	movq	%rdi, %rbx
	movw	%ax, (%rdi)
	movl	$3, %edx
	movw	%dx, 4(%rdi)
	call	bar
	movl	$3, %ecx
	movw	%cx, 2(%rbx)
	movl	$3, %esi
	movw	%si, 8(%rbx)
	popq	%rbx

using 4 different scratch registers vs without LCP stall peepholes:

	pushq	%rbx
	movq	%rdi, %rbx
	movw	$3, (%rdi)
	movw	$3, 4(%rdi)
	call	bar
	movw	$3, 2(%rbx)
	movw	$3, 8(%rbx)
	popq	%rbx

Add ix86_output_lcp_stall_peephole to generate LCP stall peepholes with
the previous scratch register:

1. Scan backward for the previous scratch register definition with
the same immediate operand in the same basic block.
2. The previous scratch register is unusable if it is set between the
previous scratch register definition and the current instruction.
3. If a usable previous scratch register is found, ignore the allocated
scratch register and use the previous scratch register.  Otherwise, use
the allocated scratch register.

so that the same scratch register can be reused if possible:

	movl	$3, %eax
	pushq	%rbx
	movq	%rdi, %rbx
	movw	%ax, (%rdi)
	movw	%ax, 4(%rdi)
	call	bar
	movl	$3, %ecx
	movw	%cx, 2(%rbx)
	movw	%cx, 8(%rbx)
	popq	%rbx

I backported this patch to GCC 16:

1. When bootstrapping GCC 16 with only C and C++ enabled, this optimization
triggers 54 times.  No regressions.
2. When building glibc 2.44, this optimization triggers 33 times.  No
regressions.
3. When building Linux kernel 7.1.1, this optimization triggers 2099 times.
Kernel boots correctly.

gcc/

	PR target/125893
	* config/i386/i386-protos.h (ix86_output_lcp_stall_peephole):
	New.
	* config/i386/i386.cc (ix86_output_lcp_stall_peephole): Likewise.
	* config/i386/i386.md (TARGET_LCP_STALL peepholes): Call
	ix86_output_lcp_stall_peephole.

gcc/testsuite/

	PR target/125893
	* gcc.target/i386/pr125893-1.c: New test.
	* gcc.target/i386/pr125893-2.c: Likewise.
	* gcc.target/i386/pr125893-3.c: Likewise.
	* gcc.target/i386/pr125893-4.c: Likewise.
	* gcc.target/i386/pr125893-5.c: Likewise.
	* gcc.target/i386/pr125893-6.c: Likewise.
	* gcc.target/i386/pr125893-7.c: Likewise.
	* gcc.target/i386/pr125893-8.c: Likewise.
	* gcc.target/i386/pr125893-9.c: Likewise.
	* gcc.target/i386/pr125893-10.c: Likewise.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/config/i386/i386-protos.h               |   1 +
 gcc/config/i386/i386.cc                     | 157 ++++++++++++++++++++
 gcc/config/i386/i386.md                     |  13 +-
 gcc/testsuite/gcc.target/i386/pr125893-1.c  |  27 ++++
 gcc/testsuite/gcc.target/i386/pr125893-10.c |  38 +++++
 gcc/testsuite/gcc.target/i386/pr125893-2.c  |  33 ++++
 gcc/testsuite/gcc.target/i386/pr125893-3.c  |  27 ++++
 gcc/testsuite/gcc.target/i386/pr125893-4.c  |  33 ++++
 gcc/testsuite/gcc.target/i386/pr125893-5.c  |  34 +++++
 gcc/testsuite/gcc.target/i386/pr125893-6.c  |  34 +++++
 gcc/testsuite/gcc.target/i386/pr125893-7.c  |  31 ++++
 gcc/testsuite/gcc.target/i386/pr125893-8.c  |  38 +++++
 gcc/testsuite/gcc.target/i386/pr125893-9.c  |  31 ++++
 13 files changed, 491 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-10.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125893-9.c

diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 695e50dccb5..a15eeb4bd17 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -40,6 +40,7 @@ extern void ix86_output_addr_vec_elt (FILE *, int);
 extern void ix86_output_addr_diff_elt (FILE *, int, int);
 
 extern const char *ix86_output_ssemov (rtx_insn *, rtx *);
+extern void ix86_output_lcp_stall_peephole (rtx_insn *, rtx *);
 
 extern enum calling_abi ix86_cfun_abi (void);
 extern enum calling_abi ix86_function_type_abi (const_tree);
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 42c1f07e804..f3d206afeaa 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -6036,6 +6036,163 @@ ix86_output_ssemov (rtx_insn *insn, rtx *operands)
     }
 }
 
+/* Output LCP stall or long immediate peephole for INSN.  Use the
+   previous scratch register if possible.  */
+
+void
+ix86_output_lcp_stall_peephole (rtx_insn *insn, rtx *operands)
+{
+  rtx imm, scratch;
+  bool use_xor;
+  machine_mode mode = GET_MODE (operands[0]);
+
+  /* Get the immediate operand and the allocated scratch register.  */
+  if (operands[2] == const0_rtx)
+    {
+      use_xor = true;
+      imm = const0_rtx;
+      scratch = operands[1];
+    }
+  else
+    {
+      use_xor = false;
+      imm = operands[1];
+      scratch = operands[2];
+    }
+
+  df_ref def;
+  rtx_insn *prev, *prev_insn = nullptr;
+  rtx set, prev_scratch = nullptr;
+
+  /* Scan backward for the previous scratch register def with IMM in
+     the same basic block.  */
+  basic_block bb = BLOCK_FOR_INSN (insn);
+  for (prev = PREV_INSN (insn);
+       prev != BB_HEAD (bb);
+       prev = PREV_INSN (prev))
+    {
+      if (NONDEBUG_INSN_P (prev))
+	FOR_EACH_INSN_DEF (def, prev)
+	  if (!DF_REF_IS_ARTIFICIAL (def)
+	      && !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)
+	      && !DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
+	    {
+	      rtx reg = DF_REF_REG (def);
+	      if (HARD_REGISTER_P (reg) && REGNO (reg) != FLAGS_REG)
+		{
+		  set = single_set (prev);
+		  if (!set)
+		    continue;
+
+		  rtx dest = SET_DEST (set);
+		  /* The previous scratch register mode must be at least
+		     MODE.  */
+		  if (!REG_P (dest)
+		      || (GET_MODE_SIZE (GET_MODE (dest))
+			  < GET_MODE_SIZE (mode)))
+		    continue;
+
+		  rtx src = SET_SRC (set);
+		  if (rtx_equal_p (src, imm))
+		    {
+		      /* A previous scratch register is found.  */
+		      prev_scratch = dest;
+		      prev_insn = prev;
+		      break;
+		    }
+		}
+	    }
+
+      if (prev_scratch)
+	break;
+    }
+
+  if (prev_scratch)
+    {
+      /* The previous scratch register is unusable if it is set between
+	 PREV_INSN and INSN.  */
+      unsigned int regno = REGNO (prev_scratch);
+
+      /* Scan backward for the previous scratch register def.  */
+      for (prev = PREV_INSN (insn);
+	   prev != prev_insn;
+	   prev = PREV_INSN (prev))
+	{
+	  if (NONDEBUG_INSN_P (prev))
+	    FOR_EACH_INSN_DEF (def, prev)
+	      if (HARD_REGISTER_P (DF_REF_REAL_REG (def))
+		  && DF_REF_REGNO (def) == regno)
+		{
+		  /* Since the previous scratch register is set, it is
+		     unusable.  */
+		  if (dump_file)
+		    {
+		      fprintf (dump_file,
+			       "\nThe previous scratch register:\n\n");
+		      print_rtl_single (dump_file, prev_scratch);
+		      fprintf (dump_file, "\nset in:\n\n");
+		      print_rtl_single (dump_file, prev_insn);
+		      fprintf (dump_file,
+			       "\nis unusable by:\n\n");
+		      print_rtl_single (dump_file, insn);
+		      fprintf (dump_file,
+			       "\nsince it is overridden by:\n\n");
+		      print_rtl_single (dump_file, prev);
+		      fprintf (dump_file, "\n");
+		    }
+		  prev_scratch = nullptr;
+		  break;
+		}
+
+	  if (!prev_scratch)
+	    break;
+	}
+
+      if (prev_scratch)
+	{
+	  /* Ignore the allocated scratch register and use the previous
+	     scratch register.  */
+	  if (dump_file)
+	    {
+	      fprintf (dump_file,
+		       "\nIgnore the allocated scratch register:\n\n");
+	      print_rtl_single (dump_file, scratch);
+	      fprintf (dump_file,
+		       "\nand use the previous scratch register:\n\n");
+	      print_rtl_single (dump_file, prev_scratch);
+	      fprintf (dump_file, "\nset in:\n\n");
+	      print_rtl_single (dump_file, prev_insn);
+	      fprintf (dump_file, "\nfor:\n\n");
+	      print_rtl_single (dump_file, insn);
+	      fprintf (dump_file, "\n");
+	    }
+	  scratch = gen_lowpart (mode, prev_scratch);
+	  set = gen_rtx_SET (operands[0], scratch);
+	  emit_insn (set);
+	  return;
+	}
+    }
+
+  /* If there is no usable previous scratch register, use the allocated
+     scratch register.  */
+  if (use_xor)
+    {
+      /* Generate "*movsi_xor".  */
+      rtx x = gen_lowpart (SImode, scratch);
+      rtvec p = rtvec_alloc (2);
+      set = gen_rtx_SET (x, const0_rtx);
+      RTVEC_ELT (p, 0) = set;
+      rtx clobber = gen_rtx_REG (CCmode, FLAGS_REG);
+      RTVEC_ELT (p, 1) = gen_rtx_CLOBBER (VOIDmode, clobber);
+      set = gen_rtx_PARALLEL (VOIDmode, p);
+    }
+  else
+    set = gen_rtx_SET (scratch, imm);
+  emit_insn (set);
+  set = gen_rtx_SET (operands[0], scratch);
+  emit_insn (set);
+}
+
 /* Returns true if OP contains a symbol reference */
 
 bool
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a837121c33f..cc9589f9fef 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -29029,10 +29029,11 @@ (define_peephole2
           && TARGET_SPLIT_LONG_MOVES
           && get_attr_length (insn) >= ix86_cur_cost ()->large_insn))
    && peep2_regno_dead_p (0, FLAGS_REG)"
-  [(parallel [(set (match_dup 2) (const_int 0))
-	      (clobber (reg:CC FLAGS_REG))])
-   (set (match_dup 0) (match_dup 1))]
-  "operands[2] = gen_lowpart (SImode, operands[1]);")
+  [(const_int 0)]
+{
+  operands[2] = const0_rtx;
+  ix86_output_lcp_stall_peephole (curr_insn, operands);
+})
 
 (define_peephole2
   [(match_scratch:SWI124 2 "<r>")
@@ -29043,8 +29044,8 @@ (define_peephole2
        && TARGET_LCP_STALL)
        || (TARGET_SPLIT_LONG_MOVES
           && get_attr_length (insn) >= ix86_cur_cost ()->large_insn))"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 0) (match_dup 2))])
+  [(const_int 0)]
+  "ix86_output_lcp_stall_peephole (curr_insn, operands);")
 
 ;; Don't compare memory with zero, load and use a test instead.
 (define_peephole2
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-1.c b/gcc/testsuite/gcc.target/i386/pr125893-1.c
new file mode 100644
index 00000000000..22749363c6b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-1.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	movl	\$3, %[a-z0-9]+
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 6\(%[a-z0-9]+\)
+**...
+*/
+
+void
+foo (short *dst)
+{
+  dst[0] = 3;
+  asm volatile ("" : : : "memory");
+  dst[1] = 3;
+  asm volatile ("" : : : "memory");
+  dst[2] = 3;
+  asm volatile ("" : : : "memory");
+  dst[3] = 3;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-10.c b/gcc/testsuite/gcc.target/i386/pr125893-10.c
new file mode 100644
index 00000000000..5ad38f14092
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-10.c
@@ -0,0 +1,38 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -fomit-frame-pointer -momit-leaf-frame-pointer -mtune=pentiumpro"  } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	xorl	%eax, %eax
+**...
+**	movl	%eax, 24\(%esp\)
+**	movl	%eax, 28\(%esp\)
+**	leal	24\(%esp\), %ebx
+**	movl	%ebx, \(%esp\)
+**	call	bar
+**	xorl	%ecx, %ecx
+**	movl	%ecx, 32\(%esp\)
+**	movl	%ebx, \(%esp\)
+**	movl	%ecx, 36\(%esp\)
+**	call	bar
+**...
+*/
+
+extern void bar (int *dst);
+
+void
+foo (void)
+{
+  int dst[10];
+  dst[0] = 0;
+  asm volatile ("" : : : "memory");
+  dst[1] = 0;
+  bar (dst);
+  dst[2] = 0;
+  asm volatile ("" : : : "memory");
+  dst[3] = 0;
+  bar (dst);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-2.c b/gcc/testsuite/gcc.target/i386/pr125893-2.c
new file mode 100644
index 00000000000..e241633a3d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-2.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	movl	\$3, %[a-z0-9]+
+**...
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	call	_?bar
+**	movl	\$3, %[a-z0-9]+
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 8\(%[a-z0-9]+\)
+**...
+*/
+
+
+extern void bar (void);
+
+void
+foo (short *dst)
+{
+  dst[0] = 3;
+  asm volatile ("" : : : "memory");
+  dst[2] = 3;
+  bar ();
+  dst[1] = 3;
+  asm volatile ("" : : : "memory");
+  dst[4] = 3;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-3.c b/gcc/testsuite/gcc.target/i386/pr125893-3.c
new file mode 100644
index 00000000000..7c01661e7d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-3.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	xorl	%[a-z0-9]+, %[a-z0-9]+
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 6\(%[a-z0-9]+\)
+**...
+*/
+
+void
+foo (short *dst)
+{
+  dst[0] = 0;
+  asm volatile ("" : : : "memory");
+  dst[1] = 0;
+  asm volatile ("" : : : "memory");
+  dst[2] = 0;
+  asm volatile ("" : : : "memory");
+  dst[3] = 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-4.c b/gcc/testsuite/gcc.target/i386/pr125893-4.c
new file mode 100644
index 00000000000..88488a5b6a5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-4.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	xorl	%[a-z0-9]+, %[a-z0-9]+
+**...
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	call	_?bar
+**	xorl	%[a-z0-9]+, %[a-z0-9]+
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 8\(%[a-z0-9]+\)
+**...
+*/
+
+
+extern void bar (void);
+
+void
+foo (short *dst)
+{
+  dst[0] = 0;
+  asm volatile ("" : : : "memory");
+  dst[2] = 0;
+  bar ();
+  dst[1] = 0;
+  asm volatile ("" : : : "memory");
+  dst[4] = 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-5.c b/gcc/testsuite/gcc.target/i386/pr125893-5.c
new file mode 100644
index 00000000000..fa8858533f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-5.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	movl	\$3, %[a-z0-9]+
+**...
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	call	_?bar
+**	movl	\$3, %[a-z0-9]+
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 8\(%[a-z0-9]+\)
+**...
+*/
+
+
+extern int bar (void);
+
+int
+foo (short *dst)
+{
+  dst[0] = 3;
+  asm volatile ("" : : : "memory");
+  dst[2] = 3;
+  int ret = bar ();
+  dst[1] = 3;
+  asm volatile ("" : : : "memory");
+  dst[4] = 3;
+  return ret;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-6.c b/gcc/testsuite/gcc.target/i386/pr125893-6.c
new file mode 100644
index 00000000000..62584cf4d77
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-6.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune-ctrl=lcp_stall" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	xorl	%[a-z0-9]+, %[a-z0-9]+
+**...
+**	movw	%[a-z0-9]+, \(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 4\(%[a-z0-9]+\)
+**	call	_?bar
+**	xorl	%[a-z0-9]+, %[a-z0-9]+
+**	movw	%[a-z0-9]+, 2\(%[a-z0-9]+\)
+**	movw	%[a-z0-9]+, 8\(%[a-z0-9]+\)
+**...
+*/
+
+
+extern int bar (void);
+
+int
+foo (short *dst)
+{
+  dst[0] = 0;
+  asm volatile ("" : : : "memory");
+  dst[2] = 0;
+  int ret = bar ();
+  dst[1] = 0;
+  asm volatile ("" : : : "memory");
+  dst[4] = 0;
+  return ret;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-7.c b/gcc/testsuite/gcc.target/i386/pr125893-7.c
new file mode 100644
index 00000000000..73292fcfb76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -fomit-frame-pointer -momit-leaf-frame-pointer -mtune=pentiumpro"  } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	movl	\$3, %eax
+**	movl	%eax, 16\(%esp\)
+**	movl	%eax, 20\(%esp\)
+**	movl	%eax, 24\(%esp\)
+**	movl	%eax, 28\(%esp\)
+**...
+*/
+
+extern void bar (int *dst);
+
+void
+foo (void)
+{
+  int dst[16];
+  dst[0] = 3;
+  asm volatile ("" : : : "memory");
+  dst[1] = 3;
+  asm volatile ("" : : : "memory");
+  dst[2] = 3;
+  asm volatile ("" : : : "memory");
+  dst[3] = 3;
+  bar (dst);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-8.c b/gcc/testsuite/gcc.target/i386/pr125893-8.c
new file mode 100644
index 00000000000..2c60dd4271f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-8.c
@@ -0,0 +1,38 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -fomit-frame-pointer -momit-leaf-frame-pointer -mtune=pentiumpro"  } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	movl	\$3, %eax
+**...
+**	movl	%eax, 24\(%esp\)
+**	movl	%eax, 28\(%esp\)
+**	leal	24\(%esp\), %ebx
+**	movl	%ebx, \(%esp\)
+**	call	bar
+**	movl	\$3, %ecx
+**	movl	%ecx, 32\(%esp\)
+**	movl	%ebx, \(%esp\)
+**	movl	%ecx, 36\(%esp\)
+**	call	bar
+**...
+*/
+
+extern void bar (int *dst);
+
+void
+foo (void)
+{
+  int dst[10];
+  dst[0] = 3;
+  asm volatile ("" : : : "memory");
+  dst[1] = 3;
+  bar (dst);
+  dst[2] = 3;
+  asm volatile ("" : : : "memory");
+  dst[3] = 3;
+  bar (dst);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125893-9.c b/gcc/testsuite/gcc.target/i386/pr125893-9.c
new file mode 100644
index 00000000000..c33b4913fb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125893-9.c
@@ -0,0 +1,31 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -fomit-frame-pointer -momit-leaf-frame-pointer -mtune=pentiumpro"  } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target *-*-* } {^\t?\.} } } */
+
+/*
+**foo:
+**...
+**	xorl	%eax, %eax
+**	movl	%eax, 16\(%esp\)
+**	movl	%eax, 20\(%esp\)
+**	movl	%eax, 24\(%esp\)
+**	movl	%eax, 28\(%esp\)
+**...
+*/
+
+extern void bar (int *dst);
+
+void
+foo (void)
+{
+  int dst[16];
+  dst[0] = 0;
+  asm volatile ("" : : : "memory");
+  dst[1] = 0;
+  asm volatile ("" : : : "memory");
+  dst[2] = 0;
+  asm volatile ("" : : : "memory");
+  dst[3] = 0;
+  bar (dst);
+}
-- 
2.54.0

Reply via email to