[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

moving 10 bytes between buffers



>I have pointers p1 and p2 to two buffers and I regularly need to move 10
>bytes of data from p1 to p2.  I could do it with a loop that moves a byte
>or word at a time, but I wanted to do it more efficiently.  One way I
>thought of is to declare a dummy record type and then use copy-record:
>
>(defrecord (dummy :pointer)
>  (a :long)
>  (b :long)
>  (c :word))
>
>(copy-record p1 dummy p2)
>
>Is this better than using a loop?  Is there a method more efficient than
>either of these?

copy-record expands into #_BlockMove, which is very fast for moving
large numbers of bytes, but costs a lot for trap overhead when moving
small buffers.

The following macro generates code that is almost as fast as an
assembly language loop. The important speedy features are declaring
the macptrs to be macptrs, and generating in-line code (no backward
branch means the compiler will not generate an out-of-line call to
check for events). You can't move four bytes at a time with %get-long
because it may cons a bignum in the process of being boxed (yes, the
compiler should notice that it doesn't need to box, but it doesn't).

---------------------------------------------------------------------

; Copy COUNT bytes from the macptr in FROM to the macptr in TO.
; if ASSUME-EVEN-ADDRESSES is specified and non-NIL, will generate
; word moves which is almost twice as fast (and will generate an odd
; address trap on a 68000, if the address from FROM or TO is not even).
; Assumes that FROM and TO are macptrs, will crash if not.
; Assumes that COUNT is a fixnum. If it is a constant fixnum at
; macroexpand time, will generate significantly faster code.
; Not good for copying large buffers. For that, use #_BlockMove.
(defmacro copy-bytes (from to count &optional assume-even-addresses)
  (let ((from-var (gensym))
          (to-var (gensym)))
    `(let ((,from-var ,from)
           (,to-var ,to))
       (declare (type macptr ,from-var ,to-var))
       ,(if (fixnump count)
          (if assume-even-addresses
            `(progn
               ,@(let ((res nil))
                   (dotimes (i (floor count 2) (nreverse res))
                     (push `(setf (%get-word ,from-var ,i)
                                  (%get-word ,to-var ,i))
                           res)))
               ,@(unless (eql 0 (mod count 2))
                   `(setf (%get-byte ,from-var ,(1- count))
                          (%get-byte ,to-var ,(1- count))))
               nil)
            `(progn
               ,@(let ((res nil))
                   (dotimes (i count (nreverse res))
                     (push `(setf (%get-byte ,from-var ,i)
                                  (%get-byte ,to-var ,i))
                           res)))
               nil))
          (let ((i (gensym)))
            `(dotimes (,i (the fixnum ,count))
               (setf (%get-byte ,from-var ,i) (%get-byte ,to-var ,i))))))))