diff --git a/pkgs/racket-pkgs/racket-test/tests/racket/optimize.rktl b/pkgs/racket-pkgs/racket-test/tests/racket/optimize.rktl index d9d9f70185..76e341e427 100644 --- a/pkgs/racket-pkgs/racket-test/tests/racket/optimize.rktl +++ b/pkgs/racket-pkgs/racket-test/tests/racket/optimize.rktl @@ -1009,6 +1009,7 @@ (let ([x (cons w z)]) (car x))) '(lambda (w z) w)) + (test-comp '(lambda (w z) (let ([x (cons w z)]) (cdr x))) @@ -1393,6 +1394,39 @@ (if r #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) '(if (let ([z (random)]) #t) 1 2)) @@ -3883,6 +3917,30 @@ (set! f f) (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) diff --git a/racket/src/racket/src/optimize.c b/racket/src/racket/src/optimize.c index 2e852a68f0..3b10dc7b94 100644 --- a/racket/src/racket/src/optimize.c +++ b/racket/src/racket/src/optimize.c @@ -1155,6 +1155,9 @@ static int single_valued_noncm_expression(Scheme_Object *expr, int fuel) && single_valued_noncm_expression(b->fbranch, fuel - 1)); } break; + case scheme_compiled_unclosed_procedure_type: + case scheme_case_lambda_sequence_type: + return 1; default: if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_) return 1; @@ -1286,6 +1289,11 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt return 1; } 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: if (SCHEME_TYPE(expr) > _scheme_compiled_values_types_) return 1; @@ -2531,12 +2539,12 @@ static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info return le; } - sub_context = 0; + sub_context = OPT_CONTEXT_SINGLED; if (i > 0) { int ty; ty = wants_local_type_arguments(app->args[0], i - 1); if (ty) - sub_context = (ty << OPT_CONTEXT_TYPE_SHIFT); + sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT); } 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_Object *le; - int rator_flags = 0, sub_context = 0, ty; + int rator_flags = 0, sub_context, ty; Optimize_Info_Sequence info_seq; 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); - 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; { @@ -2829,7 +2839,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf } if (SAME_PTR(scheme_not_prim, app->rator)){ - sub_context = OPT_CONTEXT_BOOLEAN; + sub_context |= OPT_CONTEXT_BOOLEAN; } else { ty = wants_local_type_arguments(app->rator, 0); if (ty) @@ -3064,7 +3074,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf { Scheme_App3_Rec *app; 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; 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); + sub_context = OPT_CONTEXT_SINGLED; + le = scheme_optimize_expr(app->rator, info, sub_context); 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); - 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) */ 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); - 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); - 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, to increment vclock to prevent expressions incorrectly @@ -3905,7 +3917,7 @@ set_optimize(Scheme_Object *data, Optimize_Info *info, int context) var = sb->var; val = sb->val; - val = scheme_optimize_expr(val, info, 0); + val = scheme_optimize_expr(val, info, OPT_CONTEXT_SINGLED); info->preserves_marks = 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); - f = scheme_optimize_expr(f, info, 0); + f = scheme_optimize_expr(f, info, OPT_CONTEXT_SINGLED); 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) { 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; } else { 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; 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) --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)) { Scheme_Once_Used *o = (Scheme_Once_Used *)val; if (((o->vclock == info->vclock) - && ((context & OPT_CONTEXT_BOOLEAN) + && ((context & OPT_CONTEXT_SINGLED) || single_valued_noncm_expression(o->expr, 5))) || movable_expression(o->expr, info, o->delta, o->cross_lambda, o->kclock != info->kclock, @@ -6710,6 +6728,7 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in if (val) { info->size -= 1; o->used = 1; + info->inline_fuel = 0; /* no more inlining; o->expr was already optimized */ return scheme_optimize_expr(val, info, context); } } diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index 4b8b980598..42770f4fca 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -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_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, int context); +/* Context uses result as a boolean: */ #define OPT_CONTEXT_BOOLEAN 0x1 +/* Context might duplicate the expression: */ #define OPT_CONTEXT_NO_SINGLE 0x2 -#define OPT_CONTEXT_TYPE_SHIFT 3 -#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) +/* Context checks that result is a single value: */ +#define OPT_CONTEXT_SINGLED 0x4 +#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_tail_context(c) scheme_optimize_result_context(c)