optimizer: generalize moving expressions to single-value context
Gemeralize Gustavo's change so that immediately-used right-hand sides can be moved into any position that (like the binding context) enforces single-valuedness --- for arbitrary right-hand expressions.
This commit is contained in:
parent
25c05d66b6
commit
a7a912eeab
|
@ -1009,6 +1009,7 @@
|
||||||
(let ([x (cons w z)])
|
(let ([x (cons w z)])
|
||||||
(car x)))
|
(car x)))
|
||||||
'(lambda (w z) w))
|
'(lambda (w z) w))
|
||||||
|
|
||||||
(test-comp '(lambda (w z)
|
(test-comp '(lambda (w z)
|
||||||
(let ([x (cons w z)])
|
(let ([x (cons w z)])
|
||||||
(cdr x)))
|
(cdr x)))
|
||||||
|
@ -1393,6 +1394,39 @@
|
||||||
(if r #t (something-else))))
|
(if r #t (something-else))))
|
||||||
'(lambda (x) (if (something) #t (something-else))))
|
'(lambda (x) (if (something) #t (something-else))))
|
||||||
|
|
||||||
|
(test-comp '(lambda (x) (let ([r (something)])
|
||||||
|
(r)))
|
||||||
|
'(lambda (x) ((something))))
|
||||||
|
(test-comp '(lambda (x) (let ([r (something)])
|
||||||
|
(r (something-else))))
|
||||||
|
'(lambda (x) ((something) (something-else))))
|
||||||
|
(test-comp '(lambda (x z) (let ([r (something)])
|
||||||
|
(z r)))
|
||||||
|
'(lambda (x z) (z (something))))
|
||||||
|
(test-comp '(lambda (x) (let ([r (something)])
|
||||||
|
(r (something-else) 1 2)))
|
||||||
|
'(lambda (x) ((something) (something-else) 1 2)))
|
||||||
|
(test-comp '(lambda (x z) (let ([r (something)])
|
||||||
|
(with-continuation-mark r z (something-else))))
|
||||||
|
'(lambda (x z) (with-continuation-mark (something) z (something-else))))
|
||||||
|
(test-comp '(lambda (x z) (let ([r (something)])
|
||||||
|
(with-continuation-mark z r (something-else))))
|
||||||
|
'(lambda (x z) (with-continuation-mark z (something) (something-else))))
|
||||||
|
(test-comp '(lambda (x z) (let ([r (something)])
|
||||||
|
(set! z r)))
|
||||||
|
'(lambda (x z) (set! z (something))))
|
||||||
|
(test-comp '(lambda (x z) (let ([r (something)])
|
||||||
|
(call-with-values (lambda () (z)) r)))
|
||||||
|
'(lambda (x z) (call-with-values (lambda () (z)) (something))))
|
||||||
|
|
||||||
|
;; Don't move closure allocation:
|
||||||
|
(test-comp '(lambda (z) (let ([r (lambda () z)])
|
||||||
|
(lambda () r)))
|
||||||
|
'(lambda (z) (lambda ()
|
||||||
|
(lambda () z)))
|
||||||
|
#f)
|
||||||
|
|
||||||
|
|
||||||
(test-comp '(if (let ([z (random)]) null) 1 2)
|
(test-comp '(if (let ([z (random)]) null) 1 2)
|
||||||
'(if (let ([z (random)]) #t) 1 2))
|
'(if (let ([z (random)]) #t) 1 2))
|
||||||
|
|
||||||
|
@ -3883,6 +3917,30 @@
|
||||||
(set! f f)
|
(set! f f)
|
||||||
(err/rt-test (f #t)))
|
(err/rt-test (f #t)))
|
||||||
|
|
||||||
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Make sure compilation doesn't try to inline forever:
|
||||||
|
|
||||||
|
(module cfg-extract-test racket/base
|
||||||
|
(define (report-answer-all k)
|
||||||
|
(k (list (random 10))))
|
||||||
|
|
||||||
|
(lambda ()
|
||||||
|
(let loop ([success-k 0]
|
||||||
|
[fail-k 1]
|
||||||
|
[k 0])
|
||||||
|
(let ([new-got-k
|
||||||
|
(lambda (val stream depth tasks next-k)
|
||||||
|
(let ([next-k (lambda (x y tasks)
|
||||||
|
(loop (random)
|
||||||
|
1
|
||||||
|
(lambda (end tasks success-k fail-k)
|
||||||
|
(next-k success-k fail-k 8))))])
|
||||||
|
(report-answer-all (lambda (tasks)
|
||||||
|
(success-k 0 1 2 3 next-k)))))])
|
||||||
|
(k 5 5 new-got-k
|
||||||
|
(lambda (tasks)
|
||||||
|
(report-answer-all 8)))))))
|
||||||
|
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(report-errs)
|
(report-errs)
|
||||||
|
|
|
@ -1155,6 +1155,9 @@ static int single_valued_noncm_expression(Scheme_Object *expr, int fuel)
|
||||||
&& single_valued_noncm_expression(b->fbranch, fuel - 1));
|
&& single_valued_noncm_expression(b->fbranch, fuel - 1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case scheme_compiled_unclosed_procedure_type:
|
||||||
|
case scheme_case_lambda_sequence_type:
|
||||||
|
return 1;
|
||||||
default:
|
default:
|
||||||
if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_)
|
if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1286,6 +1289,11 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case scheme_compiled_unclosed_procedure_type:
|
||||||
|
case scheme_case_lambda_sequence_type:
|
||||||
|
/* Can't move across lambda or continuation if not closed, since
|
||||||
|
that changes allocation of a closure. */
|
||||||
|
return !cross_lambda && !cross_k;
|
||||||
default:
|
default:
|
||||||
if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_)
|
if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2531,12 +2539,12 @@ static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info
|
||||||
return le;
|
return le;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_context = 0;
|
sub_context = OPT_CONTEXT_SINGLED;
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
int ty;
|
int ty;
|
||||||
ty = wants_local_type_arguments(app->args[0], i - 1);
|
ty = wants_local_type_arguments(app->args[0], i - 1);
|
||||||
if (ty)
|
if (ty)
|
||||||
sub_context = (ty << OPT_CONTEXT_TYPE_SHIFT);
|
sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize_info_seq_step(info, &info_seq);
|
optimize_info_seq_step(info, &info_seq);
|
||||||
|
@ -2804,7 +2812,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf
|
||||||
{
|
{
|
||||||
Scheme_App2_Rec *app;
|
Scheme_App2_Rec *app;
|
||||||
Scheme_Object *le;
|
Scheme_Object *le;
|
||||||
int rator_flags = 0, sub_context = 0, ty;
|
int rator_flags = 0, sub_context, ty;
|
||||||
Optimize_Info_Sequence info_seq;
|
Optimize_Info_Sequence info_seq;
|
||||||
|
|
||||||
app = (Scheme_App2_Rec *)o;
|
app = (Scheme_App2_Rec *)o;
|
||||||
|
@ -2818,7 +2826,9 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf
|
||||||
|
|
||||||
optimize_info_seq_init(info, &info_seq);
|
optimize_info_seq_init(info, &info_seq);
|
||||||
|
|
||||||
le = scheme_optimize_expr(app->rator, info, 0);
|
sub_context = OPT_CONTEXT_SINGLED;
|
||||||
|
|
||||||
|
le = scheme_optimize_expr(app->rator, info, sub_context);
|
||||||
app->rator = le;
|
app->rator = le;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2829,7 +2839,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SAME_PTR(scheme_not_prim, app->rator)){
|
if (SAME_PTR(scheme_not_prim, app->rator)){
|
||||||
sub_context = OPT_CONTEXT_BOOLEAN;
|
sub_context |= OPT_CONTEXT_BOOLEAN;
|
||||||
} else {
|
} else {
|
||||||
ty = wants_local_type_arguments(app->rator, 0);
|
ty = wants_local_type_arguments(app->rator, 0);
|
||||||
if (ty)
|
if (ty)
|
||||||
|
@ -3064,7 +3074,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf
|
||||||
{
|
{
|
||||||
Scheme_App3_Rec *app;
|
Scheme_App3_Rec *app;
|
||||||
Scheme_Object *le;
|
Scheme_Object *le;
|
||||||
int rator_flags = 0, sub_context = 0, ty, flags;
|
int rator_flags = 0, sub_context, ty, flags;
|
||||||
Optimize_Info_Sequence info_seq;
|
Optimize_Info_Sequence info_seq;
|
||||||
|
|
||||||
app = (Scheme_App3_Rec *)o;
|
app = (Scheme_App3_Rec *)o;
|
||||||
|
@ -3092,6 +3102,8 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf
|
||||||
|
|
||||||
optimize_info_seq_init(info, &info_seq);
|
optimize_info_seq_init(info, &info_seq);
|
||||||
|
|
||||||
|
sub_context = OPT_CONTEXT_SINGLED;
|
||||||
|
|
||||||
le = scheme_optimize_expr(app->rator, info, sub_context);
|
le = scheme_optimize_expr(app->rator, info, sub_context);
|
||||||
app->rator = le;
|
app->rator = le;
|
||||||
|
|
||||||
|
@ -3642,7 +3654,7 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int
|
||||||
|
|
||||||
optimize_info_seq_init(info, &info_seq);
|
optimize_info_seq_init(info, &info_seq);
|
||||||
|
|
||||||
t = scheme_optimize_expr(t, info, OPT_CONTEXT_BOOLEAN);
|
t = scheme_optimize_expr(t, info, OPT_CONTEXT_BOOLEAN | OPT_CONTEXT_SINGLED);
|
||||||
|
|
||||||
/* Try optimize: (if (not x) y z) => (if x z y) */
|
/* Try optimize: (if (not x) y z) => (if x z y) */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -3838,11 +3850,11 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co
|
||||||
|
|
||||||
optimize_info_seq_init(info, &info_seq);
|
optimize_info_seq_init(info, &info_seq);
|
||||||
|
|
||||||
k = scheme_optimize_expr(wcm->key, info, 0);
|
k = scheme_optimize_expr(wcm->key, info, OPT_CONTEXT_SINGLED);
|
||||||
|
|
||||||
optimize_info_seq_step(info, &info_seq);
|
optimize_info_seq_step(info, &info_seq);
|
||||||
|
|
||||||
v = scheme_optimize_expr(wcm->val, info, 0);
|
v = scheme_optimize_expr(wcm->val, info, OPT_CONTEXT_SINGLED);
|
||||||
|
|
||||||
/* The presence of a key can be detected by other expressions,
|
/* The presence of a key can be detected by other expressions,
|
||||||
to increment vclock to prevent expressions incorrectly
|
to increment vclock to prevent expressions incorrectly
|
||||||
|
@ -3905,7 +3917,7 @@ set_optimize(Scheme_Object *data, Optimize_Info *info, int context)
|
||||||
var = sb->var;
|
var = sb->var;
|
||||||
val = sb->val;
|
val = sb->val;
|
||||||
|
|
||||||
val = scheme_optimize_expr(val, info, 0);
|
val = scheme_optimize_expr(val, info, OPT_CONTEXT_SINGLED);
|
||||||
|
|
||||||
info->preserves_marks = 1;
|
info->preserves_marks = 1;
|
||||||
info->single_result = 1;
|
info->single_result = 1;
|
||||||
|
@ -4041,7 +4053,7 @@ apply_values_optimize(Scheme_Object *data, Optimize_Info *info, int context)
|
||||||
|
|
||||||
optimize_info_seq_init(info, &info_seq);
|
optimize_info_seq_init(info, &info_seq);
|
||||||
|
|
||||||
f = scheme_optimize_expr(f, info, 0);
|
f = scheme_optimize_expr(f, info, OPT_CONTEXT_SINGLED);
|
||||||
|
|
||||||
optimize_info_seq_step(info, &info_seq);
|
optimize_info_seq_step(info, &info_seq);
|
||||||
|
|
||||||
|
@ -5102,7 +5114,10 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i
|
||||||
|
|
||||||
if (!skip_opts) {
|
if (!skip_opts) {
|
||||||
optimize_info_seq_step(rhs_info, &info_seq);
|
optimize_info_seq_step(rhs_info, &info_seq);
|
||||||
value = scheme_optimize_expr(pre_body->value, rhs_info, 0);
|
value = scheme_optimize_expr(pre_body->value, rhs_info,
|
||||||
|
((pre_body->count == 1)
|
||||||
|
? OPT_CONTEXT_SINGLED
|
||||||
|
: 0));
|
||||||
pre_body->value = value;
|
pre_body->value = value;
|
||||||
} else {
|
} else {
|
||||||
value = pre_body->value;
|
value = pre_body->value;
|
||||||
|
@ -5410,7 +5425,10 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i
|
||||||
rhs_info->use_psize = info->use_psize;
|
rhs_info->use_psize = info->use_psize;
|
||||||
|
|
||||||
optimize_info_seq_step(rhs_info, &info_seq);
|
optimize_info_seq_step(rhs_info, &info_seq);
|
||||||
value = scheme_optimize_expr(self_value, rhs_info, 0);
|
value = scheme_optimize_expr(self_value, rhs_info,
|
||||||
|
((clv->count == 1)
|
||||||
|
? OPT_CONTEXT_SINGLED
|
||||||
|
: 0));
|
||||||
|
|
||||||
if (!OPT_DISCOURAGE_EARLY_INLINE)
|
if (!OPT_DISCOURAGE_EARLY_INLINE)
|
||||||
--rhs_info->letrec_not_twice;
|
--rhs_info->letrec_not_twice;
|
||||||
|
@ -6701,7 +6719,7 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in
|
||||||
if (SAME_TYPE(SCHEME_TYPE(val), scheme_once_used_type)) {
|
if (SAME_TYPE(SCHEME_TYPE(val), scheme_once_used_type)) {
|
||||||
Scheme_Once_Used *o = (Scheme_Once_Used *)val;
|
Scheme_Once_Used *o = (Scheme_Once_Used *)val;
|
||||||
if (((o->vclock == info->vclock)
|
if (((o->vclock == info->vclock)
|
||||||
&& ((context & OPT_CONTEXT_BOOLEAN)
|
&& ((context & OPT_CONTEXT_SINGLED)
|
||||||
|| single_valued_noncm_expression(o->expr, 5)))
|
|| single_valued_noncm_expression(o->expr, 5)))
|
||||||
|| movable_expression(o->expr, info, o->delta, o->cross_lambda,
|
|| movable_expression(o->expr, info, o->delta, o->cross_lambda,
|
||||||
o->kclock != info->kclock,
|
o->kclock != info->kclock,
|
||||||
|
@ -6710,6 +6728,7 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in
|
||||||
if (val) {
|
if (val) {
|
||||||
info->size -= 1;
|
info->size -= 1;
|
||||||
o->used = 1;
|
o->used = 1;
|
||||||
|
info->inline_fuel = 0; /* no more inlining; o->expr was already optimized */
|
||||||
return scheme_optimize_expr(val, info, context);
|
return scheme_optimize_expr(val, info, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2873,11 +2873,15 @@ Scheme_Object *scheme_letrec_check_expr(Scheme_Object *);
|
||||||
Scheme_Object *scheme_optimize_expr(Scheme_Object *, Optimize_Info *, int context);
|
Scheme_Object *scheme_optimize_expr(Scheme_Object *, Optimize_Info *, int context);
|
||||||
Scheme_Object *scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, int context);
|
Scheme_Object *scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, int context);
|
||||||
|
|
||||||
|
/* Context uses result as a boolean: */
|
||||||
#define OPT_CONTEXT_BOOLEAN 0x1
|
#define OPT_CONTEXT_BOOLEAN 0x1
|
||||||
|
/* Context might duplicate the expression: */
|
||||||
#define OPT_CONTEXT_NO_SINGLE 0x2
|
#define OPT_CONTEXT_NO_SINGLE 0x2
|
||||||
#define OPT_CONTEXT_TYPE_SHIFT 3
|
/* Context checks that result is a single value: */
|
||||||
#define OPT_CONTEXT_TYPE_MASK (SCHEME_MAX_LOCAL_TYPE_MASK << OPT_CONTEXT_TYPE_SHIFT)
|
#define OPT_CONTEXT_SINGLED 0x4
|
||||||
#define OPT_CONTEXT_TYPE(oc) ((oc & OPT_CONTEXT_TYPE_MASK) >> OPT_CONTEXT_TYPE_SHIFT)
|
#define OPT_CONTEXT_TYPE_SHIFT 4
|
||||||
|
#define OPT_CONTEXT_TYPE_MASK (SCHEME_MAX_LOCAL_TYPE_MASK << OPT_CONTEXT_TYPE_SHIFT)
|
||||||
|
#define OPT_CONTEXT_TYPE(oc) ((oc & OPT_CONTEXT_TYPE_MASK) >> OPT_CONTEXT_TYPE_SHIFT)
|
||||||
|
|
||||||
#define scheme_optimize_result_context(c) (c & (~(OPT_CONTEXT_TYPE_MASK | OPT_CONTEXT_NO_SINGLE)))
|
#define scheme_optimize_result_context(c) (c & (~(OPT_CONTEXT_TYPE_MASK | OPT_CONTEXT_NO_SINGLE)))
|
||||||
#define scheme_optimize_tail_context(c) scheme_optimize_result_context(c)
|
#define scheme_optimize_tail_context(c) scheme_optimize_result_context(c)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user