4 ms·
It might also be interesting for readers to see what the resulting code is from these three functions. I recompiled your code with SAFETY 0 and here is the res
by lokedhs 10y ago
It might also be interesting for readers to see what the resulting code is from these three functions.
I recompiled your code with SAFETY 0 and here is the result. This example also shows off how you can look at the disassembly of any function directly from the REPL.
First, ADD1. Since the compiler doesn't know anything about the types (the arguments could be floating points numbers, rationals, bignums or any other type) so it will simply call the GENERIC-+ function which does all of this. Needless to say, it's much slower than a native addition.
CL-USER> (disassemble #'add1)
; disassembly for ADD1
; Size: 14 bytes. Origin: #x2291202A
; 2A: 488BD1 MOV RDX, RCX ; no-arg-parsing entry point
; 2D: E86EE26EFD CALL #x200002A0 ; GENERIC-+
; 32: 488BE5 MOV RSP, RBP
; 35: F8 CLC
; 36: 5D POP RBP
; 37: C3 RET
The function ADD2 still has unknown types, so there is not much the compiler can do but to call GENERIC-+ in this case.
CL-USER> (disassemble #'add2)
; disassembly for ADD2
; Size: 14 bytes. Origin: #x22911FBA
; BA: 488BD1 MOV RDX, RCX ; no-arg-parsing entry point
; BD: E8DEE26EFD CALL #x200002A0 ; GENERIC-+
; C2: 488BE5 MOV RSP, RBP
; C5: F8 CLC
; C6: 5D POP RBP
; C7: C3 RET
Since the compiler knows that both arguments are bytes, it can simply call the ADD instruction. With the exception of some extra bookkeeping needed when returning from the function, this is just as efficient as what a C++ compiler would generate. You can also declare a function as INLINE to allow the compiler to inline the call.
CL-USER> (disassemble #'add3)
; disassembly for ADD3
; Size: 12 bytes. Origin: #x22911F4A
; 4A: 4801F9 ADD RCX, RDI ; no-arg-parsing entry point
; 4D: 488BD1 MOV RDX, RCX
; 50: 488BE5 MOV RSP, RBP
; 53: F8 CLC
; 54: 5D POP RBP
; 55: C3 RET