Skip to content

Instantly share code, notes, and snippets.

@jackrusher
Last active February 22, 2016 02:30
Show Gist options
  • Save jackrusher/57525bef17382c9a7207 to your computer and use it in GitHub Desktop.
Save jackrusher/57525bef17382c9a7207 to your computer and use it in GitHub Desktop.
;; This is the sort of thing that makes me think you'd enjoy using one
;; of the better Common Lisp implementations for certain kinds of
;; work. I'm using the latest version of SBCL here.
;; Ok, contrived example, but easy to imagine the code that it should
;; generate...
(defun add (x y)
(+ x y))
(disassemble #'add)
; disassembly for ADD
; Size: 41 bytes. Origin: #x1004CB7393
; 93: 498B4C2460 MOV RCX, [R12+96] ; thread.binding-stack-pointer
; no-arg-parsing entry point
; 98: 48894DF8 MOV [RBP-8], RCX
; 9C: 488BD6 MOV RDX, RSI
; 9F: 488BFB MOV RDI, RBX
; A2: 41BBD0010020 MOV R11D, 536871376 ; GENERIC-+
; A8: 41FFD3 CALL R11
; AB: 488B5DE8 MOV RBX, [RBP-24]
; AF: 488B75F0 MOV RSI, [RBP-16]
; B3: 488BE5 MOV RSP, RBP
; B6: F8 CLC
; B7: 5D POP RBP
; B8: C3 RET
; B9: 0F0B10 BREAK 16 ; Invalid argument count trap
;; ... not terrible, especially for a runtime that provides arbitrary
;; precision arithmetic and traps errors in a civilized way, but with
;; safety and generic #'+ that figures out arity and handles different
;; types we pay a price in performance relative to the asm we'd write.
;; There are a number of different ways to speed this up: declaring a
;; greater speed to safety preference, annotating types. Here's an
;; optimized version with that sort of ugly cruft added to get really
;; good performance specifically for 32-bit integers.
(defun add (x y)
(declare
(type (unsigned-byte 32) x y)
(optimize (speed 3) (safety 0)))
(the (unsigned-byte 32) (+ x y)))
(disassemble #'add)
; disassembly for ADD
; Size: 12 bytes. Origin: #x1004CEFD82
; 2: 4801F9 ADD RCX, RDI ; no-arg-parsing entry point
; 5: 488BD1 MOV RDX, RCX
; 8: 488BE5 MOV RSP, RBP
; B: F8 CLC
; C: 5D POP RBP
; D: C3 RET
;; ... I can definitely live with that.
;; We can write macros that produce code with these annotation to
;; compile our own high-level DSLs into the assembly we would have
;; written. Common Lisp has its warts, but it really is amazing when
;; it comes building whatever abstractions you prefer while retaining
;; control over low-level code generation.
;; I'm not sure what Common Lisp you're using, ot why you'd want to
;; use a counter to repeatedly poke some data into a value cell, but
;; but with SBCL's compiler I get:
(defun test ()
(let ((x 0))
(declare
(optimize (speed 3) (safety 0)))
(type (unsigned-byte 32) x)
(loop for i to 999999999 do (incf x))))
(disassemble #'test)
; disassembly for TEST
; Size: 58 bytes. Origin: #x1004AA1614
; 14: 498B442460 MOV RAX, [R12+96] ; thread.binding-stack-pointer
; no-arg-parsing entry point
; 19: 488945F8 MOV [RBP-8], RAX
; 1D: 31D2 XOR EDX, EDX
; 1F: 31C0 XOR EAX, EAX
; 21: EB15 JMP L1
; 23: 660F1F840000000000 NOP
; 2C: 0F1F4000 NOP
; 30: L0: 4883C202 ADD RDX, 2
; 34: 4883C002 ADD RAX, 2
; 38: L1: 483DFE933577 CMP RAX, 1999999998
; 3E: 7EF0 JLE L0
; 40: BA17001020 MOV EDX, 537919511
; 45: 488BE5 MOV RSP, RBP
; 48: F8 CLC
; 49: 5D POP RBP
; 4A: C3 RET
; 4B: 0F0B10 BREAK 16 ; Invalid argument count trap
;; ... which runs in 0.000586 seconds of system time at 99.67% CPU utilization:
;; 811,693,353 processor cycles
;; 0 bytes consed
;; ... note that this last bit means no memory was allocated during the function call and loop.
@Ismael-VC
Copy link

@jackrusher it doesn't work for me in neither lisp implementation:

Clisp

Break 1 [3]> (defun test ()
  (let ((x 0))
    (declare
      (optimize (speed 3) (safety 0)))
      (type (unsigned-byte 32) x)
    (loop for i to 999999999 do (incf x))))
TEST

Break 1 [3]> (time (test))
*** - EVAL: undefined function TYPE
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of (FDEFINITION 'TYPE).
RETRY          :R2      Retry
STORE-VALUE    :R3      Input a new value for (FDEFINITION 'TYPE).
ABORT          :R4      Abort debug loop

Break 2 [4]> (disassemble #'test)
WARNING: in TEST : Function TYPE is not defined
WARNING: in TEST : Function UNSIGNED-BYTE is not defined

Disassembly of function TEST
(CONST 0) = 0
(CONST 1) = 32
(CONST 2) = UNSIGNED-BYTE
(CONST 3) = TYPE
(CONST 4) = 999999999
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
16 byte-code instructions:
0     (CONST&PUSH 0)                      ; 0
1     (CONST&PUSH 1)                      ; 32
2     (CALL1&PUSH 2)                      ; UNSIGNED-BYTE
4     (LOAD&PUSH 1)
5     (CALL2 3)                           ; TYPE
7     (CONST&PUSH 0)                      ; 0
8     (JMP L14)
10    L10
10    (LOAD&INC&STORE 1)
12    (LOAD&INC&STORE 0)
14    L14
14    (LOAD&PUSH 0)
15    (CONST&PUSH 4)                      ; 999999999
16    (CALLSR&JMPIFNOT 1 50 L10)          ; >
20    (NIL)
21    (SKIP&RET

CBSL

* (defun test () 
  (let ((x 0))
    (declare
      (optimize (speed 3) (safety 0)))
      (type (unsigned-byte 32) x)
    (loop for i to 999999999 do (incf x))))
; in: DEFUN TEST
;     (TYPE (UNSIGNED-BYTE 32) X)
; 
; caught WARNING:
;   The function TYPE is undefined, and its name is reserved by ANSI CL so that
;   even if it were defined later, the code doing so would not be portable.

;     (UNSIGNED-BYTE 32)
; 
; caught WARNING:
;   The function UNSIGNED-BYTE is undefined, and its name is reserved by ANSI CL so
;   that even if it were defined later, the code doing so would not be portable.
; 
; compilation unit finished
;   Undefined functions:
;     TYPE UNSIGNED-BYTE
;   caught 2 WARNING conditions

TEST

* (time (test))

debugger invoked on a UNDEFINED-FUNCTION in thread
#<THREAD "main thread" RUNNING {1002AAC483}>:
  The function COMMON-LISP:UNSIGNED-BYTE is undefined.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

("undefined function")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment