Commit 51e3f17d64c for php.net

commit 51e3f17d64c902842ccba0a79d4d68444c5820b6
Author: Marc <m@pyc.ac>
Date:   Thu Sep 17 17:13:28 2026 +0200

    zend_strtod: use trunc(dval(&u)) instead of (Long)(dval(&u)) to keep per-digit dependency chain in float register (#22676)

diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c
index f0a15a2f4f4..4a81d20e358 100644
--- a/Zend/zend_strtod.c
+++ b/Zend/zend_strtod.c
@@ -3700,6 +3700,15 @@ zend_freedtoa(char *s)
  *	   calculation.
  */

+/* trunc(dval(&u)) keeps the per-digit remainder chain in the FP unit instead of a
+ * FP->int->FP round-trip, cutting the digit loop's critical-path latency and
+ * speeding up fixed-precision float->string ((string)/echo/printf/number_format).
+ * Only a win where trunc() lowers to one instruction (aarch64 frintz, x86
+ * roundsd), elsewhere it's a call, so keep (Long)(dval(&u)). */
+#if defined(__SSE4_1__) || defined(__aarch64__)
+# define FAST_TRUNC
+#endif
+
 ZEND_API char *zend_dtoa(double dd, int mode, int ndigits, int *decpt, bool *sign, char **rve)
 {
  /*	Arguments ndigits, decpt, sign are similar to those
@@ -3747,6 +3756,9 @@ ZEND_API char *zend_dtoa(double dd, int mode, int ndigits, int *decpt, bool *sig
 	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
 	U d2, eps, u;
 	double ds;
+#ifdef FAST_TRUNC
+	double tr;
+#endif
 	char *s, *s0;
 #ifndef No_leftright
 #ifdef IEEE_Arith
@@ -4047,9 +4059,16 @@ ZEND_API char *zend_dtoa(double dd, int mode, int ndigits, int *decpt, bool *sig
 			/* Generate ilim digits, then fix them up. */
 			dval(&eps) *= tens[ilim-1];
 			for(i = 1;; i++, dval(&u) *= 10.) {
+#ifdef FAST_TRUNC
+				tr = trunc(dval(&u));
+				L = (Long)tr;
+				if (!(dval(&u) -= tr))
+					ilim = i;
+#else
 				L = (Long)(dval(&u));
 				if (!(dval(&u) -= L))
 					ilim = i;
+#endif
 				*s++ = '0' + (int)L;
 				if (i == ilim) {
 					if (dval(&u) > 0.5 + dval(&eps))
@@ -4084,8 +4103,14 @@ ZEND_API char *zend_dtoa(double dd, int mode, int ndigits, int *decpt, bool *sig
 			goto one_digit;
 			}
 		for(i = 1;; i++, dval(&u) *= 10.) {
+#ifdef FAST_TRUNC
+			tr = trunc(dval(&u) / ds);
+			L = (Long)tr;
+			dval(&u) -= tr*ds;
+#else
 			L = (Long)(dval(&u) / ds);
 			dval(&u) -= L*ds;
+#endif
 #ifdef Check_FLT_ROUNDS
 			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
 			if (dval(&u) < 0) {