Last active
February 22, 2016 02:30
-
-
Save jackrusher/57525bef17382c9a7207 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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. |
@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
Julia
(using the LispREPL)
Common Lisp:
How would you do this efficiently?
What am I doing wrong?
Edit:
I read more about it and used let:
Python
(I tried to use the Hy lang) but I didn't understand how to use loop and recur even for something so trivial, well I have to admit I am hungry and sleepy)