optimizer: transform ((begin ... proc) x) to (begin ... (proc x))

Currently the optimizer can convert ((let (...) ... proc) x) to
(let (...) ... (proc x)). This is useful especially if proc can be
inlined. Extend this to begin's forms.
This commit is contained in:
Gustavo Massaccesi 2014-08-22 21:41:41 -03:00 committed by Matthew Flatt
parent 63e940d147
commit d14b4a8095
2 changed files with 73 additions and 52 deletions

View File

@ -1004,6 +1004,23 @@
'(lambda (g) '(lambda (g)
(let ([r (read)]) (let ([r (read)])
(+ r r)))) (+ r r))))
(test-comp '(lambda (g z)
((begin
(read)
(lambda () (+ z z)))))
'(lambda (g z)
(begin
(read)
(+ z z))))
(test-comp '(lambda (g z)
((begin
(read)
(lambda (x) (+ z z)))
g))
'(lambda (g z)
(begin
(read)
(+ z z))))
(test-comp '(lambda (w z) (test-comp '(lambda (w z)
(let ([x (cons w z)]) (let ([x (cons w z)])

View File

@ -682,6 +682,29 @@ static Scheme_Object *make_discarding_first_sequence(Scheme_Object *e1, Scheme_O
return make_sequence_2(e1, e2); return make_sequence_2(e1, e2);
} }
static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *inside, Scheme_Object *orig) {
if (inside) {
switch (SCHEME_TYPE(inside)) {
case scheme_sequence_type:
if (((Scheme_Sequence *)inside)->count)
((Scheme_Sequence *)inside)->array[((Scheme_Sequence *)inside)->count-1] = alt;
else
scheme_signal_error("internal error: strange inside replacement");
break;
case scheme_compiled_let_void_type:
((Scheme_Let_Header *)inside)->body = alt;
break;
case scheme_compiled_let_value_type:
((Scheme_Compiled_Let_Value *)inside)->body = alt;
break;
default:
scheme_signal_error("internal error: strange inside replacement");
}
return orig;
}
return alt;
}
static int is_inspector_call(Scheme_Object *a) static int is_inspector_call(Scheme_Object *a)
{ {
if (SAME_TYPE(SCHEME_TYPE(a), scheme_application_type)) { if (SAME_TYPE(SCHEME_TYPE(a), scheme_application_type)) {
@ -1512,7 +1535,7 @@ static Scheme_Object *no_potential_size(Scheme_Object *v)
static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, Optimize_Info *info, static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, Optimize_Info *info,
int argc, Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3, int argc, Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3,
int context, int context,
int nested_count, Scheme_Object *orig, Scheme_Object *le_prev, intptr_t prev_offset) int nested_count, Scheme_Object *orig, Scheme_Object *le_prev)
{ {
Scheme_Let_Header *lh; Scheme_Let_Header *lh;
Scheme_Compiled_Let_Value *lv, *prev = NULL; Scheme_Compiled_Let_Value *lv, *prev = NULL;
@ -1531,11 +1554,7 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data,
info->next->preserves_marks = info->preserves_marks; info->next->preserves_marks = info->preserves_marks;
optimize_info_done(info, NULL); optimize_info_done(info, NULL);
if (le_prev) { return replace_tail_inside(p, le_prev, orig);
*((Scheme_Object **)(((char *)le_prev) + prev_offset)) = p;
return orig;
} else
return p;
} }
lh = MALLOC_ONE_TAGGED(Scheme_Let_Header); lh = MALLOC_ONE_TAGGED(Scheme_Let_Header);
@ -1605,11 +1624,7 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data,
info->preserves_marks = sub_info->preserves_marks; info->preserves_marks = sub_info->preserves_marks;
optimize_info_done(sub_info, NULL); optimize_info_done(sub_info, NULL);
if (le_prev) { return replace_tail_inside(p, le_prev, orig);
*((Scheme_Object **)(((char *)le_prev) + prev_offset)) = p;
return orig;
} else
return p;
} }
int scheme_check_leaf_rator(Scheme_Object *le, int *_flags) int scheme_check_leaf_rator(Scheme_Object *le, int *_flags)
@ -1647,28 +1662,41 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a
{ {
int offset = 0, single_use = 0, psize = 0; int offset = 0, single_use = 0, psize = 0;
Scheme_Object *bad_app = NULL, *prev = NULL, *orig_le = le; Scheme_Object *bad_app = NULL, *prev = NULL, *orig_le = le;
intptr_t prev_offset = 0; int nested = 0, nested_count = 0, outside_nested = 0, already_opt = optimized_rator, nonleaf;
int nested_count = 0, outside_nested = 0, already_opt = optimized_rator, nonleaf;
if ((info->inline_fuel < 0) && info->has_nonleaf) if ((info->inline_fuel < 0) && info->has_nonleaf)
return NULL; return NULL;
/* Move inside `let' bindings, so we can convert ((let (....) proc) arg ...) /* Move inside `let' bindings, so we can convert ((let (....) proc) arg ...)
to (let (....) (proc arg ...)) */ to (let (....) (proc arg ...)) */
while (optimized_rator && SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_let_void_type)) { if (optimized_rator) {
while (1) {
if (SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_let_void_type)) {
Scheme_Let_Header *lh; Scheme_Let_Header *lh;
int i; int i;
lh = (Scheme_Let_Header *)le; lh = (Scheme_Let_Header *)le;
prev = le; prev = le;
prev_offset = (intptr_t)&(((Scheme_Let_Header *)0x0)->body);
le = lh->body; le = lh->body;
for (i = 0; i < lh->num_clauses; i++) { for (i = 0; i < lh->num_clauses; i++) {
prev = le; prev = le;
prev_offset = (intptr_t)&(((Scheme_Compiled_Let_Value *)0x0)->body);
le = ((Scheme_Compiled_Let_Value *)le)->body; le = ((Scheme_Compiled_Let_Value *)le)->body;
} }
nested_count += lh->count; nested_count += lh->count;
if (lh->count)
nested = 1;
} else if (SAME_TYPE(SCHEME_TYPE(le), scheme_sequence_type)) {
Scheme_Sequence *seq = (Scheme_Sequence *)le;
if (seq->count) {
prev = le;
le = seq->array[seq->count-1];
if (seq->count > 1)
nested = 1;
} else
break;
} else
break;
}
} }
if (SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_unclosed_procedure_type)) { if (SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_unclosed_procedure_type)) {
@ -1795,10 +1823,9 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a
if ((sz >= 0) && (single_use || (sz <= threshold))) { if ((sz >= 0) && (single_use || (sz <= threshold))) {
Optimize_Info *sub_info; Optimize_Info *sub_info;
if (nested_count) { if (nested_count) {
/* Pessimistcally assume that we moved inside past an effect */
sub_info = optimize_info_add_frame(info, nested_count, nested_count, 0); sub_info = optimize_info_add_frame(info, nested_count, nested_count, 0);
sub_info->vclock++; /* We only go into `let` and `begin` only for an optimized rator, so
sub_info->kclock++; the virtual clock was already incremented as needed. */
/* We could propagate bound values in sub_info, but relevant inlining /* We could propagate bound values in sub_info, but relevant inlining
and propagatation has probably already happened when the rator was and propagatation has probably already happened when the rator was
optimized. */ optimized. */
@ -1822,7 +1849,7 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a
threshold, threshold,
scheme_optimize_context_to_string(info->context)); scheme_optimize_context_to_string(info->context));
le = apply_inlined(le, data, sub_info, argc, app, app2, app3, context, le = apply_inlined(le, data, sub_info, argc, app, app2, app3, context,
nested_count, orig_le, prev, prev_offset); nested_count, orig_le, prev);
if (nested_count) if (nested_count)
optimize_info_done(sub_info, NULL); optimize_info_done(sub_info, NULL);
return le; return le;
@ -2824,29 +2851,6 @@ static Scheme_Object *try_reduce_predicate(Scheme_Object *rator, Scheme_Object *
return make_discarding_app_sequence(arg_app, -1, (matches ? scheme_true : scheme_false), info, id_offset); return make_discarding_app_sequence(arg_app, -1, (matches ? scheme_true : scheme_false), info, id_offset);
} }
static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *inside, Scheme_Object *orig) {
if (inside) {
switch (SCHEME_TYPE(inside)) {
case scheme_sequence_type:
if (((Scheme_Sequence *)inside)->count)
((Scheme_Sequence *)inside)->array[((Scheme_Sequence *)inside)->count-1] = alt;
else
scheme_signal_error("internal error: strange inside replacement");
break;
case scheme_compiled_let_void_type:
((Scheme_Let_Header *)inside)->body = alt;
break;
case scheme_compiled_let_value_type:
((Scheme_Compiled_Let_Value *)inside)->body = alt;
break;
default:
scheme_signal_error("internal error: strange inside replacement");
}
return orig;
}
return alt;
}
static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *info, int context) static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *info, int context)
{ {
Scheme_App2_Rec *app; Scheme_App2_Rec *app;