One way CL doesn't suck (was Re: How Common Lisp sucks)



Peter Seibel <peter@xxxxxxxxxxxxxxx> writes:

Christophe Rhodes <csr21@xxxxxxxxx> writes:

Peter Seibel <peter@xxxxxxxxxxxxxxx> writes:

Now let's see what effect some declarations have:

CL-USER> (defun foo (x y)
(declare (optimize (speed 3) (safety 0)))
(declare (fixnum x y))
(+ x y))
FOO
CL-USER> (disassemble 'foo)
;; disassembly of #<Function (:ANONYMOUS-LAMBDA 13) @ #x107c84c2>
;; formals: X Y

;; code start: #x107c84a4:
0: 7c632014 addc r3,r3,r4
4: 3a000001 [addi] lil r16,1
8: 81a1000c lwz r13,12(r1)
12: 4e800020 blr

Isn't this quite a bad example to use when demonstrating things for a
newbie, given that it is nonconforming output? [ I believe Allegro
documents this deviation, but try (foo most-positive-fixnum
most-positive-fixnum) ]

Sure. Out of curiosity, is it non-conforming given that I declared
safety 0? Or is the implementation still required to produce correct
results?

Yes. 0 safety does not permit an implementation which purports to
conform to ANSI to give the wrong results if none of the constraints
(including user type declarations) are violated. [ My interpretation
of the spec only, yadda yadda; the good people at Franz may not have
more pedantic language lawyers, but they almost certainly have better
law lawyers :-) ]

Which would mean I'd technically have to explicitly mask the
result of (+ x y) down to fixnum bits. And then Allegro doesn't
optimize away the LOGAND. Does SBCL. I.e. if I write:

(defun foo (x y)
(declare (optimize (speed 3) (safety 0)))
(declare (fixnum x y))
(the fixnum (logand (+ x y) #.(1- (expt 2 (integer-length most-positive-fixnum))))))

Well, no, but that's because here your LOGAND doesn't do what I think
you think it does, because a FIXNUM is a signed quantity. The LOGAND
isn't optimized away, but it does compile to two machine instructions
(x86 this time):

; 0A85BCEC: 01FA ADD EDX, EDI ; no-arg-parsing entry point
; CEE: 81E2FFFFFF1F AND EDX, 536870911
; [+ return sequence ]

If instead you do

(defun sfoo (x y)
(declare (optimize (speed 3) (safety 0)))
(declare (fixnum x y))
(sb-c::mask-signed-field 30 (+ x y))) ; 30 fixnum bits on x86

you get just the add:

; 0AA4221E: 01FA ADD EDX, EDI ; no-arg-parsing entry point
; [+ return sequence ]

MASK-SIGNED-FIELD, or some equivalent, will eventually make it to
documented and exported status in SBCL, because this is a thing that
Lisp coders want to do; the contortion of an extra operator is needed
because there's no signed equivalent to LOGAND or LDB, which express
the equivalent unsigned operation.

I wouldn't recommend using FIXNUM declarations, though; they're not
only machine-dependent but implementation-dependent too. Use
(signed-byte 32) or (unsigned-byte 32) (or 64 bits, if that's what
your algorithm needs, or (signed-byte 19) come to that).

Christophe
.



Relevant Pages

  • Re: How Common Lisp sucks
    ... CL-USER> (defun foo (x y) ... (declare (fixnum x y)) ... CL-USER> ... result of down to fixnum bits. ...
    (comp.lang.lisp)
  • Re: why is lisp fast?
    ... Why do you equate "wanting to compete ... of the addition as a fixnum if the user wishes to inform the system ... lisp objects. ... (declare (fixnums-remain-fixnum t)) ...
    (comp.lang.lisp)
  • Re: static, dynamic and implicitely typed languages
    ... If you *are* sure of that, then you can tell a CL compiler ... | (declare (type number a) ... | (declare (type fixnum a b c) ... (defun foobar (a b c) ...
    (comp.lang.lisp)
  • Re: how to speed up some lisp code?
    ... >> representing these as lists. ... declare the variables to be FIXNUM. ...
    (comp.lang.lisp)
  • lang effort: type conversions
    ... the lang will be dynamically typed with a prototype ... long, either a fixnum or an on-heap object, with undefined precision (for ... will declare a mutable one. ...
    (comp.lang.misc)