Substitute constants with modular equivalents more safely
authorPaul Khuong <pvk@pvk.ca>
Sat, 20 Apr 2013 11:50:52 +0000 (13:50 +0200)
committerPaul Khuong <pvk@pvk.ca>
Sat, 20 Apr 2013 11:59:03 +0000 (13:59 +0200)
* Modular arithmetic sometimes lets us narrow constants down,
  especially with signed arithmetic. We now update the receiving
  LVAR's type conservatively when there are multiple uses; otherwise,
  conflicting type information results in spurious dead code
  elimination.

* Test case by Eric Marsden.

* Reported by Eric Marsden on sbcl-devel (2013-04-18).

NEWS
src/compiler/srctran.lisp
tests/compiler.pure.lisp

diff --git a/NEWS b/NEWS
index c2cf5f2..7ba1204 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 ;;;; -*- coding: utf-8; fill-column: 78 -*-
 changes relative to sbcl-1.1.6
+  * bug fix: modular arithmetic involving large constants and conditionals
+    should no longer result in spurious dead code elimination. Reported by 
+    Eric Marsden on sbcl-devel.
   * bug fix: our mach exception handler can seemingly called very early in
     the program execution process on OS X 10.8.0. Try and handle that case
     robustly, without potentially leaking mach ports too much.
index 5858da9..f6369e6 100644 (file)
                                        (ldb (byte width 0) constant-value))))
                    (unless (= constant-value new-value)
                      (change-ref-leaf node (make-constant new-value))
-                     (setf (lvar-%derived-type (node-lvar node)) (make-values-type :required (list (ctype-of new-value))))
+                     (let ((lvar (node-lvar node)))
+                       (setf (lvar-%derived-type lvar)
+                             (and (lvar-has-single-use-p lvar)
+                                  (make-values-type :required (list (ctype-of new-value))))))
                      (setf (block-reoptimize (node-block node)) t)
                      (reoptimize-component (node-component node) :maybe)
                      (return-from cut-node t))))
index 1a4fc7d..0e7c53c 100644 (file)
   (compile nil `(lambda (x)
                   (symbol-macrolet ((sv x))
                     (values (svref sv 0) (setf (svref sv 0) 99))))))
+
+;; The compiler used to update the receiving LVAR's type too
+;; aggressively when converting a large constant to a smaller
+;; (potentially signed) one, causing other branches to be
+;; inferred as dead.
+(with-test (:name :modular-cut-constant-to-width)
+  (let ((test (compile nil
+                       `(lambda (x)
+                          (logand 254
+                                  (case x
+                                    ((3) x)
+                                    ((2 2 0 -2 -1 2) 9223372036854775803)
+                                    (t 358458651)))))))
+    (assert (= (funcall test -10470605025) 26))))