Update determine_block_size to set len_rtx to min size if min size ==
max size.

gcc/

PR middle-end/125977
* builtins.cc (determine_block_size): Change len_rtx to reference
and set it to min size if min size == max size.
* expr.cc (emit_block_move_via_pattern): Assert count == min_size
if min_size == max_size.
(set_storage_via_setmem): Likewise.

gcc/testsuite/

PR middle-end/125977
* g++.dg/pr125977.C: New test.


-- 
H.J.
From 5dd521f465105b031c48b0c787affc458b17f6ca Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Fri, 26 Jun 2026 08:43:20 +0800
Subject: [PATCH] determine_block_size: Set len_rtx to min size if min size ==
 max size

Update determine_block_size to set len_rtx to min size if min size ==
max size.

gcc/

	PR middle-end/125977
	* builtins.cc (determine_block_size): Change len_rtx to reference
	and set it to min size if min size == max size.
	* expr.cc (emit_block_move_via_pattern): Assert count == min_size
	if min_size == max_size.
	(set_storage_via_setmem): Likewise.

gcc/testsuite/

	PR middle-end/125977
	* g++.dg/pr125977.C: New test.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/builtins.cc                 | 12 +++++---
 gcc/expr.cc                     |  4 +++
 gcc/testsuite/g++.dg/pr125977.C | 50 +++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr125977.C

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 59ac630e30c..52dd51bad55 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -3589,7 +3589,7 @@ builtin_memcpy_read_str (void *data, void *, HOST_WIDE_INT offset,
    set it into PROBABLE_MAX_SIZE.  */
 
 static void
-determine_block_size (tree len, rtx len_rtx,
+determine_block_size (tree len, rtx &len_rtx,
 		      unsigned HOST_WIDE_INT *min_size,
 		      unsigned HOST_WIDE_INT *max_size,
 		      unsigned HOST_WIDE_INT *probable_max_size)
@@ -3650,9 +3650,13 @@ determine_block_size (tree len, rtx len_rtx,
 	    *probable_max_size = min.to_uhwi () - 1;
 	}
     }
-  gcc_checking_assert (*max_size <=
-		       (unsigned HOST_WIDE_INT)
-			  GET_MODE_MASK (GET_MODE (len_rtx)));
+
+  if (*min_size == *max_size)
+    len_rtx = GEN_INT (*min_size);
+  else
+    gcc_checking_assert (*max_size <=
+			 (unsigned HOST_WIDE_INT)
+			 GET_MODE_MASK (GET_MODE (len_rtx)));
 }
 
 /* Expand a call EXP to the memcpy builtin.
diff --git a/gcc/expr.cc b/gcc/expr.cc
index de73215ccc6..43931687d63 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -2320,6 +2320,8 @@ emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align,
 	      else
 		create_fixed_operand (&ops[8], NULL);
 	    }
+	  gcc_assert (min_size != max_size
+		      || rtx_equal_p (ops[2].value, ops[6].value));
 	  if (maybe_expand_insn (code, nops, ops))
 	    return true;
 	}
@@ -4045,6 +4047,8 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
 	      else
 		create_fixed_operand (&ops[8], NULL);
 	    }
+	  gcc_assert (min_size != max_size
+		      || rtx_equal_p (ops[1].value, ops[6].value));
 	  if (maybe_expand_insn (code, nops, ops))
 	    return true;
 	}
diff --git a/gcc/testsuite/g++.dg/pr125977.C b/gcc/testsuite/g++.dg/pr125977.C
new file mode 100644
index 00000000000..de174b72ecc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr125977.C
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu++17" } */
+
+template <typename> class allocator;
+char copy___s2[12];
+void assign(char, char &);
+template <typename> struct allocator_traits;
+template <typename _Tp> struct allocator_traits<allocator<_Tp>> {
+  using pointer = _Tp *;
+};
+allocator_traits<allocator<char>>::pointer _M_p;
+struct _Alloc_result {
+  allocator_traits<allocator<char>>::pointer __ptr;
+};
+unsigned _M_string_length;
+enum { _S_local_capacity = 5 } _M_allocated_capacity;
+bool _M_is_local() {
+  if (_M_p) {
+    if (_M_string_length > _S_local_capacity)
+      __builtin_unreachable();
+    return true;
+  }
+  return false;
+}
+int capacity() {
+  long __sz = _M_is_local() ? _S_local_capacity : _M_allocated_capacity;
+  return __sz;
+}
+struct Trans_NS___cxx11_basic_string {
+  void operator=(char) { _M_string_length = 0; }
+  void operator+=(char __c) {
+    _Alloc_result __trans_tmp_7;
+    if (_M_string_length + 1 > capacity()) {
+      char __s;
+      if (_M_string_length == 1)
+        assign(*__trans_tmp_7.__ptr, __s);
+      __builtin_memcpy(__trans_tmp_7.__ptr, &copy___s2, _M_string_length);
+      if (_M_string_length > _S_local_capacity)
+        __builtin_unreachable();
+    }
+    assign(_M_string_length, __c);
+  }
+};
+long build_attr_access_from_parms_specend;
+void build_attr_access_from_parms() {
+  Trans_NS___cxx11_basic_string spec;
+  if (build_attr_access_from_parms_specend)
+    spec = '+';
+  spec += '[';
+}
-- 
2.54.0

Reply via email to