Marc:
Here's a simple benchmark harness plus two tests:
(declare (standard-bindings) (extended-bindings) (block))
(declare (inline))
(define (inline-unsafe-flonum-+ x y) (declare (not safe) (flonum)) (+ x y))
(define (inline-safe-flonum-+ x y) (declare (flonum)) (+ x y))
(define-macro (test fn x y)
(define (extend-name fn) (string->symbol (string-append "test-" (symbol->string fn))))
`(begin (define (,(extend-name fn) x y) (declare (not safe)) (let outer-loop ((x x) (y y) (number-of-tests 2) (begin-time #f) (i #f)) (##gc) (let inner-loop ((x x) (y y) (number-of-tests number-of-tests) (begin-time (cpu-time)) (i 0)) (if (fx< i number-of-tests) (begin (let () (declare (inlining-limit 10000)) (,fn x y)) (inner-loop x y number-of-tests begin-time (fx+ i 1))) (let ((run-time (fl- (cpu-time) begin-time))) (if (fl< 1.0 run-time) (pp (list (fl/ (exact->inexact number-of-tests) run-time) '(,fn x y) )) (outer-loop x y (fx* 2 number-of-tests) begin-time #f))))))) (,(extend-name fn) ,x ,y)))
(test inline-unsafe-flonum-+ 2. 3.) (test inline-safe-flonum-+ 2. 3.)
Here's the compiled output:
heine:~/programs/gambc-v4_6_2-devel> gsc -c -expansion crap-test+.scm Expansion:
(define inline-unsafe-flonum-+ (lambda (x y) ('#<procedure #2 ##fl+> x y)))
(define inline-safe-flonum-+ (lambda (x y) (if (and ('#<procedure #3 ##flonum?> y) ('#<procedure #3 ##flonum?> x)) ('#<procedure #2 ##fl+> x y) ('#<procedure #4 fl+> x y))))
(define test-inline-unsafe-flonum-+ (lambda (x y) (letrec ((outer-loop (lambda (x y number-of-tests begin-time i) (let ((begin-temp.1 (##gc))) (letrec ((inner-loop (lambda (x y number-of-tests begin-time i) (if ('#<procedure #5 ##fx<> i number-of-tests) (let ((begin-temp.0 (let ((x x) (y y)) ('#<procedure #2 ##fl+> x y)))) (inner-loop x y number-of-tests begin-time ('#<procedure #6 ##fx+> i 1))) (let ((run-time ('#<procedure #7 ##fl-> (cpu-time) begin-time))) (if ('#<procedure #8 ##fl<> 1. run-time) (pp ('#<procedure #9 ##list> ('#<procedure #10 ##fl/> (if ('#<procedure #11 ##fixnum?> number-of-tests) ('#<procedure #12 ##fl<-fx> number-of-tests) (if ('#<procedure #3 ##flonum?> number-of-tests) number-of-tests ('#<procedure #13 exact->inexact> number-of-tests))) run-time) '(inline-unsafe-flonum-+ x y))) (outer-loop x y ('#<procedure #14 ##fx*> 2 number-of-tests) begin-time #f))))))) (inner-loop x y number-of-tests (cpu-time) 0)))))) (outer-loop x y 2 #f #f))))
(test-inline-unsafe-flonum-+ 2. 3.)
(define test-inline-safe-flonum-+ (lambda (x y) (letrec ((outer-loop (lambda (x y number-of-tests begin-time i) (let ((begin-temp.3 (##gc))) (letrec ((inner-loop (lambda (x y number-of-tests begin-time i) (if ('#<procedure #5 ##fx<> i number-of-tests) (let ((begin-temp.2 (let ((x x) (y y)) (if (and ('#<procedure #3 ##flonum?> y) ('#<procedure #3 ##flonum?> x)) ('#<procedure #2 ##fl+> x y) ('#<procedure #4 fl+> x y))))) (inner-loop x y number-of-tests begin-time ('#<procedure #6 ##fx+> i 1))) (let ((run-time ('#<procedure #7 ##fl-> (cpu-time) begin-time))) (if ('#<procedure #8 ##fl<> 1. run-time) (pp ('#<procedure #9 ##list> ('#<procedure #10 ##fl/> (if ('#<procedure #11 ##fixnum?> number-of-tests) ('#<procedure #12 ##fl<-fx> number-of-tests) (if ('#<procedure #3 ##flonum?> number-of-tests) number-of-tests ('#<procedure #13 exact->inexact> number-of-tests))) run-time) '(inline-safe-flonum-+ x y))) (outer-loop x y ('#<procedure #14 ##fx*> 2 number-of-tests) begin-time #f))))))) (inner-loop x y number-of-tests (cpu-time) 0)))))) (outer-loop x y 2 #f #f))))
(test-inline-safe-flonum-+ 2. 3.)
Now see that
('#<procedure #2 ##fl+> x y))
is in the expansion of each test loop (at begin-temp.0 and begin-temp.2), but that addition is not in the C-code (presumably because it is not referenced).
It's OK with me that the compiler removes this code; what I find troubling is that it's still in the "expansion" of the scheme code---it appears that there are optimizations done after the expansion but before code generation.
I'd like to rely on the output of '-expansion' more and to rely on reading the C code (or the resulting assembly code in extreme cases) less in trying to figure out how gsc will compile my code.
Can the '-expansion' be emitted later in the compilation process, after all code-visible optimizations have been made?
Brad
Afficher les réponses par date
On 2011-11-17, at 3:02 PM, Bradley Lucier wrote:
It's OK with me that the compiler removes this code; what I find troubling is that it's still in the "expansion" of the scheme code---it appears that there are optimizations done after the expansion but before code generation.
I'd like to rely on the output of '-expansion' more and to rely on reading the C code (or the resulting assembly code in extreme cases) less in trying to figure out how gsc will compile my code.
Can the '-expansion' be emitted later in the compilation process, after all code-visible optimizations have been made?
These optimizations are done in _front.scm after the source-to-source rewrites in _ptree[12].scm . So there is no moment in time where the AST represents these optimizations. Moving these optimizations to _ptree[12].scm is conceivable but would require a fair amount of refactoring.
Marc