fix mismatch between optimizer snd run-time on "constant" detection

Cross-module inlining that pulls a variable reference across a
module boundary imposes a more struct requirement that run-time
"constant" detection is consistent with the optimizer's view of
"constant" within a module. So, make sure they're the same.
This commit is contained in:
Matthew Flatt 2016-03-08 15:44:25 -07:00
parent 747185184b
commit 26d28a28fe
4 changed files with 68 additions and 13 deletions
pkgs/racket-test-core/tests/racket
racket/src/racket/src

View File

@ -3345,6 +3345,35 @@
(require (submod ".." a)) (require (submod ".." a))
(list b c (c))))) (list b c (c)))))
(test-comp `(module m racket/base
(module a racket/base
(provide b c)
(define c
(let ([x 0])
(lambda (y)
(begin0
x
(set! x y)))))
(define (b z)
(c z)))
(module d racket/base
(require (submod ".." a))
(list b c (b 1))))
`(module m racket/base
(module a racket/base
(provide b c)
(define c
(let ([x 0])
(lambda (y)
(begin0
x
(set! x y)))))
(define (b z)
(c z)))
(module d racket/base
(require (submod ".." a))
(list b c (c 1)))))
(module check-inline-request racket/base (module check-inline-request racket/base
(require racket/performance-hint) (require racket/performance-hint)
(provide loop) (provide loop)

View File

@ -2093,10 +2093,7 @@ define_execute_with_dynamic_state(Scheme_Object *vec, int delta, int defmacro,
if (SCHEME_TOPLEVEL_FLAGS(var) & SCHEME_TOPLEVEL_SEAL) { if (SCHEME_TOPLEVEL_FLAGS(var) & SCHEME_TOPLEVEL_SEAL) {
int flags = GLOB_IS_IMMUTATED; int flags = GLOB_IS_IMMUTATED;
if (SCHEME_PROCP(vals_expr) if (scheme_is_statically_proc(vals_expr, NULL, OMITTABLE_RESOLVED))
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_lambda_type)
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_case_lambda_sequence_type)
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_inline_variant_type))
flags |= GLOB_IS_CONSISTENT; flags |= GLOB_IS_CONSISTENT;
((Scheme_Bucket_With_Flags *)b)->flags |= flags; ((Scheme_Bucket_With_Flags *)b)->flags |= flags;
} }

View File

@ -5736,24 +5736,53 @@ int scheme_ir_propagate_ok(Scheme_Object *value, Optimize_Info *info)
return 0; return 0;
} }
int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info) int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info, int flags)
/* Does `value` definitely produce a procedure of a specific shape? */ /* Does `value` definitely produce a procedure of a specific shape?
This function can be used on resolved (and SFS) forms, too, and it
must be consistent with (i.e., as least as accepting as)
optimization-time decisions. The `flags` argument is for
scheme_omittable_expr(). */
{ {
while (1) { while (1) {
if (SCHEME_LAMBDAP(value)) { if (SCHEME_LAMBDAP(value)
|| SCHEME_PROCP(value)
|| SAME_TYPE(SCHEME_TYPE(value), scheme_lambda_type)
|| SAME_TYPE(SCHEME_TYPE(value), scheme_case_lambda_sequence_type)
|| SAME_TYPE(SCHEME_TYPE(value), scheme_inline_variant_type))
return 1; return 1;
} else if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_let_header_type)) { else if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_let_header_type)) {
/* Look for (let ([x <omittable>]) <proc>), which is generated for optional arguments. */ /* Look for (let ([x <omittable>]) <proc>), which is generated for optional arguments. */
Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)value; Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)value;
if (lh->num_clauses == 1) { if (lh->num_clauses == 1) {
Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body; Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
if (scheme_omittable_expr(lv->value, lv->count, 20, 0, info, NULL)) { if (scheme_omittable_expr(lv->value, lv->count, 20, flags, info, NULL)) {
value = lv->body; value = lv->body;
info = NULL;
} else } else
break; break;
} else } else
break; break;
} else if (SAME_TYPE(SCHEME_TYPE(value), scheme_let_one_type)) {
Scheme_Let_One *lo = (Scheme_Let_One *)value;
if (scheme_omittable_expr(lo->value, 1, 20, flags, info, NULL)) {
value = lo->body;
} else
break;
} else if (SAME_TYPE(SCHEME_TYPE(value), scheme_boxenv_type)) {
value = SCHEME_PTR2_VAL(value);
} else if (SAME_TYPE(SCHEME_TYPE(value), scheme_sequence_type)
/* Handle a sequence for resolved mode, because it might
be for safe-for-space clears around a procedure */
&& (flags & OMITTABLE_RESOLVED)) {
Scheme_Sequence *seq = (Scheme_Sequence *)value;
int i;
for (i = 0; i < seq->count-1; i++) {
if (!scheme_omittable_expr(seq->array[i], 1, 5, flags, info, NULL))
break;
}
if (i == seq->count-1) {
value = seq->array[i];
} else
break;
} else } else
break; break;
} }
@ -7709,7 +7738,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context)
if (n == 1) { if (n == 1) {
if (scheme_ir_propagate_ok(e, info)) if (scheme_ir_propagate_ok(e, info))
cnst = 1; cnst = 1;
else if (scheme_is_statically_proc(e, info)) { else if (scheme_is_statically_proc(e, info, 0)) {
cnst = 1; cnst = 1;
sproc = 1; sproc = 1;
} }
@ -7864,7 +7893,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context)
} }
if (!scheme_ir_propagate_ok(e, info) if (!scheme_ir_propagate_ok(e, info)
&& scheme_is_statically_proc(e, info)) { && scheme_is_statically_proc(e, info, 0)) {
/* If we previously installed a procedure for inlining, /* If we previously installed a procedure for inlining,
don't replace that with a worse approximation. */ don't replace that with a worse approximation. */
if (SCHEME_LAMBDAP(old_e)) if (SCHEME_LAMBDAP(old_e))

View File

@ -3267,7 +3267,7 @@ Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e,
int scheme_ir_duplicate_ok(Scheme_Object *o, int cross_mod); int scheme_ir_duplicate_ok(Scheme_Object *o, int cross_mod);
int scheme_ir_propagate_ok(Scheme_Object *o, Optimize_Info *info); int scheme_ir_propagate_ok(Scheme_Object *o, Optimize_Info *info);
int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info); int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info, int flags);
XFORM_NONGCING int scheme_predicate_to_local_type(Scheme_Object *pred); XFORM_NONGCING int scheme_predicate_to_local_type(Scheme_Object *pred);
Scheme_Object *scheme_make_noninline_proc(Scheme_Object *e); Scheme_Object *scheme_make_noninline_proc(Scheme_Object *e);
Scheme_Object *scheme_optimize_extract_tail_inside(Scheme_Object *t2); Scheme_Object *scheme_optimize_extract_tail_inside(Scheme_Object *t2);