[Ecls-list] A few compiled results questions

Matthew Mondor mm_lists at pulsar-zone.net
Tue Oct 29 02:06:35 UTC 2013

Hello again,

I have two compiter-related questions.  These are not bug reports and
if they point at aspects where optimizations could be safely enhanced,
it is low priority, as the generated code is not buggy.  It's all for
the better if I can learn more about how the compiler deals with these.

First a question relative to LOOP/LET and FIXNUM:

I see that the following function correctly immediately produces
cl_fixnum variables with their inline use.

(defun buffer-history (buffer)
  "Returns a list holding all the currently held objects of BUFFER.
Conses but is rarely called versus BUFFER-APPEND."
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (check-type buffer buffer)
  (mp:with-lock ((buffer-lock buffer))
       with vector of-type (simple-vector *) = (buffer-buf buffer)
       with head of-type fixnum = (buffer-head buffer)
       with tail of-type fixnum = (buffer-tail buffer)
       with size of-type fixnum = (buffer-size buffer)
       for i of-type fixnum = head then (the fixnum (1+ (the fixnum i)))
       when (= size i) do (setf i 0)
       until (= tail i)
       collect (svref vector i))))

        cl_fixnum v10head;
        v10head = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[6])(1, v1buffer) /*  BUFFER-HEAD */);
         cl_fixnum v11tail;
         v11tail = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[7])(1, v1buffer) /*  BUFFER-TAIL */);
          cl_fixnum v12size;
          v12size = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[8])(1, v1buffer) /*  BUFFER-SIZE */);
          cl_fixnum v13i;
          if (!((v12size)==(v13i))) { goto L27; }

However, in the following function, interestingy, a cl_object is
maintained instead, with inline operations using the ecl_fixnum() macro

(defun buffer-resize (buffer newsize)
  "Resizes BUFFER to be able to hold SIZE number of items.
The old history is preserved but may be partial if the size is shrunk."
  (declare (optimize (speed 3) (safety 0) (debug 0))
           (type fixnum newsize))
  (check-type buffer buffer)
  (check-type newsize fixnum)
  (incf newsize)
  (mp:with-lock ((buffer-lock buffer))
    (with-accessors ((bbuf buffer-buf)
                     (bhead buffer-head)
                     (btail buffer-tail)
                     (bsize buffer-size)) buffer
      (let ((oldbuf bbuf)
            (oldhead bhead)
            (oldtail btail)
            (oldsize bsize))
        (declare (type (simple-vector *) oldbuf)
                 (type fixnum oldhead oldtail oldsize))
        (setf bbuf (make-array newsize
                               :initial-element nil
                               :adjustable nil
                               :fill-pointer nil)
              bhead 0
              btail 0
              bsize newsize)
           for i of-type fixnum = oldhead then
             (the fixnum (1+ (the fixnum i)))
           when (= oldsize i) do (setf i 0)
           until (= oldtail i)
             (buffer-append buffer (svref oldbuf i))))))

       cl_object v11;
       cl_object v12;
       cl_object v13;
       cl_object v14;
       v11 = ecl_function_dispatch(cl_env_copy,VV[5])(1, v1buffer) /*  BUFFER-BUF */;
       v12 = ecl_function_dispatch(cl_env_copy,VV[6])(1, v1buffer) /*  BUFFER-HEAD */;
       v13 = ecl_function_dispatch(cl_env_copy,VV[7])(1, v1buffer) /*  BUFFER-TAIL */;
       v14 = ecl_function_dispatch(cl_env_copy,VV[8])(1, v1buffer) /*  BUFFER-SIZE */;
        if (!((ecl_fixnum(v14))==(v15i))) { goto L42; }
        if (!((ecl_fixnum(v13))==(v15i))) { goto L45; }

If using instead in the above function:

      (let ((oldbuf bbuf)
            (oldhead (the fixnum bhead))
            (oldtail (the fixnum btail))
            (oldsize (the fixnum bsize)))
        (declare (type (simple-vector *) oldbuf)
                 (type fixnum oldhead oldtail oldsize))

Then a more efficient result is generated:

       cl_fixnum v12;
       cl_fixnum v13;
       cl_fixnum v14;
       v12 = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[6])(1, v1buffer) /*  BUFFER-HEAD */);
       v13 = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[7])(1, v1buffer) /*  BUFFER-TAIL */);
       v14 = ecl_fixnum(ecl_function_dispatch(cl_env_copy,VV[8])(1, v1buffer) /*  BUFFER-SIZE */);
        if (!((v14)==(v15i))) { goto L42; }
        if (!((v13)==(v15i))) { goto L45; }

I thus assume that LOOP must be inserting THE automatically here.  But
is it expected that the DECLARE (TYPE FIXNUM ... are not sufficient to
produce this automatically with LET and SAFETY 0?

This next question has to do with structure accessors:

As can be seen above, a function dispatch is done to access the slots in
read mode.  But interestingly, for SETF, a more inline result is
obtained assigning directly on the slot:

         cl_object v16;
         v16 = v1buffer;
        cl_object v15;
        v15 = ecl_make_fixnum(0);
         cl_object v16;
         v16 = v1buffer;

I realize that with CLOS this would be more complex, but this is a
simple struct, with the consequences voluntarily undefined if it's
redefined without recompiling its dependent code.  Could it be that
SETF can infer better than LET in this case?  Or is there another
reason why inline read slot access should not be done here, but that
it's safer for SETF?

I have tried declaring INLINE the accessors BBUF, BHEAD, BTAIL and
BSIZE with the same results.  Not using WITH-ACCESSORS and adding
INLINE to DECLARE for the accessors also didn't help.


More information about the ecl-devel mailing list