Wrong vop used for integer-length of (unsigned-byte 31) number?
Describe the bug
For some reason we use the signed-byte-32-int-len
vop when the arg
is an (unsigned-byte 31)
. Here is a test function:
(defun baz (n)
(declare (type (unsigned-byte 32) n)
(optimize (speed 3)))
(let ((x (ash n -1)))
(values x
(integer-length x)
(integer-length n))))
To Reproduce
Steps to reproduce the behavior:
- Save the test function in a file and compile it with the
:trace-file t
option. - Examine the trace file.
- We can see in one case we use the
signed-byte-32-int-len
VOP
Expected behavior
I was expecting to see the unsigned-byte-32-int-len
VOP for both
cases.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
- OS: x86
- Version: snapshot-2023-04 and probably earlier
Additional context
The relevant part of the trace file is:
IR2 block start c1
L4:
0: SAP-MOVE t19[S1]>t23[EAX] => t24[S1]<t25[EAX]
1: NOTE-ENVIRONMENT-START {#<NEW-ASSEM:LABEL 5>}
2: FAST-ASH-RIGHT/UNSIGNED=>UNSIGNED N!14[EDX] '1!26 => t27[EAX]
3: WORD-MOVE t27[EAX] => t28[ECX]
4: SIGNED-BYTE-32-LEN t28[ECX] => t29[EDI]
5: UNSIGNED-BYTE-32-LEN N!14[EDX] => t30[ESI]
Maybe the solution is to get rid of signed-byte-32-int-len
VOP and
have the compiler generate a (lognot x)
when x
is a negative
number? But I see that sparc and ppc already have both signed and
unsigned versions, so this approach would work for those other archs
as well.
I don't know why the compiler is choosing the signed version of the
vop when the arg type is an (unsigned-byte 31)
. (You can see this
by doing (describe 'baz)
and looking at the return types.)