From 195ca6b9a37511e2681e75a35781074b16101a42 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Wed, 21 Jun 2023 16:56:12 +0200
Subject: [PATCH] Don't compile (+ X 0) as (* X 1)

Previously (+ X 0) was reduced to (+ X) which became (* X 1) in
codegen, but this is wrong for X = -0.0 and also slightly slower.

* lisp/emacs-lisp/byte-opt.el (byte-optimize-plus): Don't reduce an
addition to (+ X) by eliminating zeros; retain one 0 argument.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test case.
---
 lisp/emacs-lisp/byte-opt.el            | 8 +++++++-
 test/lisp/emacs-lisp/bytecomp-tests.el | 4 ++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index f64674d5a6c..307e3841e9b 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -873,7 +873,13 @@ for speeding up processing.")
   (cons accum args))
 
 (defun byte-optimize-plus (form)
-  (let ((args (remq 0 (byte-opt--arith-reduce #'+ 0 (cdr form)))))
+  (let* ((not-0 (remq 0 (byte-opt--arith-reduce #'+ 0 (cdr form))))
+         (args (if (and (= (length not-0) 1)
+                        (> (length form) 2))
+                   ;; We removed numbers and only one arg remains: add a 0
+                   ;; so that it isn't turned into (* X 1) later on.
+                   (append not-0 '(0))
+                 not-0)))
     (cond
      ;; (+) -> 0
      ((null args) 0)
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index 963ea9abe0c..278496f5259 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -776,6 +776,10 @@ inner loops respectively."
       (nconc x nil nil))
     (let ((x (cons 1 (cons 2 (cons 3 4)))))
       (nconc nil x nil (list 5 6) nil))
+
+    ;; (+ 0 -0.0) etc
+    (let ((x (bytecomp-test-identity -0.0)))
+      (list x (+ x) (+ 0 x) (+ x 0) (+ 1 2 -3 x) (+ 0 x 0)))
     )
   "List of expressions for cross-testing interpreted and compiled code.")
 
-- 
2.39.5