Liu Fung Sin <fungsin.lui@gmail.com> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) wrote:
| > Upon further reflection, I noticed a *much* simpler way to do this...
...
| I did some comparisons, for educational purpose.
| It seems that (at least on 32-bit lisp) because everything is tagged
| and there's no 32-bit fixnum arithmetic, there are certain things that
| can't be done as efficiently as languages that are "closer" to the
| machine (e.g. C)
...
| (deftype ipv4-integer ()
| '(integer 0 #xffffffff))
|
| (defun ipv4-netmask-p (x)
| (declare (optimize (speed 3) (safety 0)))
| (declare (ipv4-integer x))
| (= x (the ipv4-integer
| (- #.(ash 1 32)
| (the ipv4-integer
| (logand x (the (integer #x-ffffffff 0) (- x))))))))
|
| (disassemble #'ipv4-netmask-p)
| ...[elided]...
+---------------
Well, if you *only* want to do the 32-bit case, then my code is
a bit too general. Part of the problem you're seeing is the
(ASH 1 32), which is generating a 33-bit number, which forces
bignum arithmetic. (Oops.)
If one rewrites the expression to get rid of that, and uses
an explicit LOGAND to trim the result to 32 bits instead of
declarations or THE [which *don't* always trim them properly],
then things get quite a bit better [at least in CMUCL, which seems
to do a pretty good job of propagating (LOGAND #xffffffff EXPR)
down to the leaves of EXPR] -- not much bigger than your C code
if you ignore the differences in calling-sequence overheads:
> (defun ipv4-netmask-p (x)
(declare (optimize (speed 3) (safety 0)))
(declare (type (unsigned-byte 32) x))
(and (plusp x) ; Needed 'cuz the tight version doesn't reject 0.
(= x (logand #xffffffff (1+ (- #xffffffff (logand x (- x))))))))
IPV4-NETMASK-P
> (disassemble *)
; Compiling LAMBDA (X):
; Compiling Top-Level Form:
48131020: .ENTRY "LAMBDA (X)"(x) ; (FUNCTION (#) (MEMBER T NIL))
38: POP DWORD PTR [EBP-8]
3B: LEA ESP, [EBP-32]
3E: MOV EAX, EDX
40: TEST AL, 3 ; [:NON-LOCAL-ENTRY]
42: JEQ L0
44: MOV EAX, [EAX-3]
47: JMP L1
49: L0: SAR EAX, 2
4C: L1: CMP EAX, 0 ; No-arg-parsing entry point
; [:NON-LOCAL-ENTRY]
4F: JNBE L4
;;; [11] (AND (PLUSP X) (= X (LOGAND 4294967295 #)))
51: MOV EDX, #x28F0000B ; NIL
; [:BLOCK-START]
56: L2: L3:MOV ECX, [EBP-8] ; [:BLOCK-START]
59: MOV EAX, [EBP-4]
5C: ADD ECX, 2
5F: MOV ESP, EBP
61: MOV EBP, EAX
63: JMP ECX
;;; [15] (1+ (- 4294967295 (LOGAND X #)))
65: L4: MOV ECX, EAX ; [:BLOCK-START]
67: NEG ECX
69: MOV EDX, EAX
6B: AND EDX, ECX
6D: MOV ECX, 4294967295
72: SUB ECX, EDX
74: INC ECX
75: CMP ECX, EAX
77: JEQ L5
;;; [13] (= X (LOGAND 4294967295 (1+ #)))
79: MOV EDX, #x28F0000B ; NIL
; [:BLOCK-START]
7E: JMP L3
80: L5: MOV EDX, 686817319 ; T
; [:BLOCK-START]
85: JMP L3
87: NOP
>
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607