@@ -2905,19 +2905,6 @@ f(x) = yt(x)
2905
2905
(or (assq s (car (lam:vinfo lam)))
2906
2906
(assq s (cadr (lam:vinfo lam)))))
2907
2907
2908
- (define (table.merge! l r )
2909
- (table.foreach (lambda (k v ) (put! l k v))
2910
- r))
2911
-
2912
- (define (table.delete-if! p t )
2913
- (let ((to-del '() ))
2914
- (table.foreach (lambda (v _ )
2915
- (if (p v)
2916
- (set! to-del (cons v to-del))))
2917
- t)
2918
- (for-each (lambda (v ) (del! t v))
2919
- to-del)))
2920
-
2921
2908
; ; Try to identify never-undef variables, and then clear the `captured` flag for single-assigned,
2922
2909
; ; never-undef variables to avoid allocating unnecessary `Box`es.
2923
2910
(define (lambda-optimize-vars! lam )
@@ -2931,81 +2918,90 @@ f(x) = yt(x)
2931
2918
(let ((am (all-methods-for ex stmts)))
2932
2919
(put! allmethods-table mn am)
2933
2920
am))))
2934
- (define (expr-uses-var ex v body )
2935
- (cond ((atom? ex) (expr-contains-eq v ex))
2936
- ((assignment? ex) (expr-contains-eq v (caddr ex)))
2937
- ((eq? (car ex) 'method )
2938
- (and (length> ex 2 )
2939
- ; ; a method expression captures a variable if any methods for the
2940
- ; ; same function do.
2941
- (let* ((mn (method-expr-name ex))
2942
- (all-methods (if (local-in? mn lam)
2943
- (get-methods ex body)
2944
- (list ex))))
2945
- (any (lambda (ex )
2946
- (assq v (cadr (lam:vinfo (cadddr ex)))))
2947
- all-methods))))
2948
- (else (expr-contains-eq v ex))))
2949
2921
; ; This does a basic-block-local dominance analysis to find variables that
2950
2922
; ; are never used undef.
2951
2923
(let ((vi (car (lam:vinfo lam)))
2952
2924
(unused (table)) ; ; variables not (yet) used (read from) in the current block
2953
2925
(live (table)) ; ; variables that have been set in the current block
2954
- (seen (table)) ; ; all variables we've seen assignments to
2955
- (b1vars '() ) ; ; vars set in first basic block
2956
- (first #t )) ; ; are we in the first basic block?
2926
+ (seen (table))) ; ; all variables we've seen assignments to
2957
2927
; ; Collect candidate variables: those that are captured (and hence we want to optimize)
2958
2928
; ; and only assigned once. This populates the initial `unused` table.
2959
2929
(for-each (lambda (v )
2960
2930
(if (and (vinfo:capt v) (vinfo:sa v))
2961
2931
(put! unused (car v) #t )))
2962
2932
vi)
2933
+ (define (restore old )
2934
+ (table.foreach (lambda (k v )
2935
+ (if (not (has? old k))
2936
+ (put! unused k v)))
2937
+ live)
2938
+ (set! live old))
2963
2939
(define (kill )
2964
2940
; ; when we see control flow, empty live set back into unused set
2965
- (if first
2966
- (begin (set! first #f )
2967
- (set! b1vars (table.keys live))))
2968
- (table.merge! unused live)
2969
- (set! live (table)))
2970
- (define (mark-used e )
2971
- ; ; remove variables used by `e` from the unused table
2972
- (table.delete-if! (lambda (v ) (expr-uses-var e v (lam:body lam)))
2973
- unused))
2941
+ (restore (table)))
2942
+ (define (mark-used var )
2943
+ ; ; remove variable from the unused table
2944
+ (if (has? unused var)
2945
+ (del! unused var)))
2946
+ (define (assign! var )
2947
+ (if (has? unused var)
2948
+ ; ; When a variable is assigned, move it to the live set to protect
2949
+ ; ; it from being removed from `unused`.
2950
+ (begin (put! live var #t )
2951
+ (put! seen var #t )
2952
+ (del! unused var))))
2974
2953
(define (visit e )
2975
- (cond ((atom? e) (if (symbol? e) (mark-used e)))
2954
+ ; ; returns whether e contained a symboliclabel
2955
+ (cond ((atom? e) (if (symbol? e) (mark-used e))
2956
+ #f )
2976
2957
((lambda-opt-ignored-exprs (car e))
2977
- #t )
2958
+ #f )
2978
2959
((eq? (car e) 'scope-block )
2979
2960
(visit (cadr e)))
2980
- ((eq? (car e) 'block )
2981
- (for-each visit (cdr e)))
2961
+ ((memq (car e) ' ( block call new _do_while) )
2962
+ (eager-any visit (cdr e)))
2982
2963
((eq? (car e) 'break-block )
2983
2964
(visit (caddr e)))
2984
2965
((eq? (car e) 'return )
2985
- (visit (cadr e))
2986
- (kill))
2987
- ((memq (car e) ' (break label symboliclabel symbolicgoto))
2988
- (kill))
2989
- ((memq (car e) ' (if elseif _while _do_while trycatch tryfinally))
2990
- (for-each (lambda (e )
2991
- (visit e)
2992
- (kill))
2993
- (cdr e)))
2966
+ (begin0 (visit (cadr e))
2967
+ (kill)))
2968
+ ((memq (car e) ' (break label symbolicgoto))
2969
+ (kill)
2970
+ #f )
2971
+ ((eq? (car e) 'symboliclabel )
2972
+ (kill)
2973
+ #t )
2974
+ ((memq (car e) ' (if elseif _while trycatch tryfinally))
2975
+ (let ((prev (table.clone live)))
2976
+ (if (eager-any (lambda (e ) (begin0 (visit e)
2977
+ (kill)))
2978
+ (cdr e))
2979
+ ; ; if there is a label inside, we could have skipped a prior
2980
+ ; ; variable initialization
2981
+ (begin (kill) #t )
2982
+ (begin (restore prev) #f ))))
2983
+ ((eq? (car e) '= )
2984
+ (begin0 (visit (caddr e))
2985
+ (assign! (cadr e))))
2986
+ ((eq? (car e) 'method )
2987
+ (if (length> e 2 )
2988
+ (let* ((mn (method-expr-name e))
2989
+ ; ; a method expression captures a variable if any methods for
2990
+ ; ; the same function do.
2991
+ (all-methods (if (local-in? mn lam)
2992
+ (get-methods e (lam:body lam))
2993
+ (list e))))
2994
+ (for-each (lambda (ex )
2995
+ (for-each mark-used
2996
+ (map car (cadr (lam:vinfo (cadddr ex))))))
2997
+ all-methods)
2998
+ (assign! (cadr e))))
2999
+ #f )
2994
3000
(else
2995
- (if (eq? (car e) '= )
2996
- (visit (caddr e))
2997
- (mark-used e))
2998
- (if (and (or (eq? (car e) '= )
2999
- (and (eq? (car e) 'method ) (length> e 2 )))
3000
- (has? unused (cadr e)))
3001
- ; ; When a variable is assigned, move it to the live set to protect
3002
- ; ; it from being removed from `unused`.
3003
- (begin (put! live (cadr e) #t )
3004
- (put! seen (cadr e) #t )
3005
- (del! unused (cadr e)))
3006
- ; ; in all other cases there's nothing to do except assert that
3007
- ; ; all expression heads have been handled.
3008
- #; (assert (memq (car e) '(= method new call foreigncall cfunction |::|)))))))
3001
+ (eager-any visit (cdr e))
3002
+ ; ; in all other cases there's nothing to do except assert that
3003
+ ; ; all expression heads have been handled.
3004
+ #; (assert (memq (car e) '(foreigncall cfunction |::|))))))
3009
3005
(visit (lam:body lam))
3010
3006
; ; Finally, variables can be marked never-undef if they were set in the first block,
3011
3007
; ; or are currently live, or are back in the unused set (because we've left the only
@@ -3014,7 +3010,7 @@ f(x) = yt(x)
3014
3010
(if (has? seen v)
3015
3011
(let ((vv (assq v vi)))
3016
3012
(vinfo:set-never-undef! vv #t ))))
3017
- (append b1vars (table.keys live) (table.keys unused)))
3013
+ (append (table.keys live) (table.keys unused)))
3018
3014
(for-each (lambda (v )
3019
3015
(if (and (vinfo:sa v) (vinfo:never-undef v))
3020
3016
(set-car! (cddr v) (logand (caddr v) (lognot 5 )))))
0 commit comments