optimizer: don't move APPN_FLAG_OMITTABLE inside lambdas
Some expressions are omittable only when the arguments have certain types. In this case the application is marked with APPN_FLAG_OMITTABLE instead of relaying on the flags of the primitive. The optimizer can't use this flag to move the expression inside a lamba or across a potential continuation capture, unlike other omittable expressions. They can be moved only in more restricted conditions. For example, in this program #lang racket/base (define n 10000) (define m 10000) (time (define xs (build-list n (lambda (x) 0))) (length xs) (define ws (list->vector xs)) ; <-- omittable (for ([i (in-range m)]) (vector-ref ws 0))) ; <-- ws is used once If the optimizer moves the expression in the definition of ws inside the recursive lambda that is created by the for, then the code is equivalent to: #lang racket/base (define n 10000) (define m 10000) (time (define xs (build-list n (lambda (x) 0))) (length xs) (for ([i (in-range m)]) (vector-ref (list->vector xs) 0))) ; <-- moved here And the new code is O(n*m) instead of O(n+m). This example is a minimized version of the function kde from the plot package, where n=m and the bug changed the run time from linear to quadratic.
This commit is contained in:
parent
004fd02501
commit
bfa269982f
|
@ -2111,6 +2111,18 @@
|
|||
'(lambda (z) (lambda ()
|
||||
(lambda () z)))
|
||||
#f)
|
||||
;; Don't move omittable expressions that keep a reference:
|
||||
(test-comp '(lambda (z) (let ([r (pair? z)])
|
||||
(lambda () r)))
|
||||
'(lambda (z) (lambda ()
|
||||
(lambda () (pair? z))))
|
||||
#f)
|
||||
(test-comp '(lambda (z) (when (list? z)
|
||||
(let ([r (list->vector z)])
|
||||
(lambda () r))))
|
||||
'(lambda (z) (when (list? z)
|
||||
(lambda () (list->vector z))))
|
||||
#f)
|
||||
|
||||
|
||||
(test-comp '(if (let ([z (random)]) null) 1 2)
|
||||
|
|
|
@ -1616,8 +1616,10 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info,
|
|||
}
|
||||
break;
|
||||
case scheme_application_type:
|
||||
if (SCHEME_APPN_FLAGS((Scheme_App_Rec *)expr) & APPN_FLAG_OMITTABLE)
|
||||
can_move = 1;
|
||||
if (!cross_lambda
|
||||
&& !cross_k
|
||||
&& (SCHEME_APPN_FLAGS((Scheme_App_Rec *)expr) & APPN_FLAG_OMITTABLE))
|
||||
can_move = -1;
|
||||
else
|
||||
can_move = is_movable_prim(((Scheme_App_Rec *)expr)->args[0], ((Scheme_App_Rec *)expr)->num_args,
|
||||
cross_lambda, cross_k, info);
|
||||
|
@ -1633,8 +1635,10 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info,
|
|||
}
|
||||
break;
|
||||
case scheme_application2_type:
|
||||
if (SCHEME_APPN_FLAGS((Scheme_App2_Rec *)expr) & APPN_FLAG_OMITTABLE)
|
||||
can_move = 1;
|
||||
if (!cross_lambda
|
||||
&& !cross_k
|
||||
&& (SCHEME_APPN_FLAGS((Scheme_App2_Rec *)expr) & APPN_FLAG_OMITTABLE))
|
||||
can_move = -1;
|
||||
else
|
||||
can_move = is_movable_prim(((Scheme_App2_Rec *)expr)->rator, 1, cross_lambda, cross_k, info);
|
||||
if (can_move) {
|
||||
|
@ -1645,8 +1649,10 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info,
|
|||
}
|
||||
break;
|
||||
case scheme_application3_type:
|
||||
if (SCHEME_APPN_FLAGS((Scheme_App3_Rec *)expr) & APPN_FLAG_OMITTABLE)
|
||||
can_move = 1;
|
||||
if (!cross_lambda
|
||||
&& !cross_k
|
||||
&& (SCHEME_APPN_FLAGS((Scheme_App3_Rec *)expr) & APPN_FLAG_OMITTABLE))
|
||||
can_move = -1;
|
||||
else
|
||||
can_move = is_movable_prim(((Scheme_App3_Rec *)expr)->rator, 2, cross_lambda, cross_k, info);
|
||||
if (can_move) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user