Commit c590fd26 authored by Raymond Toy's avatar Raymond Toy
Browse files

Fix #283: Add VOP for integer-length for an (unsigned-byte 32) arg

There's a VOP for `integer-length` for `(signed-byte 32)` arg, but not
one for `(unsigned-byte 32)`.  We can use the `BSR` instruction to
handle this case.

Not sure exactly how to test this, but I did it manually by compiling
```
(defun zot-u (n)
  (declare (type (unsigned-byte 32) n)
           (optimize (speed 3)))
  (integer-length n))
```

The disassembly is, in part

```
CL-USER> (disassemble 'zot-u)
604ad710:       .entry zot-u(n)                        ; (function
...
      70: L5:   cmp       edx, #x0                     ; No-arg-parsing entry point
                                                       ; [:non-local-entry]
      73:       je        L6
      75:       bsr       edx, edx
      78:       inc       edx
      79:       shl       edx, #x2
```

Without this VOP, the disassembly would be

```
     228: L3:   mov       eax, dword ptr [#x609c31d4]  ; #<FDEFINITION object for integer-length>
                                                       ; No-arg-parsing entry point
                                                       ; [:non-local-entry]
     22e:       mov       ecx, #x4
     233:       push      dword ptr [ebp-#x8]

;;; [9] (INTEGER-LENGTH N)

     236:       jmp       dword ptr [eax+#x5]          ; [:call-site]
```
parent 36299b0c
Loading
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -755,6 +755,26 @@
    (inst xor res res)
    DONE))

(define-vop (unsigned-byte-32-len)
  (:translate integer-length)
  (:note _N"inline (unsigned-byte 32) integer-length")
  (:policy :fast-safe)
  (:args (arg :scs (unsigned-reg)))
  (:arg-types unsigned-num)
  (:results (res :scs (any-reg)))
  (:result-types positive-fixnum)
  (:generator 30
    (move res arg)
    ;; BSR is undefined if the source is 0, so check for that here.
    (inst cmp res 0)
    (inst jmp :eq DONE)
    (inst bsr res res)
    ;; The result of BSR is one too small for what we want, so
    ;; increment the result.
    (inst inc res)
    (inst shl res 2)
    DONE))

(define-vop (unsigned-byte-32-count)
  (:translate logcount)
  (:note _N"inline (unsigned-byte 32) logcount")
+4 −0
Original line number Diff line number Diff line
@@ -296,6 +296,10 @@ msgstr ""
msgid "inline (signed-byte 32) integer-length"
msgstr ""

#: src/compiler/x86/arith.lisp
msgid "inline (unsigned-byte 32) integer-length"
msgstr ""

#: src/compiler/x86/arith.lisp
msgid "inline (unsigned-byte 32) logcount"
msgstr ""