Opened 5 years ago
Closed 5 years ago
#1620 closed defect (fixed)
Some let bindings are not replaced resulting in unnecessary CPS calls
Reported by: | sjamaan | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | 5.2 |
Component: | compiler | Version: | 5.0.0 |
Keywords: | Cc: | ||
Estimated difficulty: | hard |
Description (last modified by )
We've seen in #1604 that this is a performance killer:
This code is fast when compiled with -O5 -strict-types -fixnum-arithmetic
:
(define (fib n) (if (or (eq? n 0) (eq? n 1)) n (+ (fib (- n 1)) (fib (- n 2))))) (let loop ((n 0)) (when (< n 35) (print "n=" n " => " (fib n)) (loop (+ n 1))))
This code is slow when compiled with the same options, even though the generated intermediate Scheme code is equivalent:
(define (fib n) (if (or (= n 0) (= n 1)) n (+ (fib (- n 1)) (fib (- n 2))))) (let loop ((n 0)) (when (< n 35) (print "n=" n " => " (fib n)) (loop (+ n 1))))
The reason is that in the first case, the eq?
calls get replaced by (##core#inline "C_eqp" a b)
while in the second case, the =
calls get replaced by (let ((x a) (y b)) (##core_inline "C_eqp" x y))
and the let
is not considered replacable
even though (I think?) it should be.
That's because fib
's arguments are marked by analyze-expression
in core.scm
as captured
.
Fixing this could potentially make a lot of code a lot faster! We definitely should run the benchmarks with and without the fix to find out how dramatic the improvement is.
Change History (3)
comment:1 Changed 5 years ago by
Description: | modified (diff) |
---|
comment:2 Changed 5 years ago by
comment:3 Changed 5 years ago by
Resolution: | → fixed |
---|---|
Status: | new → closed |
Fixed by 27dbbc02d32f91712b83f6b11ffa325da6454df8
Note: The
let
bindings are actually necessary when the arguments of=
are impure; you want side-effects or exceptions to happen before calling=
. The expanded generated code contains a shortcuttingC_and
call introduced byfold-boolean
and each of the arguments except the first and the last are repeated twice, so if we got rid of thelet
completely, the resulting code would not be semantically equivalent.However, if they just alias other variables, I think they should always be replacable.