Optimize (funcall (constantly ...))
Bug #1800539 reported by
Paul F. Dietz
This bug affects 1 person
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
(as seen on #lisp)
(funcall (constantly x)) should optimize to x in compiled code. Currently, even at speed 3 and constantly declared inline, the call to constantly is not optimized away.
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
To post a comment you must log in.
I was the one who asked about this in #lisp.
More generally: it would be nice if (funcall (constantly v) a b c) could get translated to something like (prog1 v a b c).
My use case is an inlineable A* search function that takes a heuristic function as an argument. It would be nice if, when you declare A* inline and pass (constantly 0) as the heuristic, you'd get:
(+ score (funcall heuristic target)) ; original
(+ score (funcall (constantly 0) target)) ; inlined
(+ score (prog1 0 target)) ; optimize
(+ score 0) ; optimize further
which would let it just gracefully degrade to Dijkstra's if the user passes (constant 0) for the heuristic.
This kind of optimization does happen if you pass in an equivalent lambda instead of using CONSTANTLY:
(disassemble
(lambda ()
(declare (optimize speed))
(let* ((v 0)
(h (constantly v)))
(funcall h 1 2 3))))
; disassembly for (LAMBDA ())
; Size: 56 bytes. Origin: #x52C336BB
; BB: 4883EC10 SUB RSP, 16 ; no-arg-parsing entry point
; BF: 31D2 XOR EDX, EDX
; C1: B902000000 MOV ECX, 2
; C6: 48892C24 MOV [RSP], RBP
; CA: 488BEC MOV RBP, RSP
; CD: B818643150 MOV EAX, #x50316418 ; #<FDEFN CONSTANTLY>
; D2: FFD0 CALL RAX
; D4: 488BC2 MOV RAX, RDX
; D7: BA02000000 MOV EDX, 2
; DC: BF04000000 MOV EDI, 4
; E1: BE06000000 MOV ESI, 6
; E6: B906000000 MOV ECX, 6
; EB: FF7508 PUSH QWORD PTR [RBP+8]
; EE: FF60FD JMP QWORD PTR [RAX-3]
; F1: CC0F BREAK 15 ; Invalid argument count trap
(disassemble
(declare (ignore args))
v)))
(lambda ()
(declare (optimize speed))
(let* ((v 0)
(h (lambda (&rest args)
(funcall h 1 2 3))))
; disassembly for (LAMBDA ())
; Size: 10 bytes. Origin: #x52C3352B
; 2B: 31D2 XOR EDX, EDX ; no-arg-parsing entry point
; 2D: 488BE5 MOV RSP, RBP
; 30: F8 CLC
; 31: 5D POP RBP
; 32: C3 RET
; 33: CC0F BREAK 15 ; Invalid argument count trap