Subject: Re: 23.0.60; bug of bytecomp arithmetic operations

From: "Shigeru Fukaya" <[email-masked]>
Date: Wed, 19 Nov 2008 21:27:01 +0900

Hello, Chong and everybody,

After bytecomp.el is revised, problems remains as follows;

1. Operations are all compiled to binary operations. It may cause
overflows or truncations in floating point data operations.

   ==> solved.

2. Most integer constants are moved to the end of expressions and
pre-calculated at compile time. Changing of order may cause different
result from original expressions.
(In other words, `byte-optimize-delay-constants-math' should not be called)

   ==> In multiplication/division, problems become not to occur.
       I suppose it is because difference of precision/scale size in
       elisp, execution level, processor internal (elisp < C < processor)
       take over the issue.

	    (let ((a (expt 2 -1074)) (b 0.125))
	      (list (* a b 8) (* (* a b) 8)))
	    --> (5e-324 0.0)

       I can't find the bad case so far. So, in multiplication and
       division, I suppose, at least now, changing calculation order
       is allowable and leave `byte-optimize-delay-constants-math'.

       Addition/Subtraction still show this problem.

3. Mulitiplication/Division optimization sometimes don't consider
floating point operators.

   ==> Add patterns.

   Examples.

      (let ((a most-positive-fixnum) (b 2.0)) (* a 2 b))
	 --> 1073741820.0
	 --> -4.0

      (let ((a 3) (b 2)) (/ a b 1.0))
	 --> 1.5
	 --> 1

4. In division, optimizing -1 twice and cause erroneous results.

   ==> Easy.

To get all examples at a glance, see the attached
`byte-test-minimal.el' or its log file.

Changing policy / plan

* Change functions byte-optimize-plus, byte-optimize-minus,
byte-optimize-multiply, byte-optimize-divide.

* All modifications are closed to the function itself. Don't add other
functions, symbols.

* Don't call `byte-optimize-delay-constants-math' in plus, minus
operations. Remain to call it in multiplication, division operations.

* Call `byte-optimize-predicate' at the last as in minus operation.
This will optimize expressions that all arguments are constant to
constant values.

* Consider frequency or possibility.

** Remove/Abandon some optimizations.

*** Most optimizations that need floating point data result.

**** Zero in operands of multiplication or division (first
operand). This case seems rare. If you do something, it's like
below,

Multiplication:
   (cond ((or (memql 0.0 (cdr form))
	      (and (eq 0 last) (memq t (mapcar #'floatp (cdr form)))))
	  (setq form (nconc (list 'progn)
			    (delq 0 (mapcar (lambda (x)
					      (if (or (numberp x) (symbolp x))
						  0
						x))
					    (cdr form)))
			    (list 0.0))))

Division:
   (cond ((or (eql (cadr form) 0.0)
	      (and (eq (cadr form) 0) (memq t (mapcar #'floatp (cddr form)))))
	  ;; This optimization may throw out division by zero error.
	  (setq form (nconc (list 'progn)
			    (delq 0 (mapcar (lambda (x)
					      (if (or (numberp x) (symbolp x))
						  0
						x))
					    (cdr form)))
			    (list 0.0))))
	 ((and (eq (cadr form 0) 0) (numberp last) (nthcdr 3 form))
	  (setq form (byte-compile-butlast form))
	  )

** Add some optimizations.

*** Optimize addtion/subtraction where their last operand is 1 or
-1 to use `1+', `1-' funcitons. This pattern often appears and
more effective at least in size (byte-add1 vs constant 1).

*** Other small changes.

Files:
   ChangeLog
   byte-opt.el		   - modified file.
   byte-opt.diff	   - diff by `diff -c OLD NEW >byte-opt.diff'
   byte-test-minimal.el	   - test script to compare original and revised.
   log.summary		   - sammary output by byte-test-minimal
   log.detail		   - detailed (with disassembled code) output by
byte-test-minimal.
   byte-regress-minimal.el - simple coverage test
   log.regress		   - log output of the coverage test

If something is wrong, let me know, please.

Regards,
Shigeru

2008/11/15 Chong Yidong <[email-masked]>:
> "Shigeru Fukaya" <[email-masked]> writes:
>
>>> Could you separate out the byte-optimize-*-functions part of the patch?
>>
>> They are mutually affected. So I'll make and send a patch of
>> byte-opt.el that includes minimal changes to the latest CVS. It is
>> necessary because the current byte-opt.el still has problems I
>> pointed. It will take a few days.
>>
>> Is it ok?
>
> That would be great.  Thanks!
>