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) {