(setf (block-reoptimize (node-block node)) t)
(reoptimize-component (node-component node) :maybe))
t)
- (cut-node (node &aux did-something)
+ (cut-node (node &aux did-something over-wide)
"Try to cut a node to width. The primary return value is
whether we managed to cut (cleverly), and the second whether
- anything was changed."
+ anything was changed. The third return value tells whether
+ the cut value might be wider than expected."
(when (block-delete-p (node-block node))
(return-from cut-node (values t nil)))
(typecase node
(funcall modular-fun node width)))
:exit-if-null))
(unless (eql modular-fun :good)
- (setq did-something t)
+ (setq did-something t
+ over-wide t)
(change-ref-leaf
fun-ref
(find-free-fun name "in a strange place"))
(setf (combination-kind node) :full))
(unless (functionp modular-fun)
(dolist (arg (basic-combination-args node))
- (when (cut-lvar arg)
- (setq did-something t))))
+ (multiple-value-bind (change wide)
+ (cut-lvar arg)
+ (setf did-something (or did-something change)
+ over-wide (or over-wide wide)))))
(when did-something
(reoptimize-node node name))
- (values t did-something)))))))))
- (cut-lvar (lvar &aux did-something must-insert)
+ (values t did-something over-wide)))))))))
+ (cut-lvar (lvar &key head
+ &aux did-something must-insert over-wide)
"Cut all the LVAR's use nodes. If any of them wasn't handled
and its type is too wide for the operation we wish to perform
insert an explicit bit-width narrowing operation (LOGAND or
destination is already such an operation, to avoid endless
recursion.
+ If we're at the head, forcibly insert a cut operation if the
+ result might be too wide.
+
(*) We can't easily do that for each node, and doing so might
result in code bloat, anyway. (I'm also not sure it would be
correct for complicated C/D FG)"
(do-uses (node lvar)
- (multiple-value-bind (handled any-change)
+ (multiple-value-bind (handled any-change wide)
(cut-node node)
(setf did-something (or did-something any-change)
must-insert (or must-insert
(not (or handled
(csubtypep (single-value-type
(node-derived-type node))
- type)))))))
- (when must-insert
- (setf did-something (or (insert-lvar-cut lvar) did-something)))
- did-something))
- (cut-lvar lvar))))
+ type))))
+ over-wide (or over-wide wide))))
+ (when (or must-insert
+ (and head over-wide))
+ (setf did-something (or (insert-lvar-cut lvar) did-something)
+ ;; we're just the right width after an explicit cut.
+ over-wide nil))
+ (values did-something over-wide)))
+ (cut-lvar lvar :head t))))
(defun best-modular-version (width signedp)
;; 1. exact width-matched :untagged
(ash b (min 25 lv1))
0)
-2)))))
+
+;; non-trivial modular arithmetic operations would evaluate to wider results
+;; than expected, and never be cut to the right final bitwidth.
+(with-test (:name :bug-1199428-1)
+ (let ((f1 (compile nil `(lambda (a c)
+ (declare (type (integer -2 1217810089) a))
+ (declare (type (integer -6895591104928 -561736648588) c))
+ (declare (optimize (speed 2) (space 0) (safety 2) (debug 0)
+ (compilation-speed 3)))
+ (logandc1 (gcd c)
+ (+ (- a c)
+ (loop for lv2 below 1 count t))))))
+ (f2 (compile nil `(lambda (a c)
+ (declare (notinline - + gcd logandc1))
+ (declare (optimize (speed 1) (space 1) (safety 0) (debug 1)
+ (compilation-speed 3)))
+ (logandc1 (gcd c)
+ (+ (- a c)
+ (loop for lv2 below 1 count t)))))))
+ (let ((a 530436387)
+ (c -4890629672277))
+ (assert (eql (funcall f1 a c)
+ (funcall f2 a c))))))
+
+(with-test (:name :bug-1199428-2)
+ (let ((f1 (compile nil `(lambda (a b)
+ (declare (type (integer -1869232508 -6939151) a))
+ (declare (type (integer -11466348357 -2645644006) b))
+ (declare (optimize (speed 1) (space 0) (safety 2) (debug 2)
+ (compilation-speed 2)))
+ (logand (lognand a -6) (* b -502823994)))))
+ (f2 (compile nil `(lambda (a b)
+ (logand (lognand a -6) (* b -502823994))))))
+ (let ((a -1491588365)
+ (b -3745511761))
+ (assert (eql (funcall f1 a b)
+ (funcall f2 a b))))))