1 (in-package "SB-ROTATE-BYTE")
3 (defknown rotate-byte
(integer byte-specifier integer
) integer
5 :overwrite-fndb-silently t
)
6 (defknown %rotate-byte
(integer bit-index bit-index integer
) integer
8 :overwrite-fndb-silently t
)
9 (defknown %unsigned-32-rotate-byte
((integer -
31 31) (unsigned-byte 32))
12 :overwrite-fndb-silently t
)
14 (defknown %unsigned-64-rotate-byte
((integer -
63 63) (unsigned-byte 64))
17 :overwrite-fndb-silently t
)
19 (macrolet (;; see src/compiler/srctran.lisp
20 (with-byte-specifier ((size-var pos-var spec
) &body body
)
21 (once-only ((spec `(handler-case (macroexpand ,spec
)
23 (return (values nil t
)))))
25 `(if (and (consp ,spec
)
26 (eq (car ,spec
) 'byte
)
28 (let ((,size-var
(second ,spec
))
29 (,pos-var
(third ,spec
)))
31 (let ((,size-var
`(byte-size ,,temp
))
32 (,pos-var
`(byte-position ,,temp
)))
33 `(let ((,,temp
,,spec
))
35 (define-source-transform rotate-byte
(count spec num
)
37 (with-byte-specifier (size pos spec
)
38 `(%rotate-byte
,count
,size
,pos
,num
)))))
40 (defoptimizer (%rotate-byte derive-type
) ((count size posn num
))
41 ;; FIXME: this looks fairly unwieldy. I'm sure it can be made
42 ;; simpler, and also be made to deal with negative integers too.
43 (declare (ignore count
))
44 (let ((size (sb-c::lvar-type size
))
45 (posn (sb-c::lvar-type posn
)))
46 (if (and (numeric-type-p size
)
48 (numeric-type-high size
)
49 (numeric-type-high posn
))
50 (let ((size-high (+ (numeric-type-high size
)
51 (numeric-type-high posn
)))
52 (num-type (sb-c::lvar-type num
)))
53 (if (and (typep size-high
'(integer 1))
55 (<= size-high sb-vm
:n-word-bits
)
57 (specifier-type `(unsigned-byte ,size-high
))))
58 (specifier-type `(unsigned-byte ,size-high
))
62 (deftransform %rotate-byte
((count size pos integer
)
64 (constant-arg (member 32))
65 (constant-arg (member 0))
66 (unsigned-byte 32)) *)
67 "inline 32-bit rotation"
68 '(%unsigned-32-rotate-byte count integer
))
70 ;; Generic implementation for platforms that don't supply VOPs for 32-bit
72 #-
(or x86 x86-64 ppc arm arm64 riscv
)
73 (deftransform %unsigned-32-rotate-byte
((.count. .integer.
)
75 (unsigned-byte 32)) *)
77 (logior (ldb (byte 32 0) (ash .integer.
(+ .count.
32)))
78 (ash .integer. .count.
))
79 (logior (ldb (byte 32 0) (ash .integer. .count.
))
80 (ash .integer.
(- .count.
32)))))
83 (deftransform %rotate-byte
((count size pos integer
)
85 (constant-arg (member 64))
86 (constant-arg (member 0))
87 (unsigned-byte 64)) *)
88 "inline 64-bit rotation"
89 '(%unsigned-64-rotate-byte count integer
))
91 ;;; This transform needs to come after the others to ensure it gets
92 ;;; first crack at a zero COUNT, since transforms are currently run
93 ;;; latest-defined first.
94 (deftransform %rotate-byte
((count size pos integer
)
95 ((constant-arg (member 0)) t t t
) *)
96 "fold identity operation"