1 /* This file implements bytecode optimization.
2
3 See "eval.c" for an overview of compilation passes. */
4
5 #include "schpriv.h"
6 #include "schrunst.h"
7 #include "schmach.h"
8
9 /* Controls for inlining algorithm: */
10 #define OPT_ESTIMATE_FUTURE_SIZES 1
11 #define OPT_DISCOURAGE_EARLY_INLINE 1
12 #define OPT_LIMIT_FUNCTION_RESIZE 0
13 #define OPT_BRANCH_ADDS_NO_SIZE 1
14 #define OPT_DELAY_GROUP_PROPAGATE 0
15 #define OPT_PRE_OPTIMIZE_FOR_CROSS_LINKLET(size_override) (size_override)
16
17 #define MAX_PROC_INLINE_SIZE 256
18 #define CROSS_LINKLET_INLINE_SIZE 8
19
20 /* Various kinds of fuel ensure that
21 the compiler doesn't go into a loop
22 or take non-linear time */
23 #define INITIAL_INLINING_FUEL 32
24 #define INITIAL_FLATTENING_FUEL 16
25
26
27 #define SCHEME_LAMBDA_FRAME 1
28
29 typedef struct Cross_Linklet_Info
30 {
31 /* Must be all pointers; allocated with scheme_malloc() */
32 Scheme_Object *get_import; /* NULL or (key -> linklet (vector key ...)) */
33 Scheme_Hash_Tree *import_keys; /* import-position -> key */
34 Scheme_Hash_Tree *rev_import_keys; /* key -> import-position */
35 Scheme_Hash_Tree *linklets; /* key -> linklet-or-instance */
36 Scheme_Hash_Tree *import_next_keys; /* key -> (vector key ...) */
37 Scheme_Hash_Tree *inline_variants; /* key -> symbol -> value */
38 Scheme_Hash_Tree *import_syms; /* import-position -> ((symbol -> variable-position)
39 . + (variable-position -> symbol)) */
40 int used_import_shape;
41 } Cross_Linklet_Info;
42
43 /* Clasification for predicates.
44 Each one implies the smaller. */
45 #define RLV_IS_RELEVANT 1 /* The predicate is remembered by the optimizer */
46 #define RLV_EQV_TESTEABLE 2 /* (equal? x <pred>) can be replaced by (eqv? x <pred>) */
47 #define RLV_EQ_TESTEABLE 3 /* (equal? x <pred>) can be replaced by (eq? x <pred>) */
48 #define RLV_SINGLETON 4 /* Recognizes a single value */
49
50 struct Optimize_Info
51 {
52 MZTAG_IF_REQUIRED
53 short flags;
54 struct Optimize_Info *next;
55 struct Scheme_Linklet *linklet;
56 int init_kclock;
57
58 /* For cross-linklet inlining: */
59 Cross_Linklet_Info *cross;
60
61 /* Track which imports are still used after optimization */
62 Scheme_Hash_Tree **imports_used; /* import position -> variable position -> true */
63
64 /* Propagated up and down the chain: */
65 int size;
66 int vclock; /* virtual clock that ticks for a side effect, a branch,
67 observation of a side effect (such as an unbox),
68 or a dependency on an earlier side effect (such as a
69 previous guard on an unsafe operation's argument);
70 the clock is only compared between binding sites and
71 uses, so we can rewind the clock at a join after an
72 increment that models a branch (if the branch is not
73 taken or doesn't increment the clock) */
74 int aclock; /* virtual clock that ticks for allocation without side effects,
75 for constraining the reordering of operations that might
76 capture a continuation */
77 int kclock; /* virtual clock that ticks for a potential continuation capture,
78 for constraining the movement of allocation operations */
79 int sclock; /* virtual clock that ticks when space consumption is potentially observed */
80 int psize;
81 short inline_fuel, flatten_fuel;
82 char letrec_not_twice, enforce_const, unsafe_mode, use_psize, has_nonleaf;
83 Scheme_Hash_Table *top_level_consts;
84
85 int maybe_values_argument; /* triggers an approximation for clock increments */
86
87 /* Set by expression optimization: */
88 int single_result, preserves_marks; /* negative means "tentative", due to fixpoint in progress */
89 int escapes; /* flag to signal that the expression always escapes. When escapes is 1, it's assumed
90 that single_result and preserves_marks are also 1, and that it's not necessary to
91 use optimize_ignored before including the expression. */
92
93 int lambda_depth; /* counts nesting depth under `lambda`s */
94 int used_toplevel; /* tracks whether any non-local variables or syntax-object literals are used */
95
96 Scheme_Hash_Table *uses; /* used variables, accumulated for closures */
97
98 Scheme_IR_Local *transitive_use_var; /* set when optimizing a letrec-bound procedure
99 to record variables that were added to `uses` */
100
101 Scheme_Object *context; /* for logging */
102 Scheme_Logger *logger;
103 Scheme_Hash_Tree *types; /* maps position (from this frame) to predicate */
104 int no_types; /* disables use of type info */
105 };
106
107 typedef struct Optimize_Info_Sequence {
108 int init_flatten_fuel, min_flatten_fuel;
109 } Optimize_Info_Sequence;
110
111 static Scheme_Object *optimize_expr(Scheme_Object *expr, Optimize_Info *info, int context);
112
113 static int get_rator_flags(Scheme_Object *rator, int num_args, Optimize_Info *info);
114 Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *le, int argc);
115 static void merge_lambda_arg_types(Scheme_Lambda *lam1, Scheme_Lambda *lam2);
116 static void check_lambda_arg_types_registered(Scheme_Lambda *lam, int app_count);
117 static int lambda_body_size_plus_info(Scheme_Lambda *lam, int check_assign,
118 Optimize_Info *info, int *is_leaf);
119 static int lambda_has_top_level(Scheme_Lambda *lam);
120
121 static Scheme_Object *make_sequence_2(Scheme_Object *a, Scheme_Object *b);
122
123 XFORM_NONGCING static int wants_local_type_arguments(Scheme_Object *rator, int argpos);
124
125 static void add_types_for_f_branch(Scheme_Object *t, Optimize_Info *info, int fuel);
126
127 static void register_use(Scheme_IR_Local *var, Optimize_Info *info);
128 static Scheme_Object *optimize_info_lookup(Scheme_Object *var);
129 static Scheme_Object *optimize_info_propagate_local(Scheme_Object *var);
130 static void optimize_info_used_top(Optimize_Info *info);
131 static Scheme_Object *optimize_get_predicate(Optimize_Info *info, Scheme_Object *var, int ignore_no_types);
132 static void add_type(Optimize_Info *info, Scheme_Object *var, Scheme_Object *pred);
133 static void merge_types(Optimize_Info *src_info, Optimize_Info *info, Scheme_Hash_Tree *skip_vars);
134
135 static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info);
136 static Scheme_Object *do_expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info,
137 int *_involves_k_cross, int fuel,
138 Scheme_Hash_Tree *ignore_vars);
139 static int produces_local_type(Scheme_Object *rator, int argc);
140 static int optimize_any_uses(Optimize_Info *info, Scheme_IR_Let_Value *at_irlv, int n);
141 static void optimize_uses_of_mutable_imply_early_alloc(Scheme_IR_Let_Value *at_irlv, int n);
142 static void propagate_used_variables(Optimize_Info *info);
143 static int env_uses_toplevel(Optimize_Info *frame);
144 static Scheme_IR_Local *clone_variable(Scheme_IR_Local *var);
145 static void increment_use_count(Scheme_IR_Local *var, int as_rator);
146
147 static Optimize_Info *optimize_info_create(Scheme_Linklet *linklet,
148 int enforce_const, int can_inline, int unsafe_mode);
149 static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int flags);
150 static void optimize_info_done(Optimize_Info *info, Optimize_Info *parent);
151
152 static void register_transitive_uses(Scheme_IR_Local *var, Optimize_Info *info);
153
154 static void optimize_info_seq_init(Optimize_Info *info, Optimize_Info_Sequence *info_seq);
155 static void optimize_info_seq_step(Optimize_Info *info, Optimize_Info_Sequence *info_seq);
156 static void optimize_info_seq_done(Optimize_Info *info, Optimize_Info_Sequence *info_seq);
157
158 static int ir_propagate_ok(Scheme_Object *o, Optimize_Info *info, int used_once, Scheme_IR_Local *once_var);
159
160 static Scheme_Object *estimate_closure_size(Scheme_Object *e);
161 static Scheme_Object *no_potential_size(Scheme_Object *value);
162
163 static Scheme_Object *optimize_lets(Scheme_Object *form, Optimize_Info *info, int context);
164
165 static Scheme_Object *optimize_clone(int single_use, Scheme_Object *obj, Optimize_Info *info, Scheme_Hash_Tree *var_map, int as_rator);
166
167 static Scheme_Object *get_import_shape(Optimize_Info *info, Scheme_IR_Toplevel *var);
168 static Scheme_Object *get_import_inline(Optimize_Info *info, Scheme_IR_Toplevel *var, int argc, int case_ok);
169 static void register_import_used(Optimize_Info *info, Scheme_IR_Toplevel *expr);
170 static void record_optimize_shapes(Optimize_Info *info, Scheme_Linklet *linklet, Scheme_Object **_import_keys);
171 static Scheme_Object *get_value_shape(Scheme_Object *v, int imprecise);
172
173 XFORM_NONGCING static int relevant_predicate(Scheme_Object *pred);
174 XFORM_NONGCING static int predicate_implies(Scheme_Object *pred1, Scheme_Object *pred2);
175 XFORM_NONGCING static int predicate_implies_not(Scheme_Object *pred1, Scheme_Object *pred2);
176 static int single_valued_expression(Scheme_Object *expr, Optimize_Info *info, int fuel);
177 static int single_valued_noncm_expression(Scheme_Object *expr, Optimize_Info *info, int fuel);
178 static int noncm_expression(Scheme_Object *expr, Optimize_Info *info, int fuel);
179 static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info,
180 int expected_vals, int maybe_omittable,
181 int fuel);
182 static Scheme_Object *equivalent_exprs(Scheme_Object *a, Scheme_Object *b,
183 Optimize_Info *a_info, Optimize_Info *b_info, int context);
184 static int movable_expression(Scheme_Object *expr, Optimize_Info *info,
185 int cross_lambda, int cross_k, int cross_s,
186 int check_space, int fuel);
187 Scheme_Object *optimize_apply_values(Scheme_Object *f, Scheme_Object *e,
188 Optimize_Info *info,
189 int e_single_result,
190 int context);
191
192 #define SCHEME_LAMBDAP(vals_expr) (SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_ir_lambda_type) \
193 || SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_case_lambda_sequence_type))
194
195 #define SCHEME_WILL_BE_LAMBDAP(v) SAME_TYPE(SCHEME_TYPE(v), scheme_will_be_lambda_type)
196 #define SCHEME_WILL_BE_LAMBDA_SIZE(v) SCHEME_PINT_VAL(v)
197 #define SCHEME_WILL_BE_LAMBDA(v) SCHEME_IPTR_VAL(v)
198
199 static int lambda_body_size(Scheme_Object *o, int less_args);
200
201 typedef struct Scheme_Once_Used {
202 Scheme_Object so;
203 Scheme_Object *expr;
204 Scheme_IR_Local *var;
205 int vclock; /* record clocks at binding site */
206 int aclock;
207 int kclock;
208 int sclock;
209 int spans_k; /* potentially captures a continuation */
210 int moved;
211 } Scheme_Once_Used;
212
213 static Scheme_Once_Used *make_once_used(Scheme_Object *val, Scheme_IR_Local *var,
214 int vclock, int aclock, int kclock, int sclock, int spans_k);
215
216 static ROSYM Scheme_Hash_Tree *empty_eq_hash_tree;
217
218 #ifdef MZ_PRECISE_GC
219 static void register_traversers(void);
220 #endif
221
scheme_init_optimize()222 void scheme_init_optimize()
223 {
224 REGISTER_SO(empty_eq_hash_tree);
225 empty_eq_hash_tree = scheme_make_hash_tree(SCHEME_hashtr_eq);
226
227 #ifdef MZ_PRECISE_GC
228 register_traversers();
229 #endif
230 }
231
232 /*========================================================================*/
233 /* logging */
234 /*========================================================================*/
235
note_match(int actual,int expected,Optimize_Info * warn_info)236 static void note_match(int actual, int expected, Optimize_Info *warn_info)
237 {
238 if (!warn_info || (expected == -1))
239 return;
240
241 if (actual != expected) {
242 scheme_log(warn_info->logger,
243 SCHEME_LOG_WARNING,
244 0,
245 "warning%s: %d values produced when %d expected",
246 scheme_optimize_context_to_string(warn_info->context),
247 actual, expected);
248 }
249 }
250
scheme_optimize_context_to_string(Scheme_Object * context)251 char *scheme_optimize_context_to_string(Scheme_Object *context)
252 /* Convert a context to a string that is suitable for use in logging */
253 {
254 if (context) {
255 Scheme_Object *linklet, *func;
256 const char *ctx, *prefix, *mctx, *mprefix;
257 char *all;
258 int clen, plen, mclen, mplen, len;
259
260 if (SCHEME_PAIRP(context)) {
261 func = SCHEME_CAR(context);
262 linklet = SCHEME_CDR(context);
263 } else if (SAME_TYPE(SCHEME_TYPE(context), scheme_linklet_type)) {
264 func = scheme_false;
265 linklet = context;
266 } else {
267 func = context;
268 linklet = scheme_false;
269 }
270
271 if (SAME_TYPE(SCHEME_TYPE(func), scheme_ir_lambda_type)) {
272 Scheme_Object *name;
273
274 name = ((Scheme_Lambda *)func)->name;
275 if (name) {
276 if (SCHEME_VECTORP(name)) {
277 Scheme_Object *port;
278 int print_width = 1024;
279 intptr_t plen;
280
281 port = scheme_make_byte_string_output_port();
282
283 scheme_write_proc_context(port, print_width,
284 SCHEME_VEC_ELS(name)[0],
285 SCHEME_VEC_ELS(name)[1], SCHEME_VEC_ELS(name)[2],
286 SCHEME_VEC_ELS(name)[3], SCHEME_VEC_ELS(name)[4],
287 SCHEME_TRUEP(SCHEME_VEC_ELS(name)[6]));
288
289 ctx = scheme_get_sized_byte_string_output(port, &plen);
290 prefix = " in: ";
291 } else {
292 ctx = scheme_get_proc_name(func, &len, 0);
293 prefix = " in: ";
294 }
295 } else {
296 ctx = "";
297 prefix = "";
298 }
299 } else {
300 ctx = "";
301 prefix = "";
302 }
303
304 if (SAME_TYPE(SCHEME_TYPE(linklet), scheme_linklet_type)) {
305 mctx = scheme_display_to_string(((Scheme_Linklet *)linklet)->name, NULL);
306 mprefix = " in module: ";
307 } else {
308 mctx = "";
309 mprefix = "";
310 }
311
312 clen = strlen(ctx);
313 plen = strlen(prefix);
314 mclen = strlen(mctx);
315 mplen = strlen(mprefix);
316
317 if (!clen && !mclen)
318 return "";
319
320 all = scheme_malloc_atomic(clen + plen + mclen + mplen + 1);
321 memcpy(all, prefix, plen);
322 memcpy(all + plen, ctx, clen);
323 memcpy(all + plen + clen, mprefix, mplen);
324 memcpy(all + plen + clen + mplen, mctx, mclen);
325 all[clen + plen + mclen + mplen] = 0;
326 return all;
327 } else
328 return "";
329 }
330
scheme_optimize_info_context(Optimize_Info * info)331 char *scheme_optimize_info_context(Optimize_Info *info)
332 {
333 return scheme_optimize_context_to_string(info->context);
334 }
335
scheme_optimize_info_logger(Optimize_Info * info)336 Scheme_Logger *scheme_optimize_info_logger(Optimize_Info *info)
337 {
338 return info->logger;
339 }
340
341 /*========================================================================*/
342 /* utils */
343 /*========================================================================*/
344
set_optimize_mode(Scheme_IR_Local * var)345 static void set_optimize_mode(Scheme_IR_Local *var)
346 {
347 MZ_ASSERT(SAME_TYPE(var->so.type, scheme_ir_local_type));
348 memset(&var->optimize, 0, sizeof(var->optimize));
349 var->mode = SCHEME_VAR_MODE_OPTIMIZE;
350 }
351
352 #define SCHEME_PRIM_IS_UNSAFE_NONMUTATING (SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL | SCHEME_PRIM_IS_UNSAFE_OMITABLE)
353
scheme_is_functional_nonfailing_primitive(Scheme_Object * rator,int num_args,int expected_vals)354 int scheme_is_functional_nonfailing_primitive(Scheme_Object *rator, int num_args, int expected_vals)
355 /* A call to a functional, non-failing primitive (i.e., it accepts any argument)
356 can be discarded if its results are ignored.
357 Return 2 => true, and results are a constant when arguments are constants. */
358 {
359 if (SCHEME_PRIMP(rator)
360 && ((SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING)
361 || scheme_is_omitable_primitive(rator, num_args))
362 && (num_args >= ((Scheme_Primitive_Proc *)rator)->mina)
363 && (num_args <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)
364 && ((expected_vals < 0)
365 || ((expected_vals == 1) && !(SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_MULTI_RESULT))
366 || (SAME_OBJ(scheme_values_proc, rator)
367 && (expected_vals == num_args)))) {
368 if (SAME_OBJ(scheme_values_proc, rator))
369 return 2;
370 return 1;
371 } else
372 return 0;
373 }
374
scheme_is_omitable_primitive(Scheme_Object * rator,int num_args)375 int scheme_is_omitable_primitive(Scheme_Object *rator, int num_args)
376 {
377 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_OMITABLE
378 | SCHEME_PRIM_IS_OMITABLE_ALLOCATION
379 | SCHEME_PRIM_IS_UNSAFE_OMITABLE))
380 return 1;
381
382 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_ARITY_0_OMITABLE_ALLOCATION)
383 return (num_args == 0);
384
385 if ((SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_EVEN_ARITY_OMITABLE_ALLOCATION))
386 return !(num_args & 0x1);
387
388 return 0;
389 }
390
391 int scheme_is_functional_nonfailing_primitive(Scheme_Object *rator, int num_args, int expected_vals);
392
get_defn_shape(Optimize_Info * info,Scheme_IR_Toplevel * var)393 static Scheme_Object *get_defn_shape(Optimize_Info *info, Scheme_IR_Toplevel *var)
394 {
395 Scheme_Object *v;
396
397 if (info->top_level_consts && (var->instance_pos == -1)) {
398 v = scheme_hash_get(info->top_level_consts, scheme_make_integer(var->variable_pos));
399 if (v) return v;
400
401 v = scheme_hash_get(info->top_level_consts, scheme_false);
402 if (v && scheme_hash_get((Scheme_Hash_Table *)v, scheme_make_integer(var->variable_pos)))
403 return scheme_fixed_key;
404 }
405
406 return NULL;
407 }
408
get_struct_proc_shape(Scheme_Object * rator,Optimize_Info * info,int prop_ok)409 static Scheme_Object *get_struct_proc_shape(Scheme_Object *rator, Optimize_Info *info, int prop_ok)
410 /* Determines whether `rator` is known to be a struct accessor, etc. */
411 {
412 Scheme_Object *c;
413
414 if (info && SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_toplevel_type)) {
415 c = get_defn_shape(info, (Scheme_IR_Toplevel *)rator);
416 if (!c)
417 c = get_import_shape(info, (Scheme_IR_Toplevel *)rator);
418
419 if (c && (SAME_TYPE(SCHEME_TYPE(c), scheme_struct_proc_shape_type)
420 || (prop_ok && SAME_TYPE(SCHEME_TYPE(c), scheme_struct_prop_proc_shape_type))))
421 return c;
422 }
423
424 return NULL;
425 }
426
scheme_is_struct_functional(Scheme_Object * rator,int num_args,Optimize_Info * info,int vals)427 int scheme_is_struct_functional(Scheme_Object *rator, int num_args, Optimize_Info *info, int vals)
428 /* Determines whether `rator` is a functional, non-failing struct operation */
429 {
430 Scheme_Object *c;
431
432 if ((vals == 1) || (vals == -1)) {
433 c = get_struct_proc_shape(rator, info, 1);
434 if (c) {
435 if (SAME_TYPE(SCHEME_TYPE(c), scheme_struct_proc_shape_type)) {
436 int mode = (SCHEME_PROC_SHAPE_MODE(c) & STRUCT_PROC_SHAPE_MASK);
437 int field_count = (SCHEME_PROC_SHAPE_MODE(c) >> STRUCT_PROC_SHAPE_SHIFT);
438 if (((num_args == 1) && (mode == STRUCT_PROC_SHAPE_PRED))
439 || ((num_args == field_count)
440 && (mode == STRUCT_PROC_SHAPE_CONSTR)
441 && (SCHEME_PROC_SHAPE_MODE(c) & STRUCT_PROC_SHAPE_NONFAIL_CONSTR))) {
442 return 1;
443 }
444 } else if (SAME_TYPE(SCHEME_TYPE(c), scheme_struct_prop_proc_shape_type)) {
445 int mode = (SCHEME_PROP_PROC_SHAPE_MODE(c) & STRUCT_PROC_SHAPE_MASK);
446 if ((mode == STRUCT_PROP_PROC_SHAPE_PRED)
447 && (num_args == 1))
448 return 1;
449 }
450 }
451 }
452
453 return 0;
454 }
455
extract_specialized_proc(Scheme_Object * le,Scheme_Object * default_val)456 static Scheme_Object *extract_specialized_proc(Scheme_Object *le, Scheme_Object *default_val)
457 /* Look through `(procedure-specialize <e>)` to get `<e>` */
458 {
459 if (SAME_TYPE(SCHEME_TYPE(le), scheme_application2_type)) {
460 Scheme_App2_Rec *app = (Scheme_App2_Rec *)le;
461 if (SAME_OBJ(app->rator, scheme_procedure_specialize_proc)) {
462 if (SCHEME_PROCP(app->rand) || SCHEME_LAMBDAP(app->rand))
463 return app->rand;
464 }
465 }
466
467 return default_val;
468 }
469
scheme_omittable_expr(Scheme_Object * o,int vals,int fuel,int flags,Optimize_Info * opt_info,Optimize_Info * warn_info)470 int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int flags,
471 Optimize_Info *opt_info, Optimize_Info *warn_info)
472 /* Checks whether the bytecode `o` returns `vals` values with no
473 side-effects and without pushing and using continuation marks.
474 A -1 for `vals` means that any return count is ok.
475 Also used with fully resolved expression by `linklet` to check
476 for "functional" bodies, in which case `flags` includes
477 `OMITTABLE_RESOLVED`.
478 The `opt_info` argument is used only to access linklet-level
479 information, not local bindings.
480 If `warn_info` is supplied, complain when a mismatch is detected.
481 We rely on the letrec-check pass to avoid omitting early references
482 to letrec-bound variables, but `flags` can include `OMITTABLE_KEEP_VARS`
483 to keep all variable references.
484 If flags includes `OMITTABLE_KEEP_MUTABLE_VARS`, then references
485 to mutable variables are kept, which allows this function to be
486 a conservative approximation for "reorderable". */
487 {
488 Scheme_Type vtype;
489
490 /* FIXME: can overflow the stack */
491
492 try_again:
493
494 vtype = SCHEME_TYPE(o);
495
496 if ((vtype > _scheme_ir_values_types_)
497 || ((vtype == scheme_ir_local_type)
498 && !(flags & OMITTABLE_KEEP_VARS)
499 && (!(flags & OMITTABLE_KEEP_MUTABLE_VARS)
500 || !SCHEME_VAR(o)->mutated))
501 || ((vtype == scheme_local_type)
502 && !(flags & OMITTABLE_KEEP_VARS)
503 && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ))
504 || ((vtype == scheme_local_unbox_type)
505 && !(flags & (OMITTABLE_KEEP_VARS | OMITTABLE_KEEP_MUTABLE_VARS))
506 && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ))
507 || (vtype == scheme_lambda_type)
508 || (vtype == scheme_ir_lambda_type)
509 || (vtype == scheme_inline_variant_type)
510 || (vtype == scheme_case_lambda_sequence_type)
511 || (vtype == scheme_varref_form_type)) {
512 note_match(1, vals, warn_info);
513 return ((vals == 1) || (vals < 0));
514 }
515
516 if ((vtype == scheme_toplevel_type) || (vtype == scheme_static_toplevel_type)) {
517 note_match(1, vals, warn_info);
518 if (!(flags & OMITTABLE_KEEP_VARS) && (flags & OMITTABLE_RESOLVED) && ((vals == 1) || (vals < 0))) {
519 int tl_flags = SCHEME_TOPLEVEL_FLAGS(o);
520 if (tl_flags & SCHEME_TOPLEVEL_FLAGS_MASK)
521 return 1;
522 else
523 return 0;
524 }
525 }
526
527 if (vtype == scheme_ir_toplevel_type) {
528 note_match(1, vals, warn_info);
529 if ((vals == 1) || (vals < 0)) {
530 if (!(flags & OMITTABLE_KEEP_VARS)
531 && ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_READY))
532 return 1;
533 else if ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_CONST)
534 return 1;
535 else
536 return 0;
537 }
538 }
539
540 /* check for struct-type declaration: */
541 if (!(flags & OMITTABLE_IGNORE_MAKE_STRUCT_TYPE)) {
542 Scheme_Object *auto_e;
543 int auto_e_depth;
544 auto_e = scheme_is_simple_make_struct_type(o, vals,
545 (((flags & OMITTABLE_RESOLVED) ? CHECK_STRUCT_TYPE_RESOLVED : 0)
546 | CHECK_STRUCT_TYPE_ALWAYS_SUCCEED
547 | CHECK_STRUCT_TYPE_DELAY_AUTO_CHECK),
548 &auto_e_depth,
549 NULL, NULL,
550 opt_info,
551 NULL, NULL, 0, NULL, NULL,
552 5);
553 if (auto_e) {
554 if (scheme_omittable_expr(auto_e, 1, fuel - 1, flags, opt_info, warn_info))
555 return 1;
556 }
557 }
558
559 if (vtype == scheme_branch_type) {
560 Scheme_Branch_Rec *b;
561 b = (Scheme_Branch_Rec *)o;
562 return (scheme_omittable_expr(b->test, 1, fuel - 1, flags, opt_info, warn_info)
563 && scheme_omittable_expr(b->tbranch, vals, fuel - 1, flags, opt_info, warn_info)
564 && scheme_omittable_expr(b->fbranch, vals, fuel - 1, flags, opt_info, warn_info));
565 }
566
567 if (vtype == scheme_let_one_type) {
568 Scheme_Let_One *lo = (Scheme_Let_One *)o;
569 return (scheme_omittable_expr(lo->value, 1, fuel - 1, flags, opt_info, warn_info)
570 && scheme_omittable_expr(lo->body, vals, fuel - 1, flags, opt_info, warn_info));
571 }
572
573 if (vtype == scheme_let_void_type) {
574 Scheme_Let_Void *lv = (Scheme_Let_Void *)o;
575 /* recognize (letrec ([x <omittable>]) ...): */
576 MZ_ASSERT(flags & OMITTABLE_RESOLVED);
577 if (SAME_TYPE(SCHEME_TYPE(lv->body), scheme_let_value_type)) {
578 Scheme_Let_Value *lv2 = (Scheme_Let_Value *)lv->body;
579 if ((lv2->count == 1)
580 && (lv2->position == 0)
581 && scheme_omittable_expr(lv2->value, 1, fuel - 1, flags, opt_info, warn_info)) {
582 o = lv2->body;
583 } else
584 o = lv->body;
585 } else
586 o = lv->body;
587 goto try_again;
588 }
589
590 if (vtype == scheme_ir_let_header_type) {
591 /* recognize another (let ([x <omittable>]) ...) pattern: */
592 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)o;
593 int i;
594 MZ_ASSERT(!(flags & OMITTABLE_RESOLVED));
595 o = lh->body;
596 for (i = 0; i < lh->num_clauses; i++) {
597 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)o;
598 if (!scheme_omittable_expr(lv->value, lv->count, fuel - 1, flags, opt_info, warn_info))
599 return 0;
600 o = lv->body;
601 }
602 goto try_again;
603 }
604
605 if (vtype == scheme_letrec_type) {
606 MZ_ASSERT(flags & OMITTABLE_RESOLVED);
607 o = ((Scheme_Letrec *)o)->body;
608 goto try_again;
609 }
610
611 if (vtype == scheme_application_type) {
612 Scheme_App_Rec *app = (Scheme_App_Rec *)o;
613
614 if ((app->num_args >= 4) && (app->num_args <= 11)
615 && SAME_OBJ(scheme_make_struct_type_proc, app->args[0])) {
616 note_match(5, vals, warn_info);
617 }
618
619 if (scheme_is_functional_nonfailing_primitive(app->args[0], app->num_args, vals)
620 || scheme_is_struct_functional(app->args[0], app->num_args, opt_info, vals)
621 || ((SCHEME_APPN_FLAGS(app) & APPN_FLAG_OMITTABLE) && !(flags & OMITTABLE_IGNORE_APPN_OMIT))) {
622 int i;
623 for (i = app->num_args; i--; ) {
624 if (!scheme_omittable_expr(app->args[i + 1], 1, fuel - 1, flags, opt_info, warn_info))
625 return 0;
626 }
627 return 1;
628 } else if (SCHEME_PRIMP(app->args[0])) {
629 if (!(SCHEME_PRIM_PROC_FLAGS(app->args[0]) & SCHEME_PRIM_IS_MULTI_RESULT)) {
630 note_match(1, vals, warn_info);
631 } else if (SAME_OBJ(scheme_values_proc, app->args[0])) {
632 note_match(app->num_args, vals, warn_info);
633 }
634 }
635
636 if (!SAME_OBJ(scheme_make_struct_type_proc, app->args[0]))
637 return 0;
638 }
639
640 if (vtype == scheme_application2_type) {
641 Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
642 if (scheme_is_functional_nonfailing_primitive(app->rator, 1, vals)
643 || scheme_is_struct_functional(app->rator, 1, opt_info, vals)
644 || ((SCHEME_APPN_FLAGS(app) & APPN_FLAG_OMITTABLE) && !(flags & OMITTABLE_IGNORE_APPN_OMIT))) {
645 if (scheme_omittable_expr(app->rand, 1, fuel - 1, flags, opt_info, warn_info))
646 return 1;
647 } else if (SAME_OBJ(app->rator, scheme_make_vector_proc)
648 && (vals == 1 || vals == -1)
649 && (SCHEME_INTP(app->rand)
650 && (SCHEME_INT_VAL(app->rand) >= 0))
651 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand))) {
652 return 1;
653 } else if (SAME_OBJ(app->rator, scheme_procedure_specialize_proc)) {
654 if ((vals == 1 || vals == -1) && extract_specialized_proc(o, NULL))
655 return 1;
656 } else if (SCHEME_PRIMP(app->rator)) {
657 if (!(SCHEME_PRIM_PROC_FLAGS(app->rator) & SCHEME_PRIM_IS_MULTI_RESULT)
658 || SAME_OBJ(scheme_values_proc, app->rator)) {
659 note_match(1, vals, warn_info);
660 }
661 }
662
663 if (!SAME_OBJ(scheme_make_struct_type_property_proc, app->rator))
664 return 0;
665 }
666
667 if (vtype == scheme_application3_type) {
668 Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
669 if (scheme_is_functional_nonfailing_primitive(app->rator, 2, vals)
670 || scheme_is_struct_functional(app->rator, 2, opt_info, vals)
671 || ((SCHEME_APPN_FLAGS(app) & APPN_FLAG_OMITTABLE) && !(flags & OMITTABLE_IGNORE_APPN_OMIT))) {
672 if (scheme_omittable_expr(app->rand1, 1, fuel - 1, flags, opt_info, warn_info)
673 && scheme_omittable_expr(app->rand2, 1, fuel - 1, flags, opt_info, warn_info))
674 return 1;
675 } else if (SAME_OBJ(app->rator, scheme_make_vector_proc)
676 && (vals == 1 || vals == -1)
677 && (SCHEME_INTP(app->rand1)
678 && (SCHEME_INT_VAL(app->rand1) >= 0)
679 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand1)))
680 && scheme_omittable_expr(app->rand2, 1, fuel - 1, flags, opt_info, warn_info)) {
681 return 1;
682 } else if (SCHEME_PRIMP(app->rator)) {
683 if (!(SCHEME_PRIM_PROC_FLAGS(app->rator) & SCHEME_PRIM_IS_MULTI_RESULT)) {
684 note_match(1, vals, warn_info);
685 } else if (SAME_OBJ(scheme_values_proc, app->rator)) {
686 note_match(2, vals, warn_info);
687 }
688 }
689
690 if (!SAME_OBJ(scheme_make_struct_type_property_proc, app->rator))
691 return 0;
692 }
693
694 /* check for (set! x x) */
695 if (vtype == scheme_set_bang_type) {
696 Scheme_Set_Bang *sb = (Scheme_Set_Bang *)o;
697 if (SAME_TYPE(scheme_local_type, SCHEME_TYPE(sb->var))
698 && SAME_TYPE(scheme_local_type, SCHEME_TYPE(sb->val))
699 && (SCHEME_LOCAL_POS(sb->var) == SCHEME_LOCAL_POS(sb->val)))
700 return 1;
701 else if (SAME_TYPE(scheme_ir_local_type, SCHEME_TYPE(sb->var))
702 && SAME_OBJ(sb->var, sb->val)
703 && ((((Scheme_IR_Local *)sb->var)->mode != SCHEME_VAR_MODE_COMPILE)
704 || !((Scheme_IR_Local *)sb->var)->compile.keep_assignment))
705 return 1;
706 }
707
708 /* check for struct-type property declaration: */
709 if (!(flags & OMITTABLE_IGNORE_MAKE_STRUCT_TYPE)) {
710 if (scheme_is_simple_make_struct_type_property(o, vals,
711 (((flags & OMITTABLE_RESOLVED) ? CHECK_STRUCT_TYPE_RESOLVED : 0)
712 | CHECK_STRUCT_TYPE_ALWAYS_SUCCEED),
713 NULL,
714 opt_info,
715 NULL, NULL, 0, NULL,
716 5))
717 return 1;
718 }
719
720 return 0;
721 }
722
ensure_single_value(Scheme_Object * e,Optimize_Info * info)723 static Scheme_Object *ensure_single_value(Scheme_Object *e, Optimize_Info *info)
724 /* Wrap `e` so that it either produces a single value or fails */
725 {
726 Scheme_App2_Rec *app2;
727 if (single_valued_expression(e, info, 5))
728 return e;
729
730 app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec);
731 app2->iso.so.type = scheme_application2_type;
732 app2->rator = scheme_values_proc;
733 app2->rand = e;
734 SCHEME_APPN_FLAGS(app2) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
735
736 return (Scheme_Object *)app2;
737 }
738
ensure_single_value_noncm(Scheme_Object * e,Optimize_Info * info)739 static Scheme_Object *ensure_single_value_noncm(Scheme_Object *e, Optimize_Info *info)
740 /* Wrap `e` so that it either produces a single value or fails.
741 Also, wrap `e` in case it may have a `with-continuation-mark`
742 in tail position. */
743 {
744 Scheme_App2_Rec *app2;
745 if (single_valued_noncm_expression(e, info, 5))
746 return e;
747
748 app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec);
749 app2->iso.so.type = scheme_application2_type;
750 app2->rator = scheme_values_proc;
751 app2->rand = e;
752 SCHEME_APPN_FLAGS(app2) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
753
754 return (Scheme_Object *)app2;
755 }
756
ensure_noncm(Scheme_Object * e,Optimize_Info * info)757 static Scheme_Object *ensure_noncm(Scheme_Object *e, Optimize_Info *info)
758 /* Wrap `e` in case it may have a `with-continuation-mark` form in tail
759 position. This is useful when `e` escapes, and it is lifted and the
760 surrounding is discarded, in which case the shift out of a nested
761 position is observable. */
762 {
763 Scheme_Sequence *seq;
764
765 if (noncm_expression(e, info, 5))
766 return e;
767
768 seq = scheme_malloc_sequence(1);
769 seq->so.type = scheme_begin0_sequence_type;
770 seq->count = 1;
771 seq->array[0] = e;
772
773 return (Scheme_Object *)seq;
774 }
775
do_make_discarding_sequence(Scheme_Object * e1,Scheme_Object * e2,Optimize_Info * info,int ignored,int rev)776 static Scheme_Object *do_make_discarding_sequence(Scheme_Object *e1, Scheme_Object *e2,
777 Optimize_Info *info,
778 int ignored, int rev)
779 /* Evaluate `e1` then `e2` (or opposite order if rev), and each must
780 produce a single value. The result of `e1` is ignored and the
781 result is `e2` --- except that `e2` is ignored, too, if
782 `ignored`. */
783 {
784 if (ignored)
785 e2 = optimize_ignored(e2, info, 1, 0, 5);
786
787 e2 = ensure_single_value_noncm(e2, info);
788
789 if (scheme_omittable_expr(e1, 1, 5, 0, info, NULL))
790 return e2;
791
792 e1 = ensure_single_value(optimize_ignored(e1, info, 1, 0, 5), info);
793
794 if (ignored && scheme_omittable_expr(e2, 1, 5, 0, info, NULL))
795 return ensure_single_value_noncm(e1, info);
796
797 /* use `begin` instead of `begin0` if we can swap the order: */
798 if (rev && movable_expression(e2, info, 0, 1, 1, 0, 50))
799 rev = 0;
800
801 if (!rev && SAME_TYPE(SCHEME_TYPE(e1), scheme_sequence_type)) {
802 Scheme_Sequence *seq = (Scheme_Sequence *)e1;
803
804 if (SCHEME_TYPE(seq->array[seq->count - 1]) > _scheme_ir_values_types_) {
805 seq->array[seq->count - 1] = e2;
806 return e1;
807 }
808 }
809
810 return scheme_make_sequence_compilation(scheme_make_pair((rev ? e2 : e1),
811 scheme_make_pair((rev ? e1 : e2), scheme_null)),
812 rev ? -1 : 1,
813 0);
814 }
815
make_discarding_sequence(Scheme_Object * e1,Scheme_Object * e2,Optimize_Info * info)816 static Scheme_Object *make_discarding_sequence(Scheme_Object *e1, Scheme_Object *e2,
817 Optimize_Info *info)
818 {
819 return do_make_discarding_sequence(e1, e2, info, 0, 0);
820 }
821
make_discarding_reverse_sequence(Scheme_Object * e1,Scheme_Object * e2,Optimize_Info * info)822 static Scheme_Object *make_discarding_reverse_sequence(Scheme_Object *e1, Scheme_Object *e2,
823 Optimize_Info *info)
824 {
825 return do_make_discarding_sequence(e1, e2, info, 0, 1);
826 }
827
make_discarding_sequence_3(Scheme_Object * e1,Scheme_Object * e2,Scheme_Object * e3,Optimize_Info * info)828 static Scheme_Object *make_discarding_sequence_3(Scheme_Object *e1, Scheme_Object *e2, Scheme_Object *e3,
829 Optimize_Info *info)
830 {
831 return make_discarding_sequence(e1, make_discarding_sequence(e2, e3, info), info);
832 }
833
make_discarding_app_sequence(Scheme_App_Rec * appr,int result_pos,Scheme_Object * result,Optimize_Info * info)834 static Scheme_Object *make_discarding_app_sequence(Scheme_App_Rec *appr, int result_pos, Scheme_Object *result,
835 Optimize_Info *info)
836 /* Generalize do_make_discarding_sequence() to a sequence of argument
837 expressions, where `result_pos` is the position of the returned
838 argument. If `result_pos` is -1, then all argument results will be
839 ignored. If `result`, then it is used as the result after all
840 arguments are evaluated.*/
841 {
842 int i;
843 Scheme_Object *l = scheme_null;
844
845 result_pos = result_pos + 1;
846 if (result)
847 l = scheme_make_pair(result, l);
848
849 for (i = appr->num_args; i; i--) {
850 Scheme_Object *e;
851 e = appr->args[i];
852 e = ensure_single_value(e, info);
853 if (i == result_pos) {
854 if (SCHEME_NULLP(l)) {
855 e = ensure_single_value_noncm(e, info);
856 l = scheme_make_pair(e, scheme_null);
857 } else {
858 l = scheme_make_sequence_compilation(scheme_make_pair(e, l), -1, 0);
859 l = scheme_make_pair(l, scheme_null);
860 }
861 } else {
862 e = optimize_ignored(e, info, 1, 1, 5);
863 if (e)
864 l = scheme_make_pair(e, l);
865 }
866 }
867
868 if (SCHEME_NULLP(l))
869 return scheme_void;
870
871 if (SCHEME_NULLP(SCHEME_CDR(l)))
872 return SCHEME_CAR(l);
873
874 return scheme_make_sequence_compilation(l, 1, 0);
875 }
876
optimize_ignored(Scheme_Object * e,Optimize_Info * info,int expected_vals,int maybe_omittable,int fuel)877 static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info,
878 int expected_vals, int maybe_omittable,
879 int fuel)
880 /* Simplify an expression whose result will be ignored. The
881 `expected_vals` is 1 or -1. If `maybe_omittable`, the result can be
882 NULL to indicate that it can be omitted. */
883 {
884 if (scheme_omittable_expr(e, expected_vals, 5, 0, info, NULL))
885 return maybe_omittable? NULL : scheme_false;
886
887 if (fuel) {
888 /* We could do a lot more here, but for now, we just avoid purely
889 functional, always successful operations --- especially allocating ones. */
890 switch (SCHEME_TYPE(e)) {
891 case scheme_application2_type:
892 {
893 Scheme_App2_Rec *app = (Scheme_App2_Rec *)e;
894
895 if (!SAME_OBJ(app->rator, scheme_values_proc)) /* `values` is probably here to ensure a single result */
896 if (scheme_is_functional_nonfailing_primitive(app->rator, 1, expected_vals))
897 return do_make_discarding_sequence(app->rand, scheme_void, info, 1, 0);
898
899 /* (make-vector <num>) => <void> */
900 if (SAME_OBJ(app->rator, scheme_make_vector_proc)
901 && (SCHEME_INTP(app->rand)
902 && (SCHEME_INT_VAL(app->rand) >= 0))
903 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand)))
904 return (maybe_omittable ? NULL : scheme_void);
905 }
906 break;
907 case scheme_application3_type:
908 {
909 Scheme_App3_Rec *app = (Scheme_App3_Rec *)e;
910
911 if (scheme_is_functional_nonfailing_primitive(app->rator, 2, expected_vals))
912 return do_make_discarding_sequence(app->rand1,
913 do_make_discarding_sequence(app->rand2,
914 scheme_void,
915 info,
916 1, 0),
917 info,
918 1, 0);
919
920 /* (make-vector <num> <expr>) => <expr> */
921 if (SAME_OBJ(app->rator, scheme_make_vector_proc)
922 && (SCHEME_INTP(app->rand1)
923 && (SCHEME_INT_VAL(app->rand1) >= 0))
924 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand1))) {
925 Scheme_Object *val;
926 val = ensure_single_value_noncm(app->rand2, info);
927 return optimize_ignored(val, info, 1, maybe_omittable, 5);
928 }
929 }
930 break;
931 case scheme_application_type:
932 {
933 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
934
935 if (scheme_is_functional_nonfailing_primitive(app->args[0], app->num_args, expected_vals))
936 return make_discarding_app_sequence(app, -1, NULL, info);
937 }
938 break;
939 case scheme_branch_type:
940 {
941 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e;
942 Scheme_Object *tb, *fb;
943
944 tb = optimize_ignored(b->tbranch, info, expected_vals, 1, fuel - 1);
945 fb = optimize_ignored(b->fbranch, info, expected_vals, 1, fuel - 1);
946
947 if (tb || fb) {
948 b->tbranch = tb ? tb : scheme_false;
949 b->fbranch = fb ? fb : scheme_false;
950 return (Scheme_Object*)b;
951 } else {
952 Scheme_Object *val;
953 val = ensure_single_value_noncm(b->test, info);
954 return optimize_ignored(val, info, 1, maybe_omittable, 5);
955 }
956 }
957 break;
958 case scheme_sequence_type:
959 {
960 Scheme_Sequence *seq = (Scheme_Sequence *)e;
961 Scheme_Object *last;
962
963 last = optimize_ignored(seq->array[seq->count - 1], info, expected_vals, 1, fuel - 1);
964
965 if (last) {
966 seq->array[seq->count - 1] = last;
967 return (Scheme_Object*)seq;
968 } else if (seq->count == 2
969 && (expected_vals == -1
970 || single_valued_noncm_expression(seq->array[0], info, 5))) {
971 return seq->array[0];
972 } else {
973 seq->array[seq->count - 1] = scheme_false;
974 return (Scheme_Object*)seq;
975 }
976 }
977 case scheme_begin0_sequence_type:
978 {
979 Scheme_Sequence *seq = (Scheme_Sequence *)e;
980 Scheme_Object *first;
981
982 first = optimize_ignored(seq->array[0], info, expected_vals, 1, fuel - 1);
983
984 if (first) {
985 seq->array[0] = first;
986 return (Scheme_Object*)seq;
987 } else if (seq->count == 2
988 && (expected_vals == -1
989 || single_valued_noncm_expression(seq->array[1], info, 5))) {
990 return seq->array[1];
991 } else {
992 seq->array[0] = scheme_false;
993 return (Scheme_Object*)seq;
994 }
995 }
996 break;
997 case scheme_ir_let_header_type:
998 {
999 Scheme_IR_Let_Header *head = (Scheme_IR_Let_Header *)e;
1000 Scheme_IR_Let_Value *lv;
1001 Scheme_Object *body;
1002 int i;
1003
1004 body = head->body;
1005 if (0 == head->num_clauses)
1006 lv = (Scheme_IR_Let_Value *)body;
1007 for (i = head->num_clauses; i--; ) {
1008 lv = (Scheme_IR_Let_Value *)body;
1009 body = lv->body;
1010 }
1011 body = optimize_ignored(body, info, expected_vals, 0, fuel - 1);
1012 lv->body = body;
1013 return (Scheme_Object*)head;
1014 }
1015 break;
1016 }
1017 }
1018
1019 return e;
1020 }
1021
make_sequence_2(Scheme_Object * a,Scheme_Object * b)1022 static Scheme_Object *make_sequence_2(Scheme_Object *a, Scheme_Object *b)
1023 {
1024 return scheme_make_sequence_compilation(scheme_make_pair(a, scheme_make_pair(b, scheme_null)), 1, 0);
1025 }
1026
make_discarding_first_sequence(Scheme_Object * e1,Scheme_Object * e2,Optimize_Info * info)1027 static Scheme_Object *make_discarding_first_sequence(Scheme_Object *e1, Scheme_Object *e2,
1028 Optimize_Info *info)
1029 /* Like make_discarding_sequence(), but second expression is not constrained to
1030 a single result. */
1031 {
1032 e1 = optimize_ignored(e1, info, 1, 1, 5);
1033 if (!e1)
1034 return e2;
1035 e1 = ensure_single_value(e1, info);
1036 return make_sequence_2(e1, e2);
1037 }
1038
make_application_2(Scheme_Object * a,Scheme_Object * b,Optimize_Info * info)1039 static Scheme_Object *make_application_2(Scheme_Object *a, Scheme_Object *b, Optimize_Info *info)
1040 {
1041 return scheme_make_application(scheme_make_pair(a, scheme_make_pair(b, scheme_null)), info);
1042 }
1043
make_application_3(Scheme_Object * a,Scheme_Object * b,Scheme_Object * c,Optimize_Info * info)1044 static Scheme_Object *make_application_3(Scheme_Object *a, Scheme_Object *b, Scheme_Object *c,
1045 Optimize_Info *info)
1046 {
1047 return scheme_make_application(scheme_make_pair(a, scheme_make_pair(b, scheme_make_pair(c, scheme_null))),
1048 info);
1049 }
1050
replace_tail_inside(Scheme_Object * alt,Scheme_Object * inside,Scheme_Object * orig)1051 static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *inside, Scheme_Object *orig)
1052 /* Installs a new expression in the result position of various forms, such as `begin`;
1053 extract_tail_inside() needs to be consistent with this function */
1054 {
1055 if (inside) {
1056 switch (SCHEME_TYPE(inside)) {
1057 case scheme_sequence_type:
1058 if (((Scheme_Sequence *)inside)->count)
1059 ((Scheme_Sequence *)inside)->array[((Scheme_Sequence *)inside)->count-1] = alt;
1060 else
1061 scheme_signal_error("internal error: strange inside replacement");
1062 break;
1063 case scheme_ir_let_header_type:
1064 ((Scheme_IR_Let_Header *)inside)->body = alt;
1065 break;
1066 case scheme_ir_let_value_type:
1067 ((Scheme_IR_Let_Value *)inside)->body = alt;
1068 break;
1069 case scheme_with_cont_mark_type:
1070 ((Scheme_With_Continuation_Mark *)inside)->body = alt;
1071 break;
1072 default:
1073 scheme_signal_error("internal error: strange inside replacement");
1074 }
1075 return orig;
1076 }
1077 return alt;
1078 }
1079
extract_tail_inside(Scheme_Object ** _t2,Scheme_Object ** _inside,int for_immediate_body)1080 static void extract_tail_inside(Scheme_Object **_t2, Scheme_Object **_inside, int for_immediate_body)
1081 /* Looks through various forms, like `begin` to extract a result expression;
1082 replace_tail_inside() needs to be consistent with this function */
1083 {
1084 while (1) {
1085 if (SAME_TYPE(SCHEME_TYPE(*_t2), scheme_ir_let_header_type)) {
1086 Scheme_IR_Let_Header *head = (Scheme_IR_Let_Header *)*_t2;
1087 int i;
1088 *_inside = *_t2;
1089 *_t2 = head->body;
1090 for (i = head->num_clauses; i--; ) {
1091 *_inside = *_t2;
1092 *_t2 = ((Scheme_IR_Let_Value *)*_t2)->body;
1093 }
1094 } else if (SAME_TYPE(SCHEME_TYPE(*_t2), scheme_sequence_type)) {
1095 Scheme_Sequence *seq = (Scheme_Sequence *)*_t2;
1096 if (seq->count) {
1097 *_inside = *_t2;
1098 *_t2 = seq->array[seq->count-1];
1099 } else
1100 break;
1101 } else if (SAME_TYPE(SCHEME_TYPE(*_t2), scheme_with_cont_mark_type)
1102 && for_immediate_body) {
1103 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)*_t2;
1104 *_inside = *_t2;
1105 *_t2 = wcm->body;
1106 } else
1107 break;
1108 }
1109 }
1110
scheme_optimize_extract_tail_inside(Scheme_Object * t2)1111 Scheme_Object *scheme_optimize_extract_tail_inside(Scheme_Object *t2)
1112 {
1113 Scheme_Object *inside;
1114 extract_tail_inside(&t2, &inside, 0);
1115 return t2;
1116 }
1117
1118 /*========================================================================*/
1119 /* detecting `make-struct-type` calls and struct shapes */
1120 /*========================================================================*/
1121
is_inspector_call(Scheme_Object * a)1122 static int is_inspector_call(Scheme_Object *a)
1123 /* Does `a` produce an inspector? */
1124 {
1125 if (SAME_TYPE(SCHEME_TYPE(a), scheme_application_type)) {
1126 Scheme_App_Rec *app = (Scheme_App_Rec *)a;
1127 if (!app->num_args
1128 && (SAME_OBJ(app->args[0], scheme_current_inspector_proc)
1129 || SAME_OBJ(app->args[0], scheme_make_inspector_proc)))
1130 return 1;
1131 }
1132 return 0;
1133 }
1134
is_proc_spec_proc(Scheme_Object * p,int init_field_count)1135 static int is_proc_spec_proc(Scheme_Object *p, int init_field_count)
1136 /* Does `p` produce a good `prop:procedure` value? */
1137 {
1138 Scheme_Type vtype;
1139
1140 if (SCHEME_INTP(p)
1141 && (SCHEME_INT_VAL(p) >= 0)
1142 && (SCHEME_INT_VAL(p) < init_field_count))
1143 return 1;
1144
1145 if (SCHEME_PROCP(p)) {
1146 p = scheme_get_or_check_arity(p, -1);
1147 if (SCHEME_INTP(p)) {
1148 return (SCHEME_INT_VAL(p) >= 1);
1149 } else if (SCHEME_STRUCTP(p)
1150 && scheme_is_struct_instance(scheme_arity_at_least, p)) {
1151 p = ((Scheme_Structure *)p)->slots[0];
1152 if (SCHEME_INTP(p))
1153 return (SCHEME_INT_VAL(p) >= 1);
1154 }
1155 return 0;
1156 }
1157
1158 vtype = SCHEME_TYPE(p);
1159
1160 if ((vtype == scheme_lambda_type) || (vtype == scheme_ir_lambda_type)) {
1161 if (((Scheme_Lambda *)p)->num_params >= 1)
1162 return 1;
1163 }
1164
1165 return 0;
1166 }
1167
is_local_ref(Scheme_Object * e,int p,int r,Scheme_IR_Local ** vars)1168 static int is_local_ref(Scheme_Object *e, int p, int r, Scheme_IR_Local **vars)
1169 /* Does `e` refer to...
1170 In resolved mode: variables at offset `p` though `p+r`?
1171 In optimizer IR mode: variables in `vars`? */
1172 {
1173 if (!vars && SAME_TYPE(SCHEME_TYPE(e), scheme_local_type)) {
1174 if ((SCHEME_LOCAL_POS(e) >= p)
1175 && (SCHEME_LOCAL_POS(e) < (p + r)))
1176 return 1;
1177 } else if (vars && SAME_TYPE(SCHEME_TYPE(e), scheme_ir_local_type)) {
1178 int i;
1179 for (i = p; i < p + r; i++) {
1180 if (SAME_OBJ(e, (Scheme_Object *)vars[i]))
1181 return 1;
1182 }
1183 }
1184
1185 return 0;
1186 }
1187
is_int_list(Scheme_Object * o,int up_to)1188 static int is_int_list(Scheme_Object *o, int up_to)
1189 /* Is `o` a list of distinct integers that are less than `up_to`? */
1190 {
1191 if (SCHEME_PAIRP(o)) {
1192 char *s, quick[8];
1193 Scheme_Object *e;
1194 if (up_to <= 8)
1195 s = quick;
1196 else
1197 s = (char *)scheme_malloc_atomic(up_to);
1198 memset(s, 0, up_to);
1199 while (SCHEME_PAIRP(o)) {
1200 e = SCHEME_CAR(o);
1201 o = SCHEME_CDR(o);
1202 if (!SCHEME_INTP(e)
1203 || (SCHEME_INT_VAL(e) < 0)
1204 || (SCHEME_INT_VAL(e) > up_to)
1205 || s[SCHEME_INT_VAL(e)])
1206 return 0;
1207 s[SCHEME_INT_VAL(e)] = 1;
1208 }
1209 }
1210
1211 return SCHEME_NULLP(o);
1212 }
1213
ok_proc_creator_args(Scheme_Object * rator,Scheme_Object * rand1,Scheme_Object * rand2,Scheme_Object * rand3,int delta2,int field_count,Scheme_IR_Local ** vars)1214 static int ok_proc_creator_args(Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2, Scheme_Object *rand3,
1215 int delta2, int field_count, Scheme_IR_Local **vars)
1216 /* Does `rator` plus `rand1` and `rand2` create a struct accessor or mutator? */
1217 {
1218 if ((SAME_OBJ(rator, scheme_make_struct_field_accessor_proc)
1219 && is_local_ref(rand1, delta2+3, 1, vars))
1220 || (SAME_OBJ(rator, scheme_make_struct_field_mutator_proc)
1221 && is_local_ref(rand1, delta2+4, 1, vars))) {
1222 if (SCHEME_INTP(rand2)
1223 && (SCHEME_INT_VAL(rand2) >= 0)
1224 && (SCHEME_INT_VAL(rand2) < field_count)
1225 && (!rand3 || SCHEME_SYMBOLP(rand3))) {
1226 return 1;
1227 }
1228 }
1229
1230 return 0;
1231 }
1232
is_values_with_accessors_and_mutators(Scheme_Object * e,int vals,int resolved,Simple_Struct_Type_Info * _stinfo,Scheme_IR_Local ** vars)1233 static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int resolved,
1234 Simple_Struct_Type_Info *_stinfo,
1235 Scheme_IR_Local **vars)
1236 /* Does `e` produce values for a structure type, mutators, and accessors in the
1237 usual order? */
1238 {
1239 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) {
1240 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
1241 int delta = (resolved ? app->num_args : 0);
1242 if (SAME_OBJ(app->args[0], scheme_values_proc)
1243 && (app->num_args == vals)
1244 && (app->num_args >= 3)
1245 && is_local_ref(app->args[1], delta, 1, vars)
1246 && is_local_ref(app->args[2], delta+1, 1, vars)
1247 && is_local_ref(app->args[3], delta+2, 1, vars)) {
1248 int i, num_gets = 0, num_sets = 0, normal_ops = 1;
1249 int setter_fields = 0, normal_sets = 1;
1250 int prev_setter_pos = app->num_args; /* bigger than any setter index can be */
1251 for (i = app->num_args; i > 3; i--) {
1252 if (is_local_ref(app->args[i], delta, 5, vars)) {
1253 normal_ops = 0;
1254 } else if (SAME_TYPE(SCHEME_TYPE(app->args[i]), scheme_application_type)
1255 && _stinfo->normal_ops && !_stinfo->indexed_ops) {
1256 Scheme_App_Rec *app3 = (Scheme_App_Rec *)app->args[i];
1257 int delta2 = delta + (resolved ? app3->num_args : 0);
1258 if (app3->num_args == 3) {
1259 if (!ok_proc_creator_args(app3->args[0], app3->args[1], app3->args[2], app3->args[3],
1260 delta2, _stinfo->field_count, vars))
1261 break;
1262 if (SAME_OBJ(app3->args[0], scheme_make_struct_field_mutator_proc)) {
1263 int pos = SCHEME_INT_VAL(app3->args[2]);
1264 if (num_gets) {
1265 /* Since we're walking backwards, it's not normal to hit a mutator
1266 after (i.e., before in argument order) a selector */
1267 normal_ops = 0;
1268 }
1269 if (normal_sets) {
1270 if (pos >= prev_setter_pos) {
1271 /* setters are not in the usual order; zero out the mask */
1272 normal_sets = 0;
1273 setter_fields = 0;
1274 } else if (pos < (31 - STRUCT_PROC_SHAPE_SHIFT)) {
1275 setter_fields |= (1 << pos);
1276 prev_setter_pos = pos;
1277 }
1278 }
1279 num_sets++;
1280 } else {
1281 if (SCHEME_INT_VAL(app3->args[2]) != (i - 4)) {
1282 /* selectors are not in the usual order */
1283 normal_ops = 0;
1284 }
1285 num_gets++;
1286 }
1287 } else
1288 break;
1289 } else if (SAME_TYPE(SCHEME_TYPE(app->args[i]), scheme_application3_type)
1290 && _stinfo->normal_ops && !_stinfo->indexed_ops) {
1291 Scheme_App3_Rec *app3 = (Scheme_App3_Rec *)app->args[i];
1292 int delta2 = delta + (resolved ? 2 : 0);
1293 if (!ok_proc_creator_args(app3->rator, app3->rand1, app3->rand2, NULL,
1294 delta2, _stinfo->field_count, vars))
1295 break;
1296 if (SAME_OBJ(app3->rator, scheme_make_struct_field_mutator_proc)) {
1297 if (num_gets) normal_ops = 0;
1298 num_sets++;
1299 } else {
1300 if (SCHEME_INT_VAL(app3->rand2) != (i - 4)) normal_ops = 0;
1301 num_gets++;
1302 }
1303 } else
1304 break;
1305 }
1306 if (i <= 3) {
1307 _stinfo->normal_ops = normal_ops;
1308 _stinfo->indexed_ops = 1;
1309 _stinfo->num_gets = num_gets;
1310 _stinfo->num_sets = num_sets;
1311 _stinfo->setter_fields = setter_fields;
1312 return 1;
1313 }
1314 }
1315 }
1316
1317 return 0;
1318 }
1319
skip_clears(Scheme_Object * body)1320 static Scheme_Object *skip_clears(Scheme_Object *body)
1321 /* If `body` is a `begin` form that exists only to clear variables
1322 as installed by the SFS pass, then extract the result form. */
1323 {
1324 if (SAME_TYPE(SCHEME_TYPE(body), scheme_sequence_type)) {
1325 Scheme_Sequence *seq = (Scheme_Sequence *)body;
1326 int i;
1327 for (i = seq->count - 1; i--; ) {
1328 if (!SAME_TYPE(SCHEME_TYPE(seq->array[i]), scheme_local_type))
1329 break;
1330 }
1331 if (i < 0)
1332 return seq->array[seq->count-1];
1333 }
1334 return body;
1335 }
1336
1337 typedef int (*Ok_Value_Callback)(void *data, Scheme_Object *v, int mode);
1338 #define OK_CONSTANT_SHAPE 1
1339 #define OK_CONSTANT_ENCODED_SHAPE 2
1340 #define OK_CONSTANT_VALIDATE_SHAPE 3
1341 #define OK_CONSTANT_VARIANT 4
1342 #define OK_CONSTANT_VALUE 5
1343
is_ok_value(Ok_Value_Callback ok_value,void * data,Scheme_Object * arg,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet)1344 static int is_ok_value(Ok_Value_Callback ok_value, void *data,
1345 Scheme_Object *arg,
1346 Optimize_Info *info,
1347 Scheme_Hash_Table *top_level_table,
1348 Scheme_Object **runstack, int rs_delta,
1349 Scheme_Linklet *enclosing_linklet)
1350 /* Does `arg` produce a value that satisfies `ok_value`? */
1351 {
1352 int pos;
1353 Scheme_Object *v;
1354
1355 if (SAME_TYPE(SCHEME_TYPE(arg), scheme_ir_toplevel_type)) {
1356 if (info) {
1357 /* This is optimize mode */
1358 v = get_defn_shape(info, (Scheme_IR_Toplevel *)arg);
1359 if (!v)
1360 v = get_import_shape(info, (Scheme_IR_Toplevel *)arg);
1361 if (v)
1362 return ok_value(data, v, OK_CONSTANT_SHAPE);
1363 }
1364 } else if (SAME_TYPE(SCHEME_TYPE(arg), scheme_toplevel_type)
1365 || SAME_TYPE(SCHEME_TYPE(arg), scheme_static_toplevel_type)) {
1366 pos = SCHEME_TOPLEVEL_POS(arg);
1367 if (runstack) {
1368 /* This is eval mode; conceptually, this code belongs in
1369 define_execute_with_dynamic_state() */
1370 Scheme_Bucket *b;
1371 Scheme_Prefix *toplevels;
1372 if (SAME_TYPE(SCHEME_TYPE(arg), scheme_toplevel_type))
1373 toplevels = (Scheme_Prefix *)runstack[SCHEME_TOPLEVEL_DEPTH(arg) - rs_delta];
1374 else
1375 toplevels = SCHEME_STATIC_TOPLEVEL_PREFIX(arg);
1376 b = (Scheme_Bucket *)toplevels->a[pos];
1377 if (b->val && (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_IS_CONSISTENT))
1378 return ok_value(data, b->val, OK_CONSTANT_VALUE);
1379 } else if (enclosing_linklet) {
1380 /* This is linklet-export mode; conceptually, this code belongs in
1381 linklet_setup_constants() */
1382 if (pos > enclosing_linklet->num_total_imports) {
1383 Scheme_Object *name;
1384 pos -= (enclosing_linklet->num_total_imports + 1);
1385 name = SCHEME_VEC_ELS(enclosing_linklet->defns)[pos];
1386 v = scheme_hash_get(enclosing_linklet->constants, name);
1387 if (v)
1388 return ok_value(data, v, OK_CONSTANT_VARIANT);
1389 } else if (pos >= 1
1390 && (pos <= enclosing_linklet->num_total_imports)
1391 && enclosing_linklet->import_shapes) {
1392 pos -= 1;
1393 return ok_value(data, SCHEME_VEC_ELS(enclosing_linklet->import_shapes)[pos], OK_CONSTANT_ENCODED_SHAPE);
1394 }
1395 } else if (top_level_table) {
1396 /* This is validate mode; conceptually, this code belongs in
1397 define_values_validate() */
1398 v = scheme_hash_get(top_level_table, scheme_make_integer(pos));
1399 if (v) {
1400 return ok_value(data, v, OK_CONSTANT_VALIDATE_SHAPE);
1401 }
1402 }
1403 } else if (SCHEME_TYPE(arg) > _scheme_ir_values_types_)
1404 return ok_value(data, arg, OK_CONSTANT_VALUE);
1405
1406 return 0;
1407 }
1408
ok_constant_super_value(void * data,Scheme_Object * v,int mode)1409 static int ok_constant_super_value(void *data, Scheme_Object *v, int mode)
1410 /* Is `v` a structure type (which can serve as a supertype)? */
1411 {
1412 Scheme_Object **_parent_identity = (Scheme_Object **)((void **)data)[0];
1413 int *_nonfail_constr = (int *)((void **)data)[1];
1414 int *_prefab = (int *)((void **)data)[2];
1415
1416 if (mode == OK_CONSTANT_SHAPE) {
1417 if (SAME_TYPE(SCHEME_TYPE(v), scheme_struct_proc_shape_type)) {
1418 int mode = (SCHEME_PROC_SHAPE_MODE(v) & STRUCT_PROC_SHAPE_MASK);
1419 int field_count = (SCHEME_PROC_SHAPE_MODE(v) >> STRUCT_PROC_SHAPE_SHIFT);
1420 if (mode == STRUCT_PROC_SHAPE_STRUCT) {
1421 if (_parent_identity)
1422 *_parent_identity = SCHEME_PROC_SHAPE_IDENTITY(v);
1423 if (_nonfail_constr)
1424 *_nonfail_constr = SCHEME_PROC_SHAPE_MODE(v) & STRUCT_PROC_SHAPE_NONFAIL_CONSTR;
1425 if (_prefab)
1426 *_prefab = SCHEME_PROC_SHAPE_MODE(v) & STRUCT_PROC_SHAPE_PREFAB;
1427 return field_count + 1;
1428 }
1429 }
1430 } else if (mode == OK_CONSTANT_ENCODED_SHAPE) {
1431 intptr_t k;
1432 if (scheme_decode_struct_shape(v, &k)) {
1433 if ((k & STRUCT_PROC_SHAPE_MASK) == STRUCT_PROC_SHAPE_STRUCT) {
1434 if (_nonfail_constr)
1435 *_nonfail_constr = k & STRUCT_PROC_SHAPE_NONFAIL_CONSTR;
1436 if (_prefab)
1437 *_prefab = k & STRUCT_PROC_SHAPE_PREFAB;
1438 return (k >> STRUCT_PROC_SHAPE_SHIFT) + 1;
1439 }
1440 }
1441 } else if (mode == OK_CONSTANT_VALIDATE_SHAPE) {
1442 int k = SCHEME_INT_VAL(v);
1443 if ((k >= 0)
1444 && (k & STRUCT_PROC_SHAPE_MASK) == STRUCT_PROC_SHAPE_STRUCT) {
1445 if (_nonfail_constr)
1446 *_nonfail_constr = k & STRUCT_PROC_SHAPE_NONFAIL_CONSTR;
1447 if (_prefab)
1448 *_prefab = k & STRUCT_PROC_SHAPE_PREFAB;
1449 return (k >> STRUCT_PROC_SHAPE_SHIFT) + 1;
1450 }
1451 } else if (mode == OK_CONSTANT_VARIANT) {
1452 if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 3)) {
1453 if (_parent_identity)
1454 *_parent_identity = SCHEME_VEC_ELS(v)[2];
1455 v = SCHEME_VEC_ELS(v)[1];
1456 if (v && SCHEME_INTP(v)) {
1457 int mode = (SCHEME_INT_VAL(v) & STRUCT_PROC_SHAPE_MASK);
1458 int field_count = (SCHEME_INT_VAL(v) >> STRUCT_PROC_SHAPE_SHIFT);
1459 if (mode == STRUCT_PROC_SHAPE_STRUCT) {
1460 if (_nonfail_constr)
1461 *_nonfail_constr = SCHEME_INT_VAL(v) & STRUCT_PROC_SHAPE_NONFAIL_CONSTR;
1462 if (_prefab)
1463 *_prefab = SCHEME_INT_VAL(v) & STRUCT_PROC_SHAPE_PREFAB;
1464 return field_count + 1;
1465 }
1466 }
1467 }
1468 } else if (mode == OK_CONSTANT_VALUE) {
1469 if (SCHEME_STRUCT_TYPEP(v)) {
1470 Scheme_Struct_Type *st = (Scheme_Struct_Type *)v;
1471 if (st->num_slots == st->num_islots) {
1472 if (_nonfail_constr)
1473 *_nonfail_constr = (st->more_flags & STRUCT_TYPE_FLAG_NONFAIL_CONSTRUCTOR);
1474 if (_prefab)
1475 *_prefab = !!st->prefab_key;
1476 return st->num_slots + 1;
1477 }
1478 }
1479 }
1480
1481 return 0;
1482 }
1483
is_constant_super(Scheme_Object * arg,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet,Scheme_Object ** _parent_identity,int * _nonfail_constr,int * _prefab)1484 static int is_constant_super(Scheme_Object *arg,
1485 Optimize_Info *info,
1486 Scheme_Hash_Table *top_level_table,
1487 Scheme_Object **runstack, int rs_delta,
1488 Scheme_Linklet *enclosing_linklet,
1489 Scheme_Object **_parent_identity,
1490 int *_nonfail_constr,
1491 int *_prefab)
1492 /* Does `arg` produce another structure type (which can serve as a supertype)? */
1493 {
1494 void *data[3];
1495
1496 data[0] = _parent_identity;
1497 data[1] = _nonfail_constr;
1498 data[2] = _prefab;
1499
1500 return is_ok_value(ok_constant_super_value, data,
1501 arg,
1502 info,
1503 top_level_table,
1504 runstack, rs_delta,
1505 enclosing_linklet);
1506 }
1507
ok_constant_property_without_guard(void * data,Scheme_Object * v,int mode)1508 static int ok_constant_property_without_guard(void *data, Scheme_Object *v, int mode)
1509 {
1510 intptr_t k = -1;
1511
1512 if (mode == OK_CONSTANT_SHAPE) {
1513 if (SAME_TYPE(SCHEME_TYPE(v), scheme_struct_prop_proc_shape_type)) {
1514 k = SCHEME_PROP_PROC_SHAPE_MODE(v);
1515 }
1516 } else if (mode == OK_CONSTANT_ENCODED_SHAPE) {
1517 if (!scheme_decode_struct_prop_shape(v, &k))
1518 k = 0;
1519 } else if (mode == OK_CONSTANT_VALIDATE_SHAPE) {
1520 int k = SCHEME_INT_VAL(v);
1521 if (k < 0)
1522 k = -(k+1);
1523 else
1524 k = 0;
1525 } else if (mode == OK_CONSTANT_VARIANT) {
1526 if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 4)) {
1527 v = SCHEME_VEC_ELS(v)[1];
1528 if (v && SCHEME_INTP(v))
1529 k = SCHEME_INT_VAL(v);
1530 }
1531 } else if (mode == OK_CONSTANT_VALUE) {
1532 if (SAME_TYPE(SCHEME_TYPE(v), scheme_struct_property_type)) {
1533 if (!((Scheme_Struct_Property *)v)->guard)
1534 return 1;
1535 }
1536 }
1537
1538 return (k == STRUCT_PROP_PROC_SHAPE_PROP);
1539 }
1540
is_struct_type_property_without_guard(Scheme_Object * arg,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet)1541 static int is_struct_type_property_without_guard(Scheme_Object *arg,
1542 Optimize_Info *info,
1543 Scheme_Hash_Table *top_level_table,
1544 Scheme_Object **runstack, int rs_delta,
1545 Scheme_Linklet *enclosing_linklet)
1546 /* Does `arg` produce a structure type property that has no guard (so that any value is ok)? */
1547 {
1548 return is_ok_value(ok_constant_property_without_guard, NULL,
1549 arg,
1550 info,
1551 top_level_table,
1552 runstack, rs_delta,
1553 enclosing_linklet);
1554 }
1555
is_simple_property_list(Scheme_Object * a,int resolved,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet,int just_for_authentic,int * _authentic)1556 static int is_simple_property_list(Scheme_Object *a, int resolved,
1557 Optimize_Info *info,
1558 Scheme_Hash_Table *top_level_table,
1559 Scheme_Object **runstack, int rs_delta,
1560 Scheme_Linklet *enclosing_linklet,
1561 int just_for_authentic, int *_authentic)
1562 /* Does `a` produce a property list that always lets `make-struct-type` succeed? */
1563 {
1564 Scheme_Object *arg;
1565 int i, count;
1566
1567 if (SAME_TYPE(SCHEME_TYPE(a), scheme_application_type)) {
1568 if (!SAME_OBJ(((Scheme_App_Rec *)a)->args[0], scheme_list_proc))
1569 return 0;
1570 count = ((Scheme_App_Rec *)a)->num_args;
1571 } else if (SAME_TYPE(SCHEME_TYPE(a), scheme_application2_type)) {
1572 if (!SAME_OBJ(((Scheme_App2_Rec *)a)->rator, scheme_list_proc))
1573 return 0;
1574 count = 1;
1575 } else if (SAME_TYPE(SCHEME_TYPE(a), scheme_application3_type)) {
1576 if (!SAME_OBJ(((Scheme_App3_Rec *)a)->rator, scheme_list_proc))
1577 return 0;
1578 count = 2;
1579 } else
1580 return 0;
1581
1582 for (i = 0; i < count; i++) {
1583 if (SAME_TYPE(SCHEME_TYPE(a), scheme_application_type))
1584 arg = ((Scheme_App_Rec *)a)->args[i+1];
1585 else if (SAME_TYPE(SCHEME_TYPE(a), scheme_application2_type))
1586 arg = ((Scheme_App2_Rec *)a)->rand;
1587 else {
1588 if (i == 0)
1589 arg = ((Scheme_App3_Rec *)a)->rand1;
1590 else
1591 arg = ((Scheme_App3_Rec *)a)->rand2;
1592 }
1593
1594 if (SAME_TYPE(SCHEME_TYPE(arg), scheme_application3_type)) {
1595 Scheme_App3_Rec *a3 = (Scheme_App3_Rec *)arg;
1596
1597 if (!SAME_OBJ(a3->rator, scheme_cons_proc)) {
1598 if (!just_for_authentic)
1599 return 0;
1600 } else {
1601 if (_authentic && SAME_OBJ(a3->rand1, scheme_authentic_property))
1602 *_authentic = 1;
1603 if (!just_for_authentic) {
1604 if (is_struct_type_property_without_guard(a3->rand1,
1605 info,
1606 top_level_table,
1607 runstack, rs_delta,
1608 enclosing_linklet)) {
1609 if (!scheme_omittable_expr(a3->rand2, 1, 3, (resolved ? OMITTABLE_RESOLVED : 0), NULL, NULL))
1610 return 0;
1611 } else
1612 return 0;
1613 }
1614 }
1615 } else {
1616 if (!just_for_authentic)
1617 return 0;
1618 }
1619 }
1620
1621 return 1;
1622 }
1623
scheme_is_simple_make_struct_type(Scheme_Object * e,int vals,int flags,GC_CAN_IGNORE int * _auto_e_depth,Simple_Struct_Type_Info * _stinfo,Scheme_Object ** _parent_identity,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet,Scheme_Object ** _name,int fuel)1624 Scheme_Object *scheme_is_simple_make_struct_type(Scheme_Object *e, int vals, int flags,
1625 GC_CAN_IGNORE int *_auto_e_depth,
1626 Simple_Struct_Type_Info *_stinfo,
1627 Scheme_Object **_parent_identity,
1628 Optimize_Info *info,
1629 Scheme_Hash_Table *top_level_table,
1630 Scheme_Object **runstack, int rs_delta,
1631 Scheme_Linklet *enclosing_linklet,
1632 Scheme_Object **_name,
1633 int fuel)
1634 /* Checks whether it's a `make-struct-type' call --- that, if `flags` includes
1635 `CHECK_STRUCT_TYPE_ALWAYS_SUCCEED`, certainly succeeds (i.e., no exception) ---
1636 pending a check of the auto-value argument if `flags` includes `CHECK_STRUCT_TYPE_DELAY_AUTO_CHECK`.
1637 The expression itself must have no side-effects except for errors (but the possibility
1638 of errors means that the expression is not necessarily omittable).
1639 The result is the auto-value argument or scheme_true if it's simple, NULL if not.
1640 The first result of `e` will be a struct type, the second a constructor, and the third a predicate;
1641 the rest are selectors and mutators. */
1642 {
1643 int resolved = (flags & CHECK_STRUCT_TYPE_RESOLVED);
1644
1645 if (!fuel) return NULL;
1646
1647 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) {
1648 if ((vals == 5) || (vals < 0)) {
1649 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
1650
1651 if ((app->num_args >= 4) && (app->num_args <= 11)
1652 && SAME_OBJ(scheme_make_struct_type_proc, app->args[0])) {
1653 int super_count_plus_one, super_nonfail_constr = 1, super_prefab = 1;
1654
1655 if (_parent_identity)
1656 *_parent_identity = scheme_null;
1657 if (!SCHEME_FALSEP(app->args[2]))
1658 super_count_plus_one = is_constant_super(app->args[2],
1659 info, top_level_table, runstack,
1660 rs_delta + app->num_args,
1661 enclosing_linklet, _parent_identity,
1662 &super_nonfail_constr,
1663 &super_prefab);
1664 else
1665 super_count_plus_one = 0;
1666
1667 if (SCHEME_SYMBOLP(app->args[1])
1668 && (SCHEME_FALSEP(app->args[2]) /* super */
1669 || super_count_plus_one)
1670 && SCHEME_INTP(app->args[3])
1671 && (SCHEME_INT_VAL(app->args[3]) >= 0)
1672 && SCHEME_INTP(app->args[4])
1673 && (SCHEME_INT_VAL(app->args[4]) >= 0)
1674 && ((app->num_args < 5)
1675 /* auto-field value: */
1676 || (flags & CHECK_STRUCT_TYPE_DELAY_AUTO_CHECK)
1677 || scheme_omittable_expr(app->args[5], 1, 3, (resolved ? OMITTABLE_RESOLVED : 0), NULL, NULL))
1678 && ((app->num_args < 6)
1679 /* no properties... */
1680 || SCHEME_NULLP(app->args[6])
1681 /* ... or properties that might make the `make-struct-type`
1682 call itself fail, but otherwise don't affect the constructor
1683 or selectors in a way that matters (although supplying the
1684 `prop:chaperone-unsafe-undefined` property can affect the
1685 constructor in an optimizer-irrelevant way) */
1686 || (!(flags & CHECK_STRUCT_TYPE_ALWAYS_SUCCEED)
1687 && scheme_omittable_expr(app->args[6], 1, 4, (resolved ? OMITTABLE_RESOLVED : 0), NULL, NULL))
1688 || ((flags & CHECK_STRUCT_TYPE_ALWAYS_SUCCEED)
1689 && is_simple_property_list(app->args[6], resolved,
1690 info,
1691 top_level_table,
1692 runstack, rs_delta,
1693 enclosing_linklet,
1694 0, NULL)))
1695 && ((app->num_args < 7)
1696 /* inspector: */
1697 || SCHEME_FALSEP(app->args[7])
1698 || (super_prefab
1699 && SCHEME_SYMBOLP(app->args[7])
1700 && !strcmp("prefab", SCHEME_SYM_VAL(app->args[7]))
1701 && !SCHEME_SYM_WEIRDP(app->args[7]))
1702 || is_inspector_call(app->args[7]))
1703 && ((app->num_args < 8)
1704 /* procedure property: */
1705 || SCHEME_FALSEP(app->args[8])
1706 || is_proc_spec_proc(app->args[8], SCHEME_INT_VAL(app->args[3])))
1707 && ((app->num_args < 9)
1708 /* immutables: */
1709 || is_int_list(app->args[9],
1710 SCHEME_INT_VAL(app->args[3])))
1711 && ((app->num_args < 10)
1712 /* guard: */
1713 || SCHEME_FALSEP(app->args[10])
1714 /* Could try to check for procedure with correct arity: */
1715 || !(flags & CHECK_STRUCT_TYPE_ALWAYS_SUCCEED))
1716 && ((app->num_args < 11)
1717 /* constructor name: */
1718 || SCHEME_FALSEP(app->args[11])
1719 || SCHEME_SYMBOLP(app->args[11]))) {
1720 if (_auto_e_depth)
1721 *_auto_e_depth = (resolved ? app->num_args : 0);
1722 if (_name)
1723 *_name = app->args[1];
1724 if (_stinfo) {
1725 int authentic = 0;
1726 int super_count = (super_count_plus_one
1727 ? (super_count_plus_one - 1)
1728 : 0);
1729 _stinfo->init_field_count = SCHEME_INT_VAL(app->args[3]) + super_count;
1730 _stinfo->field_count = (SCHEME_INT_VAL(app->args[3])
1731 + SCHEME_INT_VAL(app->args[4])
1732 + super_count);
1733 _stinfo->uses_super = (super_count_plus_one ? 1 : 0);
1734 _stinfo->super_field_count = (super_count_plus_one ? (super_count_plus_one - 1) : 0);
1735 _stinfo->normal_ops = 1;
1736 _stinfo->indexed_ops = 0;
1737 _stinfo->authentic = 0;
1738 if ((app->num_args > 6)
1739 && is_simple_property_list(app->args[6], resolved,
1740 info,
1741 top_level_table,
1742 runstack, rs_delta,
1743 enclosing_linklet,
1744 1, &authentic))
1745 _stinfo->authentic = authentic;
1746 _stinfo->nonfail_constructor = (super_nonfail_constr
1747 && ((app->num_args < 10) || SCHEME_FALSEP(app->args[10])));
1748 _stinfo->prefab = ((app->num_args > 7)
1749 && SCHEME_SYMBOLP(app->args[7]));
1750 _stinfo->num_gets = 1;
1751 _stinfo->num_sets = 1;
1752 }
1753 return ((app->num_args < 5) ? scheme_true : app->args[5]);
1754 }
1755 }
1756 }
1757 }
1758
1759 if (SAME_TYPE(SCHEME_TYPE(e), scheme_ir_let_header_type)) {
1760 /* check for (let-values ([(: mk ? ref- set-!) (make-struct-type ...)]) (values ...))
1761 as generated by the expansion of `struct' */
1762 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)e;
1763 if ((lh->count == 5) && (lh->num_clauses == 1)) {
1764 if (SAME_TYPE(SCHEME_TYPE(lh->body), scheme_ir_let_value_type)) {
1765 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
1766 if (SAME_TYPE(SCHEME_TYPE(lv->value), scheme_application_type)) {
1767 Scheme_Object *auto_e;
1768 Simple_Struct_Type_Info stinfo;
1769 if (!_stinfo) _stinfo = &stinfo;
1770 auto_e = scheme_is_simple_make_struct_type(lv->value, 5, flags,
1771 _auto_e_depth, _stinfo, _parent_identity,
1772 info, top_level_table,
1773 runstack, rs_delta,
1774 enclosing_linklet,
1775 _name,
1776 fuel-1);
1777 if (auto_e) {
1778 /* We have (let-values ([... (make-struct-type)]) ....), so make sure body
1779 just uses `make-struct-field-{accessor,mutator}'. */
1780 if (is_values_with_accessors_and_mutators(lv->body, vals, resolved, _stinfo, lv->vars)) {
1781 return auto_e;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 }
1788
1789 if (SAME_TYPE(SCHEME_TYPE(e), scheme_let_void_type)) {
1790 /* same thing, but in resolved form */
1791 Scheme_Let_Void *lvd = (Scheme_Let_Void *)e;
1792 if (lvd->count == 5) {
1793 if (SAME_TYPE(SCHEME_TYPE(lvd->body), scheme_let_value_type)) {
1794 Scheme_Let_Value *lv = (Scheme_Let_Value *)lvd->body;
1795 if ((lv->position == 0) && (lv->count == 5)) {
1796 Scheme_Object *e2;
1797 e2 = skip_clears(lv->value);
1798 if (SAME_TYPE(SCHEME_TYPE(e2), scheme_application_type)) {
1799 Scheme_Object *auto_e;
1800 Simple_Struct_Type_Info stinfo;
1801 if (!_stinfo) _stinfo = &stinfo;
1802 auto_e = scheme_is_simple_make_struct_type(e2, 5, flags,
1803 _auto_e_depth, _stinfo, _parent_identity,
1804 info, top_level_table,
1805 runstack, rs_delta + lvd->count,
1806 enclosing_linklet,
1807 _name,
1808 fuel-1);
1809 if (auto_e) {
1810 /* We have (let-values ([... (make-struct-type)]) ....), so make sure body
1811 just uses `make-struct-field-{accessor,mutator}'. */
1812 e2 = skip_clears(lv->body);
1813 if (is_values_with_accessors_and_mutators(e2, vals, resolved, _stinfo, NULL)) {
1814 if (_auto_e_depth) *_auto_e_depth += lvd->count;
1815 return auto_e;
1816 }
1817 }
1818 }
1819 }
1820 }
1821 }
1822 }
1823
1824 return NULL;
1825 }
1826
scheme_is_simple_make_struct_type_property(Scheme_Object * e,int vals,int flags,int * _has_guard,Optimize_Info * info,Scheme_Hash_Table * top_level_table,Scheme_Object ** runstack,int rs_delta,Scheme_Linklet * enclosing_linklet,int fuel)1827 int scheme_is_simple_make_struct_type_property(Scheme_Object *e, int vals, int flags,
1828 int *_has_guard,
1829 Optimize_Info *info,
1830 Scheme_Hash_Table *top_level_table,
1831 Scheme_Object **runstack, int rs_delta,
1832 Scheme_Linklet *enclosing_linklet,
1833 int fuel)
1834 /* Reports whether `app` is a call to `make-struct-type-property` to
1835 produce a property. The `flag` argument can indicate further that the
1836 expression must always succeed without raising an exception. */
1837 {
1838 int resolved = (flags & CHECK_STRUCT_TYPE_RESOLVED);
1839
1840 if ((vals != 3) && (vals >= 0)) return 0;
1841
1842 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application2_type)) {
1843 Scheme_App2_Rec *app = (Scheme_App2_Rec *)e;
1844 if (SAME_OBJ(app->rator, scheme_make_struct_type_property_proc)) {
1845 if (SCHEME_SYMBOLP(app->rand)) {
1846 if (_has_guard) *_has_guard = 0;
1847 return 1;
1848 }
1849 }
1850 }
1851
1852 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) {
1853 Scheme_App3_Rec *app = (Scheme_App3_Rec *)e;
1854 if (SAME_OBJ(app->rator, scheme_make_struct_type_property_proc)) {
1855 if (SCHEME_SYMBOLP(app->rand1)
1856 && (!(flags & CHECK_STRUCT_TYPE_ALWAYS_SUCCEED)
1857 || SCHEME_FALSEP(app->rand2)
1858 || (SCHEME_LAMBDAP(app->rand2)
1859 && (((Scheme_Lambda *)app->rand2)->num_params == 2)))
1860 && (scheme_omittable_expr(app->rator, 1, 4, (resolved ? OMITTABLE_RESOLVED : 0), NULL, NULL))) {
1861 if (_has_guard) *_has_guard = 1;
1862 return 1;
1863 }
1864 }
1865 }
1866
1867 return 0;
1868 }
1869
1870 /*========================================================================*/
1871 /* more utils */
1872 /*========================================================================*/
1873
scheme_get_struct_proc_shape(int k,Simple_Struct_Type_Info * stinfo)1874 intptr_t scheme_get_struct_proc_shape(int k, Simple_Struct_Type_Info *stinfo)
1875 {
1876 switch (k) {
1877 case 0:
1878 if (stinfo->field_count == stinfo->init_field_count)
1879 return (STRUCT_PROC_SHAPE_STRUCT
1880 | (stinfo->authentic ? STRUCT_PROC_SHAPE_AUTHENTIC : 0)
1881 | (stinfo->nonfail_constructor ? STRUCT_PROC_SHAPE_NONFAIL_CONSTR : 0)
1882 | (stinfo->prefab ? STRUCT_PROC_SHAPE_PREFAB : 0)
1883 | (stinfo->field_count << STRUCT_PROC_SHAPE_SHIFT));
1884 else
1885 return STRUCT_PROC_SHAPE_OTHER;
1886 break;
1887 case 1:
1888 return (STRUCT_PROC_SHAPE_CONSTR
1889 | (stinfo->init_field_count << STRUCT_PROC_SHAPE_SHIFT)
1890 | (stinfo->nonfail_constructor ? STRUCT_PROC_SHAPE_NONFAIL_CONSTR : 0));
1891 break;
1892 case 2:
1893 return (STRUCT_PROC_SHAPE_PRED
1894 | (stinfo->authentic ? STRUCT_PROC_SHAPE_AUTHENTIC : 0));
1895 break;
1896 default:
1897 if (stinfo && stinfo->normal_ops && stinfo->indexed_ops) {
1898 if (k - 3 < stinfo->num_gets) {
1899 /* record index of field */
1900 return (STRUCT_PROC_SHAPE_GETTER
1901 | (stinfo->authentic ? STRUCT_PROC_SHAPE_AUTHENTIC : 0)
1902 | ((stinfo->super_field_count + (k - 3)) << STRUCT_PROC_SHAPE_SHIFT));
1903 } else {
1904 int idx = (k - 3 - stinfo->num_gets), setter_fields = stinfo->setter_fields, pos = 0;
1905
1906 /* setter_fields is a bitmap for first (31-STRUCT_PROC_SHAPE_SHIFT) fields that may have a setter */
1907 while ((idx > 0) || !(setter_fields & 1)) {
1908 if (setter_fields & 1) {
1909 idx--;
1910 }
1911 setter_fields = setter_fields >> 1;
1912 pos++;
1913 if (!setter_fields) break;
1914 }
1915
1916 if (!idx && (setter_fields & 1))
1917 pos += stinfo->super_field_count + 1;
1918 else {
1919 /* represent "unknown" by zero */
1920 pos = 0;
1921 }
1922
1923 return (STRUCT_PROC_SHAPE_SETTER
1924 | (stinfo->authentic ? STRUCT_PROC_SHAPE_AUTHENTIC : 0)
1925 | (pos << STRUCT_PROC_SHAPE_SHIFT));
1926 }
1927 }
1928 }
1929
1930 return STRUCT_PROC_SHAPE_OTHER;
1931 }
1932
scheme_make_struct_proc_shape(intptr_t k,Scheme_Object * identity)1933 Scheme_Object *scheme_make_struct_proc_shape(intptr_t k, Scheme_Object *identity)
1934 {
1935 Scheme_Object *ps;
1936
1937 ps = scheme_malloc_small_tagged(sizeof(Scheme_Simple_Object));
1938 ps->type = scheme_struct_proc_shape_type;
1939 SCHEME_PROC_SHAPE_MODE(ps) = k;
1940 SCHEME_PROC_SHAPE_IDENTITY(ps) = identity;
1941
1942 return ps;
1943 }
1944
scheme_get_struct_property_proc_shape(int k,int has_guard)1945 intptr_t scheme_get_struct_property_proc_shape(int k, int has_guard)
1946 {
1947 switch (k) {
1948 case 0:
1949 if (has_guard)
1950 return STRUCT_PROP_PROC_SHAPE_GUARDED_PROP;
1951 else
1952 return STRUCT_PROP_PROC_SHAPE_PROP;
1953 case 1:
1954 return STRUCT_PROP_PROC_SHAPE_PRED;
1955 case 2:
1956 default:
1957 return STRUCT_PROP_PROC_SHAPE_GETTER;
1958 }
1959 }
1960
scheme_make_struct_property_proc_shape(intptr_t k)1961 Scheme_Object *scheme_make_struct_property_proc_shape(intptr_t k)
1962 {
1963 Scheme_Object *ps;
1964
1965 ps = scheme_alloc_small_object();
1966 ps->type = scheme_struct_prop_proc_shape_type;
1967 SCHEME_PROP_PROC_SHAPE_MODE(ps) = k;
1968
1969 return ps;
1970 }
1971
is_struct_identity_subtype(Scheme_Object * sub,Scheme_Object * sup)1972 XFORM_NONGCING static int is_struct_identity_subtype(Scheme_Object *sub, Scheme_Object *sup)
1973 {
1974 /* A structure identity is typically a list of symbols, but the symbols are
1975 just for debugging. Instead, the address of each pair forming the
1976 list represents an identiity. */
1977 while (SCHEME_PAIRP(sub)) {
1978 if (SAME_OBJ(sub, sup))
1979 return 1;
1980 sub = SCHEME_CDR(sub);
1981 }
1982 return 0;
1983 }
1984
single_valued_noncm_function(Scheme_Object * rator,int num_args,Optimize_Info * info,int s_v,int non_cm)1985 static int single_valued_noncm_function(Scheme_Object *rator, int num_args,
1986 Optimize_Info *info, int s_v, int non_cm)
1987 {
1988 int flags;
1989
1990 if (!s_v && !non_cm)
1991 return 1;
1992
1993 flags = get_rator_flags(rator, num_args, info);
1994 if (s_v && !(flags & LAMBDA_SINGLE_RESULT))
1995 return 0;
1996 if (non_cm && !(flags & LAMBDA_PRESERVES_MARKS))
1997 return 0;
1998
1999 return 1;
2000 }
2001
do_single_valued_noncm_expression(Scheme_Object * expr,Optimize_Info * info,int fuel,int s_v,int non_cm)2002 static int do_single_valued_noncm_expression(Scheme_Object *expr, Optimize_Info *info, int fuel, int s_v, int non_cm)
2003 /* Not necessarily omittable or copyable expression.
2004 If `s_v`, the expression must not be single-valued.
2005 If `non_cm`, the expression must be not sensitive to tail position. In particular,
2006 it has no with-continuation-mark in tail position, unless the body is omittable.
2007 The conservative answer is 0. */
2008 {
2009 if (!s_v && !non_cm)
2010 return 1;
2011
2012 while (fuel) {
2013 switch (SCHEME_TYPE(expr)) {
2014 case scheme_ir_local_type:
2015 case scheme_local_type:
2016 case scheme_local_unbox_type:
2017 case scheme_ir_toplevel_type:
2018 return 1;
2019 break;
2020 case scheme_application_type:
2021 {
2022 Scheme_App_Rec *app = (Scheme_App_Rec *)expr;
2023 return single_valued_noncm_function(app->args[0], app->num_args, info, s_v, non_cm);
2024 }
2025 break;
2026 case scheme_application2_type:
2027 {
2028 Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr;
2029 return single_valued_noncm_function(app->rator, 1, info, s_v, non_cm);
2030 }
2031 break;
2032 case scheme_application3_type:
2033 {
2034 Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr;
2035 return single_valued_noncm_function(app->rator, 2, info, s_v, non_cm);
2036 }
2037 break;
2038 case scheme_branch_type:
2039 {
2040 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr;
2041 return (do_single_valued_noncm_expression(b->tbranch, info, fuel - 1, s_v, non_cm)
2042 && do_single_valued_noncm_expression(b->fbranch, info, fuel - 1, s_v, non_cm));
2043 }
2044 break;
2045 case scheme_ir_let_header_type:
2046 {
2047 Scheme_IR_Let_Header *hl = (Scheme_IR_Let_Header *)expr;
2048 expr = hl->body;
2049 }
2050 break;
2051 case scheme_ir_let_value_type:
2052 {
2053 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)expr;
2054 expr = lv->body;
2055 }
2056 break;
2057 case scheme_sequence_type:
2058 {
2059 Scheme_Sequence *seq = (Scheme_Sequence *)expr;
2060 expr = seq->array[seq->count-1];
2061 }
2062 break;
2063 case scheme_begin0_sequence_type:
2064 {
2065 Scheme_Sequence *seq = (Scheme_Sequence *)expr;
2066 expr = seq->array[0];
2067 }
2068 break;
2069 case scheme_with_cont_mark_type:
2070 {
2071 Scheme_With_Continuation_Mark * wcm = (Scheme_With_Continuation_Mark *)expr;
2072 if (non_cm) {
2073 /* To avoid being sensitive to tail position, the body must not inspect
2074 the continuation at all. */
2075 return scheme_omittable_expr(wcm->body, s_v ? 1 : -1, 5, 0, NULL, NULL);
2076 } else {
2077 expr = wcm->body;
2078 }
2079 }
2080 break;
2081 case scheme_ir_lambda_type:
2082 case scheme_case_lambda_sequence_type:
2083 case scheme_set_bang_type:
2084 return 1;
2085 break;
2086 default:
2087 if (SCHEME_TYPE(expr) > _scheme_ir_values_types_)
2088 return 1;
2089 break;
2090 }
2091 fuel--;
2092 }
2093
2094 return 0;
2095 }
2096
single_valued_noncm_expression(Scheme_Object * expr,Optimize_Info * info,int fuel)2097 static int single_valued_noncm_expression(Scheme_Object *expr, Optimize_Info *info, int fuel)
2098 {
2099 return do_single_valued_noncm_expression(expr, info, fuel, 1, 1);
2100 }
2101
single_valued_expression(Scheme_Object * expr,Optimize_Info * info,int fuel)2102 static int single_valued_expression(Scheme_Object *expr, Optimize_Info *info, int fuel)
2103 {
2104 return do_single_valued_noncm_expression(expr, info, fuel, 1, 0);
2105 }
2106
noncm_expression(Scheme_Object * expr,Optimize_Info * info,int fuel)2107 static int noncm_expression(Scheme_Object *expr, Optimize_Info *info, int fuel)
2108 {
2109 return do_single_valued_noncm_expression(expr, info, fuel, 0, 1);
2110 }
2111
is_movable_prim(Scheme_Object * rator,int n,int cross_lambda,int cross_k,Optimize_Info * info)2112 static int is_movable_prim(Scheme_Object *rator, int n, int cross_lambda, int cross_k, Optimize_Info *info)
2113 /* Can we move a call to `rator` relative to other function calls?
2114 A -1 return means that the arguments must be movable without
2115 changing space complexity (which is the case for `cons`, for example). */
2116 {
2117 if (rator && SCHEME_PRIMP(rator)) {
2118 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL) {
2119 /* Although it's semantically ok to return -1 even when cross_lambda,
2120 doing so risks duplicating a computation if the relevant `lambda'
2121 is later inlined. */
2122 if (cross_lambda) return 0;
2123 if (cross_k
2124 && !(SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONALLOCATE)
2125 && (produces_local_type(rator, n) != SCHEME_LOCAL_TYPE_FIXNUM)) {
2126 return 0;
2127 }
2128 return -1;
2129 }
2130 }
2131
2132 if (SAME_OBJ(scheme_void_proc, rator))
2133 return -1;
2134
2135 if (!cross_lambda
2136 && !cross_k /* because all calls below allocate */
2137 /* Note that none of these have space-safety issues, since they
2138 return values that contain all arguments: */
2139 && (SAME_OBJ(scheme_list_proc, rator)
2140 || (SAME_OBJ(scheme_cons_proc, rator) && (n == 2))
2141 || (SAME_OBJ(scheme_mcons_proc, rator) && (n == 2))
2142 || (SAME_OBJ(scheme_unsafe_cons_list_proc, rator) && (n == 2))
2143 || SAME_OBJ(scheme_list_star_proc, rator)
2144 || SAME_OBJ(scheme_vector_proc, rator)
2145 || SAME_OBJ(scheme_vector_immutable_proc, rator)
2146 || (SAME_OBJ(scheme_box_proc, rator) && (n == 1))
2147 || (SAME_OBJ(scheme_box_immutable_proc, rator) && (n == 1))))
2148 return 1;
2149
2150 return 0;
2151 }
2152
movable_expression(Scheme_Object * expr,Optimize_Info * info,int cross_lambda,int cross_k,int cross_s,int check_space,int fuel)2153 static int movable_expression(Scheme_Object *expr, Optimize_Info *info,
2154 int cross_lambda, int cross_k, int cross_s,
2155 int check_space, int fuel)
2156 /* A movable expression can't necessarily be constant-folded,
2157 but can be delayed because it has no side-effects (or is unsafe),
2158 produces a single value,
2159 and is not sensitive to being in tail position */
2160 {
2161 int can_move;
2162
2163 if (fuel < 0) return 0;
2164
2165 switch (SCHEME_TYPE(expr)) {
2166 case scheme_toplevel_type:
2167 case scheme_static_toplevel_type:
2168 return ((SCHEME_TOPLEVEL_FLAGS(expr) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_FIXED);
2169 case scheme_ir_local_type:
2170 {
2171 /* Ok if not mutable */
2172 if (!SCHEME_VAR(expr)->mutated) {
2173 if (check_space) {
2174 if (SCHEME_VAR(expr)->val_type)
2175 return 1;
2176 /* the value of the identifier might be something that would
2177 retain significant memory, so we can't delay evaluation */
2178 return 0;
2179 }
2180 return 1;
2181 }
2182 }
2183 break;
2184 case scheme_application_type:
2185 if (!cross_lambda
2186 && !cross_k
2187 && (SCHEME_APPN_FLAGS((Scheme_App_Rec *)expr) & APPN_FLAG_OMITTABLE))
2188 can_move = -1;
2189 else
2190 can_move = is_movable_prim(((Scheme_App_Rec *)expr)->args[0], ((Scheme_App_Rec *)expr)->num_args,
2191 cross_lambda, cross_k, info);
2192 if (can_move) {
2193 int i;
2194 for (i = ((Scheme_App_Rec *)expr)->num_args; i--; ) {
2195 if (!movable_expression(((Scheme_App_Rec *)expr)->args[i+1], info,
2196 cross_lambda, cross_k, cross_s,
2197 check_space || (cross_s && (can_move < 0)), fuel - 1))
2198 return 0;
2199 }
2200 return 1;
2201 }
2202 break;
2203 case scheme_application2_type:
2204 if (!cross_lambda
2205 && !cross_k
2206 && (SCHEME_APPN_FLAGS((Scheme_App2_Rec *)expr) & APPN_FLAG_OMITTABLE))
2207 can_move = -1;
2208 else
2209 can_move = is_movable_prim(((Scheme_App2_Rec *)expr)->rator, 1, cross_lambda, cross_k, info);
2210 if (can_move) {
2211 if (movable_expression(((Scheme_App2_Rec *)expr)->rand, info,
2212 cross_lambda, cross_k, cross_s,
2213 check_space || (cross_s && (can_move < 0)), fuel - 1))
2214 return 1;
2215 }
2216 break;
2217 case scheme_application3_type:
2218 if (!cross_lambda
2219 && !cross_k
2220 && (SCHEME_APPN_FLAGS((Scheme_App3_Rec *)expr) & APPN_FLAG_OMITTABLE))
2221 can_move = -1;
2222 else
2223 can_move = is_movable_prim(((Scheme_App3_Rec *)expr)->rator, 2, cross_lambda, cross_k, info);
2224 if (can_move) {
2225 if (movable_expression(((Scheme_App3_Rec *)expr)->rand1, info,
2226 cross_lambda, cross_k, cross_s,
2227 check_space || (cross_s && (can_move < 0)), fuel - 1)
2228 && movable_expression(((Scheme_App3_Rec *)expr)->rand2, info,
2229 cross_lambda, cross_k, cross_s,
2230 check_space || (cross_s && (can_move < 0)), fuel - 1))
2231 return 1;
2232 }
2233 break;
2234 case scheme_branch_type:
2235 {
2236 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr;
2237 if (movable_expression(b->test, info, cross_lambda, cross_k, cross_s, check_space, fuel-1)
2238 /* Check space for branches if cross_s, because evaluating `if` eliminates one of them */
2239 && movable_expression(b->tbranch, info, cross_lambda, cross_k, cross_s, check_space || cross_s, fuel-1)
2240 && movable_expression(b->fbranch, info, cross_lambda, cross_k, cross_s, check_space || cross_s, fuel-1))
2241 return 1;
2242 }
2243 break;
2244 case scheme_ir_lambda_type:
2245 case scheme_case_lambda_sequence_type:
2246 /* Can't move across lambda or continuation if not closed, since
2247 that changes allocation of a closure (i.e., might allocate the
2248 closure multiple times). */
2249 return !cross_lambda && !cross_k;
2250 default:
2251 if (SCHEME_TYPE(expr) > _scheme_ir_values_types_)
2252 return 1;
2253 }
2254
2255 return 0;
2256 }
2257
scheme_is_ir_lambda(Scheme_Object * o,int can_be_closed,int can_be_liftable)2258 int scheme_is_ir_lambda(Scheme_Object *o, int can_be_closed, int can_be_liftable)
2259 {
2260 if (SAME_TYPE(SCHEME_TYPE(o), scheme_ir_lambda_type)) {
2261 if (!can_be_closed || !can_be_liftable) {
2262 Scheme_Lambda *lam;
2263 lam = (Scheme_Lambda *)o;
2264 /* Because == 0 is like a constant */
2265 if (!can_be_closed && !lam->closure_size)
2266 return 0;
2267 /* Because procs that reference only globals are lifted: */
2268 if (!can_be_liftable && (lam->closure_size == 1) && lambda_has_top_level(lam))
2269 return 0;
2270 }
2271 return 1;
2272 } else
2273 return 0;
2274 }
2275
small_inline_number(Scheme_Object * o)2276 XFORM_NONGCING static int small_inline_number(Scheme_Object *o)
2277 {
2278 if (SCHEME_BIGNUMP(o))
2279 return SCHEME_BIGLEN(o) < 32;
2280 else if (SCHEME_COMPLEXP(o))
2281 return (small_inline_number(scheme_complex_real_part(o))
2282 && small_inline_number(scheme_complex_imaginary_part(o)));
2283 else if (SCHEME_RATIONALP(o))
2284 return (small_inline_number(scheme_rational_numerator(o))
2285 && small_inline_number(scheme_rational_denominator(o)));
2286 else
2287 return 1;
2288 }
2289
2290 #define STR_INLINE_LIMIT 256
2291
scheme_ir_duplicate_ok(Scheme_Object * fb,int cross_linklet)2292 int scheme_ir_duplicate_ok(Scheme_Object *fb, int cross_linklet)
2293 /* Is the constant a value that we can "copy" in the code? */
2294 {
2295 return (SCHEME_VOIDP(fb)
2296 || SAME_OBJ(fb, scheme_true)
2297 || SAME_OBJ(fb, scheme_undefined)
2298 || SCHEME_FALSEP(fb)
2299 || (SCHEME_SYMBOLP(fb)
2300 && (!cross_linklet || (!SCHEME_SYM_WEIRDP(fb)
2301 && (SCHEME_SYM_LEN(fb) < STR_INLINE_LIMIT))))
2302 || (SCHEME_KEYWORDP(fb)
2303 && (!cross_linklet || (SCHEME_KEYWORD_LEN(fb) < STR_INLINE_LIMIT)))
2304 || SCHEME_EOFP(fb)
2305 || SCHEME_INTP(fb)
2306 || SCHEME_NULLP(fb)
2307 || (SCHEME_HASHTRP(fb) && !((Scheme_Hash_Tree *)fb)->count)
2308 || (!cross_linklet && SAME_TYPE(SCHEME_TYPE(fb), scheme_ir_toplevel_type))
2309 || (!cross_linklet && SAME_TYPE(SCHEME_TYPE(fb), scheme_ir_local_type))
2310 || SCHEME_PRIMP(fb)
2311 /* Values that are hashed by the printer and/or interned on
2312 read to avoid duplication: */
2313 || SCHEME_CHARP(fb)
2314 || (SCHEME_CHAR_STRINGP(fb)
2315 && (!cross_linklet || (SCHEME_CHAR_STRLEN_VAL(fb) < STR_INLINE_LIMIT)))
2316 || (SCHEME_BYTE_STRINGP(fb)
2317 && (!cross_linklet || (SCHEME_BYTE_STRLEN_VAL(fb) < STR_INLINE_LIMIT)))
2318 || SAME_TYPE(SCHEME_TYPE(fb), scheme_regexp_type)
2319 || (SCHEME_NUMBERP(fb)
2320 && (!cross_linklet || small_inline_number(fb)))
2321 || SAME_TYPE(SCHEME_TYPE(fb), scheme_ctype_type));
2322 }
2323
2324 /*========================================================================*/
2325 /* applications, branches, sequences */
2326 /*========================================================================*/
2327
2328 static Scheme_Object *finish_optimize_application(Scheme_App_Rec *app, Optimize_Info *info, int context);
2329 static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimize_Info *info, int context);
2330 static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimize_Info *info, int context);
2331
try_optimize_fold(Scheme_Object * f,Scheme_Object * args,Scheme_Object * o,Optimize_Info * info)2332 static Scheme_Object *try_optimize_fold(Scheme_Object *f, Scheme_Object *args, Scheme_Object *o, Optimize_Info *info)
2333 /* If `args` is NULL, extract arguments from `o` */
2334 {
2335 if (scheme_is_foldable_prim(f)) {
2336
2337 if (!args) {
2338 switch (SCHEME_TYPE(o)) {
2339 case scheme_application_type:
2340 {
2341 Scheme_App_Rec *app = (Scheme_App_Rec *)o;
2342 int i;
2343
2344 args = scheme_null;
2345 for (i = app->num_args; i--; ) {
2346 args = scheme_make_pair(app->args[i + 1], args);
2347 }
2348 }
2349 break;
2350 case scheme_application2_type:
2351 {
2352 Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
2353 args = scheme_make_pair(app->rand, scheme_null);
2354 }
2355 break;
2356 case scheme_application3_type:
2357 default:
2358 {
2359 Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
2360 args = scheme_make_pair(app->rand1,
2361 scheme_make_pair(app->rand2,
2362 scheme_null));
2363 }
2364 break;
2365 }
2366 }
2367
2368 return scheme_try_apply(f, args, info);
2369 }
2370
2371 return NULL;
2372 }
2373
estimate_expr_size(Scheme_Object * expr,int sz,int fuel)2374 static int estimate_expr_size(Scheme_Object *expr, int sz, int fuel)
2375 {
2376 Scheme_Type t;
2377
2378 if (sz > 128)
2379 return sz;
2380 if (fuel < 0)
2381 return sz + 128;
2382
2383 t = SCHEME_TYPE(expr);
2384
2385 switch(t) {
2386 case scheme_ir_local_type:
2387 {
2388 sz += 1;
2389 break;
2390 }
2391 case scheme_case_lambda_sequence_type:
2392 {
2393 int max_sz = sz + 1, a_sz;
2394 Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)expr;
2395 int i;
2396 for (i = cl->count; i--; ) {
2397 a_sz = estimate_expr_size(cl->array[i], sz, fuel);
2398 if (a_sz > max_sz) max_sz = a_sz;
2399 }
2400 sz = max_sz;
2401 }
2402 break;
2403 case scheme_application2_type:
2404 {
2405 Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr;
2406
2407 sz = estimate_expr_size(app->rator, sz, fuel - 1);
2408 sz = estimate_expr_size(app->rand, sz, fuel - 1);
2409 sz++;
2410
2411 break;
2412 }
2413 case scheme_application_type:
2414 {
2415 Scheme_App_Rec *app = (Scheme_App_Rec *)expr;
2416 int i;
2417
2418 for (i = app->num_args + 1; i--; ) {
2419 sz = estimate_expr_size(app->args[i], sz, fuel - 1);
2420 }
2421 sz++;
2422
2423 break;
2424 }
2425 case scheme_application3_type:
2426 {
2427 Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr;
2428
2429 sz = estimate_expr_size(app->rator, sz, fuel - 1);
2430 sz = estimate_expr_size(app->rand1, sz, fuel - 1);
2431 sz = estimate_expr_size(app->rand2, sz, fuel - 1);
2432 sz++;
2433
2434 break;
2435 }
2436 case scheme_ir_let_header_type:
2437 {
2438 Scheme_IR_Let_Header *head = (Scheme_IR_Let_Header *)expr;
2439 Scheme_Object *body;
2440 Scheme_IR_Let_Value *lv;
2441 int i;
2442
2443 body = head->body;
2444 for (i = head->num_clauses; i--; ) {
2445 lv = (Scheme_IR_Let_Value *)body;
2446 sz = estimate_expr_size(lv->value, sz, fuel - 1);
2447 body = lv->body;
2448 sz++;
2449 }
2450 sz = estimate_expr_size(body, sz, fuel - 1);
2451 break;
2452 }
2453 case scheme_sequence_type:
2454 case scheme_begin0_sequence_type:
2455 {
2456 Scheme_Sequence *seq = (Scheme_Sequence *)expr;
2457 int i;
2458
2459 for (i = seq->count; i--; ) {
2460 sz = estimate_expr_size(seq->array[i], sz, fuel - 1);
2461 }
2462
2463 break;
2464 }
2465 case scheme_branch_type:
2466 {
2467 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr;
2468
2469 sz = estimate_expr_size(b->test, sz, fuel - 1);
2470 sz = estimate_expr_size(b->tbranch, sz, fuel - 1);
2471 sz = estimate_expr_size(b->fbranch, sz, fuel - 1);
2472 break;
2473 }
2474 case scheme_ir_lambda_type:
2475 {
2476 sz = estimate_expr_size(((Scheme_Lambda *)expr)->body, sz, fuel - 1);
2477 sz++;
2478 break;
2479 }
2480 case scheme_ir_toplevel_type:
2481 /* FIXME: other syntax types not covered */
2482 default:
2483 sz += 1;
2484 break;
2485 }
2486
2487 return sz;
2488 }
2489
estimate_closure_size(Scheme_Object * e)2490 static Scheme_Object *estimate_closure_size(Scheme_Object *e)
2491 {
2492 Scheme_Object *wbl;
2493 int sz;
2494 sz = estimate_expr_size(e, 0, 32);
2495
2496 wbl = scheme_alloc_object();
2497 wbl->type = scheme_will_be_lambda_type;
2498 SCHEME_WILL_BE_LAMBDA_SIZE(wbl) = sz;
2499 SCHEME_WILL_BE_LAMBDA(wbl) = e;
2500
2501 return wbl;
2502 }
2503
no_potential_size(Scheme_Object * v)2504 static Scheme_Object *no_potential_size(Scheme_Object *v)
2505 {
2506 if (v && SCHEME_WILL_BE_LAMBDAP(v))
2507 return NULL;
2508 else
2509 return v;
2510 }
2511
apply_inlined(Scheme_Lambda * lam,Optimize_Info * info,int argc,Scheme_App_Rec * app,Scheme_App2_Rec * app2,Scheme_App3_Rec * app3,int context,Scheme_Object * orig,Scheme_Object * le_prev,int single_use)2512 static Scheme_Object *apply_inlined(Scheme_Lambda *lam, Optimize_Info *info,
2513 int argc, Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3,
2514 int context, Scheme_Object *orig, Scheme_Object *le_prev,
2515 int single_use)
2516 /* Optimize the body of `lam` given the known arguments in `app`, `app2`, or `app3` */
2517 {
2518 Scheme_IR_Let_Header *lh;
2519 Scheme_IR_Let_Value *lv, *prev = NULL;
2520 Scheme_Object *val;
2521 int i, expected;
2522 Optimize_Info *sub_info;
2523 Scheme_IR_Local **vars;
2524 Scheme_Object *p = lam->body;
2525
2526 expected = lam->num_params;
2527
2528 if (!expected) {
2529 /* No arguments, so no need for a `let` wrapper: */
2530 sub_info = optimize_info_add_frame(info, 0);
2531 if (!single_use || lam->ir_info->is_dup)
2532 sub_info->inline_fuel >>= 1;
2533 p = optimize_expr(p, sub_info, context);
2534 info->single_result = sub_info->single_result;
2535 info->preserves_marks = sub_info->preserves_marks;
2536 optimize_info_done(sub_info, NULL);
2537 merge_types(sub_info, info, NULL);
2538
2539 return replace_tail_inside(p, le_prev, orig);
2540 }
2541
2542 lh = MALLOC_ONE_TAGGED(Scheme_IR_Let_Header);
2543 lh->iso.so.type = scheme_ir_let_header_type;
2544 lh->count = expected;
2545 lh->num_clauses = expected;
2546
2547 for (i = 0; i < expected; i++) {
2548 lv = MALLOC_ONE_TAGGED(Scheme_IR_Let_Value);
2549 lv->iso.so.type = scheme_ir_let_value_type;
2550 lv->count = 1;
2551
2552 vars = MALLOC_N(Scheme_IR_Local*, 1);
2553 vars[0] = lam->ir_info->vars[i];
2554 lv->vars = vars;
2555
2556 if ((i == expected - 1)
2557 && (SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_HAS_REST)) {
2558 int j;
2559 Scheme_Object *l = scheme_null;
2560
2561 for (j = argc; j-- > i; ) {
2562 if (app)
2563 val = app->args[j + 1];
2564 else if (app3)
2565 val = (j ? app3->rand2 : app3->rand1);
2566 else if (app2)
2567 val = app2->rand;
2568 else
2569 val = scheme_false;
2570
2571 l = scheme_make_pair(val, l);
2572 }
2573 l = scheme_make_pair(scheme_list_proc, l);
2574 val = scheme_make_application(l, info);
2575 } else if (app)
2576 val = app->args[i + 1];
2577 else if (app3)
2578 val = (i ? app3->rand2 : app3->rand1);
2579 else
2580 val = app2->rand;
2581
2582 lv->value = val;
2583
2584 if (prev)
2585 prev->body = (Scheme_Object *)lv;
2586 else
2587 lh->body = (Scheme_Object *)lv;
2588 prev = lv;
2589 }
2590
2591 if (prev)
2592 prev->body = p;
2593 else
2594 lh->body = p;
2595
2596 sub_info = optimize_info_add_frame(info, 0);
2597 if (!single_use || lam->ir_info->is_dup)
2598 sub_info->inline_fuel >>= 1;
2599
2600 p = optimize_lets((Scheme_Object *)lh, sub_info, context);
2601
2602 info->single_result = sub_info->single_result;
2603 info->preserves_marks = sub_info->preserves_marks;
2604 optimize_info_done(sub_info, NULL);
2605 merge_types(sub_info, info, NULL);
2606
2607 return replace_tail_inside(p, le_prev, orig);
2608 }
2609
scheme_check_leaf_rator(Scheme_Object * le)2610 int scheme_check_leaf_rator(Scheme_Object *le)
2611 {
2612 if (le && SCHEME_PRIMP(le)) {
2613 int opt;
2614 opt = ((Scheme_Prim_Proc_Header *)le)->flags & SCHEME_PRIM_OPT_MASK;
2615 if (opt >= SCHEME_PRIM_OPT_IMMEDIATE)
2616 return 1;
2617 }
2618 return 0;
2619 }
2620
get_rator_flags(Scheme_Object * rator,int num_args,Optimize_Info * info)2621 static int get_rator_flags(Scheme_Object *rator, int num_args, Optimize_Info *info)
2622 {
2623 rator = lookup_constant_proc(info, rator, num_args);
2624 if (!rator) {
2625 return 0;
2626 } else if (SAME_OBJ(rator, scheme_true)) {
2627 /* wrong arity */
2628 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2629 } else if (SAME_TYPE(SCHEME_TYPE(rator), scheme_struct_proc_shape_type)) {
2630 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2631 } else if (SAME_TYPE(SCHEME_TYPE(rator), scheme_struct_prop_proc_shape_type)) {
2632 switch (SCHEME_PROP_PROC_SHAPE_MODE(rator)) {
2633 case STRUCT_PROP_PROC_SHAPE_PRED:
2634 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2635 case STRUCT_PROP_PROC_SHAPE_GETTER:
2636 if (num_args == 1)
2637 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2638 }
2639 } else if (SCHEME_PRIMP(rator)) {
2640 int opt;
2641 /* special cases for values */
2642 if (SAME_OBJ(rator, scheme_values_proc) && num_args == 1) {
2643 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2644 }
2645 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_ALWAYS_ESCAPES) {
2646 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2647 }
2648 opt = ((Scheme_Prim_Proc_Header *)rator)->flags & SCHEME_PRIM_OPT_MASK;
2649 if (opt >= SCHEME_PRIM_OPT_NONCM) {
2650 return (LAMBDA_PRESERVES_MARKS | LAMBDA_SINGLE_RESULT);
2651 }
2652 } else if (SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_lambda_type)) {
2653 Scheme_Lambda *lam = (Scheme_Lambda *)rator;
2654 return SCHEME_LAMBDA_FLAGS(lam);
2655 }
2656 return 0;
2657 }
2658
check_single_use(Scheme_Object * var)2659 int check_single_use(Scheme_Object *var)
2660 {
2661 Scheme_IR_Local *v = SCHEME_VAR(var);
2662
2663 return ((v->use_count == 1)
2664 /* If we're outside the binding, then the binding
2665 itself will remain as a used: */
2666 && !v->optimize_outside_binding
2667 /* To help avoid infinite unrolling,
2668 don't count a self use as "single" use. */
2669 && !v->optimize_unready);
2670 }
2671
check_potential_size(Scheme_Object * var)2672 int check_potential_size(Scheme_Object *var)
2673 {
2674 Scheme_Object* n;
2675
2676 n = SCHEME_VAR(var)->optimize.known_val;
2677 if (n && SCHEME_WILL_BE_LAMBDAP(n)) {
2678 return SCHEME_WILL_BE_LAMBDA_SIZE(n);
2679 }
2680
2681 return 0;
2682 }
2683
do_lookup_constant_proc(Optimize_Info * info,Scheme_Object * le,int argc,int for_inline,int for_props,int * _single_use,Scheme_Object ** _single_use_var)2684 Scheme_Object *do_lookup_constant_proc(Optimize_Info *info, Scheme_Object *le,
2685 int argc, int for_inline, int for_props,
2686 int *_single_use, Scheme_Object **_single_use_var)
2687 /* Return a known procedure, if any.
2688 When argc == -1, the result may be a case-lambda or `scheme_constant_key`;
2689 otherwise, unless `for_props`, the arity is used to split a case-lambda to extact
2690 the relevant lambda, and if the arity is wrong, the result is `scheme_true`.
2691 If `for_inline`, the result may be a potential size, otherwise this function
2692 goes inside potential sizes, noinline procedures, lets, begins and other construction,
2693 so the result can't be inlined and must be used only to get the properties
2694 of the actual procedure. */
2695 {
2696 Scheme_Object *prev = NULL;
2697
2698 *_single_use = 0;
2699
2700 /* Move inside `let' bindings to get the inner procedure */
2701 if (!for_inline)
2702 extract_tail_inside(&le, &prev, 0);
2703
2704 le = extract_specialized_proc(le, le);
2705
2706 if (SCHEME_LAMBDAP(le)) {
2707 /* Found a `((lambda' */
2708 *_single_use = 1;
2709 }
2710
2711 if (SAME_TYPE(SCHEME_TYPE(le), scheme_ir_local_type)) {
2712 int tmp;
2713 tmp = check_single_use(le);
2714 *_single_use = tmp;
2715 if (tmp)
2716 *_single_use_var = le;
2717 if ((SCHEME_VAR(le)->mode != SCHEME_VAR_MODE_OPTIMIZE)) {
2718 /* We got a local that is bound in a let that is not yet optimized. */
2719 return NULL;
2720 }
2721 le = SCHEME_VAR(le)->optimize.known_val;
2722 if (!le)
2723 return NULL;
2724 }
2725
2726 if (SAME_TYPE(SCHEME_TYPE(le), scheme_ir_toplevel_type)) {
2727 Scheme_Object *inl;
2728 *_single_use = 0;
2729 do {
2730 inl = get_import_inline(info, (Scheme_IR_Toplevel *)le, argc, for_props);
2731 if ((argc < 0) && SAME_OBJ(inl, scheme_constant_key))
2732 return inl;
2733 if (!inl) inl = get_defn_shape(info, (Scheme_IR_Toplevel *)le);
2734 if (inl) le = inl;
2735 } while (inl && SAME_TYPE(SCHEME_TYPE(le), scheme_ir_toplevel_type));
2736 }
2737
2738 if (SCHEME_WILL_BE_LAMBDAP(le)) {
2739 if (for_inline)
2740 return le;
2741 else
2742 le = SCHEME_WILL_BE_LAMBDA(le);
2743 }
2744
2745 if (!for_inline && SAME_TYPE(scheme_noninline_proc_type, SCHEME_TYPE(le))) {
2746 le = SCHEME_BOX_VAL(le);
2747 }
2748
2749 if (SAME_TYPE(SCHEME_TYPE(le), scheme_struct_proc_shape_type)) {
2750 int ok_arity;
2751 switch (SCHEME_PROC_SHAPE_MODE(le) & STRUCT_PROC_SHAPE_MASK) {
2752 case STRUCT_PROC_SHAPE_CONSTR:
2753 ok_arity = (argc == (SCHEME_PROC_SHAPE_MODE(le) >> STRUCT_PROC_SHAPE_SHIFT));
2754 break;
2755 case STRUCT_PROC_SHAPE_PRED:
2756 ok_arity = (argc == 1);
2757 break;
2758 case STRUCT_PROC_SHAPE_GETTER:
2759 ok_arity = (argc == 1);
2760 break;
2761 case STRUCT_PROC_SHAPE_SETTER:
2762 ok_arity = (argc == 2);
2763 break;
2764 default:
2765 return NULL;
2766 }
2767 if (ok_arity || (argc == -1)) {
2768 return for_inline ? NULL : le;
2769 } else if (for_props)
2770 return le;
2771 else
2772 return scheme_true;
2773 }
2774
2775 if (SAME_TYPE(SCHEME_TYPE(le), scheme_struct_prop_proc_shape_type)) {
2776 int ok_arity;
2777 switch (SCHEME_PROP_PROC_SHAPE_MODE(le)) {
2778 case STRUCT_PROP_PROC_SHAPE_PRED:
2779 ok_arity = (argc == 1);
2780 break;
2781 case STRUCT_PROP_PROC_SHAPE_GETTER:
2782 ok_arity = (argc == 1) || (argc == 2);
2783 break;
2784 default:
2785 return NULL;
2786 }
2787 if (ok_arity || (argc == -1)) {
2788 return for_inline ? NULL : le;
2789 } else if (for_props)
2790 return le;
2791 else
2792 return scheme_true;
2793 }
2794
2795 if (SAME_TYPE(SCHEME_TYPE(le), scheme_case_lambda_sequence_type)) {
2796 Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)le;
2797 Scheme_Object *cp;
2798 int i, count;
2799
2800 if ((argc == -1) || for_props)
2801 return le;
2802
2803 count = cl->count;
2804 for (i = 0; i < count; i++) {
2805 cp = cl->array[i];
2806 if (SAME_TYPE(SCHEME_TYPE(cp), scheme_ir_lambda_type)) {
2807 Scheme_Lambda *lam = (Scheme_Lambda *)cp;
2808 if ((lam->num_params == argc)
2809 || ((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_HAS_REST)
2810 && (argc + 1 >= lam->num_params))) {
2811 return cp;
2812 }
2813 } else {
2814 scheme_signal_error("internal error: strange case-lambda");
2815 }
2816 }
2817 if (i >= count) {
2818 return scheme_true;
2819 }
2820 }
2821
2822 if (SAME_TYPE(SCHEME_TYPE(le), scheme_ir_lambda_type)) {
2823 Scheme_Lambda *lam = (Scheme_Lambda *)le;
2824
2825 if ((argc == -1) || for_props)
2826 return le;
2827
2828 if ((lam->num_params == argc)
2829 || ((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_HAS_REST)
2830 && (argc + 1 >= lam->num_params))) {
2831 return le;
2832 } else {
2833 return scheme_true;
2834 }
2835 }
2836
2837 if (SCHEME_PROCP(le)) {
2838 Scheme_Object *a[1];
2839
2840 if ((argc == -1) || for_props)
2841 return le;
2842
2843 a[0] = le;
2844 if (scheme_check_proc_arity(NULL, argc, 0, 1, a))
2845 return le;
2846 else
2847 return scheme_true;
2848 }
2849
2850 if (for_props
2851 && le
2852 && (SAME_TYPE(SCHEME_TYPE(le), scheme_lambda_type)
2853 || SAME_TYPE(SCHEME_TYPE(le), scheme_case_lambda_sequence_type)))
2854 return le;
2855
2856 return NULL;
2857 }
2858
lookup_constant_proc(Optimize_Info * info,Scheme_Object * le,int argc)2859 Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *le, int argc)
2860 {
2861 int single_use = 0;
2862 Scheme_Object *single_use_var;
2863 return do_lookup_constant_proc(info, le, argc, 0, 0, &single_use, &single_use_var);
2864 }
2865
2866 #if 0
2867 # define LOG_INLINE(x) x
2868 #else
2869 # define LOG_INLINE(x) /*empty*/
2870 #endif
2871
optimize_for_inline(Optimize_Info * info,Scheme_Object * le,int argc,Scheme_App_Rec * app,Scheme_App2_Rec * app2,Scheme_App3_Rec * app3,int context,int optimized_rator)2872 Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int argc,
2873 Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3,
2874 int context, int optimized_rator)
2875 /* One of app, app2 and app3 should be non-NULL.
2876 If app, we're inlining a general application. If app2, we're inlining an
2877 application with a single argument and if app3, we're inlining an
2878 application with two arguments. */
2879 {
2880 int single_use = 0, psize = 0;
2881 Scheme_Object *prev = NULL, *orig_le = le, *le2, *single_use_var = NULL;
2882 int already_opt = optimized_rator;
2883
2884 if ((info->inline_fuel < 0) && info->has_nonleaf)
2885 return NULL;
2886
2887 /* Move inside `let' bindings, so we can convert ((let (....) proc) arg ...)
2888 to (let (....) (proc arg ...)) */
2889 if (already_opt)
2890 extract_tail_inside(&le, &prev, 0);
2891
2892 le = extract_specialized_proc(le, le);
2893
2894 if (!already_opt
2895 && SCHEME_LAMBDAP(le)) {
2896 /* We have an immediate `lambda' that wasn't optimized, yet.
2897 Go optimize it, first. */
2898 return NULL;
2899 }
2900
2901 le2 = le;
2902 le = do_lookup_constant_proc(info, le, argc, 1, 0, &single_use, &single_use_var);
2903
2904 if (!le) {
2905 info->has_nonleaf = 1;
2906 return NULL;
2907 }
2908
2909 if (SCHEME_WILL_BE_LAMBDAP(le)) {
2910 psize = SCHEME_WILL_BE_LAMBDA_SIZE(le);
2911 LOG_INLINE(fprintf(stderr, "Potential inline %d %d\n", psize, info->inline_fuel * (argc + 2)));
2912 /* If we inline, the enclosing function will get larger, so we increase
2913 its potential size. */
2914 if (psize <= (info->inline_fuel * (argc + 2)))
2915 info->psize += psize;
2916 info->has_nonleaf = 1;
2917 return NULL;
2918 }
2919
2920 if (SAME_OBJ(le, scheme_true)) {
2921 /* wrong arity */
2922 int len;
2923 const char *pname = NULL, *context;
2924 info->escapes = 1;
2925 le2 = do_lookup_constant_proc(info, le2, argc, 1, 1, &single_use, &single_use_var);
2926 if (!SAME_TYPE(SCHEME_TYPE(le2), scheme_struct_proc_shape_type)
2927 && !SAME_TYPE(SCHEME_TYPE(le2), scheme_struct_prop_proc_shape_type)){
2928 pname = scheme_get_proc_name(le2, &len, 0);
2929 }
2930 context = scheme_optimize_context_to_string(info->context);
2931 scheme_log(info->logger,
2932 SCHEME_LOG_WARNING,
2933 0,
2934 "warning%s: optimizer detects procedure incorrectly applied to %d arguments%s%s",
2935 context,
2936 argc,
2937 pname ? ": " : "",
2938 pname ? pname : "");
2939 return NULL;
2940 }
2941
2942 if (SAME_TYPE(SCHEME_TYPE(le), scheme_ir_lambda_type) && (info->inline_fuel >= 0)) {
2943 Scheme_Lambda *lam = (Scheme_Lambda *)le;
2944 int sz, threshold, is_leaf = 0;
2945
2946 sz = lambda_body_size_plus_info(lam, 1, info, &is_leaf);
2947 if (is_leaf) {
2948 /* encourage inlining of leaves: */
2949 sz >>= 2;
2950 }
2951 threshold = info->inline_fuel * (2 + argc);
2952
2953 /* Do we have enough fuel? */
2954 if ((sz >= 0) && (single_use || (sz <= threshold))) {
2955 Optimize_Info *sub_info;
2956 sub_info = info;
2957
2958 /* If optimize_clone succeeds, inlining succeeds. */
2959 le = optimize_clone(single_use, (Scheme_Object *)lam, sub_info, empty_eq_hash_tree, 0);
2960
2961 if (le) {
2962 LOG_INLINE(fprintf(stderr, "Inline %d[%d]<=%d@%d %d %s\n", sz, is_leaf, threshold, info->inline_fuel,
2963 single_use, scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL)));
2964 if (scheme_log_level_p(info->logger, SCHEME_LOG_DEBUG))
2965 scheme_log(info->logger,
2966 SCHEME_LOG_DEBUG,
2967 0,
2968 "inlining %s size: %d threshold: %d#<separator>%s",
2969 scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
2970 sz,
2971 threshold,
2972 scheme_optimize_context_to_string(info->context));
2973 if (single_use_var)
2974 SCHEME_VAR(single_use_var)->optimize_used = 0; /* just in case tentatively used */
2975 le = apply_inlined((Scheme_Lambda *)le, sub_info, argc, app, app2, app3, context,
2976 orig_le, prev, single_use);
2977 return le;
2978 } else {
2979 LOG_INLINE(fprintf(stderr, "No inline %s\n", scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL)));
2980 if (scheme_log_level_p(info->logger, SCHEME_LOG_DEBUG))
2981 scheme_log(info->logger,
2982 SCHEME_LOG_DEBUG,
2983 0,
2984 "no-inlining %s size: %d threshold: %d#<separator>%s",
2985 scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
2986 sz,
2987 threshold,
2988 scheme_optimize_context_to_string(info->context));
2989 }
2990 } else {
2991 LOG_INLINE(fprintf(stderr, "No fuel %s %d[%d]>%d@%d %d\n", scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
2992 sz, is_leaf, threshold,
2993 info->inline_fuel, info->use_psize));
2994 if (scheme_log_level_p(info->logger, SCHEME_LOG_DEBUG))
2995 scheme_log(info->logger,
2996 SCHEME_LOG_DEBUG,
2997 0,
2998 "out-of-fuel %s size: %d threshold: %d#<separator>%s",
2999 scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
3000 sz,
3001 threshold,
3002 scheme_optimize_context_to_string(info->context));
3003 }
3004 }
3005
3006 if (!scheme_check_leaf_rator(le))
3007 info->has_nonleaf = 1;
3008
3009 return NULL;
3010 }
3011
is_local_type_expression(Scheme_Object * expr,Optimize_Info * info)3012 static int is_local_type_expression(Scheme_Object *expr, Optimize_Info *info)
3013 /* Get an unboxing type (e.g., flonum) for `expr` */
3014 {
3015 return scheme_predicate_to_local_type(expr_implies_predicate(expr, info));
3016 }
3017
register_local_argument_types(Scheme_App_Rec * app,Scheme_App2_Rec * app2,Scheme_App3_Rec * app3,Optimize_Info * info)3018 static void register_local_argument_types(Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3,
3019 Optimize_Info *info)
3020 /* If `rator` is a variable bound to a `lambda`, record the types of actual arguments
3021 provided in a function call. If all calls are consistent with unboxing, then the
3022 procedure will accept unboxed arguments at run time. */
3023 {
3024 Scheme_Object *rator, *rand, *le;
3025 int n, i, nth_app;
3026
3027 if (app) {
3028 rator = app->args[0];
3029 n = app->num_args;
3030 nth_app = SCHEME_APPN_FLAGS(app) & APPN_POSITION_MASK;
3031 } else if (app2) {
3032 rator = app2->rator;
3033 n = 1;
3034 nth_app = SCHEME_APPN_FLAGS(app2) & APPN_POSITION_MASK;
3035 } else {
3036 rator = app3->rator;
3037 n = 2;
3038 nth_app = SCHEME_APPN_FLAGS(app3) & APPN_POSITION_MASK;
3039 }
3040
3041 if (SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_local_type)) {
3042 le = optimize_info_lookup(rator);
3043 if (le && SCHEME_WILL_BE_LAMBDAP(le))
3044 le = SCHEME_WILL_BE_LAMBDA(le);
3045
3046 if (le && SAME_TYPE(SCHEME_TYPE(le), scheme_ir_lambda_type)) {
3047 Scheme_Lambda *lam = (Scheme_Lambda *)le;
3048 if ((lam->num_params == n)
3049 && !(SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_HAS_REST)) {
3050 Scheme_Object *pred;
3051
3052 if (!lam->ir_info->arg_types) {
3053 Scheme_Object **arg_types;
3054 short *contributors;
3055 arg_types = MALLOC_N(Scheme_Object*, n);
3056 lam->ir_info->arg_types = arg_types;
3057 contributors = MALLOC_N_ATOMIC(short, n);
3058 memset(contributors, 0, sizeof(short) * n);
3059 lam->ir_info->arg_type_contributors = contributors;
3060 }
3061
3062 for (i = 0; i < n; i++) {
3063 if (app)
3064 rand = app->args[i+1];
3065 else if (app2)
3066 rand = app2->rand;
3067 else {
3068 if (!i)
3069 rand = app3->rand1;
3070 else
3071 rand = app3->rand2;
3072 }
3073
3074 if (lam->ir_info->arg_types[i]
3075 || !lam->ir_info->arg_type_contributors[i]) {
3076 int widen_to_top = 0;
3077
3078 pred = expr_implies_predicate(rand, info);
3079
3080 if (pred) {
3081 if (!lam->ir_info->arg_type_contributors[i]) {
3082 lam->ir_info->arg_types[i] = pred;
3083 if (nth_app)
3084 lam->ir_info->arg_type_contributors[i] |= (1 << (nth_app-1));
3085 } else if (predicate_implies(pred, lam->ir_info->arg_types[i])) {
3086 /* ok */
3087 if (nth_app)
3088 lam->ir_info->arg_type_contributors[i] |= (1 << (nth_app-1));
3089 } else if (predicate_implies(lam->ir_info->arg_types[i], pred)) {
3090 /* widen */
3091 lam->ir_info->arg_types[i] = pred;
3092 if (nth_app)
3093 lam->ir_info->arg_type_contributors[i] |= (1 << (nth_app-1));
3094 } else
3095 widen_to_top = 1;
3096 } else
3097 widen_to_top = 1;
3098
3099 if (widen_to_top) {
3100 if (nth_app) {
3101 /* Since we cant provide a nice type right now, just
3102 don't check in, in case a future iteration provides
3103 better information. If we never check in with a type,
3104 it will count as widening in the end. */
3105 } else {
3106 /* since we don't have an identity, the lambda won't
3107 be able to tell whether all apps have checked in,
3108 so we have to registers a "top" as an anonymous
3109 contributor. */
3110 lam->ir_info->arg_type_contributors[i] |= (1 << (SCHEME_USE_COUNT_INF-1));
3111 lam->ir_info->arg_types[i] = NULL;
3112 }
3113 }
3114 }
3115 }
3116 }
3117 }
3118 }
3119 }
3120
reset_rator(Scheme_Object * app,Scheme_Object * a)3121 static void reset_rator(Scheme_Object *app, Scheme_Object *a)
3122 {
3123 switch (SCHEME_TYPE(app)) {
3124 case scheme_application_type:
3125 ((Scheme_App_Rec *)app)->args[0] = a;
3126 break;
3127 case scheme_application2_type:
3128 ((Scheme_App2_Rec *)app)->rator = a;
3129 break;
3130 case scheme_application3_type:
3131 ((Scheme_App3_Rec *)app)->rator = a;
3132 break;
3133 }
3134 }
3135
set_application_omittable(Scheme_Object * app,Scheme_Object * a)3136 static void set_application_omittable(Scheme_Object *app, Scheme_Object *a)
3137 {
3138 switch (SCHEME_TYPE(app)) {
3139 case scheme_application_type:
3140 SCHEME_APPN_FLAGS((Scheme_App_Rec *)app) |= APPN_FLAG_OMITTABLE;
3141 break;
3142 case scheme_application2_type:
3143 SCHEME_APPN_FLAGS((Scheme_App2_Rec *)app) |= APPN_FLAG_OMITTABLE;
3144 break;
3145 case scheme_application3_type:
3146 SCHEME_APPN_FLAGS((Scheme_App3_Rec *)app) |= APPN_FLAG_OMITTABLE;
3147 break;
3148 }
3149 }
3150
check_app_let_rator(Scheme_Object * app,Scheme_Object * rator,Optimize_Info * info,int argc,int context)3151 static Scheme_Object *check_app_let_rator(Scheme_Object *app, Scheme_Object *rator, Optimize_Info *info,
3152 int argc, int context)
3153 /* Convert ((let (....) E) arg ...) to (let (....) (E arg ...)) and
3154 ((begin .... E) arg ...) to (begin .... (E arg ...)), in case
3155 the `let' or `begin' is immediately apparent. We check for this
3156 pattern again in optimize_for_inline() after optimizing a rator. */
3157 {
3158 Scheme_Object *orig_rator = rator, *inside = NULL;
3159
3160 extract_tail_inside(&rator, &inside, 0);
3161
3162 if (!inside)
3163 return NULL;
3164
3165 /* Moving a variable into application position: */
3166 if (SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_local_type)) {
3167 Scheme_IR_Local *var = SCHEME_VAR(rator);
3168 if (var->non_app_count < SCHEME_USE_COUNT_INF)
3169 --var->non_app_count;
3170 }
3171
3172 reset_rator(app, rator);
3173 orig_rator = replace_tail_inside(app, inside, orig_rator);
3174
3175 return optimize_expr(orig_rator, info, context);
3176 }
3177
is_primitive_allocating(Scheme_Object * rator,int argc)3178 XFORM_NONGCING static int is_primitive_allocating(Scheme_Object *rator, int argc)
3179 {
3180 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_OMITABLE_ALLOCATION
3181 | SCHEME_PRIM_IS_ARITY_0_OMITABLE_ALLOCATION
3182 | SCHEME_PRIM_IS_EVEN_ARITY_OMITABLE_ALLOCATION))
3183 return scheme_is_omitable_primitive(rator, argc);
3184
3185 return 0;
3186 }
3187
is_nonmutating_nondependant_primitive(Scheme_Object * rator,int argc)3188 XFORM_NONGCING static int is_nonmutating_nondependant_primitive(Scheme_Object *rator, int argc)
3189 /* Does not include SCHEME_PRIM_IS_UNSAFE_OMITABLE, because those can
3190 depend on earlier tests (explicit or implicit) for whether the
3191 unsafe operation is defined */
3192 {
3193 if (SCHEME_PRIMP(rator)
3194 && (((SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_IS_OMITABLE)
3195 || is_primitive_allocating(rator, argc))
3196 && !(SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_UNSAFE_OMITABLE))
3197 && !((SAME_OBJ(scheme_values_proc, rator) && (argc != 1))))
3198 && (argc >= ((Scheme_Primitive_Proc *)rator)->mina)
3199 && (argc <= ((Scheme_Primitive_Proc *)rator)->mu.maxa))
3200 return 1;
3201
3202 return 0;
3203 }
3204
is_noncapturing_primitive(Scheme_Object * rator,int n)3205 XFORM_NONGCING static int is_noncapturing_primitive(Scheme_Object *rator, int n)
3206 {
3207 if (SCHEME_PRIMP(rator)) {
3208 int opt, t;
3209 opt = ((Scheme_Prim_Proc_Header *)rator)->flags & SCHEME_PRIM_OPT_MASK;
3210 if (opt >= SCHEME_PRIM_OPT_IMMEDIATE)
3211 return 1;
3212 if (opt >= SCHEME_PRIM_OPT_NONCM) {
3213 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_ALWAYS_ESCAPES) {
3214 /* even if a continuation is captured, it won't get back */
3215 return 1;
3216 }
3217 }
3218 t = (((Scheme_Primitive_Proc *)rator)->pp.flags & SCHEME_PRIM_OTHER_TYPE_MASK);
3219 if (!n && (t == SCHEME_PRIM_TYPE_PARAMETER))
3220 return 1;
3221 if (SAME_OBJ(rator, scheme_values_proc))
3222 return 1;
3223 }
3224
3225 return 0;
3226 }
3227
is_nonsaving_primitive(Scheme_Object * rator,int n)3228 XFORM_NONGCING static int is_nonsaving_primitive(Scheme_Object *rator, int n)
3229 {
3230 if (SCHEME_PRIMP(rator)) {
3231 int opt;
3232 opt = ((Scheme_Prim_Proc_Header *)rator)->flags & SCHEME_PRIM_OPT_MASK;
3233 if (opt >= SCHEME_PRIM_OPT_IMMEDIATE)
3234 return 1;
3235 if (SAME_OBJ(rator, scheme_values_proc))
3236 return 1;
3237 }
3238
3239 return 0;
3240 }
3241
is_always_escaping_primitive(Scheme_Object * rator)3242 XFORM_NONGCING static int is_always_escaping_primitive(Scheme_Object *rator)
3243 {
3244 if (SCHEME_PRIMP(rator)
3245 && (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_ALWAYS_ESCAPES)) {
3246 return 1;
3247 }
3248 return 0;
3249 }
3250
3251 #define IS_NAMED_PRIM(p, nm) (!strcmp(((Scheme_Primitive_Proc *)p)->name, nm))
3252
wants_local_type_arguments(Scheme_Object * rator,int argpos)3253 XFORM_NONGCING static int wants_local_type_arguments(Scheme_Object *rator, int argpos)
3254 {
3255 if (SCHEME_PRIMP(rator)) {
3256 int flags;
3257 flags = SCHEME_PRIM_PROC_OPT_FLAGS(rator);
3258
3259 if (argpos == 0) {
3260 if (flags & SCHEME_PRIM_WANTS_FLONUM_FIRST)
3261 return SCHEME_LOCAL_TYPE_FLONUM;
3262 if (flags & SCHEME_PRIM_WANTS_EXTFLONUM_FIRST)
3263 return SCHEME_LOCAL_TYPE_EXTFLONUM;
3264 } else if (argpos == 1) {
3265 if (flags & SCHEME_PRIM_WANTS_FLONUM_SECOND)
3266 return SCHEME_LOCAL_TYPE_FLONUM;
3267 if (flags & SCHEME_PRIM_WANTS_EXTFLONUM_SECOND)
3268 return SCHEME_LOCAL_TYPE_EXTFLONUM;
3269 } else if (argpos == 2) {
3270 if (flags & SCHEME_PRIM_WANTS_FLONUM_THIRD)
3271 return SCHEME_LOCAL_TYPE_FLONUM;
3272 if (flags & SCHEME_PRIM_WANTS_EXTFLONUM_THIRD)
3273 return SCHEME_LOCAL_TYPE_EXTFLONUM;
3274 }
3275 }
3276
3277 return 0;
3278 }
3279
produces_local_type(Scheme_Object * rator,int argc)3280 static int produces_local_type(Scheme_Object *rator, int argc)
3281 {
3282 if (SCHEME_PRIMP(rator)
3283 && (argc >= ((Scheme_Primitive_Proc *)rator)->mina)
3284 && (argc <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)) {
3285 int flags;
3286 flags = SCHEME_PRIM_PROC_OPT_FLAGS(rator);
3287 return SCHEME_PRIM_OPT_TYPE(flags);
3288 }
3289
3290 return 0;
3291 }
3292
local_type_to_predicate(int t)3293 static Scheme_Object *local_type_to_predicate(int t)
3294 {
3295 switch (t) {
3296 case SCHEME_LOCAL_TYPE_FLONUM:
3297 return scheme_flonum_p_proc;
3298 case SCHEME_LOCAL_TYPE_FIXNUM:
3299 return scheme_fixnum_p_proc;
3300 case SCHEME_LOCAL_TYPE_EXTFLONUM:
3301 return scheme_extflonum_p_proc;
3302 }
3303 return NULL;
3304 }
3305
scheme_predicate_to_local_type(Scheme_Object * pred)3306 int scheme_predicate_to_local_type(Scheme_Object *pred)
3307 {
3308 if (!pred)
3309 return 0;
3310 if (SAME_OBJ(scheme_flonum_p_proc, pred))
3311 return SCHEME_LOCAL_TYPE_FLONUM;
3312 if (SAME_OBJ(scheme_fixnum_p_proc, pred))
3313 return SCHEME_LOCAL_TYPE_FIXNUM;
3314 if (SAME_OBJ(scheme_extflonum_p_proc, pred))
3315 return SCHEME_LOCAL_TYPE_EXTFLONUM;
3316 return 0;
3317 }
3318
scheme_expr_produces_local_type(Scheme_Object * expr,int * _involves_k_cross)3319 int scheme_expr_produces_local_type(Scheme_Object *expr, int *_involves_k_cross)
3320 {
3321 if (_involves_k_cross) *_involves_k_cross = 0;
3322 return scheme_predicate_to_local_type(do_expr_implies_predicate(expr, NULL, _involves_k_cross,
3323 10, empty_eq_hash_tree));
3324 }
3325
rator_implies_predicate(Scheme_Object * rator,Optimize_Info * info,int argc)3326 static Scheme_Object *rator_implies_predicate(Scheme_Object *rator, Optimize_Info *info, int argc)
3327 {
3328 if (SCHEME_PRIMP(rator)) {
3329 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_PRODUCES_REAL)
3330 return scheme_real_p_proc;
3331 else if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_PRODUCES_NUMBER)
3332 return scheme_number_p_proc;
3333 else if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_PRODUCES_BOOL)
3334 return scheme_boolean_p_proc;
3335 else if (SAME_OBJ(rator, scheme_cons_proc))
3336 return scheme_pair_p_proc;
3337 else if (SAME_OBJ(rator, scheme_unsafe_cons_list_proc))
3338 return scheme_list_pair_p_proc;
3339 else if (SAME_OBJ(rator, scheme_mcons_proc))
3340 return scheme_mpair_p_proc;
3341 else if (SAME_OBJ(rator, scheme_list_proc)) {
3342 if (argc >= 1)
3343 return scheme_list_pair_p_proc;
3344 else
3345 return scheme_null_p_proc;
3346 } else if (SAME_OBJ(rator, scheme_list_star_proc)) {
3347 if (argc > 2)
3348 return scheme_pair_p_proc;
3349 } else if (IS_NAMED_PRIM(rator, "vector->list")
3350 || IS_NAMED_PRIM(rator, "map")) {
3351 return scheme_list_p_proc;
3352 } else if (IS_NAMED_PRIM(rator, "string-ref")) {
3353 return scheme_char_p_proc;
3354 } else if (IS_NAMED_PRIM(rator, "string-append")
3355 || IS_NAMED_PRIM(rator, "string-append-immutable")
3356 || IS_NAMED_PRIM(rator, "string->immutable-string")
3357 || IS_NAMED_PRIM(rator, "symbol->string")
3358 || IS_NAMED_PRIM(rator, "symbol->immutable-string")
3359 || IS_NAMED_PRIM(rator, "keyword->string")
3360 || IS_NAMED_PRIM(rator, "keyword->immutable-string")) {
3361 return scheme_string_p_proc;
3362 } else if (IS_NAMED_PRIM(rator, "bytes-append")
3363 || IS_NAMED_PRIM(rator, "bytes->immutable-bytes")) {
3364 return scheme_byte_string_p_proc;
3365 } else if (SAME_OBJ(rator, scheme_vector_proc)
3366 || SAME_OBJ(rator, scheme_vector_immutable_proc)
3367 || SAME_OBJ(rator, scheme_make_vector_proc)
3368 || SAME_OBJ(rator, scheme_list_to_vector_proc)
3369 || SAME_OBJ(rator, scheme_struct_to_vector_proc)
3370 || IS_NAMED_PRIM(rator, "vector->immutable-vector"))
3371 return scheme_vector_p_proc;
3372 else if (SAME_OBJ(rator, scheme_box_proc)
3373 || SAME_OBJ(rator, scheme_box_immutable_proc))
3374 return scheme_box_p_proc;
3375 else if (SAME_OBJ(rator, scheme_void_proc))
3376 return scheme_void_p_proc;
3377 else if (SAME_OBJ(rator, scheme_procedure_specialize_proc))
3378 return scheme_procedure_p_proc;
3379 else if (IS_NAMED_PRIM(rator, "vector-set!")
3380 || IS_NAMED_PRIM(rator, "string-set!")
3381 || IS_NAMED_PRIM(rator, "bytes-set!")
3382 || IS_NAMED_PRIM(rator, "set-box!"))
3383 return scheme_void_p_proc;
3384 else if (IS_NAMED_PRIM(rator, "string->symbol")
3385 || IS_NAMED_PRIM(rator, "gensym"))
3386 return scheme_symbol_p_proc;
3387 else if (IS_NAMED_PRIM(rator, "string->keyword"))
3388 return scheme_keyword_p_proc;
3389
3390 {
3391 Scheme_Object *p;
3392 p = local_type_to_predicate(produces_local_type(rator, argc));
3393 if (p)
3394 return p;
3395 }
3396 }
3397
3398 {
3399 Scheme_Object *shape;
3400 shape = get_struct_proc_shape(rator, info, 1);
3401 if (shape) {
3402 if (SAME_TYPE(SCHEME_TYPE(shape), scheme_struct_proc_shape_type)) {
3403 if (((SCHEME_PROC_SHAPE_MODE(shape) & STRUCT_PROC_SHAPE_MASK) == STRUCT_PROC_SHAPE_PRED)) {
3404 return scheme_boolean_p_proc;
3405 }
3406 } else if (SAME_TYPE(SCHEME_TYPE(shape), scheme_struct_prop_proc_shape_type)) {
3407 if (SCHEME_PROP_PROC_SHAPE_MODE(shape) == STRUCT_PROP_PROC_SHAPE_PRED) {
3408 return scheme_boolean_p_proc;
3409 }
3410 }
3411 }
3412 }
3413
3414 return NULL;
3415 }
3416
do_expr_implies_predicate(Scheme_Object * expr,Optimize_Info * info,int * _involves_k_cross,int fuel,Scheme_Hash_Tree * ignore_vars)3417 static Scheme_Object *do_expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info,
3418 int *_involves_k_cross, int fuel,
3419 Scheme_Hash_Tree *ignore_vars)
3420 /* can be called by the JIT with info = NULL;
3421 in that case, beware that the validator must be
3422 able to reconstruct the result in a shallow way, so don't
3423 make the result of a function call depend on its arguments */
3424 {
3425 if (fuel <= 0)
3426 return NULL;
3427
3428 switch (SCHEME_TYPE(expr)) {
3429 case scheme_ir_local_type:
3430 {
3431 if (scheme_eq_hash_tree_get(ignore_vars, expr))
3432 return NULL;
3433
3434 if (!SCHEME_VAR(expr)->mutated) {
3435 Scheme_Object *p;
3436
3437 if (info) {
3438 p = optimize_get_predicate(info, expr, 0);
3439 if (p)
3440 return p;
3441 }
3442
3443 p = local_type_to_predicate(SCHEME_VAR(expr)->val_type);
3444 if (p) {
3445 if (_involves_k_cross
3446 && SCHEME_VAR(expr)->escapes_after_k_tick)
3447 *_involves_k_cross = 1;
3448 return p;
3449 }
3450
3451 if ((SCHEME_VAR(expr)->mode == SCHEME_VAR_MODE_OPTIMIZE)
3452 && SCHEME_VAR(expr)->optimize.known_val)
3453 return do_expr_implies_predicate(SCHEME_VAR(expr)->optimize.known_val, info, _involves_k_cross,
3454 fuel-1, ignore_vars);
3455 }
3456 }
3457 break;
3458 case scheme_application2_type:
3459 {
3460 Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr;
3461
3462 if (SCHEME_PRIMP(app->rator)
3463 && SCHEME_PRIM_PROC_OPT_FLAGS(app->rator) & SCHEME_PRIM_CLOSED_ON_REALS) {
3464 Scheme_Object *p;
3465 p = do_expr_implies_predicate(app->rand, info, NULL, fuel-1, ignore_vars);
3466 if (p && predicate_implies(p, scheme_real_p_proc))
3467 return scheme_real_p_proc;
3468 }
3469
3470 if (SAME_OBJ(app->rator, scheme_cdr_proc)
3471 || SAME_OBJ(app->rator, scheme_unsafe_cdr_proc)) {
3472 Scheme_Object *p;
3473 p = do_expr_implies_predicate(app->rand, info, NULL, fuel-1, ignore_vars);
3474 if (predicate_implies(p, scheme_list_p_proc))
3475 return scheme_list_p_proc;
3476 }
3477
3478 return rator_implies_predicate(app->rator, info, 1);
3479 }
3480 break;
3481 case scheme_application3_type:
3482 {
3483 Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr;
3484 if (SCHEME_PRIMP(app->rator)
3485 && (SCHEME_PRIM_PROC_OPT_FLAGS(app->rator) & SCHEME_PRIM_IS_BINARY_INLINED)
3486 && IS_NAMED_PRIM(app->rator, "bitwise-and")) {
3487 /* Assume that a fixnum argument to bitwise-and will never get lost,
3488 and so the validator will be able to confirm that a `bitwise-and`
3489 combination produces a fixnum if either argument is a literal,
3490 nonnegative fixnum. */
3491 if ((SCHEME_INTP(app->rand1)
3492 && (SCHEME_INT_VAL(app->rand1) >= 0)
3493 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand1)))
3494 || (SCHEME_INTP(app->rand2)
3495 && (SCHEME_INT_VAL(app->rand2) >= 0)
3496 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand2)))) {
3497 return scheme_fixnum_p_proc;
3498 }
3499 }
3500
3501 if (SCHEME_PRIMP(app->rator)
3502 && SCHEME_PRIM_PROC_OPT_FLAGS(app->rator) & SCHEME_PRIM_CLOSED_ON_REALS) {
3503 Scheme_Object *p;
3504 p = do_expr_implies_predicate(app->rand1, info, NULL, fuel-1, ignore_vars);
3505 if (p && predicate_implies(p, scheme_real_p_proc)) {
3506 p = do_expr_implies_predicate(app->rand2, info, NULL, fuel-1, ignore_vars);
3507 if (p && predicate_implies(p, scheme_real_p_proc)) {
3508 return scheme_real_p_proc;
3509 }
3510 }
3511 }
3512
3513 if (SAME_OBJ(app->rator, scheme_cons_proc)) {
3514 Scheme_Object *p;
3515 p = do_expr_implies_predicate(app->rand2, info, NULL, fuel-1, ignore_vars);
3516 if (SAME_OBJ(p, scheme_list_pair_p_proc)
3517 || SAME_OBJ(p, scheme_list_p_proc)
3518 || SAME_OBJ(p, scheme_null_p_proc))
3519 return scheme_list_pair_p_proc;
3520 }
3521
3522 if (SCHEME_PRIMP(app->rator)
3523 && IS_NAMED_PRIM(app->rator, "append")) {
3524 Scheme_Object *p;
3525 p = do_expr_implies_predicate(app->rand2, info, NULL, fuel-1, ignore_vars);
3526 if (SAME_OBJ(p, scheme_list_pair_p_proc))
3527 return scheme_list_pair_p_proc;
3528 if (SAME_OBJ(p, scheme_list_p_proc)
3529 || SAME_OBJ(p, scheme_null_p_proc))
3530 return scheme_list_p_proc;
3531 }
3532
3533 return rator_implies_predicate(app->rator, info, 2);
3534 }
3535 break;
3536 case scheme_application_type:
3537 {
3538 Scheme_App_Rec *app = (Scheme_App_Rec *)expr;
3539
3540 if (SCHEME_PRIMP(app->args[0])
3541 && SCHEME_PRIM_PROC_OPT_FLAGS(app->args[0]) & SCHEME_PRIM_CLOSED_ON_REALS) {
3542 Scheme_Object *p;
3543 int i;
3544 for (i = 0; i < app->num_args; i++) {
3545 p = do_expr_implies_predicate(app->args[i+1], info, NULL, fuel-1, ignore_vars);
3546 if (!p || !predicate_implies(p, scheme_real_p_proc))
3547 break;
3548 }
3549 if (i >= app->num_args)
3550 return scheme_real_p_proc;
3551 }
3552
3553 if (SCHEME_PRIMP(app->args[0])
3554 && IS_NAMED_PRIM(app->args[0], "append")) {
3555 Scheme_Object *p;
3556 p = do_expr_implies_predicate(app->args[app->num_args], info, NULL, fuel-1, ignore_vars);
3557 if (SAME_OBJ(p, scheme_list_pair_p_proc))
3558 return scheme_list_pair_p_proc;
3559 if (SAME_OBJ(p, scheme_list_p_proc)
3560 || SAME_OBJ(p, scheme_null_p_proc))
3561 return scheme_list_p_proc;
3562 }
3563
3564 return rator_implies_predicate(app->args[0], info, app->num_args);
3565 }
3566 break;
3567 case scheme_ir_lambda_type:
3568 return scheme_procedure_p_proc;
3569 break;
3570 case scheme_case_lambda_sequence_type:
3571 return scheme_procedure_p_proc;
3572 break;
3573 case scheme_branch_type:
3574 {
3575 Scheme_Object *l, *r;
3576 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr;
3577 l = do_expr_implies_predicate(b->tbranch, info, _involves_k_cross, fuel-1, ignore_vars);
3578 if (l) {
3579 r = do_expr_implies_predicate(b->fbranch, info, _involves_k_cross, fuel-1, ignore_vars);
3580 if (predicate_implies(l, r))
3581 return r;
3582 else if (predicate_implies(r, l))
3583 return l;
3584 else
3585 return NULL;
3586 }
3587 }
3588 break;
3589 case scheme_sequence_type:
3590 {
3591 Scheme_Sequence *seq = (Scheme_Sequence *)expr;
3592
3593 return do_expr_implies_predicate(seq->array[seq->count-1], info, _involves_k_cross, fuel-1, ignore_vars);
3594 }
3595 case scheme_with_cont_mark_type:
3596 {
3597 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)expr;
3598
3599 return do_expr_implies_predicate(wcm->body, info, _involves_k_cross, fuel-1, ignore_vars);
3600 }
3601 case scheme_ir_let_header_type:
3602 {
3603 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)expr;
3604 Scheme_IR_Let_Value *irlv;
3605 int i, j;
3606 expr = lh->body;
3607 for (i = 0; i < lh->num_clauses; i++) {
3608 irlv = (Scheme_IR_Let_Value *)expr;
3609 for (j = 0; j < irlv->count; j++) {
3610 ignore_vars = scheme_hash_tree_set(ignore_vars, (Scheme_Object *)irlv->vars[j],
3611 scheme_true);
3612 }
3613 expr = irlv->body;
3614 }
3615 return do_expr_implies_predicate(expr, info, _involves_k_cross, fuel-1, ignore_vars);
3616 }
3617 break;
3618 case scheme_begin0_sequence_type:
3619 {
3620 Scheme_Sequence *seq = (Scheme_Sequence *)expr;
3621
3622 return do_expr_implies_predicate(seq->array[0], info, _involves_k_cross, fuel-1, ignore_vars);
3623 }
3624 case scheme_vector_type:
3625 return scheme_vector_p_proc;
3626 break;
3627 case scheme_box_type:
3628 return scheme_box_p_proc;
3629 break;
3630 default:
3631 if (SCHEME_NUMBERP(expr)) {
3632 if (SCHEME_FLOATP(expr))
3633 return scheme_flonum_p_proc;
3634 if (SCHEME_LONG_DBLP(expr))
3635 return scheme_extflonum_p_proc;
3636 if (SCHEME_INTP(expr)
3637 && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(expr)))
3638 return scheme_fixnum_p_proc;
3639 if (SCHEME_REALP(expr))
3640 return scheme_real_p_proc;
3641 return scheme_number_p_proc;
3642 }
3643
3644 if (SCHEME_NULLP(expr))
3645 return scheme_null_p_proc;
3646 if (SCHEME_PAIRP(expr)) {
3647 if (scheme_is_list(expr))
3648 return scheme_list_pair_p_proc;
3649 return scheme_pair_p_proc;
3650 }
3651 if (SCHEME_MPAIRP(expr))
3652 return scheme_mpair_p_proc;
3653 if (SCHEME_CHAR_STRINGP(expr))
3654 return scheme_string_p_proc;
3655 if (SCHEME_BYTE_STRINGP(expr))
3656 return scheme_byte_string_p_proc;
3657 if (SCHEME_VOIDP(expr))
3658 return scheme_void_p_proc;
3659 if (SCHEME_EOFP(expr))
3660 return scheme_eof_object_p_proc;
3661 if (SCHEME_KEYWORDP(expr))
3662 return scheme_keyword_p_proc;
3663 if (SCHEME_SYMBOLP(expr))
3664 return scheme_symbol_p_proc;
3665 if (SCHEME_CHARP(expr)) {
3666 if (SCHEME_CHAR_VAL(expr) < 256)
3667 return scheme_interned_char_p_proc;
3668 return scheme_char_p_proc;
3669 }
3670 if (SAME_OBJ(expr, scheme_true))
3671 return scheme_true_object_p_proc;
3672 if (SCHEME_FALSEP(expr))
3673 return scheme_not_proc;
3674 if (SCHEME_PROCP(expr))
3675 return scheme_procedure_p_proc;
3676 if (SCHEME_LONG_DBLP(expr))
3677 return scheme_extflonum_p_proc;
3678 }
3679
3680 /* This test is slower, so put it at the end */
3681 if (info
3682 && lookup_constant_proc(info, expr, -1)) {
3683 return scheme_procedure_p_proc;
3684 }
3685
3686 return NULL;
3687 }
3688
expr_implies_predicate(Scheme_Object * expr,Optimize_Info * info)3689 static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info)
3690 {
3691 return do_expr_implies_predicate(expr, info, NULL, 5, empty_eq_hash_tree);
3692 }
3693
finish_optimize_app(Scheme_Object * o,Optimize_Info * info,int context)3694 static Scheme_Object *finish_optimize_app(Scheme_Object *o, Optimize_Info *info, int context)
3695 {
3696 switch(SCHEME_TYPE(o)) {
3697 case scheme_application_type:
3698 return finish_optimize_application((Scheme_App_Rec *)o, info, context);
3699 case scheme_application2_type:
3700 return finish_optimize_application2((Scheme_App2_Rec *)o, info, context);
3701 case scheme_application3_type:
3702 return finish_optimize_application3((Scheme_App3_Rec *)o, info, context);
3703 default:
3704 return o; /* may be a constant due to constant-folding */
3705 }
3706 }
3707
direct_apply(Scheme_Object * expr,Scheme_Object * rator,Scheme_Object * last_rand,Optimize_Info * info)3708 static Scheme_Object *direct_apply(Scheme_Object *expr, Scheme_Object *rator, Scheme_Object *last_rand, Optimize_Info *info)
3709 /* Convert `(apply f arg1 ... (list arg2 ...))` to `(f arg1 ... arg2 ...)` */
3710 {
3711 if (SAME_OBJ(rator, scheme_apply_proc)) {
3712 switch(SCHEME_TYPE(last_rand)) {
3713 case scheme_application_type:
3714 rator = ((Scheme_App_Rec *)last_rand)->args[0];
3715 break;
3716 case scheme_application2_type:
3717 rator = ((Scheme_App2_Rec *)last_rand)->rator;
3718 break;
3719 case scheme_application3_type:
3720 rator = ((Scheme_App3_Rec *)last_rand)->rator;
3721 break;
3722 case scheme_pair_type:
3723 if (scheme_is_list(last_rand))
3724 rator = scheme_list_proc;
3725 else
3726 rator = NULL;
3727 break;
3728 case scheme_null_type:
3729 rator = scheme_list_proc;
3730 break;
3731 default:
3732 rator = NULL;
3733 break;
3734 }
3735
3736 if (rator && SAME_OBJ(rator, scheme_list_proc)) {
3737 /* Convert (apply f arg1 ... (list arg2 ...))
3738 to (f arg1 ... arg2 ...) */
3739 Scheme_Object *l = scheme_null;
3740 int i;
3741
3742 switch(SCHEME_TYPE(last_rand)) {
3743 case scheme_application_type:
3744 for (i = ((Scheme_App_Rec *)last_rand)->num_args; i--; ) {
3745 l = scheme_make_pair(((Scheme_App_Rec *)last_rand)->args[i+1], l);
3746 }
3747 break;
3748 case scheme_application2_type:
3749 l = scheme_make_pair(((Scheme_App2_Rec *)last_rand)->rand, l);
3750 break;
3751 case scheme_application3_type:
3752 l = scheme_make_pair(((Scheme_App3_Rec *)last_rand)->rand2, l);
3753 l = scheme_make_pair(((Scheme_App3_Rec *)last_rand)->rand1, l);
3754 break;
3755 case scheme_pair_type:
3756 l = last_rand;
3757 break;
3758 case scheme_null_type:
3759 l = scheme_null;
3760 break;
3761 }
3762
3763 switch(SCHEME_TYPE(expr)) {
3764 case scheme_application_type:
3765 for (i = ((Scheme_App_Rec *)expr)->num_args - 1; i--; ) {
3766 l = scheme_make_pair(((Scheme_App_Rec *)expr)->args[i+1], l);
3767 }
3768 break;
3769 default:
3770 case scheme_application3_type:
3771 l = scheme_make_pair(((Scheme_App3_Rec *)expr)->rand1, l);
3772 break;
3773 }
3774
3775 return scheme_make_application(l, info);
3776 }
3777 }
3778
3779 return NULL;
3780 }
3781
call_with_immed_mark(Scheme_Object * rator,Scheme_Object * rand1,Scheme_Object * rand2,Scheme_Object * rand3,Optimize_Info * info)3782 static Scheme_Object *call_with_immed_mark(Scheme_Object *rator,
3783 Scheme_Object *rand1,
3784 Scheme_Object *rand2,
3785 Scheme_Object *rand3,
3786 Optimize_Info *info)
3787 /* Convert `(call-with-immediate-continuation-mark (lambda (arg) M))`
3788 to the with-immediate-mark bytecode form. */
3789 {
3790 if (SAME_OBJ(rator, scheme_call_with_immed_mark_proc)
3791 && SAME_TYPE(SCHEME_TYPE(rand2), scheme_ir_lambda_type)
3792 && (((Scheme_Lambda *)rand2)->num_params == 1)
3793 && !(SCHEME_LAMBDA_FLAGS(((Scheme_Lambda *)rand2)) & LAMBDA_HAS_REST)) {
3794 Scheme_With_Continuation_Mark *wcm;
3795 Scheme_Object *e;
3796
3797 wcm = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark);
3798 wcm->so.type = scheme_with_immed_mark_type;
3799
3800 wcm->key = rand1;
3801 wcm->val = (rand3 ? rand3 : scheme_false);
3802
3803 e = (Scheme_Object *)((Scheme_Lambda *)rand2)->ir_info->vars[0];
3804 e = scheme_make_mutable_pair(e, ((Scheme_Lambda *)rand2)->body);
3805 wcm->body = e;
3806
3807 return (Scheme_Object *)wcm;
3808 }
3809
3810 return NULL;
3811 }
3812
optimize_application(Scheme_Object * o,Optimize_Info * info,int context)3813 static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info, int context)
3814 {
3815 Scheme_Object *le;
3816 Scheme_App_Rec *app;
3817 int i, n, rator_apply_escapes = 0, sub_context = 0;
3818 Optimize_Info_Sequence info_seq;
3819
3820 app = (Scheme_App_Rec *)o;
3821
3822 /* Check for (apply ... (list ...)) early: */
3823 le = direct_apply((Scheme_Object *)app, app->args[0], app->args[app->num_args], info);
3824 if (le)
3825 return optimize_expr(le, info, context);
3826
3827 if (app->num_args == 3) {
3828 le = call_with_immed_mark(app->args[0], app->args[1], app->args[2], app->args[3], info);
3829 if (le)
3830 return optimize_expr(le, info, context);
3831 }
3832
3833 le = check_app_let_rator(o, app->args[0], info, app->num_args, context);
3834 if (le)
3835 return le;
3836
3837 n = app->num_args + 1;
3838
3839 optimize_info_seq_init(info, &info_seq);
3840
3841 for (i = 0; i < n; i++) {
3842 if (!i) {
3843 le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, context, 0);
3844 if (le)
3845 return le;
3846 }
3847
3848 sub_context = OPT_CONTEXT_SINGLED;
3849 if (i > 0) {
3850 int ty;
3851 ty = wants_local_type_arguments(app->args[0], i - 1);
3852 if (ty)
3853 sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT);
3854 }
3855
3856 optimize_info_seq_step(info, &info_seq);
3857 le = optimize_expr(app->args[i], info, sub_context);
3858 app->args[i] = le;
3859 if (info->escapes) {
3860 int j;
3861 Scheme_Object *e, *l;
3862 optimize_info_seq_done(info, &info_seq);
3863
3864 l = scheme_make_pair(app->args[i], scheme_null);
3865
3866 for (j = i - 1; j >= 0; j--) {
3867 e = app->args[j];
3868 e = optimize_ignored(e, info, 1, 1, 5);
3869 if (e) {
3870 e = ensure_single_value(e, info);
3871 l = scheme_make_pair(e, l);
3872 }
3873 }
3874 return ensure_noncm(scheme_make_sequence_compilation(l, 1, 0), info);
3875 }
3876
3877 if (!i) {
3878 /* Maybe found "((lambda" after optimizing; try again */
3879 le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, context, 1);
3880 if (le)
3881 return le;
3882 if (SAME_OBJ(app->args[0], scheme_values_proc)
3883 || SAME_OBJ(app->args[0], scheme_apply_proc))
3884 info->maybe_values_argument = 1;
3885 rator_apply_escapes = info->escapes;
3886 }
3887 }
3888
3889 optimize_info_seq_done(info, &info_seq);
3890
3891 /* Check for (apply ... (list ...)) after some optimizations: */
3892 le = direct_apply((Scheme_Object *)app, app->args[0], app->args[app->num_args], info);
3893 if (le) return finish_optimize_app(le, info, context);
3894
3895 /* Convert (hash-ref '#hash... key (lambda () literal))
3896 to (hash-ref '#hash... key literal) */
3897 if ((app->num_args == 3)
3898 && SAME_OBJ(scheme_hash_ref_proc, app->args[0])
3899 && SCHEME_HASHTRP(app->args[1])
3900 && SAME_TYPE(scheme_ir_lambda_type, SCHEME_TYPE(app->args[3]))
3901 && (((Scheme_Lambda *)(app->args[3]))->num_params == 0)
3902 && (SCHEME_TYPE(((Scheme_Lambda *)app->args[3])->body) > _scheme_ir_values_types_)
3903 && !SCHEME_PROCP(((Scheme_Lambda *)app->args[3])->body)) {
3904 app->args[3] = ((Scheme_Lambda *)app->args[3])->body;
3905 }
3906
3907 if (rator_apply_escapes) {
3908 info->escapes = 1;
3909 SCHEME_APPN_FLAGS(app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
3910 }
3911
3912 return finish_optimize_application(app, info, context);
3913 }
3914
appn_flags(Scheme_Object * rator,Optimize_Info * info)3915 static int appn_flags(Scheme_Object *rator, Optimize_Info *info)
3916 /* Record some properties of an application that are useful to the SFS pass. */
3917 {
3918 if (SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_toplevel_type)) {
3919 rator = get_defn_shape(info, (Scheme_IR_Toplevel *)rator);
3920 rator = no_potential_size(rator);
3921 if (!rator) return 0;
3922 if (SAME_TYPE(SCHEME_TYPE(rator), scheme_proc_shape_type)) {
3923 return APPN_FLAG_SFS_TAIL;
3924 } else if (SAME_TYPE(SCHEME_TYPE(rator), scheme_struct_proc_shape_type)) {
3925 int ps = SCHEME_PROC_SHAPE_MODE(rator) & STRUCT_PROC_SHAPE_MASK;
3926 if ((ps == STRUCT_PROC_SHAPE_PRED)
3927 || (ps == STRUCT_PROC_SHAPE_GETTER)
3928 || (ps == STRUCT_PROC_SHAPE_SETTER)
3929 || (ps == STRUCT_PROC_SHAPE_CONSTR))
3930 return (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
3931 return 0;
3932 }
3933 }
3934
3935 if (SCHEME_PRIMP(rator)) {
3936 int opt = (SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_OPT_MASK);
3937 if (opt >= SCHEME_PRIM_OPT_IMMEDIATE)
3938 return (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
3939 return 0;
3940 }
3941
3942 if (SCHEME_LAMBDAP(rator)
3943 || SAME_TYPE(scheme_noninline_proc_type, SCHEME_TYPE(rator)))
3944 return APPN_FLAG_SFS_TAIL;
3945
3946 return 0;
3947 }
3948
3949 #define CHECK_PRIM_AD_HOC_OPT_FLAGS 0
3950
check_known_variant(Optimize_Info * info,Scheme_Object * app,Scheme_Object * rator,Scheme_Object * rand,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode,Scheme_Object * implies_pred)3951 static int check_known_variant(Optimize_Info *info, Scheme_Object *app,
3952 Scheme_Object *rator, Scheme_Object *rand,
3953 const char *who, Scheme_Object *expect_pred,
3954 Scheme_Object *unsafe, int unsafe_mode,
3955 Scheme_Object *implies_pred)
3956 /* Replace the rator with an unsafe version if we know that it's ok:
3957 if the argument is consistent with `expect_pred`; if `unsafe` is
3958 #t, then just mark the application as omittable. Alternatively, the
3959 rator implies a check, so add type information for subsequent
3960 expressions: the argument is consistent with `implies_pred` (which
3961 must be itself implied by `expected_pred`, but might be weaker). If
3962 the rand has already an incompatible type, mark that this will
3963 generate an error. If unsafe is NULL then rator has no unsafe
3964 version, so only check the type. */
3965 {
3966 #if CHECK_PRIM_AD_HOC_OPT_FLAGS
3967 if (who) {
3968 Scheme_Object *p;
3969 p = scheme_builtin_value(who);
3970 if (!p) {
3971 printf("bad primitive name: %s\n", who);
3972 abort();
3973 }
3974 if (!(SCHEME_PRIM_PROC_OPT_FLAGS(p) & SCHEME_PRIM_AD_HOC_OPT)) {
3975 printf("missing SCHEME_PRIM_AD_HOC_OPT: %s\n", who);
3976 abort();
3977 }
3978 }
3979 #endif
3980
3981 MZ_ASSERT(SCHEME_PRIMP(rator));
3982 if (!who || IS_NAMED_PRIM(rator, who)) {
3983 Scheme_Object *pred;
3984
3985 if (unsafe_mode)
3986 pred = expect_pred;
3987 else
3988 pred = expr_implies_predicate(rand, info);
3989
3990 if (pred) {
3991 if (predicate_implies(pred, expect_pred)) {
3992 if (unsafe) {
3993 if (SAME_OBJ(unsafe, scheme_true))
3994 set_application_omittable(app, unsafe);
3995 else
3996 reset_rator(app, unsafe);
3997 }
3998 return 1;
3999 } else if (predicate_implies_not(pred, implies_pred)) {
4000 info->escapes = 1;
4001 }
4002 } else {
4003 if (SAME_TYPE(SCHEME_TYPE(rand), scheme_ir_local_type))
4004 add_type(info, rand, implies_pred);
4005 }
4006 }
4007
4008 return 0;
4009 }
4010
check_known(Optimize_Info * info,Scheme_Object * app,Scheme_Object * rator,Scheme_Object * rand,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode)4011 static void check_known(Optimize_Info *info, Scheme_Object *app,
4012 Scheme_Object *rator, Scheme_Object *rand,
4013 const char *who, Scheme_Object *expect_pred,
4014 Scheme_Object *unsafe, int unsafe_mode)
4015 /* When the expected predicate for unsafe substitution is the same as the implied predicate. */
4016 {
4017 (void)check_known_variant(info, app, rator, rand, who, expect_pred, unsafe, unsafe_mode, expect_pred);
4018 }
4019
check_known_rator(Optimize_Info * info,Scheme_Object * rator)4020 static void check_known_rator(Optimize_Info *info, Scheme_Object *rator)
4021 /* Check that rator is a procedure or add type information for subsequent expressions. */
4022 {
4023 Scheme_Object *pred;
4024
4025 pred = expr_implies_predicate(rator, info);
4026 if (pred) {
4027 if (predicate_implies_not(pred, scheme_procedure_p_proc))
4028 info->escapes = 1;
4029 } else {
4030 if (SAME_TYPE(SCHEME_TYPE(rator), scheme_ir_local_type))
4031 add_type(info, rator, scheme_procedure_p_proc);
4032 }
4033 }
4034
check_known_both_try(Optimize_Info * info,Scheme_Object * app,Scheme_Object * rator,Scheme_Object * rand1,Scheme_Object * rand2,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode)4035 static void check_known_both_try(Optimize_Info *info, Scheme_Object *app,
4036 Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2,
4037 const char *who, Scheme_Object *expect_pred,
4038 Scheme_Object *unsafe, int unsafe_mode)
4039 /* Replace the rator with an unsafe version if both rands have the right type.
4040 If not, don't save the type, nor mark this as an error */
4041 {
4042 MZ_ASSERT(SCHEME_PRIMP(rator));
4043 if (!who || IS_NAMED_PRIM(rator, who)) {
4044 Scheme_Object *pred1, *pred2;
4045
4046 if (unsafe_mode) {
4047 reset_rator(app, unsafe);
4048 } else {
4049 pred1 = expr_implies_predicate(rand1, info);
4050 if (pred1 && predicate_implies(pred1, expect_pred)) {
4051 pred2 = expr_implies_predicate(rand2, info);
4052 if (pred2 && predicate_implies(pred2, expect_pred)) {
4053 reset_rator(app, unsafe);
4054 }
4055 }
4056 }
4057 }
4058 }
4059
check_known_both_variant(Optimize_Info * info,Scheme_Object * app,Scheme_Object * rator,Scheme_Object * rand1,Scheme_Object * rand2,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode,Scheme_Object * implies_pred)4060 static void check_known_both_variant(Optimize_Info *info, Scheme_Object *app,
4061 Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2,
4062 const char *who, Scheme_Object *expect_pred,
4063 Scheme_Object *unsafe, int unsafe_mode,
4064 Scheme_Object *implies_pred)
4065 {
4066 MZ_ASSERT(SCHEME_PRIMP(rator));
4067 if (!who || IS_NAMED_PRIM(rator, who)) {
4068 int ok1;
4069 ok1 = check_known_variant(info, app, rator, rand1, who, expect_pred, NULL, unsafe_mode, implies_pred);
4070 check_known_variant(info, app, rator, rand2, who, expect_pred, (ok1 ? unsafe : NULL), unsafe_mode, implies_pred);
4071 }
4072 }
4073
check_known_both(Optimize_Info * info,Scheme_Object * app,Scheme_Object * rator,Scheme_Object * rand1,Scheme_Object * rand2,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode)4074 static void check_known_both(Optimize_Info *info, Scheme_Object *app,
4075 Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2,
4076 const char *who, Scheme_Object *expect_pred,
4077 Scheme_Object *unsafe, int unsafe_mode)
4078 {
4079 check_known_both_variant(info, app, rator, rand1, rand2, who, expect_pred, unsafe, unsafe_mode, expect_pred);
4080 }
4081
4082
check_known_all(Optimize_Info * info,Scheme_Object * _app,int skip_head,int skip_tail,const char * who,Scheme_Object * expect_pred,Scheme_Object * unsafe,int unsafe_mode)4083 static void check_known_all(Optimize_Info *info, Scheme_Object *_app, int skip_head, int skip_tail,
4084 const char *who, Scheme_Object *expect_pred,
4085 Scheme_Object *unsafe, int unsafe_mode)
4086 {
4087 Scheme_App_Rec *app = (Scheme_App_Rec *)_app;
4088 if (SCHEME_PRIMP(app->args[0]) && (!who || IS_NAMED_PRIM(app->args[0], who))) {
4089 int ok_so_far = 1, i;
4090
4091 for (i = skip_head; i < app->num_args - skip_tail; i++) {
4092 if (!check_known_variant(info, _app, app->args[0], app->args[i+1], who, expect_pred,
4093 NULL, unsafe_mode, expect_pred))
4094 ok_so_far = 0;
4095 }
4096
4097 if (ok_so_far && unsafe) {
4098 if (SAME_OBJ(unsafe, scheme_true))
4099 set_application_omittable(_app, unsafe);
4100 else
4101 reset_rator(_app, unsafe);
4102 }
4103 }
4104 }
4105
finish_optimize_any_application(Scheme_Object * app,Scheme_Object * rator,int argc,Optimize_Info * info,int context)4106 static Scheme_Object *finish_optimize_any_application(Scheme_Object *app, Scheme_Object *rator, int argc,
4107 Optimize_Info *info, int context)
4108 {
4109 check_known_rator(info, rator);
4110
4111 if ((context & OPT_CONTEXT_BOOLEAN) && !info->escapes) {
4112 Scheme_Object *pred;
4113 pred = rator_implies_predicate(rator, info, argc);
4114 if (pred && predicate_implies_not(pred, scheme_not_proc))
4115 return make_discarding_sequence(app, scheme_true, info);
4116 else if (pred && predicate_implies(pred, scheme_not_proc))
4117 return make_discarding_sequence(app, scheme_false, info);
4118 }
4119
4120 if (SAME_OBJ(rator, scheme_void_proc))
4121 return make_discarding_sequence(app, scheme_void, info);
4122
4123 if (is_always_escaping_primitive(rator)) {
4124 info->escapes = 1;
4125 }
4126
4127 return app;
4128 }
4129
increment_clock_counts_for_application(GC_CAN_IGNORE int * _vclock,GC_CAN_IGNORE int * _aclock,GC_CAN_IGNORE int * _kclock,GC_CAN_IGNORE int * _sclock,Scheme_Object * rator,int argc)4130 static void increment_clock_counts_for_application(GC_CAN_IGNORE int *_vclock,
4131 GC_CAN_IGNORE int *_aclock,
4132 GC_CAN_IGNORE int *_kclock,
4133 GC_CAN_IGNORE int *_sclock,
4134 Scheme_Object *rator,
4135 int argc)
4136 {
4137 if (!is_nonmutating_nondependant_primitive(rator, argc))
4138 *_vclock += 1;
4139 else if (is_primitive_allocating(rator, argc))
4140 *_aclock += 1;
4141
4142 if (!is_noncapturing_primitive(rator, argc))
4143 *_kclock += 1;
4144
4145 if (!is_nonsaving_primitive(rator, argc))
4146 *_sclock += 1;
4147 }
4148
increment_clocks_for_application(Optimize_Info * info,Scheme_Object * rator,int argc)4149 static void increment_clocks_for_application(Optimize_Info *info,
4150 Scheme_Object *rator,
4151 int argc)
4152 {
4153 int v, a, k, s;
4154
4155 v = info->vclock;
4156 a = info->aclock;
4157 k = info->kclock;
4158 s = info->sclock;
4159
4160 increment_clock_counts_for_application(&v, &a, &k, &s, rator, argc);
4161
4162 info->vclock = v;
4163 info->aclock = a;
4164 info->kclock = k;
4165 info->sclock = s;
4166 }
4167
finish_optimize_application(Scheme_App_Rec * app,Optimize_Info * info,int context)4168 static Scheme_Object *finish_optimize_application(Scheme_App_Rec *app, Optimize_Info *info, int context)
4169 {
4170 Scheme_Object *le;
4171 Scheme_Object *rator = app->args[0];
4172 int all_vals = 1, i, flags, rator_flags;
4173
4174 for (i = app->num_args; i--; ) {
4175 if (SCHEME_TYPE(app->args[i+1]) < _scheme_ir_values_types_)
4176 all_vals = 0;
4177 }
4178
4179 info->size += 1;
4180 info->preserves_marks = 1;
4181 info->single_result = 1;
4182
4183 if (all_vals) {
4184 le = try_optimize_fold(rator, NULL, (Scheme_Object *)app, info);
4185 if (le)
4186 return le;
4187 }
4188
4189 if (!app->num_args && SCHEME_PRIMP(rator)) {
4190 if (SAME_OBJ(rator, scheme_list_proc))
4191 return scheme_null;
4192 if (SAME_OBJ(rator, scheme_append_proc))
4193 return scheme_null;
4194 if (SAME_OBJ(rator, scheme_hasheq_proc))
4195 return (Scheme_Object *)scheme_make_hash_tree(0);
4196 if (SAME_OBJ(rator, scheme_hash_proc))
4197 return (Scheme_Object *)scheme_make_hash_tree(1);
4198 if (SAME_OBJ(rator, scheme_hasheqv_proc))
4199 return (Scheme_Object *)scheme_make_hash_tree(2);
4200 }
4201
4202 if (SCHEME_PRIMP(rator)
4203 && (app->num_args >= ((Scheme_Primitive_Proc *)rator)->mina)
4204 && (app->num_args <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)) {
4205 Scheme_Object *app_o = (Scheme_Object *)app;
4206 Scheme_Object *rand1 = NULL, *rand2 = NULL, *rand3 = NULL;
4207
4208 if (app->num_args >= 1)
4209 rand1 = app->args[1];
4210
4211 if (app->num_args >= 2)
4212 rand2 = app->args[2];
4213
4214 if (app->num_args >= 3)
4215 rand3 = app->args[3];
4216
4217 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_AD_HOC_OPT) {
4218 check_known(info, app_o, rator, rand1, "vector-set!", scheme_vector_p_proc, NULL, info->unsafe_mode);
4219 check_known(info, app_o, rator, rand2, "vector-set!", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4220 check_known(info, app_o, rator, rand1, "vector*-set!", scheme_vector_p_proc,
4221 (info->unsafe_mode ? scheme_unsafe_vector_star_set_proc : NULL), info->unsafe_mode);
4222 check_known(info, app_o, rator, rand2, "vector*-set!", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4223
4224 check_known(info, app_o, rator, rand1, "procedure-arity-includes?", scheme_procedure_p_proc, NULL, info->unsafe_mode);
4225
4226 check_known(info, app_o, rator, rand1, "map", scheme_procedure_p_proc, NULL, info->unsafe_mode);
4227 check_known(info, app_o, rator, rand1, "for-each", scheme_procedure_p_proc, NULL, info->unsafe_mode);
4228 check_known(info, app_o, rator, rand1, "andmap", scheme_procedure_p_proc, NULL, info->unsafe_mode);
4229 check_known(info, app_o, rator, rand1, "ormap", scheme_procedure_p_proc, NULL, info->unsafe_mode);
4230 check_known_all(info, app_o, 1, 0, "map", scheme_list_p_proc, NULL, info->unsafe_mode);
4231 check_known_all(info, app_o, 1, 0, "for-each", scheme_list_p_proc, NULL, info->unsafe_mode);
4232 check_known_all(info, app_o, 1, 0, "andmap", scheme_list_p_proc, NULL, info->unsafe_mode);
4233 check_known_all(info, app_o, 1, 0, "ormap", scheme_list_p_proc, NULL, info->unsafe_mode);
4234
4235 check_known(info, app_o, rator, rand1, "string-set!", scheme_string_p_proc,
4236 (info->unsafe_mode ? scheme_unsafe_string_set_proc : NULL), info->unsafe_mode);
4237 check_known(info, app_o, rator, rand2, "string-set!", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4238 check_known(info, app_o, rator, rand3, "string-set!", scheme_char_p_proc, NULL, info->unsafe_mode);
4239 check_known(info, app_o, rator, rand1, "bytes-set!", scheme_byte_string_p_proc,
4240 (info->unsafe_mode ? scheme_unsafe_bytes_set_proc : NULL), info->unsafe_mode);
4241 check_known(info, app_o, rator, rand2, "bytes-set!", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4242 check_known(info, app_o, rator, rand3, "bytes-set!", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4243
4244 check_known_all(info, app_o, 0, 0, "string-append", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4245 check_known_all(info, app_o, 0, 0, "bytes-append", scheme_byte_string_p_proc, scheme_true, info->unsafe_mode);
4246
4247 check_known_all(info, app_o, 0, 1, "append", scheme_list_p_proc, scheme_true, info->unsafe_mode);
4248 }
4249
4250 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_REAL)
4251 check_known_all(info, app_o, 0, 0, NULL, scheme_real_p_proc,
4252 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
4253 info->unsafe_mode);
4254 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_NUMBER)
4255 check_known_all(info, app_o, 0, 0, NULL, scheme_number_p_proc,
4256 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
4257 info->unsafe_mode);
4258
4259 /* Some of these may have changed app->rator. */
4260 rator = app->args[0];
4261 }
4262
4263 increment_clocks_for_application(info, rator, app->num_args);
4264
4265 rator_flags = get_rator_flags(rator, app->num_args, info);
4266 info->preserves_marks = !!(rator_flags & LAMBDA_PRESERVES_MARKS);
4267 info->single_result = !!(rator_flags & LAMBDA_SINGLE_RESULT);
4268 if ((rator_flags & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE) {
4269 info->preserves_marks = -info->preserves_marks;
4270 info->single_result = -info->single_result;
4271 }
4272
4273 register_local_argument_types(app, NULL, NULL, info);
4274
4275 flags = appn_flags(app->args[0], info);
4276 SCHEME_APPN_FLAGS(app) |= flags;
4277
4278 return finish_optimize_any_application((Scheme_Object *)app, app->args[0], app->num_args,
4279 info, context);
4280 }
4281
try_reduce_predicate(Scheme_Object * rator,Scheme_Object * rand,Optimize_Info * info)4282 static Scheme_Object *try_reduce_predicate(Scheme_Object *rator, Scheme_Object *rand,
4283 Optimize_Info *info)
4284 /* Change (pair? (list X complex-Y Z)) => (begin complex-Y #t), etc.
4285 It's especially nice to avoid the constructions. */
4286 {
4287 Scheme_Object *pred;
4288
4289 if (!relevant_predicate(rator))
4290 return NULL;
4291
4292 pred = expr_implies_predicate(rand, info);
4293
4294 if (!pred)
4295 return NULL;
4296
4297 if (predicate_implies(pred, rator))
4298 return make_discarding_sequence(rand, scheme_true, info);
4299 else if (predicate_implies_not(pred, rator))
4300 return make_discarding_sequence(rand, scheme_false, info);
4301
4302 return NULL;
4303 }
4304
check_ignored_call_cc(Scheme_Object * rator,Scheme_Object * rand,Optimize_Info * info,int context)4305 static Scheme_Object *check_ignored_call_cc(Scheme_Object *rator, Scheme_Object *rand,
4306 Optimize_Info *info, int context)
4307 /* Convert (call/cc (lambda (ignored) body ...)) to (begin body ...) */
4308 {
4309 if (SCHEME_PRIMP(rator)
4310 && (IS_NAMED_PRIM(rator, "call-with-current-continuation")
4311 || IS_NAMED_PRIM(rator, "call-with-composable-continuation")
4312 || IS_NAMED_PRIM(rator, "call-with-escape-continuation"))) {
4313 Scheme_Object *proc;
4314
4315 proc = lookup_constant_proc(info, rand, 1);
4316
4317 if (proc && SAME_TYPE(SCHEME_TYPE(proc), scheme_ir_lambda_type)) {
4318 Scheme_Lambda *lam = (Scheme_Lambda *)proc;
4319 if (lam->num_params == 1) {
4320 Scheme_IR_Lambda_Info *cl = lam->ir_info;
4321 if (!cl->vars[0]->use_count) {
4322 Scheme_Object *expr;
4323 info->vclock++;
4324 expr = make_application_2(rand, scheme_void, info);
4325 if (IS_NAMED_PRIM(rator, "call-with-escape-continuation")) {
4326 Scheme_Sequence *seq;
4327
4328 seq = scheme_malloc_sequence(1);
4329 seq->so.type = scheme_begin0_sequence_type;
4330 seq->count = 1;
4331 seq->array[0] = expr;
4332
4333 expr = (Scheme_Object *)seq;
4334 }
4335 return optimize_expr(expr, info, context);
4336 }
4337 }
4338 }
4339 }
4340 return NULL;
4341 }
4342
make_optimize_prim_application2(Scheme_Object * prim,Scheme_Object * rand,Optimize_Info * info,int context)4343 static Scheme_Object *make_optimize_prim_application2(Scheme_Object *prim, Scheme_Object *rand,
4344 Optimize_Info *info, int context)
4345 /* make (prim rand) and optimize it. rand must be already optimized */
4346 {
4347 Scheme_Object *alt;
4348 alt = make_application_2(prim, rand, info);
4349 /* scheme_make_application may use constant folding, check that alt is not a constant */
4350 if (SAME_TYPE(SCHEME_TYPE(alt), scheme_application2_type)) {
4351 return finish_optimize_application2((Scheme_App2_Rec *)alt, info, context);
4352 } else
4353 return alt;
4354 }
4355
4356
optimize_application2(Scheme_Object * o,Optimize_Info * info,int context)4357 static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *info, int context)
4358 {
4359 Scheme_App2_Rec *app;
4360 Scheme_Object *le;
4361 int rator_apply_escapes, sub_context, ty;
4362 Optimize_Info_Sequence info_seq;
4363
4364 app = (Scheme_App2_Rec *)o;
4365
4366 le = check_app_let_rator(o, app->rator, info, 1, context);
4367 if (le)
4368 return le;
4369
4370 le = check_ignored_call_cc(app->rator, app->rand, info, context);
4371 if (le)
4372 return le;
4373
4374 le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, context, 0);
4375 if (le)
4376 return le;
4377
4378 optimize_info_seq_init(info, &info_seq);
4379
4380 sub_context = OPT_CONTEXT_SINGLED;
4381
4382 le = optimize_expr(app->rator, info, sub_context);
4383 app->rator = le;
4384 if (info->escapes) {
4385 optimize_info_seq_done(info, &info_seq);
4386 return ensure_noncm(app->rator, info);
4387 }
4388
4389 {
4390 /* Maybe found "((lambda" after optimizing; try again */
4391 le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, context, 1);
4392 if (le)
4393 return le;
4394 rator_apply_escapes = info->escapes;
4395 }
4396
4397 if (SAME_PTR(scheme_not_proc, app->rator)){
4398 sub_context |= OPT_CONTEXT_BOOLEAN;
4399 } else {
4400 ty = wants_local_type_arguments(app->rator, 0);
4401 if (ty)
4402 sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT);
4403 }
4404
4405 optimize_info_seq_step(info, &info_seq);
4406
4407 le = optimize_expr(app->rand, info, sub_context);
4408 app->rand = le;
4409 optimize_info_seq_done(info, &info_seq);
4410 if (info->escapes) {
4411 info->size += 1;
4412 return ensure_noncm(make_discarding_first_sequence(app->rator, app->rand, info), info);
4413 }
4414
4415 if (rator_apply_escapes) {
4416 info->escapes = 1;
4417 SCHEME_APPN_FLAGS(app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4418 }
4419
4420 return finish_optimize_application2(app, info, context);
4421 }
4422
finish_optimize_application2(Scheme_App2_Rec * app,Optimize_Info * info,int context)4423 static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimize_Info *info, int context)
4424 {
4425 int flags, rator_flags;
4426 Scheme_Object *rator = app->rator;
4427 Scheme_Object *rand, *inside = NULL, *alt;
4428
4429 info->size += 1;
4430 info->preserves_marks = 1;
4431 info->single_result = 1;
4432
4433 /* Path for direct constant folding */
4434 if (SCHEME_TYPE(app->rand) > _scheme_ir_values_types_) {
4435 Scheme_Object *le;
4436 le = try_optimize_fold(rator, NULL, (Scheme_Object *)app, info);
4437 if (le)
4438 return le;
4439 }
4440
4441 rand = app->rand;
4442
4443 /* We can go inside a `begin' and a `let', which is useful in case
4444 the argument was a function call that has been inlined. */
4445 extract_tail_inside(&rand, &inside, 0);
4446
4447 if (SCHEME_TYPE(rand) > _scheme_ir_values_types_) {
4448 Scheme_Object *le;
4449 le = try_optimize_fold(rator, scheme_make_pair(rand, scheme_null), NULL, info);
4450 if (le)
4451 return replace_tail_inside(le, inside, app->rand);
4452 }
4453
4454 if (SAME_OBJ(scheme_values_proc, rator)
4455 || SAME_OBJ(scheme_list_star_proc, rator)
4456 || (SCHEME_PRIMP(rator) && IS_NAMED_PRIM(rator, "append"))) {
4457 SCHEME_APPN_FLAGS(app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4458 if ((context & OPT_CONTEXT_SINGLED)
4459 || scheme_omittable_expr(rand, 1, -1, 0, info, info)
4460 || single_valued_noncm_expression(rand, info, 5)) {
4461 return replace_tail_inside(rand, inside, app->rand);
4462 }
4463 app->rator = scheme_values_proc;
4464 rator = scheme_values_proc;
4465 }
4466
4467 if (SCHEME_PRIMP(rator)
4468 && (1 >= ((Scheme_Primitive_Proc *)rator)->mina)
4469 && (1 <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)) {
4470 /* Check for things like (cXr (cons X Y)): */
4471 switch (SCHEME_TYPE(rand)) {
4472 case scheme_application2_type:
4473 {
4474 Scheme_App2_Rec *app2 = (Scheme_App2_Rec *)rand;
4475 if (IS_NAMED_PRIM(rator, "car")
4476 || IS_NAMED_PRIM(rator, "unsafe-car")) {
4477 if (SAME_OBJ(scheme_list_proc, app2->rator)) {
4478 /* (car (list X)) */
4479 alt = ensure_single_value_noncm(app2->rand, info);
4480 return replace_tail_inside(alt, inside, app->rand);
4481 }
4482 } else if (IS_NAMED_PRIM(rator, "cdr")
4483 || IS_NAMED_PRIM(rator, "unsafe-cdr")) {
4484 if (SAME_OBJ(scheme_list_proc, app2->rator)) {
4485 /* (cdr (list X)) */
4486 alt = make_discarding_sequence(app2->rand, scheme_null, info);
4487 return replace_tail_inside(alt, inside, app->rand);
4488 }
4489 } else if (IS_NAMED_PRIM(rator, "unbox")
4490 || IS_NAMED_PRIM(rator, "unsafe-unbox")
4491 || IS_NAMED_PRIM(rator, "unsafe-unbox*")) {
4492 if (SAME_OBJ(scheme_box_proc, app2->rator)) {
4493 /* (unbox (box X)) */
4494 alt = ensure_single_value_noncm(app2->rand, info);
4495 return replace_tail_inside(alt, inside, app->rand);
4496 }
4497 }
4498 break;
4499 }
4500 case scheme_application3_type:
4501 {
4502 Scheme_App3_Rec *app3 = (Scheme_App3_Rec *)rand;
4503 if (IS_NAMED_PRIM(rator, "car")
4504 || IS_NAMED_PRIM(rator, "unsafe-car")) {
4505 if (SAME_OBJ(scheme_cons_proc, app3->rator)
4506 || SAME_OBJ(scheme_unsafe_cons_list_proc, app3->rator)
4507 || SAME_OBJ(scheme_list_proc, app3->rator)
4508 || SAME_OBJ(scheme_list_star_proc, app3->rator)) {
4509 /* (car ({cons|list|list*} X Y)) */
4510 alt = make_discarding_reverse_sequence(app3->rand2, app3->rand1, info);
4511 return replace_tail_inside(alt, inside, app->rand);
4512 }
4513 } else if (IS_NAMED_PRIM(rator, "cdr")
4514 || IS_NAMED_PRIM(rator, "unsafe-cdr")) {
4515 if (SAME_OBJ(scheme_cons_proc, app3->rator)
4516 || SAME_OBJ(scheme_unsafe_cons_list_proc, app3->rator)
4517 || SAME_OBJ(scheme_list_star_proc, app3->rator)) {
4518 /* (cdr ({cons|list*} X Y)) */
4519 alt = make_discarding_sequence(app3->rand1, app3->rand2, info);
4520 return replace_tail_inside(alt, inside, app->rand);
4521 } else if (SAME_OBJ(scheme_list_proc, app3->rator)) {
4522 /* (cdr (list X Y)) */
4523 alt = make_application_2(scheme_list_proc, app3->rand2, info);
4524 SCHEME_APPN_FLAGS(((Scheme_App_Rec *)alt)) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4525 alt = make_discarding_sequence(app3->rand1, alt, info);
4526 return replace_tail_inside(alt, inside, app->rand);
4527 }
4528 } else if (IS_NAMED_PRIM(rator, "cadr")) {
4529 if (SAME_OBJ(scheme_list_proc, app3->rator)) {
4530 /* (cadr (list X Y)) */
4531 alt = make_discarding_sequence(app3->rand1, app3->rand2, info);
4532 return replace_tail_inside(alt, inside, app->rand);
4533 }
4534 }
4535 break;
4536 }
4537 case scheme_application_type:
4538 {
4539 Scheme_App_Rec *appr = (Scheme_App_Rec *)rand;
4540 Scheme_Object *r = appr->args[0];
4541 if (IS_NAMED_PRIM(rator, "car")
4542 || IS_NAMED_PRIM(rator, "unsafe-car")) {
4543 if ((appr->args > 0)
4544 && (SAME_OBJ(scheme_list_proc, r)
4545 || SAME_OBJ(scheme_list_star_proc, r))) {
4546 /* (car ({list|list*} X Y ...)) */
4547 alt = make_discarding_app_sequence(appr, 0, NULL, info);
4548 return replace_tail_inside(alt, inside, app->rand);
4549 }
4550 } else if (IS_NAMED_PRIM(rator, "cdr")
4551 || IS_NAMED_PRIM(rator, "unsafe-cdr")) {
4552 /* (cdr ({list|list*} X Y ...)) */
4553 if ((appr->args > 0)
4554 && (SAME_OBJ(scheme_list_proc, r)
4555 || SAME_OBJ(scheme_list_star_proc, r))) {
4556 Scheme_Object *al = scheme_null;
4557 int k;
4558 for (k = appr->num_args; k > 1; k--) {
4559 al = scheme_make_pair(appr->args[k], al);
4560 }
4561 al = scheme_make_pair(r, al);
4562 alt = scheme_make_application(al, info);
4563 SCHEME_APPN_FLAGS(((Scheme_App_Rec *)alt)) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4564 alt = make_discarding_sequence(appr->args[1], alt, info);
4565 return replace_tail_inside(alt, inside, app->rand);
4566 }
4567 }
4568 break;
4569 }
4570 }
4571
4572 if (IS_NAMED_PRIM(rator, "length")
4573 && SCHEME_LISTP(rand)) {
4574 alt = scheme_make_integer(scheme_list_length(rand));
4575 return replace_tail_inside(alt, inside, app->rand);
4576 }
4577
4578 alt = try_reduce_predicate(rator, rand, info);
4579 if (alt)
4580 return replace_tail_inside(alt, inside, app->rand);
4581
4582 if (SAME_OBJ(scheme_struct_type_p_proc, rator)) {
4583 Scheme_Object *c;
4584 c = get_struct_proc_shape(rand, info, 0);
4585 if (c && ((SCHEME_PROC_SHAPE_MODE(c) & STRUCT_PROC_SHAPE_MASK)
4586 == STRUCT_PROC_SHAPE_STRUCT)) {
4587 return replace_tail_inside(scheme_true, inside, app->rand);
4588 }
4589 }
4590
4591 if (SAME_OBJ(scheme_varref_const_p_proc, rator)
4592 && SAME_TYPE(SCHEME_TYPE(rand), scheme_varref_form_type)) {
4593 Scheme_Object *var = SCHEME_PTR1_VAL(rand);
4594 if (SAME_OBJ(var, scheme_true)) {
4595 return replace_tail_inside(scheme_true, inside, app->rand);
4596 } else if (SAME_OBJ(var, scheme_false)) {
4597 return replace_tail_inside(scheme_false, inside, app->rand);
4598 } else {
4599 if (var && ir_propagate_ok(var, info, 1, NULL)) {
4600 /* can propagate => is a constant */
4601 return replace_tail_inside(scheme_true, inside, app->rand);
4602 }
4603 }
4604 }
4605
4606 /* We can resolve (variable-reference-from-unsafe (#%variable-reference))
4607 to a specific boolean result */
4608 if (SAME_OBJ(scheme_varref_unsafe_p_proc, rator)
4609 && SAME_TYPE(SCHEME_TYPE(rand), scheme_varref_form_type)) {
4610 Scheme_Object *result = (info->unsafe_mode ? scheme_true : scheme_false);
4611 return replace_tail_inside(result, inside, app->rand);
4612 }
4613
4614 if (SCHEME_PRIMP(rator)
4615 && (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_PRODUCES_BOOL)
4616 && (IS_NAMED_PRIM(rator, "zero?")
4617 || IS_NAMED_PRIM(rator, "positive?")
4618 || IS_NAMED_PRIM(rator, "negative?"))) {
4619 Scheme_Object* pred;
4620 Scheme_App3_Rec *new;
4621
4622 pred = expr_implies_predicate(rand, info);
4623 if (pred && SAME_OBJ(pred, scheme_fixnum_p_proc)) {
4624 Scheme_Object *cmp;
4625 if (IS_NAMED_PRIM(rator, "positive?"))
4626 cmp = scheme_unsafe_fx_gt_proc;
4627 else if (IS_NAMED_PRIM(rator, "negative?"))
4628 cmp = scheme_unsafe_fx_lt_proc;
4629 else
4630 cmp = scheme_unsafe_fx_eq_proc;
4631 new = (Scheme_App3_Rec *)make_application_3(cmp, app->rand, scheme_make_integer(0), info);
4632 SCHEME_APPN_FLAGS(new) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4633 return finish_optimize_application3(new, info, context);
4634 }
4635 }
4636
4637 if (SAME_OBJ(rator, scheme_system_type_proc)
4638 && SCHEME_SYMBOLP(rand)
4639 && !SCHEME_SYM_WEIRDP(rand)
4640 && !strcmp(SCHEME_SYM_VAL(rand), "vm")) {
4641 /* For the expander's benefit, optimize `(system-type 'vm)` to `'racket`
4642 to effectively select backend details statically. */
4643 return replace_tail_inside(scheme_intern_symbol("racket"), inside, app->rand);
4644 }
4645
4646 {
4647 /* Try to check the argument's type, and use the unsafe versions if possible. */
4648 Scheme_Object *app_o = (Scheme_Object *)app;
4649
4650 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_AD_HOC_OPT) {
4651 check_known_variant(info, app_o, rator, rand, "bitwise-not", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc, 0, scheme_real_p_proc);
4652 check_known_variant(info, app_o, rator, rand, "fxnot", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc, info->unsafe_mode, scheme_real_p_proc);
4653
4654 check_known(info, app_o, rator, rand, "car", scheme_pair_p_proc, scheme_unsafe_car_proc, info->unsafe_mode);
4655 check_known(info, app_o, rator, rand, "unsafe-car", scheme_pair_p_proc, NULL, info->unsafe_mode);
4656 check_known(info, app_o, rator, rand, "cdr", scheme_pair_p_proc, scheme_unsafe_cdr_proc, info->unsafe_mode);
4657 check_known(info, app_o, rator, rand, "unsafe-cdr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4658 check_known(info, app_o, rator, rand, "mcar", scheme_mpair_p_proc, scheme_unsafe_mcar_proc, info->unsafe_mode);
4659 check_known(info, app_o, rator, rand, "unsafe-mcar", scheme_mpair_p_proc, NULL, info->unsafe_mode);
4660 check_known(info, app_o, rator, rand, "mcdr", scheme_mpair_p_proc, scheme_unsafe_mcdr_proc, info->unsafe_mode);
4661 check_known(info, app_o, rator, rand, "unsafe-mcdr", scheme_mpair_p_proc, NULL, info->unsafe_mode);
4662 check_known(info, app_o, rator, rand, "string-length", scheme_string_p_proc, scheme_unsafe_string_length_proc, info->unsafe_mode);
4663 check_known(info, app_o, rator, rand, "bytes-length", scheme_byte_string_p_proc, scheme_unsafe_byte_string_length_proc, info->unsafe_mode);
4664 /* It's not clear that these are useful, since a chaperone check is needed anyway: */
4665 check_known(info, app_o, rator, rand, "unbox", scheme_box_p_proc, scheme_unsafe_unbox_proc, info->unsafe_mode);
4666 check_known(info, app_o, rator, rand, "unbox*", scheme_box_p_proc,
4667 (info->unsafe_mode ? scheme_unsafe_unbox_star_proc : NULL), info->unsafe_mode);
4668 check_known(info, app_o, rator, rand, "unsafe-unbox", scheme_box_p_proc, NULL, info->unsafe_mode);
4669 check_known(info, app_o, rator, rand, "unsafe-unbox*", scheme_box_p_proc, NULL, info->unsafe_mode);
4670 check_known(info, app_o, rator, rand, "vector-length", scheme_vector_p_proc, scheme_unsafe_vector_length_proc, info->unsafe_mode);
4671 check_known(info, app_o, rator, rand, "vector*-length", scheme_vector_p_proc,
4672 (info->unsafe_mode ? scheme_unsafe_vector_star_length_proc : NULL), info->unsafe_mode);
4673
4674 check_known(info, app_o, rator, rand, "length", scheme_list_p_proc, scheme_true, info->unsafe_mode);
4675
4676 check_known(info, app_o, rator, rand, "string-append", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4677 check_known(info, app_o, rator, rand, "string-append-immutable", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4678 check_known(info, app_o, rator, rand, "bytes-append", scheme_byte_string_p_proc, scheme_true, info->unsafe_mode);
4679 check_known(info, app_o, rator, rand, "string->immutable-string", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4680 check_known(info, app_o, rator, rand, "bytes->immutable-bytes", scheme_byte_string_p_proc, scheme_true, info->unsafe_mode);
4681
4682 check_known(info, app_o, rator, rand, "string->symbol", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4683 check_known(info, app_o, rator, rand, "symbol->string", scheme_symbol_p_proc, scheme_true, info->unsafe_mode);
4684 check_known(info, app_o, rator, rand, "symbol->string-immutable", scheme_symbol_p_proc, scheme_true, info->unsafe_mode);
4685 check_known(info, app_o, rator, rand, "string->keyword", scheme_string_p_proc, scheme_true, info->unsafe_mode);
4686 check_known(info, app_o, rator, rand, "keyword->string", scheme_keyword_p_proc, scheme_true, info->unsafe_mode);
4687
4688 check_known(info, app_o, rator, rand, "char->integer", scheme_char_p_proc, scheme_unsafe_char_to_integer_proc, info->unsafe_mode);
4689
4690 if (IS_NAMED_PRIM(rator, "real->double-flonum")
4691 || IS_NAMED_PRIM(rator, "exact->inexact")) {
4692 Scheme_Object *pred;
4693 pred = expr_implies_predicate(rand, info);
4694 if (predicate_implies(pred, scheme_flonum_p_proc))
4695 return replace_tail_inside(rand, inside, rand);
4696 else if (predicate_implies(pred, scheme_fixnum_p_proc))
4697 reset_rator(app_o, scheme_unsafe_fx_to_fl_proc);
4698 }
4699 }
4700
4701 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_REAL)
4702 check_known(info, app_o, rator, rand, NULL, scheme_real_p_proc,
4703 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
4704 info->unsafe_mode);
4705 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_NUMBER)
4706 check_known(info, app_o, rator, rand, NULL, scheme_number_p_proc,
4707 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
4708 info->unsafe_mode);
4709
4710 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_AD_HOC_OPT) {
4711 /* These operation don't have an unsafe replacement. Check to record types and detect errors: */
4712 check_known(info, app_o, rator, rand, "caar", scheme_pair_p_proc, NULL, info->unsafe_mode);
4713 check_known(info, app_o, rator, rand, "cadr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4714 check_known(info, app_o, rator, rand, "cdar", scheme_pair_p_proc, NULL, info->unsafe_mode);
4715 check_known(info, app_o, rator, rand, "cddr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4716
4717 check_known(info, app_o, rator, rand, "caddr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4718 check_known(info, app_o, rator, rand, "cdddr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4719 check_known(info, app_o, rator, rand, "cadddr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4720 check_known(info, app_o, rator, rand, "cddddr", scheme_pair_p_proc, NULL, info->unsafe_mode);
4721
4722 check_known(info, app_o, rator, rand, "list->vector", scheme_list_p_proc, scheme_true, info->unsafe_mode);
4723 check_known(info, app_o, rator, rand, "vector->list", scheme_vector_p_proc, NULL, info->unsafe_mode);
4724 check_known(info, app_o, rator, rand, "vector->values", scheme_vector_p_proc, NULL, info->unsafe_mode);
4725 check_known(info, app_o, rator, rand, "vector->immutable-vector", scheme_vector_p_proc, NULL, info->unsafe_mode);
4726 check_known(info, app_o, rator, rand, "make-vector", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
4727 }
4728
4729 /* Some of these may have changed app->rator. */
4730 rator = app->rator;
4731 }
4732 }
4733
4734 /* Using a struct getter or predicate? */
4735 alt = get_struct_proc_shape(rator, info, 0);
4736 if (alt) {
4737 int mode = (SCHEME_PROC_SHAPE_MODE(alt) & STRUCT_PROC_SHAPE_MASK);
4738
4739 if ((mode == STRUCT_PROC_SHAPE_PRED)
4740 || (mode == STRUCT_PROC_SHAPE_GETTER)) {
4741 Scheme_Object *pred;
4742 int unsafe = 0;
4743
4744 if (info->unsafe_mode && (mode == STRUCT_PROC_SHAPE_GETTER)) {
4745 pred = NULL;
4746 unsafe = 1;
4747 } else
4748 pred = expr_implies_predicate(rand, info);
4749
4750 if (unsafe
4751 || (pred
4752 && SAME_TYPE(SCHEME_TYPE(pred), scheme_struct_proc_shape_type)
4753 && is_struct_identity_subtype(SCHEME_PROC_SHAPE_IDENTITY(pred),
4754 SCHEME_PROC_SHAPE_IDENTITY(alt)))) {
4755 if (mode == STRUCT_PROC_SHAPE_PRED) {
4756 /* We know that the predicate will succeed */
4757 return replace_tail_inside(make_discarding_sequence(rand, scheme_true, info),
4758 inside,
4759 app->rand);
4760 } else {
4761 /* Struct type matches, so use `unsafe-struct-ref` */
4762 Scheme_App3_Rec *new;
4763 new = (Scheme_App3_Rec *)make_application_3(((SCHEME_PROC_SHAPE_MODE(alt) & STRUCT_PROC_SHAPE_AUTHENTIC)
4764 ? scheme_unsafe_struct_star_ref_proc
4765 : scheme_unsafe_struct_ref_proc),
4766 app->rand,
4767 scheme_make_integer(SCHEME_PROC_SHAPE_MODE(alt) >> STRUCT_PROC_SHAPE_SHIFT),
4768 info);
4769 SCHEME_APPN_FLAGS(new) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4770 return finish_optimize_application3(new, info, context);
4771 }
4772 } else if ((mode == STRUCT_PROC_SHAPE_PRED) && pred && predicate_implies_not(pred, alt)) {
4773 /* We know that the predicate will fail */
4774 return replace_tail_inside(make_discarding_sequence(rand, scheme_false, info),
4775 inside,
4776 app->rand);
4777 }
4778
4779 /* Register type based on getter succeeding: */
4780 if ((mode == STRUCT_PROC_SHAPE_GETTER)
4781 && !SCHEME_NULLP(SCHEME_PROC_SHAPE_IDENTITY(alt))
4782 && SAME_TYPE(SCHEME_TYPE(rand), scheme_ir_local_type))
4783 add_type(info, rand, scheme_make_struct_proc_shape(STRUCT_PROC_SHAPE_PRED,
4784 SCHEME_PROC_SHAPE_IDENTITY(alt)));
4785 }
4786 }
4787
4788 increment_clocks_for_application(info, rator, 1);
4789
4790 rator_flags = get_rator_flags(rator, 1, info);
4791 info->preserves_marks = !!(rator_flags & LAMBDA_PRESERVES_MARKS);
4792 info->single_result = !!(rator_flags & LAMBDA_SINGLE_RESULT);
4793 if ((rator_flags & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE) {
4794 info->preserves_marks = -info->preserves_marks;
4795 info->single_result = -info->single_result;
4796 }
4797
4798 register_local_argument_types(NULL, app, NULL, info);
4799
4800 flags = appn_flags(rator, info);
4801 SCHEME_APPN_FLAGS(app) |= flags;
4802
4803 return finish_optimize_any_application((Scheme_Object *)app, rator, 1, info, context);
4804 }
4805
optimize_application3(Scheme_Object * o,Optimize_Info * info,int context)4806 static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *info, int context)
4807 {
4808 Scheme_App3_Rec *app;
4809 Scheme_Object *le;
4810 int rator_apply_escapes, sub_context, ty, flags;
4811 Optimize_Info_Sequence info_seq;
4812
4813 app = (Scheme_App3_Rec *)o;
4814
4815 if (SAME_OBJ(app->rator, scheme_check_not_undefined_proc)
4816 && SCHEME_SYMBOLP(app->rand2)) {
4817 if (scheme_log_level_p(info->logger, SCHEME_LOG_DEBUG))
4818 scheme_log(info->logger,
4819 SCHEME_LOG_DEBUG,
4820 0,
4821 "warning%s: use-before-definition check inserted on variable: %S",
4822 scheme_optimize_context_to_string(info->context),
4823 app->rand2);
4824 }
4825
4826 /* Check for (apply ... (list ...)) early: */
4827 le = direct_apply((Scheme_Object *)app, app->rator, app->rand2, info);
4828 if (le)
4829 return optimize_expr(le, info, context);
4830
4831 le = call_with_immed_mark(app->rator, app->rand1, app->rand2, NULL, info);
4832 if (le)
4833 return optimize_expr(le, info, context);
4834
4835 le = check_app_let_rator(o, app->rator, info, 2, context);
4836 if (le)
4837 return le;
4838
4839 le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, context, 0);
4840 if (le)
4841 return le;
4842
4843 optimize_info_seq_init(info, &info_seq);
4844
4845 sub_context = OPT_CONTEXT_SINGLED;
4846
4847 le = optimize_expr(app->rator, info, sub_context);
4848 app->rator = le;
4849 if (info->escapes) {
4850 optimize_info_seq_done(info, &info_seq);
4851 return ensure_noncm(app->rator, info);
4852 }
4853
4854 {
4855 /* Maybe found "((lambda" after optimizing; try again */
4856 le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, context, 1);
4857 if (le)
4858 return le;
4859 rator_apply_escapes = info->escapes;
4860 }
4861
4862 if (SAME_OBJ(app->rator, scheme_values_proc)
4863 || SAME_OBJ(app->rator, scheme_apply_proc))
4864 info->maybe_values_argument = 1;
4865
4866 /* 1st arg */
4867
4868 ty = wants_local_type_arguments(app->rator, 0);
4869 if (ty)
4870 sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT);
4871
4872 optimize_info_seq_step(info, &info_seq);
4873
4874 le = optimize_expr(app->rand1, info, sub_context);
4875 app->rand1 = le;
4876 if (info->escapes) {
4877 info->size += 1;
4878 return ensure_noncm(make_discarding_first_sequence(app->rator, app->rand1, info), info);
4879 }
4880
4881 /* 2nd arg */
4882
4883 ty = wants_local_type_arguments(app->rator, 1);
4884 if (ty)
4885 sub_context |= (ty << OPT_CONTEXT_TYPE_SHIFT);
4886 else
4887 sub_context &= ~OPT_CONTEXT_TYPE_MASK;
4888
4889 optimize_info_seq_step(info, &info_seq);
4890
4891 le = optimize_expr(app->rand2, info, sub_context);
4892 app->rand2 = le;
4893 optimize_info_seq_done(info, &info_seq);
4894 if (info->escapes) {
4895 info->size += 1;
4896 le = make_discarding_first_sequence(app->rator,
4897 make_discarding_first_sequence(app->rand1, app->rand2,
4898 info),
4899 info);
4900 return ensure_noncm(le, info);
4901 }
4902
4903 /* Check for (apply ... (list ...)) after some optimizations: */
4904 le = direct_apply((Scheme_Object *)app, app->rator, app->rand2, info);
4905 if (le) return finish_optimize_app(le, info, context);
4906
4907 flags = appn_flags(app->rator, info);
4908 SCHEME_APPN_FLAGS(app) |= flags;
4909
4910 if (rator_apply_escapes) {
4911 info->escapes = 1;
4912 SCHEME_APPN_FLAGS(app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
4913 }
4914
4915 return finish_optimize_application3(app, info, context);
4916 }
4917
finish_optimize_application3(Scheme_App3_Rec * app,Optimize_Info * info,int context)4918 static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimize_Info *info, int context)
4919 {
4920 int flags, rator_flags;
4921 Scheme_Object *le;
4922 int all_vals = 1;
4923
4924 info->size += 1;
4925 info->preserves_marks = 1;
4926 info->single_result = 1;
4927
4928 if (SCHEME_TYPE(app->rand1) < _scheme_ir_values_types_)
4929 all_vals = 0;
4930 if (SCHEME_TYPE(app->rand2) < _scheme_ir_values_types_)
4931 all_vals = 0;
4932
4933
4934 if (all_vals) {
4935 le = try_optimize_fold(app->rator, NULL, (Scheme_Object *)app, info);
4936 if (le)
4937 return le;
4938 }
4939
4940 /* Check for (call-with-values (lambda () M) N): */
4941 if (SAME_OBJ(app->rator, scheme_call_with_values_proc)) {
4942 if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_ir_lambda_type)) {
4943 Scheme_Lambda *lam = (Scheme_Lambda *)app->rand1;
4944
4945 if (!lam->num_params) {
4946 /* Convert to apply-values form: */
4947 return optimize_apply_values(app->rand2, lam->body, info,
4948 ((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_SINGLE_RESULT)
4949 ? (((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE)
4950 ? -1
4951 : 1)
4952 : 0),
4953 context);
4954 }
4955 }
4956 }
4957
4958 if (SAME_OBJ(scheme_procedure_arity_includes_proc, app->rator)) {
4959 if (SCHEME_INTP(app->rand2) && SCHEME_INT_VAL(app->rand2) >= 0) {
4960 Scheme_Object *proc;
4961
4962 proc = lookup_constant_proc(info, app->rand1, SCHEME_INT_VAL(app->rand2));
4963 if (proc) {
4964 info->preserves_marks = 1;
4965 info->single_result = 1;
4966 return make_discarding_sequence(app->rand1,
4967 SAME_OBJ(proc, scheme_true) ? scheme_false : scheme_true,
4968 info);
4969 }
4970 }
4971 }
4972
4973 if (SAME_OBJ(app->rator, scheme_equal_proc)
4974 || SAME_OBJ(app->rator, scheme_eqv_proc)
4975 || SAME_OBJ(app->rator, scheme_eq_proc)) {
4976 if (equivalent_exprs(app->rand1, app->rand2, NULL, NULL, 0)) {
4977 return make_discarding_sequence_3(app->rand1, app->rand2, scheme_true, info);
4978 }
4979 {
4980 Scheme_Object *pred1, *pred2, *pred_new = NULL;
4981 int rel1=0, rel2=0, rel_max, eq_type=0;
4982
4983 pred1 = expr_implies_predicate(app->rand1, info);
4984 pred2 = expr_implies_predicate(app->rand2, info);
4985 rel1 = relevant_predicate(pred1);
4986 rel2 = relevant_predicate(pred2);
4987 if ((pred1 && pred2)
4988 && (predicate_implies_not(pred1, pred2)
4989 || predicate_implies_not(pred2, pred1))) {
4990 info->preserves_marks = 1;
4991 info->single_result = 1;
4992 return make_discarding_sequence_3(app->rand1, app->rand2, scheme_false, info);
4993 }
4994
4995 /* Try to transform it into a predicate */
4996 if (rel1 >= RLV_SINGLETON) {
4997 Scheme_Object *new_app;
4998 new_app = make_optimize_prim_application2(pred1, app->rand2, info, context);
4999 return make_discarding_sequence(app->rand1, new_app, info);
5000 }
5001 if (rel2 >= RLV_SINGLETON) {
5002 Scheme_Object *new_app;
5003 new_app = make_optimize_prim_application2(pred2, app->rand1, info, context);
5004 return make_discarding_reverse_sequence(app->rand2, new_app, info);
5005 }
5006
5007 /* Optimize `equal?' or `eqv?' test on certain types
5008 to `eqv?` or `eq?'. This is especially helpful for the JIT. */
5009 if (SAME_OBJ(app->rator, scheme_eqv_proc))
5010 eq_type = RLV_EQV_TESTEABLE;
5011 if (SAME_OBJ(app->rator, scheme_eq_proc))
5012 eq_type = RLV_EQ_TESTEABLE;
5013
5014 rel_max = (rel1 >= rel2) ? rel1 : rel2;
5015 if (rel_max >= RLV_EQ_TESTEABLE && eq_type < RLV_EQ_TESTEABLE)
5016 pred_new = scheme_eq_proc;
5017 else if (rel_max >= RLV_EQV_TESTEABLE && eq_type < RLV_EQV_TESTEABLE)
5018 pred_new = scheme_eqv_proc;
5019
5020 if (pred_new) {
5021 app->rator = pred_new;
5022 SCHEME_APPN_FLAGS(app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
5023
5024 /* eq? and eqv? are foldable */
5025 if (all_vals) {
5026 le = try_optimize_fold(app->rator, NULL, (Scheme_Object *)app, info);
5027 if (le)
5028 return le;
5029 }
5030 }
5031 }
5032 }
5033
5034 /* Ad hoc optimization of (unsafe-+ <x> 0), etc. */
5035 if (SCHEME_PRIMP(app->rator)
5036 && (SCHEME_PRIM_PROC_OPT_FLAGS(app->rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING)) {
5037 int z1, z2;
5038
5039 z1 = SAME_OBJ(app->rand1, scheme_make_integer(0));
5040 z2 = SAME_OBJ(app->rand2, scheme_make_integer(0));
5041 if (IS_NAMED_PRIM(app->rator, "unsafe-fx+")) {
5042 if (z1)
5043 return ensure_single_value_noncm(app->rand2, info);
5044 else if (z2)
5045 return ensure_single_value_noncm(app->rand1, info);
5046 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fx-")) {
5047 if (z2)
5048 return ensure_single_value_noncm(app->rand1, info);
5049 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fx*")) {
5050 if (z1 || z2) {
5051 if (z1 && z2)
5052 return scheme_make_integer(0);
5053 else if (z2)
5054 return make_discarding_sequence(app->rand1, scheme_make_integer(0), info);
5055 else
5056 return make_discarding_sequence(app->rand2, scheme_make_integer(0), info);
5057 }
5058 if (SAME_OBJ(app->rand1, scheme_make_integer(1)))
5059 return ensure_single_value_noncm(app->rand2, info);
5060 if (SAME_OBJ(app->rand2, scheme_make_integer(1)))
5061 return ensure_single_value_noncm(app->rand1, info);
5062 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fxquotient")) {
5063 if (z1)
5064 return make_discarding_sequence(app->rand2, scheme_make_integer(0), info);
5065 if (SAME_OBJ(app->rand2, scheme_make_integer(1)))
5066 return ensure_single_value_noncm(app->rand1, info);
5067 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fxremainder")
5068 || IS_NAMED_PRIM(app->rator, "unsafe-fxmodulo")) {
5069 if (z1)
5070 return make_discarding_sequence(app->rand2, scheme_make_integer(0), info);
5071 if (SAME_OBJ(app->rand2, scheme_make_integer(1)))
5072 return make_discarding_sequence(app->rand1, scheme_make_integer(0), info);
5073 }
5074
5075 z1 = (SCHEME_FLOATP(app->rand1) && (SCHEME_FLOAT_VAL(app->rand1) == 0.0));
5076 z2 = (SCHEME_FLOATP(app->rand2) && (SCHEME_FLOAT_VAL(app->rand2) == 0.0));
5077
5078 if (IS_NAMED_PRIM(app->rator, "unsafe-fl+")) {
5079 if (z1)
5080 return ensure_single_value_noncm(app->rand2, info);
5081 else if (z2)
5082 return ensure_single_value_noncm(app->rand1, info);
5083 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fl-")) {
5084 if (z2)
5085 return ensure_single_value_noncm(app->rand1, info);
5086 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fl*")) {
5087 if (SCHEME_FLOATP(app->rand1) && (SCHEME_FLOAT_VAL(app->rand1) == 1.0))
5088 return ensure_single_value_noncm(app->rand2, info);
5089 if (SCHEME_FLOATP(app->rand2) && (SCHEME_FLOAT_VAL(app->rand2) == 1.0))
5090 return ensure_single_value_noncm(app->rand1, info);
5091 } else if (IS_NAMED_PRIM(app->rator, "unsafe-fl/")) {
5092 if (SCHEME_FLOATP(app->rand2) && (SCHEME_FLOAT_VAL(app->rand2) == 1.0))
5093 return ensure_single_value_noncm(app->rand1, info);
5094 }
5095
5096 /* Possible improvement: detect 0 and 1 constants even when general
5097 extflonum operations are not supported. */
5098 #ifdef MZ_LONG_DOUBLE
5099 z1 = (SCHEME_LONG_DBLP(app->rand1) && long_double_is_zero(SCHEME_LONG_DBL_VAL(app->rand1)));
5100 z2 = (SCHEME_LONG_DBLP(app->rand2) && long_double_is_zero(SCHEME_LONG_DBL_VAL(app->rand2)));
5101
5102 if (IS_NAMED_PRIM(app->rator, "unsafe-extfl+")) {
5103 if (z1)
5104 return ensure_single_value_noncm(app->rand2, info);
5105 else if (z2)
5106 return ensure_single_value_noncm(app->rand1, info);
5107 } else if (IS_NAMED_PRIM(app->rator, "unsafe-extfl-")) {
5108 if (z2)
5109 return ensure_single_value_noncm(app->rand1, info);
5110 } else if (IS_NAMED_PRIM(app->rator, "unsafe-extfl*")) {
5111 if (SCHEME_LONG_DBLP(app->rand1) && long_double_is_1(SCHEME_LONG_DBL_VAL(app->rand1)))
5112 return ensure_single_value_noncm(app->rand2, info);
5113 if (SCHEME_LONG_DBLP(app->rand2) && long_double_is_1(SCHEME_LONG_DBL_VAL(app->rand2)))
5114 return ensure_single_value_noncm(app->rand1, info);
5115 } else if (IS_NAMED_PRIM(app->rator, "unsafe-extfl/")) {
5116 if (SCHEME_LONG_DBLP(app->rand2) && long_double_is_1(SCHEME_LONG_DBL_VAL(app->rand2)))
5117 return ensure_single_value_noncm(app->rand1, info);
5118 }
5119 #endif
5120 } else if (SCHEME_PRIMP(app->rator)
5121 && (SCHEME_PRIM_PROC_OPT_FLAGS(app->rator) & SCHEME_PRIM_IS_BINARY_INLINED)) {
5122 if (IS_NAMED_PRIM(app->rator, "arithmetic-shift")) {
5123 if (SCHEME_INTP(app->rand2) && (SCHEME_INT_VAL(app->rand2) <= 0)
5124 && (is_local_type_expression(app->rand1, info) == SCHEME_LOCAL_TYPE_FIXNUM)) {
5125 app->rator = scheme_unsafe_fxrshift_proc;
5126 app->rand2 = scheme_make_integer(-(SCHEME_INT_VAL(app->rand2)));
5127 }
5128 } else if (IS_NAMED_PRIM(app->rator, "string=?")) {
5129 if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_char_string_type)
5130 && SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_char_string_type)) {
5131 return scheme_string_eq_2(app->rand1, app->rand2);
5132 }
5133 } else if (IS_NAMED_PRIM(app->rator, "bytes=?")) {
5134 if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_byte_string_type)
5135 && SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_byte_string_type)) {
5136 return scheme_byte_string_eq_2(app->rand1, app->rand2);
5137 }
5138 } else if (IS_NAMED_PRIM(app->rator, "char=?")) {
5139 if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_char_type)
5140 && SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_char_type)) {
5141 return (SCHEME_CHAR_VAL(app->rand1) == SCHEME_CHAR_VAL(app->rand2)) ? scheme_true : scheme_false;
5142 }
5143 }
5144 }
5145
5146 if (SCHEME_PRIMP(app->rator)
5147 && (2 >= ((Scheme_Primitive_Proc *)app->rator)->mina)
5148 && (2 <= ((Scheme_Primitive_Proc *)app->rator)->mu.maxa)) {
5149 Scheme_Object *app_o = (Scheme_Object *)app, *rator = app->rator, *rand1 = app->rand1, *rand2 = app->rand2;
5150
5151 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_AD_HOC_OPT) {
5152 check_known_both_variant(info, app_o, rator, rand1, rand2, "bitwise-and", scheme_fixnum_p_proc,
5153 scheme_unsafe_fxand_proc, 0, scheme_real_p_proc);
5154 check_known_both_variant(info, app_o, rator, rand1, rand2, "bitwise-ior", scheme_fixnum_p_proc,
5155 scheme_unsafe_fxior_proc, 0, scheme_real_p_proc);
5156 check_known_both_variant(info, app_o, rator, rand1, rand2, "bitwise-xor", scheme_fixnum_p_proc,
5157 scheme_unsafe_fxxor_proc, 0, scheme_real_p_proc);
5158
5159 check_known_both_variant(info, app_o, rator, rand1, rand2, "fxand", scheme_fixnum_p_proc,
5160 scheme_unsafe_fxand_proc, info->unsafe_mode, scheme_real_p_proc);
5161 check_known_both_variant(info, app_o, rator, rand1, rand2, "fxior", scheme_fixnum_p_proc,
5162 scheme_unsafe_fxior_proc, info->unsafe_mode, scheme_real_p_proc);
5163 check_known_both_variant(info, app_o, rator, rand1, rand2, "fxxor", scheme_fixnum_p_proc,
5164 scheme_unsafe_fxxor_proc, info->unsafe_mode, scheme_real_p_proc);
5165
5166 check_known_both_try(info, app_o, rator, rand1, rand2, "=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc, 0);
5167 check_known_both_try(info, app_o, rator, rand1, rand2, "<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc, 0);
5168 check_known_both_try(info, app_o, rator, rand1, rand2, ">", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc, 0);
5169 check_known_both_try(info, app_o, rator, rand1, rand2, "<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc, 0);
5170 check_known_both_try(info, app_o, rator, rand1, rand2, ">=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc, 0);
5171 check_known_both_try(info, app_o, rator, rand1, rand2, "min", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc, 0);
5172 check_known_both_try(info, app_o, rator, rand1, rand2, "max", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc, 0);
5173
5174 check_known_both_try(info, app_o, rator, rand1, rand2, "fx=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc, info->unsafe_mode);
5175 check_known_both_try(info, app_o, rator, rand1, rand2, "fx<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc, info->unsafe_mode);
5176 check_known_both_try(info, app_o, rator, rand1, rand2, "fx>", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc, info->unsafe_mode);
5177 check_known_both_try(info, app_o, rator, rand1, rand2, "fx<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc, info->unsafe_mode);
5178 check_known_both_try(info, app_o, rator, rand1, rand2, "fx>=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc, info->unsafe_mode);
5179 check_known_both_try(info, app_o, rator, rand1, rand2, "fxmin", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc, info->unsafe_mode);
5180 check_known_both_try(info, app_o, rator, rand1, rand2, "fxmax", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc, info->unsafe_mode);
5181
5182 check_known_both_try(info, app_o, rator, rand1, rand2, "fx+", scheme_fixnum_p_proc, scheme_unsafe_fx_plus_proc, info->unsafe_mode);
5183 check_known_both_try(info, app_o, rator, rand1, rand2, "fx-", scheme_fixnum_p_proc, scheme_unsafe_fx_minus_proc, info->unsafe_mode);
5184 check_known_both_try(info, app_o, rator, rand1, rand2, "fx*", scheme_fixnum_p_proc, scheme_unsafe_fx_times_proc, info->unsafe_mode);
5185
5186 check_known_both_try(info, app_o, rator, rand1, rand2, "char=?", scheme_char_p_proc, scheme_unsafe_char_eq_proc, info->unsafe_mode);
5187 check_known_both_try(info, app_o, rator, rand1, rand2, "char<?", scheme_char_p_proc, scheme_unsafe_char_lt_proc, info->unsafe_mode);
5188 check_known_both_try(info, app_o, rator, rand1, rand2, "char>?", scheme_char_p_proc, scheme_unsafe_char_gt_proc, info->unsafe_mode);
5189 check_known_both_try(info, app_o, rator, rand1, rand2, "char<=?", scheme_char_p_proc, scheme_unsafe_char_lt_eq_proc, info->unsafe_mode);
5190 check_known_both_try(info, app_o, rator, rand1, rand2, "char>=?", scheme_char_p_proc, scheme_unsafe_char_gt_eq_proc, info->unsafe_mode);
5191
5192 rator = app->rator; /* in case it was updated */
5193
5194 check_known_both(info, app_o, rator, rand1, rand2, "string-append", scheme_string_p_proc, scheme_true, info->unsafe_mode);
5195 check_known_both(info, app_o, rator, rand1, rand2, "bytes-append", scheme_byte_string_p_proc, scheme_true, info->unsafe_mode);
5196 check_known(info, app_o, rator, rand1, "string-ref", scheme_string_p_proc, NULL, info->unsafe_mode);
5197 check_known(info, app_o, rator, rand2, "string-ref", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5198 check_known(info, app_o, rator, rand1, "bytes-ref", scheme_byte_string_p_proc,
5199 (info->unsafe_mode ? scheme_unsafe_bytes_ref_proc : NULL), info->unsafe_mode);
5200 check_known(info, app_o, rator, rand2, "bytes-ref", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5201
5202 check_known(info, app_o, rator, rand1, "append", scheme_list_p_proc, scheme_true, info->unsafe_mode);
5203 check_known(info, app_o, rator, rand1, "list-ref", scheme_pair_p_proc, NULL, info->unsafe_mode);
5204 check_known(info, app_o, rator, rand2, "list-ref", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5205 }
5206
5207 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_REAL)
5208 check_known_both(info, app_o, rator, rand1, rand2, NULL, scheme_real_p_proc,
5209 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
5210 info->unsafe_mode);
5211 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_WANTS_NUMBER)
5212 check_known_both(info, app_o, rator, rand1, rand2, NULL, scheme_number_p_proc,
5213 (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_OMITTABLE_ON_GOOD_ARGS) ? scheme_true : NULL,
5214 info->unsafe_mode);
5215
5216 if (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & SCHEME_PRIM_AD_HOC_OPT) {
5217 check_known(info, app_o, rator, rand1, "vector-ref", scheme_vector_p_proc, NULL, info->unsafe_mode);
5218 check_known(info, app_o, rator, rand2, "vector-ref", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5219 check_known(info, app_o, rator, rand1, "vector*-ref", scheme_vector_p_proc,
5220 (info->unsafe_mode ? scheme_unsafe_vector_star_ref_proc: NULL), info->unsafe_mode);
5221 check_known(info, app_o, rator, rand2, "vector*-ref", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5222 check_known(info, app_o, rator, rand1, "make-vector", scheme_fixnum_p_proc, NULL, info->unsafe_mode);
5223
5224 check_known(info, app_o, rator, rand1, "set-box!", scheme_box_p_proc, NULL, info->unsafe_mode);
5225 check_known(info, app_o, rator, rand1, "set-box*!", scheme_box_p_proc,
5226 (info->unsafe_mode ? scheme_unsafe_set_box_star_proc : NULL), info->unsafe_mode);
5227 check_known(info, app_o, rator, rand1, "unsafe-set-box!", scheme_box_p_proc, NULL, info->unsafe_mode);
5228 check_known(info, app_o, rator, rand1, "unsafe-set-box*!", scheme_box_p_proc, NULL, info->unsafe_mode);
5229
5230 check_known(info, app_o, rator, rand1, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5231 check_known(info, app_o, rator, rand2, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5232 check_known(info, app_o, rator, rand1, "procedure-arity-includes?", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5233
5234 check_known(info, app_o, rator, rand1, "map", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5235 check_known(info, app_o, rator, rand1, "for-each", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5236 check_known(info, app_o, rator, rand1, "andmap", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5237 check_known(info, app_o, rator, rand1, "ormap", scheme_procedure_p_proc, NULL, info->unsafe_mode);
5238 check_known(info, app_o, rator, rand2, "map", scheme_list_p_proc, NULL, info->unsafe_mode);
5239 check_known(info, app_o, rator, rand2, "for-each", scheme_list_p_proc, NULL, info->unsafe_mode);
5240 check_known(info, app_o, rator, rand2, "andmap", scheme_list_p_proc, NULL, info->unsafe_mode);
5241 check_known(info, app_o, rator, rand2, "ormap", scheme_list_p_proc, NULL, info->unsafe_mode);
5242 }
5243
5244 }
5245
5246 /* Using a struct mutator? */
5247 {
5248 Scheme_Object *alt;
5249 alt = get_struct_proc_shape(app->rator, info, 0);
5250 if (alt) {
5251 int mode = (SCHEME_PROC_SHAPE_MODE(alt) & STRUCT_PROC_SHAPE_MASK);
5252
5253 if (mode == STRUCT_PROC_SHAPE_SETTER) {
5254 Scheme_Object *pred;
5255 int unsafe = 0;
5256
5257 if (info->unsafe_mode) {
5258 pred = NULL;
5259 unsafe = 1;
5260 } else
5261 pred = expr_implies_predicate(app->rand1, info);
5262
5263 if ((unsafe
5264 || (pred
5265 && SAME_TYPE(SCHEME_TYPE(pred), scheme_struct_proc_shape_type)
5266 && is_struct_identity_subtype(SCHEME_PROC_SHAPE_IDENTITY(pred),
5267 SCHEME_PROC_SHAPE_IDENTITY(alt))))
5268 /* Only if the field position is known: */
5269 && ((SCHEME_PROC_SHAPE_MODE(alt) >> STRUCT_PROC_SHAPE_SHIFT) != 0)) {
5270 /* Struct type matches, so use `unsafe-struct-set!` */
5271 Scheme_Object *l;
5272 Scheme_App_Rec *new_app;
5273 int pos = (SCHEME_PROC_SHAPE_MODE(alt) >> STRUCT_PROC_SHAPE_SHIFT) - 1;
5274 l = scheme_make_pair(scheme_make_integer(pos),
5275 scheme_make_pair(app->rand2,
5276 scheme_null));
5277 l = scheme_make_pair(app->rand1, l);
5278 l = scheme_make_pair(((SCHEME_PROC_SHAPE_MODE(alt) & STRUCT_PROC_SHAPE_AUTHENTIC)
5279 ? scheme_unsafe_struct_star_set_proc
5280 : scheme_unsafe_struct_set_proc),
5281 l);
5282 new_app = (Scheme_App_Rec *)scheme_make_application(l, info);
5283 SCHEME_APPN_FLAGS(new_app) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL);
5284 return finish_optimize_application(new_app, info, context);
5285 }
5286
5287 /* Register type based on setter succeeding: */
5288 if (!SCHEME_NULLP(SCHEME_PROC_SHAPE_IDENTITY(alt))
5289 && SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_ir_local_type))
5290 add_type(info, app->rand1, scheme_make_struct_proc_shape(STRUCT_PROC_SHAPE_PRED,
5291 SCHEME_PROC_SHAPE_IDENTITY(alt)));
5292 }
5293 }
5294 }
5295
5296 increment_clocks_for_application(info, app->rator, 2);
5297
5298 rator_flags = get_rator_flags(app->rator, 2, info);
5299 info->preserves_marks = !!(rator_flags & LAMBDA_PRESERVES_MARKS);
5300 info->single_result = !!(rator_flags & LAMBDA_SINGLE_RESULT);
5301 if ((rator_flags & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE) {
5302 info->preserves_marks = -info->preserves_marks;
5303 info->single_result = -info->single_result;
5304 }
5305
5306 register_local_argument_types(NULL, NULL, app, info);
5307
5308 flags = appn_flags(app->rator, info);
5309 SCHEME_APPN_FLAGS(app) |= flags;
5310
5311 return finish_optimize_any_application((Scheme_Object *)app, app->rator, 2,
5312 info, context);
5313 }
5314
5315 /*========================================================================*/
5316 /* the apply-values bytecode form */
5317 /*========================================================================*/
5318
optimize_apply_values(Scheme_Object * f,Scheme_Object * e,Optimize_Info * info,int e_single_result,int context)5319 Scheme_Object *optimize_apply_values(Scheme_Object *f, Scheme_Object *e,
5320 Optimize_Info *info,
5321 int e_single_result,
5322 int context)
5323 /* f and e are already optimized */
5324 {
5325 Scheme_Object *o_f;
5326
5327 info->preserves_marks = 0;
5328 info->single_result = 0;
5329
5330 o_f = lookup_constant_proc(info, f, (e_single_result > 0) ? 1 : -1);
5331 if (o_f) {
5332 if (SAME_TYPE(SCHEME_TYPE(o_f), scheme_ir_lambda_type)) {
5333 Scheme_Lambda *lam = (Scheme_Lambda *)o_f;
5334 int flags = SCHEME_LAMBDA_FLAGS(lam);
5335 info->preserves_marks = !!(flags & LAMBDA_PRESERVES_MARKS);
5336 info->single_result = !!(flags & LAMBDA_SINGLE_RESULT);
5337 if ((flags & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE) {
5338 info->preserves_marks = -info->preserves_marks;
5339 info->single_result = -info->single_result;
5340 }
5341 }
5342 }
5343
5344 if (o_f && (e_single_result > 0)) {
5345 /* Just make it an application (N M): */
5346 Scheme_App2_Rec *app2;
5347 Scheme_Object *e_cloned, *f_cloned;
5348
5349 app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec);
5350 app2->iso.so.type = scheme_application2_type;
5351
5352 /* Try to inline... */
5353
5354 e_cloned = optimize_clone(1, e, info, empty_eq_hash_tree, 0);
5355 if (e_cloned) {
5356 if (SAME_TYPE(SCHEME_TYPE(f), scheme_ir_lambda_type))
5357 f_cloned = optimize_clone(1, f, info, empty_eq_hash_tree, 0);
5358 else {
5359 /* Otherwise, no clone is needed. */
5360 f_cloned = f;
5361 }
5362
5363 if (f_cloned) {
5364 app2->rator = f_cloned;
5365 app2->rand = e_cloned;
5366 info->inline_fuel >>= 1; /* because we've already optimized the rand */
5367 return optimize_application2((Scheme_Object *)app2, info, context);
5368 }
5369 }
5370
5371 app2->rator = f;
5372 app2->rand = e;
5373 return (Scheme_Object *)app2;
5374 }
5375
5376 {
5377 Scheme_Object *av;
5378 av = scheme_alloc_object();
5379 av->type = scheme_apply_values_type;
5380 SCHEME_PTR1_VAL(av) = f;
5381 SCHEME_PTR2_VAL(av) = e;
5382 return av;
5383 }
5384 }
5385
5386 /*========================================================================*/
5387 /* begin and begin0 */
5388 /*========================================================================*/
5389
5390 static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, int context, int sub_opt);
5391
flatten_sequence(Scheme_Object * o,Optimize_Info * info,int context)5392 static Scheme_Object *flatten_sequence(Scheme_Object *o, Optimize_Info *info, int context)
5393 {
5394 Scheme_Sequence *s = (Scheme_Sequence *)o, *s2, *s3;
5395 Scheme_Object *o3;
5396 int i, j, k, count, extra = 0, split = 0, b0, new_count;
5397
5398 if (!info->flatten_fuel)
5399 return o;
5400
5401 b0 = SAME_TYPE(SCHEME_TYPE(o), scheme_begin0_sequence_type);
5402 count = s->count;
5403
5404 /* exceptions: (begin ... (begin0 ...)) and (begin0 (begin ...) ...) */
5405 for (i = 0; i < count; i++) {
5406 o3 = s->array[i];
5407 if ((SAME_TYPE(SCHEME_TYPE(o3), scheme_sequence_type) && !(!i && b0))
5408 || (SAME_TYPE(SCHEME_TYPE(o3), scheme_begin0_sequence_type) && !(i == count - 1 && !b0))) {
5409 s3 = (Scheme_Sequence *)o3;
5410 extra += s3->count;
5411 split++;
5412 }
5413 }
5414
5415 if (!split)
5416 return o;
5417
5418 info->flatten_fuel--;
5419 info->size -= split;
5420
5421 new_count = s->count + extra - split;
5422 if (new_count > 0) {
5423 s2 = scheme_malloc_sequence(new_count);
5424 s2->so.type = s->so.type;
5425 s2->count = new_count;
5426 } else
5427 s2 = NULL;
5428 k = 0;
5429
5430 /* exceptions: (begin ... (begin0 ...)) and (begin0 (begin ...) ...) */
5431 for (i = 0; i < count; i++) {
5432 o3 = s->array[i];
5433 if ((SAME_TYPE(SCHEME_TYPE(o3), scheme_sequence_type) && !(!i && b0))
5434 || (SAME_TYPE(SCHEME_TYPE(o3), scheme_begin0_sequence_type) && !(i == count - 1 && !b0))) {
5435 s3 = (Scheme_Sequence *)o3;
5436 for (j = 0; j < s3->count; j++) {
5437 s2->array[k++] = s3->array[j];
5438 }
5439 } else {
5440 s2->array[k++] = o3;
5441 }
5442 }
5443
5444 MZ_ASSERT(k == new_count);
5445
5446 if (s2->count == 1)
5447 return s2->array[0];
5448
5449 if (SAME_TYPE(SCHEME_TYPE(s2), scheme_sequence_type))
5450 return optimize_sequence((Scheme_Object *)s2, info, context, 0);
5451 else
5452 return (Scheme_Object *)s2;
5453 }
5454
optimize_sequence(Scheme_Object * o,Optimize_Info * info,int context,int sub_opt)5455 static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, int context, int sub_opt)
5456 {
5457 Scheme_Sequence *s = (Scheme_Sequence *)o;
5458 Scheme_Object *le;
5459 int i, count, prev_size;
5460 int drop = 0, preserves_marks = 0, single_result = 0;
5461 Optimize_Info_Sequence info_seq;
5462
5463 /* If !sub_opt, then just inspect already-optimized results. Note
5464 that `info` doesn't change in this mode, so we shouldn't try to
5465 check whether an expression escapes, for example. */
5466
5467 if (sub_opt)
5468 optimize_info_seq_init(info, &info_seq);
5469 else
5470 memset(&info_seq, 0, sizeof(info_seq));
5471
5472 count = s->count;
5473 for (i = 0; i < count; i++) {
5474 prev_size = info->size;
5475
5476 if (sub_opt) {
5477 optimize_info_seq_step(info, &info_seq);
5478 le = optimize_expr(s->array[i], info,
5479 ((i + 1 == count)
5480 ? scheme_optimize_tail_context(context)
5481 : 0));
5482 } else
5483 le = s->array[i];
5484
5485 if (i + 1 == count) {
5486 single_result = info->single_result;
5487 preserves_marks = info->preserves_marks;
5488 s->array[i] = le;
5489 } else {
5490 if (!sub_opt || !info->escapes) {
5491 /* Inlining and constant propagation can expose omittable expressions. */
5492 le = optimize_ignored(le, info, -1, 1, 5);
5493 if (!le) {
5494 drop++;
5495 info->size = prev_size;
5496 s->array[i] = NULL;
5497 } else {
5498 s->array[i] = le;
5499 }
5500 } else {
5501 int j;
5502
5503 single_result = info->single_result;
5504 preserves_marks = info->preserves_marks;
5505 /* Move to last position in case the begin form is dropped */
5506 s->array[count - 1] = le;
5507 for (j = i; j < count - 1; j++) {
5508 drop++;
5509 s->array[j] = NULL;
5510 }
5511 break;
5512 }
5513 }
5514 }
5515
5516 if (sub_opt)
5517 optimize_info_seq_done(info, &info_seq);
5518
5519 info->preserves_marks = preserves_marks;
5520 info->single_result = single_result;
5521
5522 if (drop + 1 == s->count) {
5523 le = s->array[drop];
5524 if (info->escapes)
5525 le = ensure_noncm(le, info);
5526 return le;
5527 }
5528
5529 if (drop) {
5530 Scheme_Sequence *s2;
5531 int j = 0;
5532
5533 s2 = scheme_malloc_sequence(s->count - drop);
5534 s2->so.type = s->so.type;
5535 s2->count = s->count - drop;
5536
5537 for (i = 0; i < s->count; i++) {
5538 if (s->array[i]) {
5539 s2->array[j++] = s->array[i];
5540 }
5541 }
5542
5543 s = s2;
5544 }
5545
5546 return flatten_sequence((Scheme_Object *)s, info, context);
5547 }
5548
5549 /*========================================================================*/
5550 /* conditionals and types */
5551 /*========================================================================*/
5552
collapse_local(Scheme_Object * var,Optimize_Info * info,int context)5553 static Scheme_Object *collapse_local(Scheme_Object *var, Optimize_Info *info, int context)
5554 /* Replace `var` in the given context with a constant, if possible based on its type */
5555 {
5556 if (!SCHEME_VAR(var)->mutated) {
5557 Scheme_Object *pred;
5558
5559 pred = expr_implies_predicate(var, info);
5560 if (pred) {
5561 if (predicate_implies(pred, scheme_not_proc))
5562 return scheme_false;
5563
5564 if (context & OPT_CONTEXT_BOOLEAN) {
5565 if (predicate_implies_not(pred, scheme_not_proc))
5566 return scheme_true;
5567 }
5568
5569 if (SAME_OBJ(pred, scheme_true_object_p_proc))
5570 return scheme_true;
5571 if (SAME_OBJ(pred, scheme_null_p_proc))
5572 return scheme_null;
5573 if (SAME_OBJ(pred, scheme_void_p_proc))
5574 return scheme_void;
5575 if (SAME_OBJ(pred, scheme_eof_object_p_proc))
5576 return scheme_eof;
5577 }
5578 }
5579 return NULL;
5580 }
5581
5582 /* This function is used to reduce:
5583 (if <x> a b) => (begin <x> <result-a-or-b>)
5584 (if a b #f) => a , and similar
5585 (eq? a b) => (begin a b #t)
5586 The function considers only values and variable references, so <a> and <b> don't have side effects.
5587 But each reduction has a very different behavior for expressions with side effects. */
equivalent_exprs(Scheme_Object * a,Scheme_Object * b,Optimize_Info * a_info,Optimize_Info * b_info,int context)5588 static Scheme_Object *equivalent_exprs(Scheme_Object *a, Scheme_Object *b,
5589 Optimize_Info *a_info, Optimize_Info *b_info, int context)
5590 {
5591 if (SAME_OBJ(a, b))
5592 return a;
5593
5594 if (SAME_TYPE(SCHEME_TYPE(a), scheme_ir_toplevel_type)
5595 && SAME_TYPE(SCHEME_TYPE(b), scheme_ir_toplevel_type)
5596 && (SCHEME_IR_TOPLEVEL_INSTANCE(a) == SCHEME_IR_TOPLEVEL_INSTANCE(b))
5597 && (SCHEME_IR_TOPLEVEL_POS(a) == SCHEME_IR_TOPLEVEL_POS(b)))
5598 return a;
5599
5600 if (b_info
5601 && SAME_TYPE(SCHEME_TYPE(a), scheme_ir_local_type)
5602 && (SCHEME_TYPE(b) > _scheme_ir_values_types_)) {
5603 Scheme_Object *n;
5604 n = collapse_local(a, b_info, context);
5605 if (n && SAME_OBJ(n, b))
5606 return a;
5607 }
5608
5609 if (a_info
5610 && SAME_TYPE(SCHEME_TYPE(b), scheme_ir_local_type)
5611 && (SCHEME_TYPE(a) > _scheme_ir_values_types_)) {
5612 Scheme_Object *n;
5613 n = collapse_local(b, a_info, context);
5614 if (n && SAME_OBJ(n, a))
5615 return b;
5616 }
5617
5618 return NULL;
5619 }
5620
add_type(Optimize_Info * info,Scheme_Object * var,Scheme_Object * pred)5621 static void add_type(Optimize_Info *info, Scheme_Object *var, Scheme_Object *pred)
5622 /* This is conceptually an intersection, but `Any` is represented by a
5623 missing entry, so the implementation looks like an union. */
5624 {
5625 Scheme_Hash_Tree *new_types = info->types;
5626 Scheme_Object *old_pred;
5627
5628 if (SCHEME_VAR(var)->mutated)
5629 return;
5630
5631 /* Don't add the type if something is already there, which may happen when no_types,
5632 as long as the existing predicate implies the new one. */
5633 if (SCHEME_VAR(var)->val_type) /* => more specific than other predicates */
5634 return;
5635 old_pred = optimize_get_predicate(info, var, 1);
5636 if (old_pred && predicate_implies(old_pred, pred))
5637 return;
5638
5639 /* special case: list? and pair? => list-pair? */
5640 if (old_pred) {
5641 if ((SAME_OBJ(old_pred, scheme_list_p_proc)
5642 && (SAME_OBJ(pred, scheme_pair_p_proc)))
5643 || (SAME_OBJ(old_pred, scheme_pair_p_proc)
5644 && (SAME_OBJ(pred, scheme_list_p_proc)))) {
5645 pred = scheme_list_pair_p_proc;
5646 }
5647 }
5648
5649 if (!new_types)
5650 new_types = scheme_make_hash_tree(SCHEME_hashtr_eq);
5651 new_types = scheme_hash_tree_set(new_types, var, pred);
5652 info->types = new_types;
5653 }
5654
add_type_no(Optimize_Info * info,Scheme_Object * var,Scheme_Object * pred)5655 static void add_type_no(Optimize_Info *info, Scheme_Object *var, Scheme_Object *pred)
5656 /* Currently only check a few special cases for lists and booleans. */
5657 {
5658 Scheme_Object *old_pred;
5659
5660 if (SCHEME_VAR(var)->mutated)
5661 return;
5662
5663 old_pred = optimize_get_predicate(info, var, 1);
5664
5665 if (old_pred && SAME_OBJ(old_pred, scheme_list_p_proc)) {
5666 /* list? but not null? => list-pair? */
5667 if (SAME_OBJ(pred, scheme_null_p_proc))
5668 add_type(info, var, scheme_list_pair_p_proc);
5669
5670 /* list? but not pair? => null? */
5671 /* list? but not list-pair? => null? */
5672 if (SAME_OBJ(pred, scheme_pair_p_proc)
5673 ||SAME_OBJ(pred, scheme_list_pair_p_proc))
5674 add_type(info, var, scheme_null_p_proc);
5675 }
5676
5677 if (old_pred && SAME_OBJ(old_pred, scheme_boolean_p_proc)) {
5678 /* boolean? but not `not` => true-object? */
5679 if (SAME_OBJ(pred, scheme_not_proc))
5680 add_type(info, var, scheme_true_object_p_proc);
5681
5682 /* boolean? but not true-object? => `not` */
5683 if (SAME_OBJ(pred, scheme_true_object_p_proc))
5684 add_type(info, var, scheme_not_proc);
5685 }
5686 }
5687
5688
5689
merge_types(Optimize_Info * src_info,Optimize_Info * info,Scheme_Hash_Tree * skip_vars)5690 static void merge_types(Optimize_Info *src_info, Optimize_Info *info, Scheme_Hash_Tree *skip_vars)
5691 {
5692 Scheme_Hash_Tree *types = src_info->types;
5693 Scheme_Object *var, *pred;
5694 intptr_t i;
5695
5696 if (!types)
5697 return;
5698
5699 if (skip_vars) {
5700 /* Remove variables from `types` that we're supposed to skip */
5701 i = scheme_hash_tree_next(skip_vars, -1);
5702 while (i != -1) {
5703 scheme_hash_tree_index(skip_vars, i, &var, NULL);
5704 types = scheme_hash_tree_set(types, var, NULL);
5705 i = scheme_hash_tree_next(skip_vars, i);
5706 }
5707 }
5708
5709 if (!info->types || (types->count > info->types->count)) {
5710 /* It will be faster to merge the old table into the new one: */
5711 Scheme_Hash_Tree *old_types = info->types;
5712 info->types = types;
5713 if (!old_types)
5714 return;
5715 types = old_types;
5716 }
5717
5718 i = scheme_hash_tree_next(types, -1);
5719 while (i != -1) {
5720 scheme_hash_tree_index(types, i, &var, &pred);
5721 add_type(info, var, pred);
5722 i = scheme_hash_tree_next(types, i);
5723 }
5724 }
5725
merge_branchs_types(Optimize_Info * t_info,Optimize_Info * f_info,Optimize_Info * base_info)5726 static void merge_branchs_types(Optimize_Info *t_info, Optimize_Info *f_info,
5727 Optimize_Info *base_info)
5728 /* This is conceptually an union, but `Any` is represented by a
5729 missing entry, so the implementation looks like an intersection.
5730 This adds to base_info the "intersection" of the types of t_info and f_info */
5731 {
5732 Scheme_Hash_Tree *t_types = t_info->types, *f_types = f_info->types;
5733 Scheme_Object *var, *t_pred, *f_pred;
5734 intptr_t i;
5735
5736 if (!t_types || !f_types)
5737 return;
5738
5739 if (f_types->count > t_types->count) {
5740 Scheme_Hash_Tree *swap = f_types;
5741 f_types = t_types;
5742 t_types = swap;
5743 }
5744
5745 i = scheme_hash_tree_next(f_types, -1);
5746 while (i != -1) {
5747 scheme_hash_tree_index(f_types, i, &var, &f_pred);
5748 t_pred = scheme_eq_hash_tree_get(t_types, var);
5749 if (t_pred) {
5750 if (predicate_implies(f_pred, t_pred))
5751 add_type(base_info, var, t_pred);
5752 else if (predicate_implies(t_pred, f_pred))
5753 add_type(base_info, var, f_pred);
5754 else {
5755 /* special case: null? or list-pair? => list? */
5756 if ((SAME_OBJ(t_pred, scheme_null_p_proc)
5757 && (SAME_OBJ(f_pred, scheme_list_pair_p_proc)))
5758 || (SAME_OBJ(t_pred, scheme_list_pair_p_proc)
5759 && (SAME_OBJ(f_pred, scheme_null_p_proc)))) {
5760 add_type(base_info, var, scheme_list_p_proc);
5761 }
5762 /* special case: true-object? or `not` => boolean? */
5763 if ((SAME_OBJ(t_pred, scheme_not_proc)
5764 && (SAME_OBJ(f_pred, scheme_true_object_p_proc)))
5765 || (SAME_OBJ(t_pred, scheme_true_object_p_proc)
5766 && (SAME_OBJ(f_pred, scheme_not_proc)))) {
5767 add_type(base_info, var, scheme_boolean_p_proc);
5768 }
5769 }
5770 }
5771 i = scheme_hash_tree_next(f_types, i);
5772 }
5773 }
5774
relevant_predicate(Scheme_Object * pred)5775 static int relevant_predicate(Scheme_Object *pred)
5776 {
5777 /* Relevant predicates need to be disjoint for try_reduce_predicate(),
5778 finish_optimize_application3() and add_types_for_t_branch().
5779 The predicate_implies() and predicate_implies_not() functions must
5780 be kept in sync with this list. */
5781
5782 if (SAME_OBJ(pred, scheme_pair_p_proc)
5783 || SAME_OBJ(pred, scheme_list_p_proc)
5784 || SAME_OBJ(pred, scheme_list_pair_p_proc)
5785 || SAME_OBJ(pred, scheme_mpair_p_proc)
5786 || SAME_OBJ(pred, scheme_box_p_proc)
5787 || SAME_OBJ(pred, scheme_string_p_proc)
5788 || SAME_OBJ(pred, scheme_byte_string_p_proc)
5789 || SAME_OBJ(pred, scheme_vector_p_proc)
5790 || SAME_OBJ(pred, scheme_procedure_p_proc)
5791 || SAME_OBJ(pred, scheme_syntax_p_proc))
5792 return RLV_IS_RELEVANT;
5793 if (SAME_OBJ(pred, scheme_char_p_proc)
5794 || SAME_OBJ(pred, scheme_flonum_p_proc)
5795 || SAME_OBJ(pred, scheme_number_p_proc)
5796 || SAME_OBJ(pred, scheme_real_p_proc)
5797 || SAME_OBJ(pred, scheme_extflonum_p_proc))
5798 return RLV_EQV_TESTEABLE;
5799 if (SAME_OBJ(pred, scheme_symbol_p_proc)
5800 || SAME_OBJ(pred, scheme_keyword_p_proc)
5801 || SAME_OBJ(pred, scheme_fixnum_p_proc)
5802 || SAME_OBJ(pred, scheme_interned_char_p_proc)
5803 || SAME_OBJ(pred, scheme_boolean_p_proc))
5804 return RLV_EQ_TESTEABLE;
5805 if (SAME_OBJ(pred, scheme_null_p_proc)
5806 || SAME_OBJ(pred, scheme_void_p_proc)
5807 || SAME_OBJ(pred, scheme_eof_object_p_proc)
5808 || SAME_OBJ(pred, scheme_true_object_p_proc)
5809 || SAME_OBJ(pred, scheme_not_proc))
5810 return RLV_SINGLETON;
5811
5812 return 0;
5813 }
5814
predicate_implies(Scheme_Object * pred1,Scheme_Object * pred2)5815 static int predicate_implies(Scheme_Object *pred1, Scheme_Object *pred2)
5816 {
5817 if (!pred1 || !pred2)
5818 return 0;
5819
5820 /* P => P */
5821 if (SAME_OBJ(pred1, pred2))
5822 return 1;
5823
5824 /* null? => list? */
5825 if (SAME_OBJ(pred2, scheme_list_p_proc)
5826 && SAME_OBJ(pred1, scheme_null_p_proc))
5827 return 1;
5828
5829 /* list-pair? => list? */
5830 if (SAME_OBJ(pred2, scheme_list_p_proc)
5831 && SAME_OBJ(pred1, scheme_list_pair_p_proc))
5832 return 1;
5833
5834 /* list-pair? => pair? */
5835 if (SAME_OBJ(pred2, scheme_pair_p_proc)
5836 && SAME_OBJ(pred1, scheme_list_pair_p_proc))
5837 return 1;
5838
5839 /* interned-char? => char? */
5840 if (SAME_OBJ(pred2, scheme_char_p_proc)
5841 && SAME_OBJ(pred1, scheme_interned_char_p_proc))
5842 return 1;
5843
5844 /* not, true-object? => boolean? */
5845 if (SAME_OBJ(pred2, scheme_boolean_p_proc)
5846 && (SAME_OBJ(pred1, scheme_not_proc)
5847 || SAME_OBJ(pred1, scheme_true_object_p_proc)))
5848 return 1;
5849
5850 /* real?, fixnum?, or flonum? => number? */
5851 if (SAME_OBJ(pred2, scheme_number_p_proc)
5852 && (SAME_OBJ(pred1, scheme_real_p_proc)
5853 || SAME_OBJ(pred1, scheme_fixnum_p_proc)
5854 || SAME_OBJ(pred1, scheme_flonum_p_proc)))
5855 return 1;
5856
5857 /* fixnum? or flonum? => real? */
5858 if (SAME_OBJ(pred2, scheme_real_p_proc)
5859 && (SAME_OBJ(pred1, scheme_fixnum_p_proc)
5860 || SAME_OBJ(pred1, scheme_flonum_p_proc)))
5861 return 1;
5862
5863 /* structure subtype? */
5864 if (SAME_TYPE(SCHEME_TYPE(pred1), scheme_struct_proc_shape_type)
5865 && SAME_TYPE(SCHEME_TYPE(pred2), scheme_struct_proc_shape_type)
5866 && is_struct_identity_subtype(SCHEME_PROC_SHAPE_IDENTITY(pred1),
5867 SCHEME_PROC_SHAPE_IDENTITY(pred2)))
5868 return 1;
5869
5870 return 0;
5871 }
5872
predicate_implies_not(Scheme_Object * pred1,Scheme_Object * pred2)5873 static int predicate_implies_not(Scheme_Object *pred1, Scheme_Object *pred2)
5874 {
5875 if (SAME_OBJ(pred1, scheme_pair_p_proc) && SAME_OBJ(pred2, scheme_list_p_proc))
5876 return 0;
5877 if (SAME_OBJ(pred1, scheme_list_p_proc) && SAME_OBJ(pred2, scheme_pair_p_proc))
5878 return 0;
5879
5880 /* we don't track structure-type identity precisely enough to know
5881 that structures don't rule out other structures; among the
5882 tracked predicates, only `procedure?` is compatible with
5883 structures */
5884 if ((SAME_TYPE(SCHEME_TYPE(pred1), scheme_struct_proc_shape_type)
5885 || SAME_OBJ(pred1, scheme_procedure_p_proc))
5886 && (SAME_TYPE(SCHEME_TYPE(pred2), scheme_struct_proc_shape_type)
5887 || SAME_OBJ(pred2, scheme_procedure_p_proc)))
5888 return 0;
5889
5890 /* Otherwise, with our current set of predicates, overlapping matches happen
5891 only when one implies the other: */
5892 return (!predicate_implies(pred1, pred2) && !predicate_implies(pred2, pred1));
5893 }
5894
add_types_for_t_branch(Scheme_Object * t,Optimize_Info * info,int fuel)5895 static void add_types_for_t_branch(Scheme_Object *t, Optimize_Info *info, int fuel)
5896 {
5897 if (fuel < 0)
5898 return;
5899
5900 if (SAME_TYPE(SCHEME_TYPE(t), scheme_ir_local_type)) {
5901 add_type_no(info, t, scheme_not_proc);
5902 } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_application2_type)) {
5903 Scheme_App2_Rec *app = (Scheme_App2_Rec *)t;
5904 if (SCHEME_PRIMP(app->rator)
5905 && SAME_TYPE(SCHEME_TYPE(app->rand), scheme_ir_local_type)
5906 && relevant_predicate(app->rator)) {
5907 /* Looks like a predicate on a local variable. Record that the
5908 predicate succeeded, which may allow conversion of safe
5909 operations to unsafe operations. */
5910 add_type(info, app->rand, app->rator);
5911 }
5912 if (SAME_OBJ(app->rator, scheme_not_proc)) {
5913 add_types_for_f_branch(app->rand, info, fuel-1);
5914 }
5915
5916 if (SAME_TYPE(SCHEME_TYPE(app->rand), scheme_ir_local_type)) {
5917 Scheme_Object *shape;
5918 shape = get_struct_proc_shape(app->rator, info, 0);
5919 if (shape
5920 && ((SCHEME_PROC_SHAPE_MODE(shape) & STRUCT_PROC_SHAPE_MASK) == STRUCT_PROC_SHAPE_PRED)
5921 && !SCHEME_NULLP(SCHEME_PROC_SHAPE_IDENTITY(shape))) {
5922 add_type(info, app->rand, shape);
5923 }
5924 }
5925 } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_application3_type)) {
5926 Scheme_App3_Rec *app = (Scheme_App3_Rec *)t;
5927 Scheme_Object *pred1, *pred2;
5928 if (SAME_OBJ(app->rator, scheme_eq_proc)
5929 || SAME_OBJ(app->rator, scheme_eqv_proc)
5930 || SAME_OBJ(app->rator, scheme_equal_proc)) {
5931 if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_ir_local_type)) {
5932 pred1 = expr_implies_predicate(app->rand1, info);
5933 if (!pred1) {
5934 pred2 = expr_implies_predicate(app->rand2, info);
5935 if (pred2)
5936 add_type(info, app->rand1, pred2);
5937 }
5938 }
5939 if (SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_ir_local_type)) {
5940 pred2 = expr_implies_predicate(app->rand2, info);
5941 if (!pred2) {
5942 pred1 = expr_implies_predicate(app->rand1, info);
5943 if (pred1)
5944 add_type(info, app->rand2, pred1);
5945 }
5946 }
5947 }
5948
5949 } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_branch_type)) {
5950 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)t;
5951 if (SCHEME_FALSEP(b->fbranch)) {
5952 add_types_for_t_branch(b->test, info, fuel-1);
5953 add_types_for_t_branch(b->tbranch, info, fuel-1);
5954 }
5955 if (SCHEME_FALSEP(b->tbranch)) {
5956 add_types_for_f_branch(b->test, info, fuel-1);
5957 add_types_for_t_branch(b->fbranch, info, fuel-1);
5958 }
5959 }
5960 }
5961
add_types_for_f_branch(Scheme_Object * t,Optimize_Info * info,int fuel)5962 static void add_types_for_f_branch(Scheme_Object *t, Optimize_Info *info, int fuel)
5963 {
5964 if (fuel < 0)
5965 return;
5966
5967 if (SAME_TYPE(SCHEME_TYPE(t), scheme_ir_local_type)) {
5968 add_type(info, t, scheme_not_proc);
5969
5970 } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_application2_type)) {
5971 Scheme_App2_Rec *app = (Scheme_App2_Rec *)t;
5972 if (SCHEME_PRIMP(app->rator)
5973 && SAME_TYPE(SCHEME_TYPE(app->rand), scheme_ir_local_type)
5974 && relevant_predicate(app->rator)) {
5975 /* Looks like a predicate on a local variable. Record that the
5976 predicate failed, this is currently useful only for lists. */
5977 add_type_no(info, app->rand, app->rator);
5978 }
5979
5980 } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_branch_type)) {
5981 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)t;
5982 if (SAME_OBJ(b->fbranch, scheme_true)) {
5983 add_types_for_t_branch(b->test, info, fuel-1);
5984 add_types_for_f_branch(b->tbranch, info, fuel-1);
5985 }
5986 if (SAME_OBJ(b->tbranch, scheme_true)) {
5987 add_types_for_f_branch(b->test, info, fuel-1);
5988 add_types_for_f_branch(b->fbranch, info, fuel-1);
5989 }
5990 }
5991 }
5992
or_tentative(int x,int y)5993 static int or_tentative(int x, int y)
5994 {
5995 if (x && y) {
5996 if ((x < 0) || (y < 0))
5997 return -1;
5998 else
5999 return 1;
6000 } else {
6001 return 0;
6002 }
6003 }
6004
optimize_branch(Scheme_Object * o,Optimize_Info * info,int context)6005 static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int context)
6006 {
6007 Scheme_Branch_Rec *b;
6008 Scheme_Object *t, *tb, *fb;
6009 int init_vclock, init_aclock, init_kclock, init_sclock;
6010 Optimize_Info *then_info, *else_info;
6011 Optimize_Info *then_info_init, *else_info_init;
6012 Optimize_Info_Sequence info_seq;
6013
6014 b = (Scheme_Branch_Rec *)o;
6015
6016 t = b->test;
6017 tb = b->tbranch;
6018 fb = b->fbranch;
6019
6020 /* Convert (if <id> expr <id>) to (if <id> expr #f) */
6021 if (equivalent_exprs(t, fb, NULL, NULL, 0)) {
6022 fb = scheme_false;
6023 }
6024
6025 /* For test position, convert (if <id> <id> expr) to (if <id> #t expr) */
6026 if ((context & OPT_CONTEXT_BOOLEAN)
6027 && equivalent_exprs(t, tb, NULL, NULL, 0)) {
6028 tb = scheme_true;
6029 }
6030
6031 optimize_info_seq_init(info, &info_seq);
6032
6033 t = optimize_expr(t, info, OPT_CONTEXT_BOOLEAN | OPT_CONTEXT_SINGLED);
6034
6035 if (info->escapes) {
6036 optimize_info_seq_done(info, &info_seq);
6037 return ensure_noncm(t, info);
6038 }
6039
6040 /* Try to lift out `let`s and `begin`s around a test: */
6041 {
6042 Scheme_Object *inside = NULL, *t2 = t;
6043
6044 while (1) {
6045 extract_tail_inside(&t2, &inside, 0);
6046
6047 /* Try optimize: (if (not x) y z) => (if x z y) */
6048 if (SAME_TYPE(SCHEME_TYPE(t2), scheme_application2_type)) {
6049 Scheme_App2_Rec *app = (Scheme_App2_Rec *)t2;
6050
6051 if (SAME_PTR(scheme_not_proc, app->rator)) {
6052 t2 = tb;
6053 tb = fb;
6054 fb = t2;
6055
6056 t2 = app->rand;
6057 t = replace_tail_inside(t2, inside, t);
6058 } else
6059 break;
6060 } else
6061 break;
6062 }
6063
6064 if (!(SCHEME_TYPE(t2) > _scheme_ir_values_types_)) {
6065 /* (if (let (...) (cons x y)) a b) => (if (begin (let (...) (begin x y #<void>)) #t/#f) a b)
6066 but don't expand (if (let (...) (begin x K)) a b) */
6067 Scheme_Object *pred;
6068
6069 pred = expr_implies_predicate(t2, info);
6070 if (pred) {
6071 Scheme_Object *test_val = NULL;
6072
6073 if (predicate_implies(pred, scheme_not_proc))
6074 test_val = scheme_false;
6075 else if (predicate_implies_not(pred, scheme_not_proc))
6076 test_val = scheme_true;
6077
6078 if (test_val) {
6079 t2 = optimize_ignored(t2, info, 1, 0, 5);
6080 t = replace_tail_inside(t2, inside, t);
6081
6082 t2 = test_val;
6083 if (scheme_omittable_expr(t, 1, 5, 0, info, NULL)) {
6084 t = test_val;
6085 inside = NULL;
6086 } else {
6087 t = make_sequence_2(t, test_val);
6088 inside = t;
6089 }
6090 }
6091 }
6092 }
6093
6094 if (SCHEME_TYPE(t2) > _scheme_ir_values_types_) {
6095 /* Branch is statically known */
6096 Scheme_Object *xb;
6097
6098 optimize_info_seq_done(info, &info_seq);
6099 info->size -= 1;
6100
6101 if (SCHEME_FALSEP(t2))
6102 xb = optimize_expr(fb, info, scheme_optimize_tail_context(context));
6103 else
6104 xb = optimize_expr(tb, info, scheme_optimize_tail_context(context));
6105
6106 optimize_info_seq_done(info, &info_seq);
6107 return replace_tail_inside(xb, inside, t);
6108 }
6109 }
6110
6111 optimize_info_seq_step(info, &info_seq);
6112
6113 info->vclock += 1; /* model branch as clock increment */
6114
6115 init_vclock = info->vclock;
6116 init_aclock = info->aclock;
6117 init_kclock = info->kclock;
6118 init_sclock = info->sclock;
6119
6120 then_info = optimize_info_add_frame(info, 0);
6121 add_types_for_t_branch(t, then_info, 5);
6122 then_info_init = optimize_info_add_frame(then_info, 0);
6123 tb = optimize_expr(tb, then_info, scheme_optimize_tail_context(context));
6124 optimize_info_done(then_info, NULL);
6125
6126 info->escapes = 0;
6127 info->vclock = init_vclock;
6128 info->aclock = init_aclock;
6129 info->kclock = init_kclock;
6130 info->sclock = init_sclock;
6131
6132 optimize_info_seq_step(info, &info_seq);
6133
6134 else_info = optimize_info_add_frame(info, 0);
6135 add_types_for_f_branch(t, else_info, 5);
6136 else_info_init = optimize_info_add_frame(else_info, 0);
6137 fb = optimize_expr(fb, else_info, scheme_optimize_tail_context(context));
6138 optimize_info_done(else_info, NULL);
6139
6140 if (then_info->escapes && else_info->escapes) {
6141 /* both branches escaped */
6142 info->preserves_marks = 1;
6143 info->single_result = 1;
6144 info->kclock = init_kclock;
6145
6146 } else if (else_info->escapes) {
6147 info->preserves_marks = then_info->preserves_marks;
6148 info->single_result = then_info->single_result;
6149 info->kclock = then_info->kclock;
6150 merge_types(then_info, info, NULL);
6151 info->escapes = 0;
6152
6153 } else if (then_info->escapes) {
6154 info->preserves_marks = else_info->preserves_marks;
6155 info->single_result = else_info->single_result;
6156 merge_types(else_info, info, NULL);
6157 info->escapes = 0;
6158
6159 } else {
6160 int new_preserves_marks, new_single_result;
6161
6162 new_preserves_marks = or_tentative(then_info->preserves_marks, else_info->preserves_marks);
6163 info->preserves_marks = new_preserves_marks;
6164 new_single_result = or_tentative(then_info->single_result, else_info->single_result);
6165 info->single_result = new_single_result;
6166 if (then_info->kclock > info->kclock)
6167 info->kclock = then_info->kclock;
6168 merge_branchs_types(then_info, else_info, info);
6169 }
6170
6171 if (then_info->sclock > info->sclock)
6172 info->sclock = then_info->sclock;
6173 if (then_info->aclock > info->aclock)
6174 info->aclock = then_info->aclock;
6175
6176 if ((init_vclock == then_info->vclock) && (init_vclock == info->vclock)) {
6177 /* we can rewind the vclock to just after the test, because the
6178 `if` as a whole has no effect */
6179 info->vclock--;
6180 }
6181
6182 optimize_info_seq_done(info, &info_seq);
6183
6184 /* Try optimize: (if x #f #t) => (not x) */
6185 if (SCHEME_FALSEP(tb)
6186 && SAME_OBJ(fb, scheme_true)) {
6187 info->size -= 2;
6188 return make_optimize_prim_application2(scheme_not_proc, t, info, context);
6189 }
6190
6191 /* Convert (if <boolean> #t #f) to <boolean>
6192 and, for test position, convert (if <expr> #t #f) to <expr> */
6193 if (SAME_OBJ(tb, scheme_true) && SAME_OBJ(fb, scheme_false)) {
6194 Scheme_Object *pred;
6195
6196 if (context & OPT_CONTEXT_BOOLEAN)
6197 /* In a boolean context, any expression can be extrated. */
6198 pred = scheme_boolean_p_proc;
6199 else
6200 pred = expr_implies_predicate(t, info);
6201
6202 if (pred && predicate_implies(pred, scheme_boolean_p_proc)) {
6203 info->size -= 2;
6204 return ensure_single_value_noncm(t, info);
6205 }
6206 }
6207
6208 /* Try optimize: (if <expr> v v) => (begin <expr> v) */
6209 {
6210 Scheme_Object *nb;
6211
6212 nb = equivalent_exprs(tb, fb, then_info_init, else_info_init, context);
6213 if (nb) {
6214 info->size -= 1;
6215 return make_discarding_first_sequence(t, nb, info);
6216 }
6217 }
6218
6219 /* Try optimize: (if x x #f) => x
6220 This pattern is included in the previous reduction,
6221 but this is still useful if x is mutable or a top level*/
6222 if (SCHEME_FALSEP(fb)
6223 && equivalent_exprs(t, tb, NULL, NULL, 0)) {
6224 info->size -= 2;
6225 return ensure_single_value(t, info);
6226 }
6227
6228 /* Convert: expressions like
6229 (if (if M N #f) P K) => (if M (if N P K) K)
6230 for simple constants K. This is useful to expose simple
6231 tests to the JIT. */
6232 if (SAME_TYPE(SCHEME_TYPE(t), scheme_branch_type)) {
6233 Scheme_Branch_Rec *b2 = (Scheme_Branch_Rec *)t;
6234 Scheme_Object *ntb, *nfb, *nt2 = NULL;
6235 if (SCHEME_FALSEP(b2->fbranch)
6236 && scheme_ir_duplicate_ok(fb, 0)) {
6237 /* (if (if M N #f) P K) => (if M (if N P K) K) */
6238 ntb = (Scheme_Object *)b2;
6239 nfb = optimize_clone(0, fb, info, empty_eq_hash_tree, 0);
6240 nt2 = b2->tbranch;
6241 } else if (SCHEME_FALSEP(b2->tbranch)
6242 && scheme_ir_duplicate_ok(fb, 0)) {
6243 /* (if (if M #f N) P K) => (if M K (if N P K)) */
6244 ntb = optimize_clone(0, fb, info, empty_eq_hash_tree, 0);
6245 nfb = (Scheme_Object *)b2;
6246 nt2 = b2->fbranch;
6247 } else if (SAME_OBJ(b2->fbranch, scheme_true)
6248 && scheme_ir_duplicate_ok(tb, 0)) {
6249 /* (if (if M N #t) K P) => (if M (if N K P) K) */
6250 ntb = (Scheme_Object *)b2;
6251 nfb = optimize_clone(0, tb, info, empty_eq_hash_tree, 0);
6252 nt2 = b2->tbranch;
6253 } else if (SAME_OBJ(b2->tbranch, scheme_true)
6254 && scheme_ir_duplicate_ok(tb, 0)) {
6255 /* (if (if M #t N) K P) => (if M K (if N K P)) */
6256 ntb = optimize_clone(0, tb, info, empty_eq_hash_tree, 0);
6257 nfb = (Scheme_Object *)b2;
6258 nt2 = b2->fbranch;
6259 }
6260 if (nt2) {
6261 t = b2->test;
6262 b2->test = nt2;
6263 b2->tbranch = tb;
6264 b2->fbranch = fb;
6265 tb = ntb;
6266 fb = nfb;
6267 }
6268 }
6269
6270 b->test = t;
6271 b->tbranch = tb;
6272 b->fbranch = fb;
6273
6274 if (OPT_BRANCH_ADDS_NO_SIZE) {
6275 /* Seems to work better to not to increase the size
6276 specifically for `if' */
6277 } else {
6278 info->size += 1;
6279 }
6280
6281 return o;
6282 }
6283
6284 /*========================================================================*/
6285 /* with-continuation-marks */
6286 /*========================================================================*/
6287
omittable_key(Scheme_Object * k,Optimize_Info * info)6288 static int omittable_key(Scheme_Object *k, Optimize_Info *info)
6289 {
6290 /* A key is not omittable if it might refer to a chaperoned/impersonated
6291 continuation mark key, so that's why we pass OMITTABLE_KEEP_VARS: */
6292 return scheme_omittable_expr(k, 1, 20, OMITTABLE_KEEP_VARS, info, info);
6293 }
6294
optimize_wcm(Scheme_Object * o,Optimize_Info * info,int context)6295 static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int context)
6296 {
6297 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)o;
6298 Scheme_Object *k, *v, *b;
6299 int init_vclock, can_omit_key;
6300 Optimize_Info_Sequence info_seq;
6301
6302 optimize_info_seq_init(info, &info_seq);
6303
6304 k = optimize_expr(wcm->key, info, OPT_CONTEXT_SINGLED);
6305
6306 if (info->escapes) {
6307 optimize_info_seq_done(info, &info_seq);
6308 return ensure_noncm(k, info);
6309 }
6310
6311 optimize_info_seq_step(info, &info_seq);
6312
6313 v = optimize_expr(wcm->val, info, OPT_CONTEXT_SINGLED);
6314
6315 if (info->escapes) {
6316 optimize_info_seq_done(info, &info_seq);
6317 info->size += 1;
6318 return ensure_noncm(make_discarding_first_sequence(k, v, info), info);
6319 }
6320
6321 /* The presence of a key can be detected by other expressions,
6322 to increment vclock to prevent expressions incorrectly
6323 moving under the mark: */
6324 info->vclock++;
6325 init_vclock = info->vclock;
6326
6327 optimize_info_seq_step(info, &info_seq);
6328
6329 b = optimize_expr(wcm->body, info, scheme_optimize_tail_context(context));
6330
6331 if (init_vclock == info->vclock) {
6332 /* body has no effect itself, so we can rewind the clock */
6333 info->vclock--;
6334 }
6335
6336 optimize_info_seq_done(info, &info_seq);
6337
6338 /* If the body cannot inspect the continution, and if the key is not
6339 a chaperone, no need to add the mark: */
6340 can_omit_key = omittable_key(k, info);
6341 if (can_omit_key
6342 && scheme_omittable_expr(b, -1, 20, 0, info, info))
6343 return make_discarding_first_sequence(v, b, info);
6344
6345 /* info->single_result is already set */
6346 info->preserves_marks = 0;
6347
6348 wcm->key = k;
6349 wcm->val = v;
6350 wcm->body = b;
6351
6352 info->size += 1;
6353
6354 /* Simplify (with-continuation-mark <same-key> <val1>
6355 (with-continuation-mark <same-key> <val2>
6356 <body>))
6357 to (begin
6358 <val1>
6359 (with-continuation-mark <same-key> <val2>
6360 <body>))
6361 as long as <val2> doesn't inspect the continuation. */
6362 if (can_omit_key
6363 && SAME_TYPE(SCHEME_TYPE(wcm->body), scheme_with_cont_mark_type)
6364 && equivalent_exprs(wcm->key, ((Scheme_With_Continuation_Mark *)wcm->body)->key, NULL, NULL, 0)
6365 && scheme_omittable_expr(((Scheme_With_Continuation_Mark *)wcm->body)->val, 1, 20, 0, info, info))
6366 return make_discarding_first_sequence(wcm->val, wcm->body, info);
6367
6368 return (Scheme_Object *)wcm;
6369 }
6370
6371 /*========================================================================*/
6372 /* other syntax */
6373 /*========================================================================*/
6374
6375 static Scheme_Object *
define_values_optimize(Scheme_Object * data,Optimize_Info * info,int context)6376 define_values_optimize(Scheme_Object *data, Optimize_Info *info, int context)
6377 {
6378 Scheme_Object *val = SCHEME_DEFN_RHS(data);
6379
6380 optimize_info_used_top(info);
6381 val = optimize_expr(val, info, 0);
6382
6383 SCHEME_DEFN_RHS(data) = val;
6384
6385 return data;
6386 }
6387
6388 static Scheme_Object *
set_optimize(Scheme_Object * data,Optimize_Info * info,int context)6389 set_optimize(Scheme_Object *data, Optimize_Info *info, int context)
6390 {
6391 Scheme_Set_Bang *sb = (Scheme_Set_Bang *)data;
6392 Scheme_Object *var, *val;
6393
6394 var = sb->var;
6395 val = sb->val;
6396
6397 val = optimize_expr(val, info, OPT_CONTEXT_SINGLED);
6398
6399 if (info->escapes)
6400 return ensure_noncm(val, info);
6401
6402 info->preserves_marks = 1;
6403 info->single_result = 1;
6404
6405 if (SAME_TYPE(SCHEME_TYPE(var), scheme_ir_local_type)) {
6406 register_use(SCHEME_VAR(var), info);
6407 } else {
6408 MZ_ASSERT(((Scheme_IR_Toplevel *)var)->instance_pos == -1);
6409 optimize_info_used_top(info);
6410 }
6411
6412 info->vclock++;
6413
6414 sb->var = var;
6415 sb->val = val;
6416
6417 return (Scheme_Object *)sb;
6418 }
6419
6420 static Scheme_Object *
set_clone(int single_use,Scheme_Object * data,Optimize_Info * info,Scheme_Hash_Tree * var_map)6421 set_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map)
6422 {
6423 Scheme_Set_Bang *sb = (Scheme_Set_Bang *)data, *naya;
6424 Scheme_Object *var, *val;
6425
6426 naya = MALLOC_ONE_TAGGED(Scheme_Set_Bang);
6427 memcpy(naya, sb, sizeof(Scheme_Set_Bang));
6428
6429 var = naya->var;
6430 val = naya->val;
6431
6432 val = optimize_clone(single_use, val, info, var_map, 0);
6433 if (!val) return NULL;
6434 if (SAME_TYPE(SCHEME_TYPE(var), scheme_ir_local_type)) {
6435 var = optimize_clone(single_use, var, info, var_map, 0);
6436 if (!var) return NULL;
6437 }
6438
6439 naya->var = var;
6440 naya->val = val;
6441
6442 return (Scheme_Object *)naya;
6443 }
6444
6445 static Scheme_Object *
ref_optimize(Scheme_Object * data,Optimize_Info * info,int context)6446 ref_optimize(Scheme_Object *data, Optimize_Info *info, int context)
6447 {
6448 Scheme_Object *v;
6449
6450 optimize_info_used_top(info);
6451
6452 v = SCHEME_PTR1_VAL(data);
6453 if (SAME_TYPE(SCHEME_TYPE(v), scheme_ir_local_type)) {
6454 SCHEME_PTR1_VAL(data) = (SCHEME_VAR(v)->mutated ? scheme_false : scheme_true);
6455 } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_ir_toplevel_type)) {
6456 /* Knowing whether a top-level variable is fixed lets us optimize
6457 uses of `variable-reference-constant?` */
6458 if (get_defn_shape(info, (Scheme_IR_Toplevel *)v)
6459 || get_import_shape(info, (Scheme_IR_Toplevel *)v)) {
6460 v = scheme_ir_toplevel_to_flagged_toplevel(v, SCHEME_TOPLEVEL_FIXED);
6461 SCHEME_PTR1_VAL(data) = v;
6462 }
6463 register_import_used(info, (Scheme_IR_Toplevel *)v);
6464 }
6465
6466 info->preserves_marks = 1;
6467 info->single_result = 1;
6468 info->size++;
6469
6470 return data;
6471 }
6472
6473 static Scheme_Object *
ref_clone(int single_use,Scheme_Object * data,Optimize_Info * info,Scheme_Hash_Tree * var_map)6474 ref_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map)
6475 {
6476 Scheme_Object *naya;
6477 Scheme_Object *a, *b;
6478
6479 a = SCHEME_PTR1_VAL(data);
6480 a = optimize_clone(single_use, a, info, var_map, 0);
6481 if (!a) return NULL;
6482
6483 b = SCHEME_PTR2_VAL(data);
6484 b = optimize_clone(single_use, b, info, var_map, 0);
6485 if (!b) return NULL;
6486
6487 naya = scheme_alloc_object();
6488 naya->type = scheme_varref_form_type;
6489 SCHEME_PTR1_VAL(naya) = a;
6490 SCHEME_PTR2_VAL(naya) = b;
6491
6492 return naya;
6493 }
6494
6495 static Scheme_Object *
apply_values_optimize(Scheme_Object * data,Optimize_Info * info,int context)6496 apply_values_optimize(Scheme_Object *data, Optimize_Info *info, int context)
6497 {
6498 Scheme_Object *f, *e;
6499 Optimize_Info_Sequence info_seq;
6500
6501 f = SCHEME_PTR1_VAL(data);
6502 e = SCHEME_PTR2_VAL(data);
6503
6504 optimize_info_seq_init(info, &info_seq);
6505
6506 f = optimize_expr(f, info, OPT_CONTEXT_SINGLED);
6507
6508 if (info->escapes) {
6509 optimize_info_seq_done(info, &info_seq);
6510 return ensure_noncm(f, info);
6511 }
6512 optimize_info_seq_step(info, &info_seq);
6513
6514 e = optimize_expr(e, info, 0);
6515
6516 optimize_info_seq_done(info, &info_seq);
6517
6518 if (info->escapes) {
6519 info->size += 1;
6520 return ensure_noncm(make_discarding_first_sequence(f, e, info), info);
6521 }
6522
6523 info->size += 1;
6524 info->vclock += 1;
6525 info->kclock += 1;
6526 info->sclock += 1;
6527
6528 return optimize_apply_values(f, e, info, info->single_result, context);
6529 }
6530
6531 static Scheme_Object *
apply_values_clone(int single_use,Scheme_Object * data,Optimize_Info * info,Scheme_Hash_Tree * var_map)6532 apply_values_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map)
6533 {
6534 Scheme_Object *f, *e;
6535
6536 f = SCHEME_PTR1_VAL(data);
6537 e = SCHEME_PTR2_VAL(data);
6538
6539 f = optimize_clone(single_use, f, info, var_map, 0);
6540 if (!f) return NULL;
6541 e = optimize_clone(single_use, e, info, var_map, 0);
6542 if (!e) return NULL;
6543
6544 data = scheme_alloc_object();
6545 data->type = scheme_apply_values_type;
6546 SCHEME_PTR1_VAL(data) = f;
6547 SCHEME_PTR2_VAL(data) = e;
6548
6549 return data;
6550 }
6551
6552 static Scheme_Object *
with_immed_mark_optimize(Scheme_Object * data,Optimize_Info * info,int context)6553 with_immed_mark_optimize(Scheme_Object *data, Optimize_Info *info, int context)
6554 {
6555 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)data;
6556 Scheme_Object *key, *val, *body;
6557 Optimize_Info_Sequence info_seq;
6558 Optimize_Info *body_info;
6559 Scheme_IR_Local *var;
6560
6561 optimize_info_seq_init(info, &info_seq);
6562
6563 key = optimize_expr(wcm->key, info, OPT_CONTEXT_SINGLED);
6564 optimize_info_seq_step(info, &info_seq);
6565 if (info->escapes) {
6566 optimize_info_seq_done(info, &info_seq);
6567 return ensure_noncm(key, info);
6568 }
6569
6570 val = optimize_expr(wcm->val, info, OPT_CONTEXT_SINGLED);
6571 optimize_info_seq_step(info, &info_seq);
6572 if (info->escapes) {
6573 optimize_info_seq_done(info, &info_seq);
6574 return ensure_noncm(make_discarding_first_sequence(key, val, info), info);
6575 }
6576
6577 optimize_info_seq_done(info, &info_seq);
6578
6579 body_info = optimize_info_add_frame(info, 0);
6580 var = SCHEME_VAR(SCHEME_CAR(wcm->body));
6581 set_optimize_mode(var);
6582 var->optimize.lambda_depth = body_info->lambda_depth;
6583 var->optimize_used = 0;
6584 var->optimize.init_kclock = info->kclock;
6585
6586 body = optimize_expr(SCHEME_CDR(wcm->body), body_info, 0);
6587
6588 optimize_info_done(body_info, NULL);
6589
6590 wcm->key = key;
6591 wcm->val = val;
6592 SCHEME_CDR(wcm->body) = body;
6593
6594 info->preserves_marks = 0;
6595
6596 return data;
6597 }
6598
6599 static Scheme_Object *
with_immed_mark_clone(int single_use,Scheme_Object * data,Optimize_Info * info,Scheme_Hash_Tree * var_map)6600 with_immed_mark_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map)
6601 {
6602 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)data;
6603 Scheme_With_Continuation_Mark *wcm2;
6604 Scheme_Object *e;
6605 Scheme_IR_Local *var;
6606
6607 wcm2 = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark);
6608 wcm2->so.type = scheme_with_immed_mark_type;
6609
6610 e = optimize_clone(single_use, wcm->key, info, var_map, 0);
6611 if (!e) return NULL;
6612 wcm2->key = e;
6613
6614 e = optimize_clone(single_use, wcm->val, info, var_map, 0);
6615 if (!e) return NULL;
6616 wcm2->val = e;
6617
6618 var = clone_variable(SCHEME_VAR(SCHEME_CAR(wcm->body)));
6619 var_map = scheme_hash_tree_set(var_map, SCHEME_CAR(wcm->body), (Scheme_Object *)var);
6620
6621 e = optimize_clone(single_use, SCHEME_CDR(wcm->body), info, var_map, 0);
6622 if (!e) return NULL;
6623 e = scheme_make_mutable_pair((Scheme_Object *)var, e);
6624 wcm2->body = e;
6625
6626 return (Scheme_Object *)wcm2;
6627 }
6628
6629 static Scheme_Object *
case_lambda_optimize(Scheme_Object * expr,Optimize_Info * info,int context)6630 case_lambda_optimize(Scheme_Object *expr, Optimize_Info *info, int context)
6631 {
6632 Scheme_Object *le;
6633 int i;
6634 Scheme_Case_Lambda *seq = (Scheme_Case_Lambda *)expr;
6635
6636 for (i = 0; i < seq->count; i++) {
6637 le = seq->array[i];
6638 le = optimize_expr(le, info, 0);
6639 seq->array[i] = le;
6640 }
6641
6642 info->preserves_marks = 1;
6643 info->single_result = 1;
6644 info->size += 1;
6645
6646 return expr;
6647 }
6648
6649 static Scheme_Object *
case_lambda_clone(int single_use,Scheme_Object * data,Optimize_Info * info,Scheme_Hash_Tree * var_map)6650 case_lambda_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map)
6651 {
6652 Scheme_Object *le;
6653 int i, sz;
6654 Scheme_Case_Lambda *seq = (Scheme_Case_Lambda *)data;
6655 Scheme_Case_Lambda *seq2;
6656
6657 sz = sizeof(Scheme_Case_Lambda) + ((seq->count - mzFLEX_DELTA) * sizeof(Scheme_Object*));
6658 seq2 = (Scheme_Case_Lambda *)scheme_malloc_tagged(sz);
6659 memcpy(seq2, seq, sz);
6660
6661 for (i = 0; i < seq->count; i++) {
6662 le = seq->array[i];
6663 le = optimize_clone(single_use, le, info, var_map, 0);
6664 if (!le) return NULL;
6665 seq2->array[i] = le;
6666 }
6667
6668 return (Scheme_Object *)seq2;
6669 }
6670
begin0_optimize(Scheme_Object * obj,Optimize_Info * info,int context)6671 static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, int context)
6672 {
6673 int i, count, drop = 0, prev_size, single_result = 0, preserves_marks = 0, kclock = 0, sclock = 0;
6674 Scheme_Sequence *s = (Scheme_Sequence *)obj;
6675 Scheme_Object *inside = NULL, *expr, *orig_first;
6676 Scheme_Object *le;
6677 Optimize_Info_Sequence info_seq;
6678
6679 count = s->count;
6680 optimize_info_seq_init(info, &info_seq);
6681
6682 for (i = 0; i < count; i++) {
6683 prev_size = info->size;
6684
6685 optimize_info_seq_step(info, &info_seq);
6686
6687 le = optimize_expr(s->array[i],
6688 info,
6689 (!i
6690 ? scheme_optimize_result_context(context)
6691 : 0));
6692
6693 if (!i) {
6694 single_result = info->single_result;
6695 preserves_marks = info->preserves_marks;
6696 kclock = info->kclock;
6697 sclock = info->sclock;
6698 s->array[0] = le;
6699 } else {
6700 /* Inlining and constant propagation can expose omittable expressions: */
6701 le = optimize_ignored(le, info, -1, 1, 5);
6702 if (!le) {
6703 drop++;
6704 info->size = prev_size;
6705 s->array[i] = NULL;
6706 } else {
6707 s->array[i] = le;
6708 }
6709 }
6710
6711 if (info->escapes) {
6712 int j;
6713 single_result = info->single_result;
6714 preserves_marks = info->preserves_marks;
6715 for (j = i + 1; j < count; j++) {
6716 drop++;
6717 s->array[j] = NULL;
6718 }
6719 break;
6720 }
6721 }
6722
6723 optimize_info_seq_done(info, &info_seq);
6724
6725 if (info->escapes) {
6726 /* In case of an error, optimize (begin0 ... <error> ...) => (begin ... <error>) */
6727 Scheme_Sequence *s2;
6728 int j = 0;
6729
6730 info->single_result = 1;
6731 info->preserves_marks = 1;
6732
6733 if (i != 0) {
6734 /* We will ignore the first expression too */
6735 le = optimize_ignored(s->array[0], info, -1, 1, 5);
6736 if (!le) {
6737 drop++;
6738 info->size = prev_size;
6739 s->array[0] = NULL;
6740 } else {
6741 s->array[0] = le;
6742 }
6743 }
6744
6745 if ((count - drop) == 1) {
6746 /* If it's only one expression we can drop the begin0 */
6747 return ensure_noncm(s->array[i], info);
6748 }
6749
6750 s2 = scheme_malloc_sequence(count - drop);
6751 s2->so.type = scheme_sequence_type;
6752 s2->count = count - drop;
6753
6754 for (i = 0; i < count; i++) {
6755 if (s->array[i]) {
6756 s2->array[j++] = s->array[i];
6757 }
6758 }
6759 return flatten_sequence((Scheme_Object *)s2, info, context);
6760 }
6761
6762 info->preserves_marks = 1;
6763 info->single_result = single_result;
6764
6765 if ((s->count - drop) == 1 && (preserves_marks == 1)) {
6766 /* If the first expression preserves marks we can drop the begin0 */
6767 return s->array[0];
6768 }
6769
6770 expr = s->array[0];
6771 orig_first = s->array[0];
6772 extract_tail_inside(&expr, &inside, 0);
6773
6774 /* Try optimize (begin0 <movable> ...) => (begin ... <movable>) */
6775 if (movable_expression(expr, info, 0, kclock != info->kclock,
6776 sclock != info->sclock, 0, 50)) {
6777 if ((s->count - drop) == 1) {
6778 /* drop the begin0 */
6779 info->size -= 1;
6780 /* expr = expr */
6781 } else {
6782 Scheme_Sequence *s2;
6783 int j = 0;
6784
6785 s2 = scheme_malloc_sequence(s->count - drop);
6786 s2->so.type = scheme_sequence_type;
6787 s2->count = s->count - drop;
6788
6789 for (i = 1; i < s->count; i++) {
6790 if (s->array[i]) {
6791 s2->array[j++] = s->array[i];
6792 }
6793 }
6794 s2->array[j++] = expr;
6795
6796 expr = (Scheme_Object *)s2;
6797 }
6798 } else {
6799 if (drop) {
6800 Scheme_Sequence *s2;
6801 int j = 0;
6802
6803 s2 = scheme_malloc_sequence(s->count - drop);
6804 s2->so.type = s->so.type;
6805 s2->count = s->count - drop;
6806
6807 s2->array[j++] = expr;
6808 for (i = 1; i < s->count; i++) {
6809 if (s->array[i]) {
6810 s2->array[j++] = s->array[i];
6811 }
6812 }
6813
6814 expr = (Scheme_Object *)s2;
6815 } else {
6816 s->array[0] = expr;
6817 expr = (Scheme_Object *)s;
6818 }
6819 }
6820
6821 info->size += 1;
6822 expr = flatten_sequence(expr, info, context);
6823 return replace_tail_inside(expr, inside, orig_first);
6824 }
6825
6826 /*========================================================================*/
6827 /* let, let-values, letrec, etc. */
6828 /*========================================================================*/
6829
is_liftable_prim(Scheme_Object * v,int or_escape)6830 static int is_liftable_prim(Scheme_Object *v, int or_escape)
6831 /* Can we lift a call to `v` out of a `letrec` to a wrapping `let`? */
6832 {
6833 if (SCHEME_PRIMP(v)) {
6834 int opt = (((Scheme_Primitive_Proc *)v)->pp.flags & SCHEME_PRIM_OPT_MASK);
6835 if (opt >= SCHEME_PRIM_OPT_IMMEDIATE)
6836 return 1;
6837 if (or_escape && (opt >= SCHEME_PRIM_OPT_NONCM)) {
6838 if (SCHEME_PRIM_PROC_OPT_FLAGS(v) & SCHEME_PRIM_ALWAYS_ESCAPES)
6839 return 1;
6840 }
6841 }
6842
6843 if (SAME_OBJ(v, scheme_values_proc))
6844 return 1;
6845
6846 return 0;
6847 }
6848
scheme_is_liftable(Scheme_Object * o,Scheme_Hash_Tree * exclude_vars,int fuel,int as_rator,int or_escape)6849 int scheme_is_liftable(Scheme_Object *o, Scheme_Hash_Tree *exclude_vars, int fuel, int as_rator, int or_escape)
6850 /* Can we lift `o` out of a `letrec` to a wrapping `let`? Refences
6851 to `exclude_vars` are not allowed, since those are the LHS. */
6852 {
6853 Scheme_Type t = SCHEME_TYPE(o);
6854
6855 if (!fuel) return 0;
6856
6857 switch (t) {
6858 case scheme_ir_lambda_type:
6859 return !as_rator;
6860 case scheme_case_lambda_sequence_type:
6861 return !as_rator;
6862 case scheme_ir_toplevel_type:
6863 return 1;
6864 case scheme_ir_local_type:
6865 if (!scheme_eq_hash_tree_get(exclude_vars, o))
6866 return 1;
6867 break;
6868 case scheme_branch_type:
6869 {
6870 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)o;
6871 if (scheme_is_liftable(b->test, exclude_vars, fuel - 1, 0, or_escape)
6872 && scheme_is_liftable(b->tbranch, exclude_vars, fuel - 1, as_rator, or_escape)
6873 && scheme_is_liftable(b->fbranch, exclude_vars, fuel - 1, as_rator, or_escape))
6874 return 1;
6875 }
6876 break;
6877 case scheme_application_type:
6878 {
6879 Scheme_App_Rec *app = (Scheme_App_Rec *)o;
6880 int i;
6881 if (!is_liftable_prim(app->args[0], or_escape))
6882 return 0;
6883 for (i = app->num_args + 1; i--; ) {
6884 if (!scheme_is_liftable(app->args[i], exclude_vars, fuel - 1, 1, or_escape))
6885 return 0;
6886 }
6887 return 1;
6888 }
6889 break;
6890 case scheme_application2_type:
6891 {
6892 Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
6893 if (!is_liftable_prim(app->rator, or_escape))
6894 return 0;
6895 if (scheme_is_liftable(app->rator, exclude_vars, fuel - 1, 1, or_escape)
6896 && scheme_is_liftable(app->rand, exclude_vars, fuel - 1, 1, or_escape))
6897 return 1;
6898 }
6899 break;
6900 case scheme_application3_type:
6901 {
6902 Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
6903 if (!is_liftable_prim(app->rator, or_escape))
6904 return 0;
6905 if (scheme_is_liftable(app->rator, exclude_vars, fuel - 1, 1, or_escape)
6906 && scheme_is_liftable(app->rand1, exclude_vars, fuel - 1, 1, or_escape)
6907 && scheme_is_liftable(app->rand2, exclude_vars, fuel - 1, 1, or_escape))
6908 return 1;
6909 }
6910 break;
6911 case scheme_ir_let_header_type:
6912 {
6913 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)o;
6914 int i;
6915
6916 o = lh->body;
6917 for (i = lh->num_clauses; i--; ) {
6918 if (!scheme_is_liftable(((Scheme_IR_Let_Value *)o)->value, exclude_vars, fuel - 1, as_rator, or_escape))
6919 return 0;
6920 o = ((Scheme_IR_Let_Value *)o)->body;
6921 }
6922 if (scheme_is_liftable(o, exclude_vars, fuel - 1, as_rator, or_escape))
6923 return 1;
6924 break;
6925 }
6926 default:
6927 if (t > _scheme_ir_values_types_)
6928 return 1;
6929 }
6930
6931 return 0;
6932 }
6933
ir_propagate_ok(Scheme_Object * value,Optimize_Info * info,int used_once,Scheme_IR_Local * once_var)6934 int ir_propagate_ok(Scheme_Object *value, Optimize_Info *info, int used_once, Scheme_IR_Local *once_var)
6935 /* Can we constant-propagate the expression `value`?
6936 If `used_once` is true, the value is known to be used once,
6937 but if `once_var` is provided, record when the result
6938 relies on that once-usedness. */
6939 {
6940 if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_lambda_type)) {
6941 int sz;
6942 sz = lambda_body_size_plus_info((Scheme_Lambda *)value, 1, info, NULL);
6943 if ((sz >= 0) && (sz <= MAX_PROC_INLINE_SIZE))
6944 return 1;
6945 else if (used_once) {
6946 if (once_var) {
6947 /* Mark the variable as having a known value only as long as it's used just
6948 once. In case the one reference is duplicated --- perhaps because it is
6949 used in a non-application position in a function that is itself inlined
6950 --- then the known value should be cleared. */
6951 once_var->optimize.clear_known_on_multi_use = 1;
6952 }
6953 return 1;
6954 } else {
6955 if (scheme_log_level_p(info->logger, SCHEME_LOG_DEBUG)) {
6956 Scheme_Lambda *lam = (Scheme_Lambda *)value;
6957 if (sz < 0)
6958 scheme_log(info->logger,
6959 SCHEME_LOG_DEBUG,
6960 0,
6961 /* contains non-copyable body elements that prevent inlining */
6962 "non-copyable %s size: %d threshold: %d#<separator>%s",
6963 scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
6964 sz,
6965 0, /* no sensible threshold here */
6966 scheme_optimize_context_to_string(info->context));
6967 else
6968 scheme_log(info->logger,
6969 SCHEME_LOG_DEBUG,
6970 0,
6971 /* too large to be an inlining candidate */
6972 "too-large %s size: %d threshold: %d#<separator>%s",
6973 scheme_write_to_string(lam->name ? lam->name : scheme_false, NULL),
6974 sz,
6975 0, /* no sensible threshold here */
6976 scheme_optimize_context_to_string(info->context));
6977 }
6978 return 0;
6979 }
6980 }
6981
6982 if (SAME_TYPE(scheme_case_lambda_sequence_type, SCHEME_TYPE(value))) {
6983 Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)value;
6984 int i;
6985 for (i = cl->count; i--; ) {
6986 if (!ir_propagate_ok(cl->array[i], info, used_once, once_var))
6987 return 0;
6988 }
6989 return 1;
6990 }
6991
6992 if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_toplevel_type)) {
6993 if ((SCHEME_IR_TOPLEVEL_FLAGS((Scheme_IR_Toplevel *)value) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_FIXED)
6994 return 1;
6995 if (get_import_shape(info, (Scheme_IR_Toplevel *)value))
6996 return 1;
6997
6998 value = get_defn_shape(info, (Scheme_IR_Toplevel *)value);
6999 value = no_potential_size(value);
7000 if (SAME_OBJ(value, scheme_constant_key)
7001 || (value && SAME_TYPE(SCHEME_TYPE(value), scheme_struct_proc_shape_type)))
7002 return 0;
7003 else if (value)
7004 return 1;
7005 else
7006 return 0;
7007 }
7008
7009 /* Test this after the specific cases,
7010 because it recognizes locals and toplevels. */
7011 if (scheme_ir_duplicate_ok(value, 0))
7012 return 1;
7013
7014 return 0;
7015 }
7016
scheme_is_statically_proc(Scheme_Object * value,Optimize_Info * info,int flags)7017 int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info, int flags)
7018 /* Does `value` definitely produce a procedure of a specific shape?
7019 This function can be used on resolved (and SFS) forms, too, and it
7020 must be consistent with (i.e., as least as accepting as)
7021 optimization-time decisions. The `flags` argument is for
7022 scheme_omittable_expr(). */
7023 {
7024 while (1) {
7025 if (SCHEME_LAMBDAP(value)
7026 || SCHEME_PROCP(value)
7027 || SAME_TYPE(SCHEME_TYPE(value), scheme_lambda_type)
7028 || SAME_TYPE(SCHEME_TYPE(value), scheme_case_lambda_sequence_type)
7029 || SAME_TYPE(SCHEME_TYPE(value), scheme_inline_variant_type))
7030 return 1;
7031 else if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_let_header_type)) {
7032 /* Look for (let ([x <omittable>]) <proc>), which is generated for optional arguments. */
7033 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)value;
7034 if (lh->num_clauses == 1) {
7035 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
7036 if (scheme_omittable_expr(lv->value, lv->count, 20, flags, info, NULL)) {
7037 value = lv->body;
7038 } else
7039 break;
7040 } else
7041 break;
7042 } else if (SAME_TYPE(SCHEME_TYPE(value), scheme_let_one_type)) {
7043 Scheme_Let_One *lo = (Scheme_Let_One *)value;
7044 if (scheme_omittable_expr(lo->value, 1, 20, flags, info, NULL)) {
7045 value = lo->body;
7046 } else
7047 break;
7048 } else if (SAME_TYPE(SCHEME_TYPE(value), scheme_boxenv_type)) {
7049 value = SCHEME_PTR2_VAL(value);
7050 } else if (SAME_TYPE(SCHEME_TYPE(value), scheme_sequence_type)
7051 /* Handle a sequence for resolved mode, because it might
7052 be for safe-for-space clears around a procedure */
7053 && (flags & OMITTABLE_RESOLVED)) {
7054 Scheme_Sequence *seq = (Scheme_Sequence *)value;
7055 int i;
7056 for (i = 0; i < seq->count-1; i++) {
7057 if (!scheme_omittable_expr(seq->array[i], 1, 5, flags, info, NULL))
7058 break;
7059 }
7060 if (i == seq->count-1) {
7061 value = seq->array[i];
7062 } else
7063 break;
7064 } else
7065 break;
7066 }
7067
7068 return 0;
7069 }
7070
scheme_make_noninline_proc(Scheme_Object * e)7071 Scheme_Object *scheme_make_noninline_proc(Scheme_Object *e)
7072 /* Make a record that presents a procedure of a known shape, but
7073 that should not be inlined. */
7074 {
7075 Scheme_Object *ni;
7076
7077 while (SAME_TYPE(SCHEME_TYPE(e), scheme_ir_let_header_type)) {
7078 /* This must be (let ([x <omittable>]) <proc>); see scheme_is_statically_proc() */
7079 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)e;
7080 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
7081 MZ_ASSERT(lh->num_clauses == 1);
7082 e = lv->body;
7083 }
7084
7085 ni = scheme_alloc_small_object();
7086 ni->type = scheme_noninline_proc_type;
7087 SCHEME_PTR_VAL(ni) = e;
7088
7089 return ni;
7090 }
7091
is_values_apply(Scheme_Object * e,int n,Optimize_Info * info,Scheme_Hash_Tree * except_vars,int fuel)7092 static int is_values_apply(Scheme_Object *e, int n, Optimize_Info *info, Scheme_Hash_Tree *except_vars, int fuel)
7093 /* Is `e` a `(values ...)` form --- or, in the case of `if`, can be be
7094 converted to one, so that we can split apart the results
7095 statically? */
7096 {
7097 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) {
7098 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
7099 if (n != app->num_args) return 0;
7100 return SAME_OBJ(scheme_values_proc, app->args[0]);
7101 } else if ((n == 1) && SAME_TYPE(SCHEME_TYPE(e), scheme_application2_type)) {
7102 Scheme_App2_Rec *app = (Scheme_App2_Rec *)e;
7103 return SAME_OBJ(scheme_values_proc, app->rator);
7104 } else if ((n == 2) && SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) {
7105 Scheme_App3_Rec *app = (Scheme_App3_Rec *)e;
7106 return SAME_OBJ(scheme_values_proc, app->rator);
7107 } else if (fuel && SAME_TYPE(SCHEME_TYPE(e), scheme_branch_type)) {
7108 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e;
7109 if (SAME_TYPE(SCHEME_TYPE(b->test), scheme_ir_local_type)
7110 && !scheme_eq_hash_tree_get(except_vars, b->test)
7111 && !SCHEME_VAR(b->test)->mutated) {
7112 return (is_values_apply(b->tbranch, n, info, except_vars, 0)
7113 && is_values_apply(b->fbranch, n, info, except_vars, 0));
7114 }
7115 }
7116
7117 return 0;
7118 }
7119
no_mutable_bindings(Scheme_IR_Let_Value * irlv)7120 static int no_mutable_bindings(Scheme_IR_Let_Value *irlv)
7121 /* Check whether a `let` clause has any mutable bindings */
7122 {
7123 int i;
7124
7125 for (i = irlv->count; i--; ) {
7126 if (irlv->vars[i]->mutated)
7127 return 0;
7128 }
7129
7130 return 1;
7131 }
7132
update_rhs_value(Scheme_IR_Let_Value * naya,Scheme_Object * e,Optimize_Info * info,Scheme_IR_Local * tst)7133 static void update_rhs_value(Scheme_IR_Let_Value *naya, Scheme_Object *e,
7134 Optimize_Info *info, Scheme_IR_Local *tst)
7135 /* Install an expression from a split `(values ...)` */
7136 {
7137 if (tst) {
7138 Scheme_Object *n;
7139
7140 n = equivalent_exprs(naya->value, e, NULL, NULL, 0);
7141 if (!n) {
7142 Scheme_Branch_Rec *b;
7143
7144 /* We're duplicating the test */
7145 increment_use_count(tst, 0);
7146
7147 b = MALLOC_ONE_TAGGED(Scheme_Branch_Rec);
7148 b->so.type = scheme_branch_type;
7149 b->test = (Scheme_Object *)tst;
7150 b->tbranch = naya->value;
7151 b->fbranch = e;
7152
7153 naya->value = (Scheme_Object *)b;
7154 } else
7155 naya->value = n;
7156 } else
7157 naya->value = e;
7158 }
7159
unpack_values_application(Scheme_Object * e,Scheme_IR_Let_Value * naya,Optimize_Info * info,Scheme_IR_Local * branch_test)7160 static void unpack_values_application(Scheme_Object *e, Scheme_IR_Let_Value *naya,
7161 Optimize_Info *info, Scheme_IR_Local *branch_test)
7162 /* Install the expressions from a split `values` form into new `let` clauses */
7163 {
7164 if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) {
7165 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
7166 int i;
7167 for (i = 0; i < app->num_args; i++) {
7168 update_rhs_value(naya, app->args[i + 1], info, branch_test);
7169 naya = (Scheme_IR_Let_Value *)naya->body;
7170 }
7171 } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application2_type)) {
7172 Scheme_App2_Rec *app = (Scheme_App2_Rec *)e;
7173 update_rhs_value(naya, app->rand, info, branch_test);
7174 } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) {
7175 Scheme_App3_Rec *app = (Scheme_App3_Rec *)e;
7176 update_rhs_value(naya, app->rand1, info, branch_test);
7177 naya = (Scheme_IR_Let_Value *)naya->body;
7178 update_rhs_value(naya, app->rand2, info, branch_test);
7179 } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_branch_type)) {
7180 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e;
7181
7182 MZ_ASSERT(SAME_TYPE(SCHEME_TYPE(b->test), scheme_ir_local_type));
7183
7184 unpack_values_application(b->tbranch, naya, info, NULL);
7185 unpack_values_application(b->fbranch, naya, info, SCHEME_VAR(b->test));
7186 }
7187 }
7188
make_clones(Scheme_IR_Let_Value * retry_start,Scheme_IR_Let_Value * pre_body,Optimize_Info * body_info)7189 static Scheme_Object *make_clones(Scheme_IR_Let_Value *retry_start,
7190 Scheme_IR_Let_Value *pre_body,
7191 Optimize_Info *body_info)
7192 /* Clone `lambda`s for re-optimization and for a fixpoint computation of
7193 procedure properties */
7194 {
7195 Scheme_IR_Let_Value *irlv;
7196 Scheme_Object *value, *clone, *pr;
7197 Scheme_Object *last = NULL, *first = NULL;
7198
7199 irlv = retry_start;
7200 while (1) {
7201 value = irlv->value;
7202 if (SCHEME_LAMBDAP(value)) {
7203 clone = optimize_clone(1, value, body_info, empty_eq_hash_tree, 0);
7204 if (clone) {
7205 pr = scheme_make_raw_pair(scheme_make_raw_pair(value, clone), NULL);
7206 } else
7207 pr = scheme_make_raw_pair(NULL, NULL);
7208 if (last)
7209 SCHEME_CDR(last) = pr;
7210 else
7211 first = pr;
7212 last = pr;
7213 }
7214 if (irlv == pre_body)
7215 break;
7216 irlv = (Scheme_IR_Let_Value *)irlv->body;
7217 }
7218
7219 return first;
7220 }
7221
set_one_code_flags(Scheme_Object * value,int flags,Scheme_Object * first,Scheme_Object * second,int set_flags,int mask_flags,int just_tentative,int merge_local_typed)7222 static int set_one_code_flags(Scheme_Object *value, int flags,
7223 Scheme_Object *first, Scheme_Object *second,
7224 int set_flags, int mask_flags, int just_tentative,
7225 int merge_local_typed)
7226 /* Set, record, or merge procedure-property flags */
7227 {
7228 Scheme_Case_Lambda *cl, *cl2, *cl3;
7229 Scheme_Lambda *lam, *lam2, *lam3;
7230 int i, count;
7231
7232 if (SAME_TYPE(scheme_ir_lambda_type, SCHEME_TYPE(value))) {
7233 count = 1;
7234 cl = NULL;
7235 cl2 = NULL;
7236 cl3 = NULL;
7237 } else {
7238 cl = (Scheme_Case_Lambda *)value;
7239 cl2 = (Scheme_Case_Lambda *)first;
7240 cl3 = (Scheme_Case_Lambda *)second;
7241 count = cl->count;
7242 }
7243
7244 for (i = 0; i < count; i++) {
7245 if (cl) {
7246 lam = (Scheme_Lambda *)cl->array[i];
7247 lam2 = (Scheme_Lambda *)cl2->array[i];
7248 lam3 = (Scheme_Lambda *)cl3->array[i];
7249 } else {
7250 lam = (Scheme_Lambda *)value;
7251 lam2 = (Scheme_Lambda *)first;
7252 lam3 = (Scheme_Lambda *)second;
7253 }
7254
7255 if (merge_local_typed) {
7256 merge_lambda_arg_types(lam, lam2);
7257 merge_lambda_arg_types(lam, lam3);
7258 merge_lambda_arg_types(lam, lam2);
7259 }
7260
7261 if (!just_tentative || ((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE)) {
7262 flags = (flags & SCHEME_LAMBDA_FLAGS(lam));
7263 SCHEME_LAMBDA_FLAGS(lam2) = set_flags | (SCHEME_LAMBDA_FLAGS(lam2) & mask_flags);
7264 SCHEME_LAMBDA_FLAGS(lam3) = set_flags | (SCHEME_LAMBDA_FLAGS(lam3) & mask_flags);
7265 }
7266 }
7267
7268 return flags;
7269 }
7270
set_code_flags(Scheme_IR_Let_Value * retry_start,Scheme_IR_Let_Value * pre_body,Scheme_Object * clones,int set_flags,int mask_flags,int just_tentative,int merge_local_typed)7271 static int set_code_flags(Scheme_IR_Let_Value *retry_start,
7272 Scheme_IR_Let_Value *pre_body,
7273 Scheme_Object *clones,
7274 int set_flags, int mask_flags, int just_tentative,
7275 int merge_local_typed)
7276 /* Set, record, or merge procedure-property flags */
7277 {
7278 Scheme_IR_Let_Value *irlv;
7279 Scheme_Object *value, *first;
7280 int flags = LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS;
7281
7282 /* The first in a clone pair is the one that is consulted for
7283 references. The second one is the clone, and it's the one whose
7284 flags are updated by optimization. So consult the clone, and set
7285 flags in both. */
7286
7287 irlv = retry_start;
7288 while (clones) {
7289 value = irlv->value;
7290 if (SCHEME_LAMBDAP(value)) {
7291 first = SCHEME_CAR(clones);
7292
7293 if (first)
7294 flags = set_one_code_flags(value, flags,
7295 SCHEME_CAR(first), SCHEME_CDR(first),
7296 set_flags, mask_flags, just_tentative,
7297 merge_local_typed);
7298
7299 clones = SCHEME_CDR(clones);
7300 }
7301
7302 if (irlv == pre_body)
7303 break;
7304 irlv = (Scheme_IR_Let_Value *)irlv->body;
7305 }
7306
7307 return flags;
7308 }
7309
lambda_body_size(Scheme_Object * o,int less_args)7310 static int lambda_body_size(Scheme_Object *o, int less_args)
7311 {
7312 int bsz;
7313
7314 if (SAME_TYPE(SCHEME_TYPE(o), scheme_ir_lambda_type)) {
7315 bsz = lambda_body_size_plus_info((Scheme_Lambda *)o, 0, NULL, NULL);
7316 if (less_args) bsz -= ((Scheme_Lambda *)o)->num_params;
7317 return bsz;
7318 } else if (SAME_TYPE(SCHEME_TYPE(o), scheme_case_lambda_sequence_type)) {
7319 Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)o;
7320 int i, sz = 0;
7321 for (i = cl->count; i--; ) {
7322 bsz = lambda_body_size_plus_info((Scheme_Lambda *)cl->array[i], 0, NULL, NULL);
7323 if (less_args) {
7324 bsz -= ((Scheme_Lambda *)cl->array[i])->num_params;
7325 if (bsz > sz) sz = bsz;
7326 } else
7327 sz += bsz;
7328 }
7329 return sz;
7330 } else
7331 return 0;
7332 }
7333
expr_size(Scheme_Object * o)7334 static int expr_size(Scheme_Object *o)
7335 {
7336 return lambda_body_size(o, 0) + 1;
7337 }
7338
scheme_might_invoke_call_cc(Scheme_Object * value)7339 int scheme_might_invoke_call_cc(Scheme_Object *value)
7340 {
7341 return !scheme_is_liftable(value, empty_eq_hash_tree, 10, 0, 1);
7342 }
7343
7344 #define ADVANCE_CLOCKS_INIT_FUEL 3
7345
advance_clocks_for_optimized(Scheme_Object * o,GC_CAN_IGNORE int * _vclock,GC_CAN_IGNORE int * _aclock,GC_CAN_IGNORE int * _kclock,GC_CAN_IGNORE int * _sclock,Optimize_Info * info,int fuel)7346 void advance_clocks_for_optimized(Scheme_Object *o,
7347 GC_CAN_IGNORE int *_vclock,
7348 GC_CAN_IGNORE int *_aclock,
7349 GC_CAN_IGNORE int *_kclock,
7350 GC_CAN_IGNORE int *_sclock,
7351 Optimize_Info *info,
7352 int fuel)
7353 /* It's ok for this function to advance clocks *less* than
7354 accurately, but not more than accurately */
7355 {
7356 Scheme_Object *rator = NULL;
7357 int argc = 0;
7358
7359 if (!fuel) return;
7360
7361 switch (SCHEME_TYPE(o)) {
7362 case scheme_application_type:
7363 {
7364 Scheme_App_Rec *app = (Scheme_App_Rec *)o;
7365 int i;
7366 for (i = 0; i < app->num_args; i++) {
7367 advance_clocks_for_optimized(app->args[i+1],
7368 _vclock, _aclock, _kclock, _sclock,
7369 info, fuel - 1);
7370 }
7371 rator = app->args[0];
7372 argc = app->num_args;
7373 }
7374 break;
7375 case scheme_application2_type:
7376 {
7377 Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
7378 advance_clocks_for_optimized(app->rand,
7379 _vclock, _aclock, _kclock, _sclock,
7380 info, fuel - 1);
7381 rator = app->rator;
7382 argc = 1;
7383 break;
7384 }
7385 case scheme_application3_type:
7386 {
7387 Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
7388 advance_clocks_for_optimized(app->rand1,
7389 _vclock, _aclock, _kclock, _sclock,
7390 info, fuel - 1);
7391 advance_clocks_for_optimized(app->rand2,
7392 _vclock, _aclock, _kclock, _sclock,
7393 info, fuel - 1);
7394 rator = app->rator;
7395 argc = 2;
7396 }
7397 break;
7398 default:
7399 break;
7400 }
7401
7402 if (rator)
7403 increment_clock_counts_for_application(_vclock, _aclock, _kclock, _sclock, rator, argc);
7404
7405 if ((*_vclock > info->vclock)
7406 || (*_aclock > info->aclock)
7407 || (*_kclock > info->kclock)
7408 || (*_sclock > info->sclock))
7409 scheme_signal_error("internal error: optimizer clock tracking has gone wrong");
7410 }
7411
set_application_types(Scheme_Object * o,Optimize_Info * info,int fuel)7412 static void set_application_types(Scheme_Object *o, Optimize_Info *info, int fuel)
7413 /* Peek ahead in an expression to set readily apparent type information
7414 for function calls. This information is useful for type-invariant loop
7415 arguments, for example. */
7416 {
7417 if (!fuel) return;
7418
7419 switch (SCHEME_TYPE(o)) {
7420 case scheme_application_type:
7421 {
7422 Scheme_App_Rec *app = (Scheme_App_Rec *)o;
7423 int i;
7424 register_local_argument_types(app, NULL, NULL, info);
7425 for (i = 0; i < app->num_args+1; i++) {
7426 set_application_types(app->args[i], info, fuel - 1);
7427 }
7428 }
7429 break;
7430 case scheme_application2_type:
7431 {
7432 Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
7433 register_local_argument_types(NULL, app, NULL, info);
7434 set_application_types(app->rator, info, fuel - 1);
7435 set_application_types(app->rand, info, fuel - 1);
7436 break;
7437 }
7438 case scheme_application3_type:
7439 {
7440 Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
7441 register_local_argument_types(NULL, NULL, app, info);
7442 set_application_types(app->rator, info, fuel - 1);
7443 set_application_types(app->rand1, info, fuel - 1);
7444 set_application_types(app->rand2, info, fuel - 1);
7445 }
7446 break;
7447 case scheme_sequence_type:
7448 case scheme_begin0_sequence_type:
7449 {
7450 Scheme_Sequence *seq = (Scheme_Sequence *)o;
7451 int i;
7452
7453 for (i = 0; i < seq->count; i++) {
7454 set_application_types(seq->array[i], info, fuel - 1);
7455 }
7456 }
7457 break;
7458 case scheme_branch_type:
7459 {
7460 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)o;
7461 set_application_types(b->test, info, fuel - 1);
7462 set_application_types(b->tbranch, info, fuel - 1);
7463 set_application_types(b->fbranch, info, fuel - 1);
7464 }
7465 break;
7466 default:
7467 break;
7468 }
7469 }
7470
flip_transitive(Scheme_Hash_Table * ht,int on)7471 static void flip_transitive(Scheme_Hash_Table *ht, int on)
7472 /* Adjust usage flags based on recorded tentative uses */
7473 {
7474 Scheme_IR_Local *tvar;
7475 int j;
7476 Scheme_Object *to_remove = scheme_null;
7477
7478 for (j = 0; j < ht->size; j++) {
7479 if (ht->vals[j]) {
7480 tvar = SCHEME_VAR(ht->keys[j]);
7481 if (on) {
7482 if (tvar->optimize_used) {
7483 /* use of `tvar` is no longer dependent on another variable */
7484 to_remove = scheme_make_pair((Scheme_Object *)tvar,
7485 to_remove);
7486 } else
7487 tvar->optimize_used = 1;
7488 } else {
7489 /* It's possible that `tvar->optimize_used` is already 0; a variable
7490 is sometimes tenatively marked as used, and then unmarked */
7491 tvar->optimize_used = 0;
7492 }
7493 }
7494 }
7495
7496 while (!SCHEME_NULLP(to_remove)) {
7497 scheme_hash_set(ht, SCHEME_CAR(to_remove), NULL);
7498 to_remove = SCHEME_CDR(to_remove);
7499 }
7500 }
7501
start_transitive_use_record(Optimize_Info * to_info,Optimize_Info * info,Scheme_IR_Local * var)7502 static void start_transitive_use_record(Optimize_Info *to_info, Optimize_Info *info, Scheme_IR_Local *var)
7503 /* Start recording uses as tentative. Uses in a `lambda` as the RHS of
7504 the binding of `var` will only be used in the end of `var` itself
7505 is used. */
7506 {
7507 if (var->optimize_used)
7508 return;
7509
7510 info->transitive_use_var = var;
7511
7512 /* Restore use flags, if any, saved from before: */
7513 if (var->optimize.transitive_uses)
7514 flip_transitive(var->optimize.transitive_uses, 1);
7515 }
7516
end_transitive_use_record(Optimize_Info * info)7517 static void end_transitive_use_record(Optimize_Info *info)
7518 /* Stop recording uses as tentative. */
7519 {
7520 Scheme_IR_Local *var = info->transitive_use_var;
7521
7522 if (var != info->next->transitive_use_var) {
7523 info->transitive_use_var = info->next->transitive_use_var;
7524
7525 if (var->optimize.transitive_uses)
7526 flip_transitive(var->optimize.transitive_uses, 0);
7527 }
7528 }
7529
7530 /* Convert up to `c` clauses for `let-values` into a `begin`, where
7531 the converted clauses have zero bindings. The `head` argument will
7532 be non-NULL if there's a possibility of remaining clauses. */
convert_leading_zero_bindings_to_begin(Scheme_IR_Let_Header * head,Scheme_Object * start_body,int c)7533 static Scheme_Object *convert_leading_zero_bindings_to_begin(Scheme_IR_Let_Header *head,
7534 Scheme_Object *start_body,
7535 int c)
7536 {
7537 Scheme_Object *body;
7538 Scheme_IR_Let_Value *irlv;
7539 Scheme_Sequence *seq;
7540 int i, n = 0;
7541
7542 body = start_body;
7543 for (i = 0; i < c; i++) {
7544 irlv = (Scheme_IR_Let_Value *)body;
7545 if (irlv->count)
7546 break;
7547 n++;
7548 body = irlv->body;
7549 }
7550
7551 seq = scheme_malloc_sequence(n + 1);
7552 seq->so.type = scheme_sequence_type;
7553 seq->count = n + 1;
7554 body = start_body;
7555 for (i = 0; i < n; i++) {
7556 irlv = (Scheme_IR_Let_Value *)body;
7557 seq->array[i] = irlv->value;
7558 body = irlv->body;
7559 }
7560
7561 if (n < c) {
7562 head->num_clauses -= n;
7563 head->body = body;
7564 seq->array[n] = (Scheme_Object *)head;
7565 } else
7566 seq->array[n] = body;
7567
7568 return (Scheme_Object *)seq;
7569 }
7570
optimize_lets(Scheme_Object * form,Optimize_Info * info,int context)7571 static Scheme_Object *optimize_lets(Scheme_Object *form, Optimize_Info *info, int context)
7572 /* This is the main entry point for optimizing a `let[rec]-values` form. */
7573 {
7574 Optimize_Info *body_info, *rhs_info;
7575 Optimize_Info_Sequence info_seq;
7576 Scheme_IR_Let_Header *head = (Scheme_IR_Let_Header *)form;
7577 Scheme_IR_Let_Value *irlv, *pre_body, *retry_start, *prev_body;
7578 Scheme_Object *body, *value, *ready_pairs = NULL, *rp_last = NULL, *ready_pairs_start;
7579 Scheme_Object *escape_body = scheme_false;
7580 Scheme_Once_Used *once_used;
7581 Scheme_Hash_Tree *merge_skip_vars;
7582 int i, j, is_rec, not_simply_let_star = 0, undiscourage, skip_opts = 0;
7583 int did_set_value, found_escapes;
7584 int remove_last_one = 0, inline_fuel;
7585 int pre_vclock, pre_aclock, pre_kclock, pre_sclock, increments_kclock = 0;
7586 int once_vclock, once_aclock, once_kclock, once_sclock, once_increments_kclock = 0;
7587
7588 /* Special case: (let ([x M]) (if x x N)), where x is not in N,
7589 to (if M #t N), when the expression is in a test position
7590 or the result of M is a boolean?. */
7591 if (!(SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE)
7592 && (head->count == 1)
7593 && (head->num_clauses == 1)) {
7594 irlv = (Scheme_IR_Let_Value *)head->body;
7595 if (SAME_TYPE(SCHEME_TYPE(irlv->body), scheme_branch_type)
7596 && (irlv->vars[0]->use_count == 2)) {
7597 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)irlv->body;
7598 if (SAME_OBJ(b->test, (Scheme_Object *)irlv->vars[0])
7599 && SAME_OBJ(b->tbranch, (Scheme_Object *)irlv->vars[0])) {
7600 Scheme_Object *pred;
7601
7602 if (context & OPT_CONTEXT_BOOLEAN)
7603 /* In a boolean context, any expression can be moved. */
7604 pred = scheme_boolean_p_proc;
7605 else
7606 pred = expr_implies_predicate(irlv->value, info);
7607
7608 if (pred && predicate_implies(pred, scheme_boolean_p_proc)) {
7609 Scheme_Branch_Rec *b3;
7610
7611 b3 = MALLOC_ONE_TAGGED(Scheme_Branch_Rec);
7612 b3->so.type = scheme_branch_type;
7613 b3->test = irlv->value;
7614 b3->tbranch = scheme_true;
7615 b3->fbranch = b->fbranch;
7616
7617 form = optimize_expr((Scheme_Object *)b3, info, context);
7618
7619 return form;
7620 }
7621 }
7622 }
7623 }
7624
7625 is_rec = (SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE);
7626
7627 /* Special case: (let ([x E]) x) => E or (values E) */
7628 if (!is_rec
7629 && (head->count == 1)
7630 && (head->num_clauses == 1)) {
7631 irlv = (Scheme_IR_Let_Value *)head->body;
7632 if (SAME_OBJ((Scheme_Object *)irlv->vars[0], irlv->body)) {
7633 body = irlv->value;
7634 body = ensure_single_value_noncm(body, info);
7635 return optimize_expr(body, info, context);
7636 }
7637 }
7638
7639 /* Zero leading bindings in unsafe mode => convert to `begin`, since
7640 we can unsafely drop the check on the number of results */
7641 if (!is_rec && info->unsafe_mode && head->num_clauses
7642 && !((Scheme_IR_Let_Value *)head->body)->count) {
7643 body = convert_leading_zero_bindings_to_begin(head, head->body, head->num_clauses);
7644 return optimize_expr(body, info, context);
7645 }
7646
7647 if (!is_rec) {
7648 int try_again;
7649 do {
7650 try_again = 0;
7651 /* (let ([x (let ([y M]) N)]) P) => (let ([y M]) (let ([x N]) P))
7652 or (let ([x (begin M ... N)]) P) => (begin M ... (let ([x N]) P)) */
7653 if (head->num_clauses) {
7654 irlv = (Scheme_IR_Let_Value *)head->body; /* ([x ...]) */
7655 if (SAME_TYPE(SCHEME_TYPE(irlv->value), scheme_ir_let_header_type)) {
7656 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)irlv->value; /* (let ([y ...]) ...) */
7657
7658 if (!lh->num_clauses) {
7659 irlv->value = lh->body;
7660 lh->body = (Scheme_Object *)head;
7661 } else {
7662 body = lh->body;
7663 for (i = lh->num_clauses - 1; i--; ) {
7664 body = ((Scheme_IR_Let_Value *)body)->body;
7665 }
7666 irlv->value = ((Scheme_IR_Let_Value *)body)->body; /* N */
7667 ((Scheme_IR_Let_Value *)body)->body = (Scheme_Object *)head;
7668 }
7669
7670 head = lh;
7671 form = (Scheme_Object *)head;
7672 is_rec = (SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE);
7673 try_again = !is_rec;
7674 } else if (SAME_TYPE(SCHEME_TYPE(irlv->value), scheme_sequence_type)) {
7675 Scheme_Sequence *seq = (Scheme_Sequence *)irlv->value; /* (begin M ... N) */
7676
7677 irlv->value = seq->array[seq->count - 1];
7678 seq->array[seq->count - 1] = (Scheme_Object *)head;
7679
7680 return optimize_expr((Scheme_Object *)seq, info, context);
7681 }
7682 }
7683 } while (try_again);
7684 }
7685
7686 body_info = optimize_info_add_frame(info, 0);
7687 rhs_info = body_info;
7688
7689 merge_skip_vars = scheme_make_hash_tree(SCHEME_hashtr_eq);
7690 body = head->body;
7691 for (i = head->num_clauses; i--; ) {
7692 pre_body = (Scheme_IR_Let_Value *)body;
7693 for (j = pre_body->count; j--; ) {
7694 merge_skip_vars = scheme_hash_tree_set(merge_skip_vars, (Scheme_Object *)pre_body->vars[j], scheme_true);
7695 set_optimize_mode(pre_body->vars[j]);
7696 pre_body->vars[j]->optimize.lambda_depth = body_info->lambda_depth;
7697 pre_body->vars[j]->optimize_used = 0;
7698 pre_body->vars[j]->optimize_outside_binding = 0;
7699 if (!pre_body->vars[j]->mutated && is_rec) {
7700 /* Indicate that it's not yet ready, so it cannot be inlined: */
7701 Scheme_Object *rp;
7702 pre_body->vars[j]->optimize_unready = 1;
7703 rp = scheme_make_raw_pair((Scheme_Object *)pre_body->vars[j], NULL);
7704 if (rp_last)
7705 SCHEME_CDR(rp_last) = rp;
7706 else
7707 ready_pairs = rp;
7708 rp_last = rp;
7709 }
7710 }
7711 body = pre_body->body;
7712 }
7713
7714 if (OPT_ESTIMATE_FUTURE_SIZES) {
7715 if (is_rec && !body_info->letrec_not_twice) {
7716 /* For each identifier bound to a procedure, register an initial
7717 size estimate, which is used to discourage early loop unrolling
7718 at the expense of later inlining. */
7719 body = head->body;
7720 pre_body = NULL;
7721 for (i = head->num_clauses; i--; ) {
7722 pre_body = (Scheme_IR_Let_Value *)body;
7723
7724 if ((pre_body->count == 1)
7725 && SCHEME_LAMBDAP(pre_body->value)
7726 && !pre_body->vars[0]->mutated) {
7727 Scheme_Object *sz;
7728 sz = estimate_closure_size(pre_body->value);
7729 pre_body->vars[0]->optimize.known_val = sz;
7730 }
7731
7732 body = pre_body->body;
7733 }
7734 rhs_info->use_psize = 1;
7735 }
7736 }
7737
7738 optimize_info_seq_init(rhs_info, &info_seq);
7739
7740 prev_body = NULL;
7741 body = head->body;
7742 pre_body = NULL;
7743 retry_start = NULL;
7744 ready_pairs_start = NULL;
7745 did_set_value = 0;
7746 found_escapes = 0;
7747 for (i = head->num_clauses; i--; ) {
7748 pre_body = (Scheme_IR_Let_Value *)body;
7749
7750 if ((pre_body->count == 1)
7751 && SCHEME_LAMBDAP(pre_body->value)
7752 && !pre_body->vars[0]->optimize_used)
7753 start_transitive_use_record(body_info, rhs_info, pre_body->vars[0]);
7754
7755 if (is_rec && OPT_DISCOURAGE_EARLY_INLINE && !rhs_info->letrec_not_twice
7756 && SCHEME_LAMBDAP(pre_body->value)) {
7757 inline_fuel = rhs_info->inline_fuel;
7758 if (inline_fuel > 2)
7759 rhs_info->inline_fuel = 2;
7760 rhs_info->letrec_not_twice++;
7761 undiscourage = 1;
7762 } else {
7763 inline_fuel = 0;
7764 undiscourage = 0;
7765 }
7766
7767 if (!skip_opts) {
7768 pre_vclock = rhs_info->vclock;
7769 pre_aclock = rhs_info->aclock;
7770 pre_kclock = rhs_info->kclock;
7771 pre_sclock = rhs_info->sclock;
7772 if (!found_escapes) {
7773 optimize_info_seq_step(rhs_info, &info_seq);
7774 value = optimize_expr(pre_body->value, rhs_info,
7775 (((pre_body->count == 1)
7776 ? OPT_CONTEXT_SINGLED
7777 : 0)
7778 | (((pre_body->count == 1)
7779 && !pre_body->vars[0]->non_app_count)
7780 ? (pre_body->vars[0]->use_count << OPT_CONTEXT_APP_COUNT_SHIFT)
7781 : 0)));
7782 pre_body->value = value;
7783 if (rhs_info->escapes)
7784 found_escapes = 1;
7785 } else {
7786 optimize_info_seq_step(rhs_info, &info_seq);
7787 value = scheme_false;
7788 pre_body->value = value;
7789 body_info->single_result = 1;
7790 body_info->preserves_marks = 1;
7791 body_info->escapes = 1;
7792 body_info->size++;
7793 }
7794 once_vclock = rhs_info->vclock;
7795 once_aclock = rhs_info->aclock;
7796 once_kclock = rhs_info->kclock;
7797 once_sclock = rhs_info->sclock;
7798 increments_kclock = (once_kclock > pre_kclock);
7799 once_increments_kclock = increments_kclock;
7800 } else {
7801 value = pre_body->value;
7802 --skip_opts;
7803 if (skip_opts) {
7804 /* when a `values` group is split, we've lost track of the
7805 clock values for points between the `values` arguments;
7806 we can conservatively assume the clock before the whole group
7807 for the purpose of registering once-used variables,
7808 but we can also conservatively advance the clock: */
7809 if (!found_escapes)
7810 advance_clocks_for_optimized(value,
7811 &pre_vclock, &pre_aclock, &pre_kclock, &pre_sclock,
7812 rhs_info,
7813 ADVANCE_CLOCKS_INIT_FUEL);
7814 once_vclock = pre_vclock;
7815 once_aclock = pre_aclock;
7816 once_kclock = pre_kclock;
7817 once_sclock = pre_sclock;
7818 } else {
7819 /* end of split group, so rhs_info clock is right */
7820 once_vclock = rhs_info->vclock;
7821 once_aclock = rhs_info->aclock;
7822 once_kclock = rhs_info->kclock;
7823 once_sclock = rhs_info->sclock;
7824 }
7825 if (increments_kclock) {
7826 /* note that we conservatively assume that a member of a split
7827 advance the kclock, unless we can easily show otherwise */
7828 once_increments_kclock = 1;
7829 }
7830 }
7831
7832 if (undiscourage) {
7833 rhs_info->inline_fuel = inline_fuel;
7834 --rhs_info->letrec_not_twice;
7835 }
7836
7837 end_transitive_use_record(rhs_info);
7838
7839 if (is_rec && !not_simply_let_star) {
7840 /* Keep track of whether we can simplify to let*: */
7841 if (scheme_might_invoke_call_cc(value)
7842 || optimize_any_uses(body_info, pre_body, i+1))
7843 not_simply_let_star = 1;
7844 }
7845
7846 /* Change (let-values ([(id ...) (values e ...)]) body)
7847 to (let-values ([id e] ...) body) for simple e.
7848 The is_values_apply() and related functions also handle
7849 (if id (values e1 ...) (values e2 ...)) to effectively convert to
7850 (values (if id e1 e2) ...) and then split the values call, since
7851 duplicating the id use and test is likely to pay off. */
7852 if ((pre_body->count != 1)
7853 && ((!is_rec && found_escapes)
7854 || (is_values_apply(value, pre_body->count, rhs_info, merge_skip_vars, 1)
7855 && ((!is_rec && no_mutable_bindings(pre_body))
7856 /* If the right-hand side is omittable, then there are
7857 no side effects, so mutation and recursiveness are ok */
7858 || scheme_omittable_expr(value, pre_body->count, -1, 0, rhs_info, info))))) {
7859 if (!pre_body->count && !i) {
7860 /* We want to drop the clause entirely, but doing it
7861 here messes up the loop for letrec. So wait and
7862 remove it at the end. */
7863 remove_last_one = 1;
7864 /* If `found_escapes`, either this expression is the
7865 one that escaped, or `value` should have been simplified
7866 to `#f`. So, if it's not `#f`, we'll need to keep
7867 the expression part */
7868 if (!found_escapes)
7869 value = scheme_false;
7870 pre_body->value = value;
7871 } else {
7872 Scheme_IR_Let_Value *naya;
7873 Scheme_Object *rest = pre_body->body;
7874 int j;
7875
7876 for (j = pre_body->count; j--; ) {
7877 Scheme_IR_Local **new_vars;
7878 naya = MALLOC_ONE_TAGGED(Scheme_IR_Let_Value);
7879 naya->iso.so.type = scheme_ir_let_value_type;
7880 naya->body = rest;
7881 naya->count = 1;
7882 new_vars = MALLOC_N(Scheme_IR_Local *, 1);
7883 new_vars[0] = pre_body->vars[j];
7884 naya->vars = new_vars;
7885 rest = (Scheme_Object *)naya;
7886 }
7887
7888 naya = (Scheme_IR_Let_Value *)rest;
7889 if (!found_escapes) {
7890 unpack_values_application(value, naya, rhs_info, NULL);
7891 } else {
7892 Scheme_IR_Let_Value *naya2 = naya;
7893 for (j = 0; j < pre_body->count; j++) {
7894 if (!j)
7895 naya2->value = value;
7896 else
7897 naya2->value = scheme_false;
7898 naya2 = (Scheme_IR_Let_Value *)naya2->body;
7899 }
7900
7901 if (!pre_body->count && !SCHEME_FALSEP(value)) {
7902 /* Since `value` is not false, this clause must be the one
7903 that is escaping. We'll end up dropping the remaining
7904 clauses and the original body, but we need to keep the
7905 erroring expression. */
7906 escape_body = value;
7907 }
7908 }
7909
7910 if (prev_body)
7911 prev_body->body = (Scheme_Object *)naya;
7912 else
7913 head->body = (Scheme_Object *)naya;
7914 head->num_clauses += (pre_body->count - 1);
7915 i += (pre_body->count - 1);
7916 if (pre_body->count) {
7917 /* We're backing up. Since the RHSs have been optimized
7918 already, don't re-optimize. */
7919 skip_opts = pre_body->count - 1;
7920 pre_body = naya;
7921 body = (Scheme_Object *)naya;
7922 value = pre_body->value;
7923
7924 if (skip_opts) {
7925 /* Use "pre" clocks: */
7926 if (!found_escapes)
7927 advance_clocks_for_optimized(value,
7928 &pre_vclock, &pre_aclock, &pre_kclock, &pre_sclock,
7929 rhs_info,
7930 ADVANCE_CLOCKS_INIT_FUEL);
7931 once_vclock = pre_vclock;
7932 once_aclock = pre_aclock;
7933 once_kclock = pre_kclock;
7934 once_sclock = pre_sclock;
7935 }
7936 } else {
7937 /* We've dropped this clause entirely. */
7938 i++;
7939 if (i > 0) {
7940 body = (Scheme_Object *)naya;
7941 continue;
7942 } else
7943 break;
7944 }
7945 }
7946 }
7947
7948 if ((pre_body->count == 1) && !pre_body->vars[0]->mutated) {
7949 int indirect = 0, indirect_binding = 0;
7950
7951 /* extract_tail_inside with `for_immediate_body` as true needs
7952 to be consistent with this peek inside, in case a single-use
7953 variable extracted as the binding for a single-use
7954 variable */
7955 while (indirect < 10) {
7956 if (SAME_TYPE(SCHEME_TYPE(value), scheme_sequence_type)) {
7957 Scheme_Sequence *seq = (Scheme_Sequence *)value;
7958 value = seq->array[seq->count - 1];
7959 indirect++;
7960 } else if (SAME_TYPE(SCHEME_TYPE(value), scheme_with_cont_mark_type)) {
7961 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)value;
7962 value = wcm->body;
7963 indirect++;
7964 } else if (SAME_TYPE(SCHEME_TYPE(value), scheme_ir_let_header_type)) {
7965 Scheme_IR_Let_Header *head2 = (Scheme_IR_Let_Header *)value;
7966 int i;
7967
7968 if (head2->num_clauses < 10) {
7969 value = head2->body;
7970 for (i = head2->num_clauses; i--; ) {
7971 value = ((Scheme_IR_Let_Value *)value)->body;
7972 }
7973 }
7974 indirect++;
7975 if (head2->count)
7976 indirect_binding = 1;
7977 } else
7978 break;
7979 }
7980
7981 if (indirect_binding) {
7982 /* only allow constants */
7983 if (SCHEME_TYPE(value) < _scheme_ir_values_types_)
7984 value = NULL;
7985 }
7986
7987 if (value && SAME_TYPE(SCHEME_TYPE(value), scheme_ir_local_type)) {
7988 /* Don't optimize reference to a local that's mutable; also,
7989 double-check that the value is ready, because we might be
7990 nested in the RHS of a `letrec': */
7991 if (SCHEME_VAR(value)->mutated || SCHEME_VAR(value)->optimize_unready)
7992 value = NULL;
7993 }
7994
7995 if (value)
7996 value = extract_specialized_proc(value, value);
7997
7998 if (value && ir_propagate_ok(value,
7999 body_info,
8000 (!indirect && (pre_body->vars[0]->use_count == 1)),
8001 pre_body->vars[0])) {
8002 pre_body->vars[0]->optimize.known_val = value;
8003 did_set_value = 1;
8004 } else if (value && !is_rec) {
8005 int cnt, ct, involves_k_cross;
8006 Scheme_Object *pred;
8007
8008 ct = scheme_expr_produces_local_type(value, &involves_k_cross);
8009 if (ct) {
8010 SCHEME_VAR(pre_body->vars[0])->val_type = ct;
8011 if (involves_k_cross) {
8012 /* Although this variable's uses do not necessarily cross
8013 a continuation capture, the inference of its type
8014 depends on that crossing, so we treat as having a crossing.
8015 This is an accommodation to the bytecode format and
8016 validator, which has no way to distinguish between
8017 a known type and unboxing capability for that type. */
8018 SCHEME_VAR(pre_body->vars[0])->escapes_after_k_tick = 1;
8019 }
8020 }
8021
8022 pred = expr_implies_predicate(value, rhs_info);
8023
8024 if (pred)
8025 add_type(body_info, (Scheme_Object *)pre_body->vars[0], pred);
8026
8027 if (!indirect) {
8028 cnt = pre_body->vars[0]->use_count;
8029 if (cnt == 1) {
8030 /* used only once; we may be able to shift the expression to the use
8031 site, instead of binding to a temporary */
8032 once_used = make_once_used(value, pre_body->vars[0],
8033 once_vclock, once_aclock, once_kclock, once_sclock,
8034 once_increments_kclock);
8035 pre_body->vars[0]->optimize.known_val = (Scheme_Object *)once_used;
8036 pre_body->vars[0]->optimize.clear_known_on_multi_use = 1;
8037 }
8038 }
8039 }
8040 }
8041
8042 if (!retry_start) {
8043 retry_start = pre_body;
8044 ready_pairs_start = ready_pairs;
8045 }
8046
8047 /* Re-optimize to inline letrec bindings? */
8048 if (is_rec
8049 && !body_info->letrec_not_twice
8050 && ((i < 1)
8051 || (!scheme_is_ir_lambda(((Scheme_IR_Let_Value *)pre_body->body)->value, 1, 1)
8052 && !scheme_is_liftable(((Scheme_IR_Let_Value *)pre_body->body)->value, merge_skip_vars, 5, 1, 0)))) {
8053 Scheme_Object *prop_later = NULL;
8054
8055 if (did_set_value) {
8056 /* Next RHS ends a reorderable sequence.
8057 Re-optimize from retry_start to pre_body, inclusive.
8058 For procedures, assume LAMBDA_SINGLE_RESULT and LAMBDA_PRESERVES_MARKS for all,
8059 but then assume not for all if any turn out not (i.e., approximate fix point). */
8060 int flags;
8061 Scheme_Object *clones, *cl, *cl_first;
8062
8063 /* If this is the last binding, peek ahead in the body to
8064 check for easy type info in function calls */
8065 if (!i)
8066 set_application_types(pre_body->body, body_info, 5);
8067
8068 /* Reset "unready" flags: */
8069 for (rp_last = ready_pairs_start; !SAME_OBJ(rp_last, ready_pairs); rp_last = SCHEME_CDR(rp_last)) {
8070 SCHEME_VAR(SCHEME_CAR(rp_last))->optimize_unready = 1;
8071 }
8072 /* Set-flags loop: */
8073 clones = make_clones(retry_start, pre_body, rhs_info);
8074 (void)set_code_flags(retry_start, pre_body, clones,
8075 LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS | LAMBDA_STATUS_RESULT_TENTATIVE,
8076 0xFFFF,
8077 0,
8078 0);
8079 /* Re-optimize loop: */
8080 irlv = retry_start;
8081 cl = clones;
8082 while (1) {
8083 value = irlv->value;
8084 if (cl) {
8085 cl_first = SCHEME_CAR(cl);
8086 if (!cl_first)
8087 cl = SCHEME_CDR(cl);
8088 } else
8089 cl_first = NULL;
8090 if (cl_first && SAME_OBJ(value, SCHEME_CAR(cl_first))) {
8091 /* Try optimization. */
8092 Scheme_Object *self_value;
8093 int sz;
8094 char use_psize;
8095
8096 if ((irlv->count == 1)
8097 && !irlv->vars[0]->optimize_used)
8098 start_transitive_use_record(body_info, rhs_info, irlv->vars[0]);
8099
8100 cl = SCHEME_CDR(cl);
8101 self_value = SCHEME_CDR(cl_first);
8102
8103 /* Drop old size, and remove old inline fuel: */
8104 sz = lambda_body_size(value, 0);
8105 rhs_info->size -= (sz + 1);
8106
8107 /* Setting letrec_not_twice prevents inlinining
8108 of letrec bindings in this RHS. There's a small
8109 chance that we miss some optimizations, but we
8110 avoid the possibility of N^2 behavior. */
8111 if (!OPT_DISCOURAGE_EARLY_INLINE)
8112 rhs_info->letrec_not_twice++;
8113 inline_fuel = rhs_info->inline_fuel;
8114 rhs_info->inline_fuel >>= 1;
8115 use_psize = rhs_info->use_psize;
8116 rhs_info->use_psize = info->use_psize;
8117
8118 optimize_info_seq_step(rhs_info, &info_seq);
8119 value = optimize_expr(self_value, rhs_info,
8120 (((irlv->count == 1)
8121 ? OPT_CONTEXT_SINGLED
8122 : 0)
8123 | (((irlv->count == 1)
8124 && !irlv->vars[0]->non_app_count)
8125 ? (irlv->vars[0]->use_count << OPT_CONTEXT_APP_COUNT_SHIFT)
8126 : 0)));
8127
8128 if (!OPT_DISCOURAGE_EARLY_INLINE)
8129 --rhs_info->letrec_not_twice;
8130 rhs_info->inline_fuel = inline_fuel;
8131 rhs_info->use_psize = use_psize;
8132
8133 irlv->value = value;
8134
8135 if (!irlv->vars[0]->mutated) {
8136 if (ir_propagate_ok(value, rhs_info, irlv->vars[0]->use_count == 1, irlv->vars[0])) {
8137 /* Register re-optimized as the value for the binding, but
8138 maybe only if it didn't grow too much: */
8139 int new_sz;
8140 if (OPT_DELAY_GROUP_PROPAGATE || OPT_LIMIT_FUNCTION_RESIZE)
8141 new_sz = lambda_body_size(value, 0);
8142 else
8143 new_sz = 0;
8144 if (new_sz <= sz) {
8145 irlv->vars[0]->optimize.known_val = value;
8146 }
8147 else if (!OPT_LIMIT_FUNCTION_RESIZE
8148 || (new_sz < 4 * sz))
8149 prop_later = scheme_make_raw_pair(scheme_make_pair((Scheme_Object *)irlv->vars[0],
8150 value),
8151 prop_later);
8152 }
8153 }
8154
8155 end_transitive_use_record(rhs_info);
8156 }
8157 if (irlv == pre_body)
8158 break;
8159 {
8160 /* Since letrec is really letrec*, the variables
8161 for this binding are now ready: */
8162 int i;
8163 for (i = irlv->count; i--; ) {
8164 if (!irlv->vars[i]->mutated) {
8165 SCHEME_VAR(SCHEME_CAR(ready_pairs_start))->optimize_unready = 0;
8166 ready_pairs_start = SCHEME_CDR(ready_pairs_start);
8167 }
8168 }
8169 }
8170 irlv = (Scheme_IR_Let_Value *)irlv->body;
8171 }
8172 /* Check flags loop: */
8173 flags = set_code_flags(retry_start, pre_body, clones, 0, 0xFFFF, 0, 0);
8174 /* Reset-flags loop: */
8175 (void)set_code_flags(retry_start, pre_body, clones,
8176 (flags & (LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS)),
8177 ~(LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS | LAMBDA_STATUS_MASK),
8178 1,
8179 1);
8180 }
8181 retry_start = NULL;
8182 ready_pairs_start = NULL;
8183 did_set_value = 0;
8184
8185 while (prop_later) {
8186 value = SCHEME_CAR(prop_later);
8187 SCHEME_VAR(SCHEME_CAR(value))->optimize.known_val = SCHEME_CDR(value);
8188 prop_later = SCHEME_CDR(prop_later);
8189 }
8190 }
8191
8192 if (is_rec) {
8193 /* Since letrec is really letrec*, the variables
8194 for this binding are now ready: */
8195 int i;
8196 for (i = pre_body->count; i--; ) {
8197 pre_body->vars[i]->optimize.init_kclock = rhs_info->kclock;
8198 if (!pre_body->vars[i]->mutated) {
8199 SCHEME_VAR(SCHEME_CAR(ready_pairs))->optimize_unready = 0;
8200 ready_pairs = SCHEME_CDR(ready_pairs);
8201 }
8202 }
8203 }
8204
8205 if (remove_last_one) {
8206 head->num_clauses -= 1;
8207 body = (Scheme_Object *)pre_body->body;
8208
8209 if (found_escapes && !SCHEME_FALSEP(pre_body->value)) {
8210 /* Since `pre_body->value` wasn't simplified to #f,
8211 keep this as the new body */
8212 escape_body = pre_body->value;
8213 }
8214
8215 if (prev_body) {
8216 prev_body->body = body;
8217 pre_body = prev_body;
8218 } else {
8219 head->body = body;
8220 pre_body = NULL;
8221 }
8222 break;
8223 }
8224
8225 prev_body = pre_body;
8226 body = pre_body->body;
8227 }
8228
8229 if (!is_rec) {
8230 /* All `let`-bound variables are now allocated: */
8231 body = head->body;
8232 for (i = head->num_clauses; i--; ) {
8233 pre_body = (Scheme_IR_Let_Value *)body;
8234 for (j = pre_body->count; j--; ) {
8235 pre_body->vars[j]->optimize.init_kclock = body_info->kclock;
8236 }
8237 body = pre_body->body;
8238 }
8239 }
8240
8241 optimize_info_seq_done(body_info, &info_seq);
8242
8243 if (!found_escapes) {
8244 body = optimize_expr(body, body_info, scheme_optimize_tail_context(context));
8245 } else {
8246 body = ensure_noncm(escape_body, body_info);
8247 body_info->single_result = 1;
8248 body_info->preserves_marks = 1;
8249 body_info->escapes = 1;
8250 body_info->size++;
8251 }
8252 if (head->num_clauses)
8253 pre_body->body = body;
8254 else
8255 head->body = body;
8256
8257 /* Propagate any use from formerly tentative uses: */
8258 while (1) {
8259 int changed = 0;
8260 body = head->body;
8261 for (i = head->num_clauses; i--; ) {
8262 pre_body = (Scheme_IR_Let_Value *)body;
8263 for (j = pre_body->count; j--; ) {
8264 if (pre_body->vars[j]->optimize_used
8265 && pre_body->vars[j]->optimize.transitive_uses) {
8266 register_transitive_uses(pre_body->vars[j], body_info);
8267 changed = 1;
8268 pre_body->vars[j]->optimize.transitive_uses = NULL;
8269 }
8270 }
8271 body = pre_body->body;
8272 }
8273 if (!changed)
8274 break;
8275 }
8276
8277 info->single_result = body_info->single_result;
8278 info->preserves_marks = body_info->preserves_marks;
8279 info->vclock = body_info->vclock;
8280 info->aclock = body_info->aclock;
8281 info->kclock = body_info->kclock;
8282 info->sclock = body_info->sclock;
8283
8284 /* Clear used flags where possible, clear once-used references, etc. */
8285 body = head->body;
8286 prev_body = NULL;
8287 for (i = head->num_clauses; i--; ) {
8288 int used = 0, j;
8289
8290 pre_body = (Scheme_IR_Let_Value *)body;
8291
8292 if (pre_body->count == 1) {
8293 /* If the right-hand side is a function, make sure all use sites
8294 are accounted for toward type inference of arguments. */
8295 if (pre_body->vars[0]->optimize.known_val
8296 && SAME_TYPE(SCHEME_TYPE(pre_body->vars[0]->optimize.known_val), scheme_lambda_type)) {
8297 check_lambda_arg_types_registered((Scheme_Lambda *)pre_body->vars[0]->optimize.known_val,
8298 pre_body->vars[0]->use_count);
8299 }
8300 }
8301
8302 for (j = pre_body->count; j--; ) {
8303 if (pre_body->vars[j]->optimize_used) {
8304 used = 1;
8305 break;
8306 }
8307 }
8308
8309 /* once-used moved implies not optimize_used: */
8310 MZ_ASSERT(!(used
8311 && (pre_body->count == 1)
8312 && pre_body->vars[0]->optimize.known_val
8313 && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[0]->optimize.known_val))
8314 && ((Scheme_Once_Used *)pre_body->vars[0]->optimize.known_val)->moved));
8315
8316 if (!used
8317 && (scheme_omittable_expr(pre_body->value, pre_body->count, -1, 0, info, info)
8318 || ((pre_body->count == 1)
8319 && pre_body->vars[0]->optimize.known_val
8320 && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[0]->optimize.known_val))
8321 && ((Scheme_Once_Used *)pre_body->vars[0]->optimize.known_val)->moved))) {
8322 /* Drop the binding(s) */
8323 for (j = pre_body->count; j--; ) {
8324 pre_body->vars[j]->mode = SCHEME_VAR_MODE_NONE;
8325 }
8326 head->num_clauses -= 1;
8327 head->count -= pre_body->count;
8328 if (prev_body)
8329 prev_body->body = pre_body->body;
8330 else
8331 head->body = pre_body->body;
8332 /* Deduct from size to aid further inlining. */
8333 {
8334 int sz;
8335 sz = expr_size(pre_body->value);
8336 body_info->size -= sz;
8337 }
8338 } else {
8339 if (!used && (pre_body->count == 1)) {
8340 /* The whole binding is not omittable, but maybe the tail is omittable: */
8341 Scheme_Object *v2 = pre_body->value, *inside;
8342 extract_tail_inside(&v2, &inside, 1);
8343 if (scheme_omittable_expr(v2, pre_body->count, -1, 0, info, info)) {
8344 replace_tail_inside(scheme_false, inside, pre_body->value);
8345 }
8346 }
8347
8348 for (j = pre_body->count; j--; ) {
8349 int ct;
8350
8351 pre_body->vars[j]->optimize_outside_binding = 1;
8352 if (pre_body->vars[j]->optimize.known_val
8353 && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[j]->optimize.known_val))) {
8354 /* We're keeping this clause here, so don't allow movement of the once-used
8355 value when peeking under bindings via extract_tail_inside(): */
8356 pre_body->vars[j]->optimize.known_val = NULL;
8357 }
8358
8359 ct = pre_body->vars[j]->arg_type;
8360 if (ct) {
8361 if (ALWAYS_PREFER_UNBOX_TYPE(ct)
8362 || !pre_body->vars[j]->escapes_after_k_tick)
8363 pre_body->vars[j]->arg_type = ct;
8364 }
8365 }
8366 info->size += 1;
8367 prev_body = pre_body;
8368 }
8369 body = pre_body->body;
8370 }
8371
8372 optimize_info_done(body_info, NULL);
8373 merge_types(body_info, info, merge_skip_vars);
8374
8375 if (is_rec && !not_simply_let_star) {
8376 /* We can simplify letrec to let* */
8377 SCHEME_LET_FLAGS(head) -= SCHEME_LET_RECURSIVE;
8378 is_rec = 0;
8379 optimize_uses_of_mutable_imply_early_alloc((Scheme_IR_Let_Value *)head->body, head->num_clauses);
8380 }
8381
8382 /* Optimized away all clauses? */
8383 if (!head->num_clauses) {
8384 return body;
8385 }
8386
8387 if (!is_rec
8388 && ((SCHEME_TYPE(body) > _scheme_ir_values_types_)
8389 || SAME_TYPE(SCHEME_TYPE(body), scheme_ir_toplevel_type)
8390 || SAME_TYPE(SCHEME_TYPE(body), scheme_ir_local_type))) {
8391 /* If the body is a constant, toplevel or another local, the last binding
8392 is unused, so reduce (let ([x <expr>]) K) => (begin <expr> K).
8393 As a special case, include a second check for (let ([x E]) x) => E or (values E). */
8394 Scheme_Object *inside;
8395
8396 inside = (Scheme_Object *)head;
8397 pre_body = (Scheme_IR_Let_Value *)head->body;
8398 for (i = head->num_clauses - 1; i--; ) {
8399 inside = (Scheme_Object *)pre_body;
8400 pre_body = (Scheme_IR_Let_Value *)pre_body->body;
8401 }
8402
8403 if (pre_body->count == 1) {
8404 if (!SAME_OBJ((Scheme_Object *)pre_body->vars[0], body)
8405 && !found_escapes) {
8406 body = make_discarding_sequence(pre_body->value, body, info);
8407 } else {
8408 /* Special case for (let ([x E]) x) and (let ([x <error>]) #f) */
8409 body = pre_body->value;
8410 body = ensure_single_value_noncm(body, info);
8411 if (found_escapes) {
8412 found_escapes = 0; /* Perhaps the error is moved to the body. */
8413 body = ensure_noncm(body, info);
8414 }
8415 }
8416
8417 if (head->num_clauses == 1)
8418 return body;
8419
8420 (void)replace_tail_inside(body, inside, NULL);
8421 head->count--;
8422 head->num_clauses--;
8423 }
8424 }
8425
8426 if (!is_rec) {
8427 /* One last pass to peel off unused bindings */
8428 Scheme_Object *prev = NULL, *rhs;
8429
8430 body = head->body;
8431 for (i = head->num_clauses; i--; ) {
8432 pre_body = (Scheme_IR_Let_Value *)body;
8433 if ((pre_body->count == 1)
8434 && !pre_body->vars[0]->optimize_used) {
8435 Scheme_Sequence *seq;
8436 Scheme_Object *new_body;
8437
8438 pre_body->vars[0]->mode = SCHEME_VAR_MODE_NONE;
8439
8440 seq = scheme_malloc_sequence(2);
8441 seq->so.type = scheme_sequence_type;
8442 seq->count = 2;
8443
8444 rhs = pre_body->value;
8445 rhs = ensure_single_value_noncm(rhs, info);
8446 seq->array[0] = rhs;
8447
8448 head->count--;
8449 head->num_clauses--;
8450 head->body = pre_body->body;
8451
8452 new_body = (Scheme_Object *)seq;
8453
8454 if (head->num_clauses)
8455 seq->array[1] = (Scheme_Object *)head;
8456 else if (found_escapes && SCHEME_FALSEP(head->body)) {
8457 /* don't need the `#f` for the body, because some RHS escapes */
8458 new_body = ensure_noncm(rhs, info);
8459 } else
8460 seq->array[1] = head->body;
8461
8462 if (prev)
8463 (void)replace_tail_inside(new_body, prev, NULL);
8464 else
8465 form = new_body;
8466 prev = new_body;
8467
8468 body = pre_body->body;
8469 } else
8470 break;
8471 }
8472
8473 if (prev && SAME_TYPE(SCHEME_TYPE(prev), scheme_sequence_type))
8474 form = optimize_sequence(form, info, context, 0);
8475 }
8476
8477 if (!is_rec && info->unsafe_mode) {
8478 /* Peel zero-binding clauses off the end in unsafe mode? */
8479 if (SAME_TYPE(SCHEME_TYPE(form), scheme_ir_let_header_type)) {
8480 int i, c, n;
8481 head = (Scheme_IR_Let_Header *)form;
8482 c = head->num_clauses;
8483 n = head->count;
8484 prev_body = NULL;
8485 body = head->body;
8486 for (i = 0; i < c; i++) {
8487 if (!n) {
8488 /* We've seen as many bindings as exist, to the rest
8489 must be clauses with zero bindings */
8490 body = convert_leading_zero_bindings_to_begin(NULL, body, c - i);
8491 if (prev_body) {
8492 prev_body->body = body;
8493 head->num_clauses = i;
8494 } else
8495 form = body;
8496 break;
8497 } else {
8498 irlv = (Scheme_IR_Let_Value *)body;
8499 n -= irlv->count;
8500 prev_body = irlv;
8501 body = irlv->body;
8502 }
8503 }
8504 }
8505 }
8506
8507 return form;
8508 }
8509
8510 /*========================================================================*/
8511 /* lambda */
8512 /*========================================================================*/
8513
8514 static Scheme_Object *
optimize_lambda(Scheme_Object * _lam,Optimize_Info * info,int context)8515 optimize_lambda(Scheme_Object *_lam, Optimize_Info *info, int context)
8516 {
8517 Scheme_Lambda *lam;
8518 Scheme_Object *code, *ctx, *to_remove;
8519 Scheme_IR_Lambda_Info *cl;
8520 int i, init_vclock, init_aclock, init_kclock, init_sclock;
8521 Scheme_Hash_Table *ht;
8522 int app_count = OPT_CONTEXT_APP_COUNT(context);
8523
8524 lam = (Scheme_Lambda *)_lam;
8525
8526 info->single_result = 1;
8527 info->preserves_marks = 1;
8528
8529 info = optimize_info_add_frame(info, SCHEME_LAMBDA_FRAME);
8530
8531 ht = scheme_make_hash_table(SCHEME_hash_ptr);
8532 info->uses = ht;
8533
8534 init_vclock = info->vclock;
8535 init_aclock = info->aclock;
8536 init_kclock = info->kclock;
8537 init_sclock = info->sclock;
8538
8539 info->vclock += 1; /* model delayed evaluation as vclock increment */
8540 info->kclock += 1;
8541 info->sclock += 1;
8542
8543 /* For reporting warnings: */
8544 if (info->context && SCHEME_PAIRP(info->context))
8545 ctx = scheme_make_pair((Scheme_Object *)lam,
8546 SCHEME_CDR(info->context));
8547 else if (info->context)
8548 ctx = scheme_make_pair((Scheme_Object *)lam, info->context);
8549 else
8550 ctx = (Scheme_Object *)lam;
8551 info->context = ctx;
8552
8553 cl = lam->ir_info;
8554 for (i = 0; i < lam->num_params; i++) {
8555 set_optimize_mode(cl->vars[i]);
8556 cl->vars[i]->optimize.lambda_depth = info->lambda_depth;
8557 cl->vars[i]->optimize_used = 0;
8558 cl->vars[i]->optimize.init_kclock = info->kclock;
8559 if (app_count
8560 && (app_count < SCHEME_USE_COUNT_INF)
8561 && cl->arg_types
8562 && cl->arg_types[i]
8563 && (cl->arg_type_contributors[i] == ((1 << app_count) - 1))) {
8564 /* All uses accounted for, so we can rely on type info */
8565 add_type(info, (Scheme_Object *)cl->vars[i], cl->arg_types[i]);
8566 }
8567 }
8568
8569 code = optimize_expr(lam->body, info, 0);
8570
8571 propagate_used_variables(info);
8572
8573 if (info->single_result)
8574 SCHEME_LAMBDA_FLAGS(lam) |= LAMBDA_SINGLE_RESULT;
8575 else if (SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_SINGLE_RESULT)
8576 SCHEME_LAMBDA_FLAGS(lam) -= LAMBDA_SINGLE_RESULT;
8577
8578 if (info->preserves_marks)
8579 SCHEME_LAMBDA_FLAGS(lam) |= LAMBDA_PRESERVES_MARKS;
8580 else if (SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_PRESERVES_MARKS)
8581 SCHEME_LAMBDA_FLAGS(lam) -= LAMBDA_PRESERVES_MARKS;
8582
8583 if ((info->single_result > 0) && (info->preserves_marks > 0)
8584 && ((SCHEME_LAMBDA_FLAGS(lam) & LAMBDA_STATUS_MASK) == LAMBDA_STATUS_RESULT_TENTATIVE))
8585 SCHEME_LAMBDA_FLAGS(lam) -= LAMBDA_STATUS_RESULT_TENTATIVE;
8586
8587 lam->body = code;
8588
8589 /* Double check that variables registered for the closure are marked
8590 as used. Although the resolve pass double-checks use flags, we
8591 need to remove any variable that was tentaively marked as used,
8592 because it's non-use may turn a `letrec` into a `let`, and the
8593 `let`-bound variable may be later used after all --- after the
8594 `letrec`->`let` conversion is decided. In other words, ensure
8595 that the closure's free variables are consistent with any
8596 `letrec`->`let` decisions when the `lambda` appear on the
8597 right-hand side of a binding. */
8598 to_remove = scheme_null;
8599 for (i = 0; i < ht->size; i++) {
8600 if (ht->vals[i]) {
8601 Scheme_IR_Local *var = SCHEME_VAR(ht->keys[i]);
8602 if (!var->optimize_used) {
8603 /* Must have been tentively used, but not used after all. */
8604 to_remove = scheme_make_pair((Scheme_Object *)var, to_remove);
8605 }
8606 }
8607 }
8608 while (SCHEME_PAIRP(to_remove)) {
8609 scheme_hash_set(ht, SCHEME_CAR(to_remove), NULL);
8610 to_remove = SCHEME_CDR(to_remove);
8611 }
8612
8613 /* Remembers positions of used vars (and unsets usage for this level) */
8614 cl->base_closure = info->uses;
8615 if (env_uses_toplevel(info))
8616 cl->has_tl = 1;
8617 else
8618 cl->has_tl = 0;
8619 cl->body_size = info->size;
8620 cl->body_psize = info->psize;
8621 cl->has_nonleaf = info->has_nonleaf;
8622
8623 /* closure itself is not an effect */
8624 info->vclock = init_vclock;
8625 info->aclock = init_aclock;
8626 info->kclock = init_kclock;
8627 info->sclock = init_sclock;
8628 info->escapes = 0;
8629
8630 info->size++;
8631
8632 lam->closure_size = (cl->base_closure->count
8633 + (cl->has_tl ? 1 : 0));
8634
8635 optimize_info_done(info, NULL);
8636
8637 return (Scheme_Object *)lam;
8638 }
8639
merge_lambda_arg_types(Scheme_Lambda * lam1,Scheme_Lambda * lam2)8640 static void merge_lambda_arg_types(Scheme_Lambda *lam1, Scheme_Lambda *lam2)
8641 {
8642 Scheme_IR_Lambda_Info *cl1 = lam1->ir_info;
8643 Scheme_IR_Lambda_Info *cl2 = lam2->ir_info;
8644 int i;
8645
8646 if (!cl1->arg_types) {
8647 if (cl2->arg_types) {
8648 cl1->arg_types = cl2->arg_types;
8649 cl1->arg_type_contributors = cl2->arg_type_contributors;
8650 }
8651 } else {
8652 if (cl2->arg_types) {
8653 for (i = lam1->num_params; i--; ) {
8654 if (!cl1->arg_type_contributors[i]) {
8655 cl1->arg_types[i] = cl2->arg_types[i];
8656 cl1->arg_type_contributors[i] = cl2->arg_type_contributors[i];
8657 } else if (cl2->arg_type_contributors[i]) {
8658 if (!cl2->arg_types[i])
8659 cl1->arg_types[i] = NULL;
8660 else if (predicate_implies(cl1->arg_types[i], cl2->arg_types[i]))
8661 cl1->arg_types[i] = cl2->arg_types[i];
8662 else if (!predicate_implies(cl2->arg_types[i], cl1->arg_types[i])) {
8663 cl1->arg_types[i] = NULL;
8664 cl1->arg_type_contributors[i] |= (1 << (SCHEME_USE_COUNT_INF-1));
8665 }
8666 cl1->arg_type_contributors[i] |= cl2->arg_type_contributors[i];
8667 }
8668 }
8669 }
8670
8671 cl2->arg_types = cl1->arg_types;
8672 cl2->arg_type_contributors = cl1->arg_type_contributors;
8673 }
8674 }
8675
check_lambda_arg_types_registered(Scheme_Lambda * lam,int app_count)8676 static void check_lambda_arg_types_registered(Scheme_Lambda *lam, int app_count)
8677 {
8678 if (lam->ir_info->arg_types) {
8679 int i;
8680 for (i = lam->num_params; i--; ) {
8681 if (lam->ir_info->arg_types[i]) {
8682 if ((lam->ir_info->arg_type_contributors[i] & (1 << (SCHEME_USE_COUNT_INF-1)))
8683 || (lam->ir_info->arg_type_contributors[i] < ((1 << app_count) - 1))) {
8684 /* someone caller didn't weigh in with a type,
8685 of an anonymous caller had no type to record */
8686 lam->ir_info->arg_types[i] = NULL;
8687 }
8688 }
8689 }
8690 }
8691 }
8692
clone_variable(Scheme_IR_Local * var)8693 static Scheme_IR_Local *clone_variable(Scheme_IR_Local *var)
8694 {
8695 Scheme_IR_Local *var2;
8696 MZ_ASSERT(SAME_TYPE(var->so.type, scheme_ir_local_type));
8697 var2 = MALLOC_ONE_TAGGED(Scheme_IR_Local);
8698 memcpy(var2, var, sizeof(Scheme_IR_Local));
8699 scheme_set_distinct_eq_hash((Scheme_Object *)var2);
8700 return var2;
8701 }
8702
clone_variable_array(Scheme_IR_Local ** vars,int sz,Scheme_Hash_Tree ** _var_map)8703 static Scheme_IR_Local **clone_variable_array(Scheme_IR_Local **vars,
8704 int sz,
8705 Scheme_Hash_Tree **_var_map)
8706 {
8707 Scheme_IR_Local **new_vars, *var;
8708 Scheme_Hash_Tree *var_map = *_var_map;
8709 int j;
8710
8711 new_vars = MALLOC_N(Scheme_IR_Local*, sz);
8712 for (j = sz; j--; ) {
8713 var = clone_variable(vars[j]);
8714 var->mode = SCHEME_VAR_MODE_NONE;
8715 new_vars[j] = var;
8716 var_map = scheme_hash_tree_set(var_map, (Scheme_Object *)vars[j], (Scheme_Object *)new_vars[j]);
8717 }
8718
8719 *_var_map = var_map;
8720 return new_vars;
8721 }
8722
clone_lambda(int single_use,Scheme_Object * _lam,Optimize_Info * info,Scheme_Hash_Tree * var_map)8723 static Scheme_Object *clone_lambda(int single_use, Scheme_Object *_lam, Optimize_Info *info, Scheme_Hash_Tree *var_map)
8724 {
8725 Scheme_Lambda *lam, *lam2;
8726 Scheme_Object *body, *var;
8727 Scheme_Hash_Table *ht;
8728 Scheme_IR_Lambda_Info *cl;
8729 Scheme_IR_Local **vars;
8730 int sz;
8731 Scheme_Object **arg_types;
8732 short *arg_type_contributors;
8733
8734 lam = (Scheme_Lambda *)_lam;
8735
8736 lam2 = MALLOC_ONE_TAGGED(Scheme_Lambda);
8737 memcpy(lam2, lam, sizeof(Scheme_Lambda));
8738
8739 cl = MALLOC_ONE_RT(Scheme_IR_Lambda_Info);
8740 memcpy(cl, lam->ir_info, sizeof(Scheme_IR_Lambda_Info));
8741 lam2->ir_info = cl;
8742
8743 vars = clone_variable_array(cl->vars, lam2->num_params, &var_map);
8744 cl->vars = vars;
8745
8746 cl->is_dup |= !single_use;
8747
8748 body = optimize_clone(single_use, lam->body, info, var_map, 0);
8749 if (!body) return NULL;
8750
8751 lam2->body = body;
8752
8753 if (cl->arg_types) {
8754 sz = lam2->num_params;
8755 arg_types = MALLOC_N(Scheme_Object*, sz);
8756 arg_type_contributors = MALLOC_N_ATOMIC(short, sz);
8757 memcpy(arg_types, cl->arg_types, sz * sizeof(Scheme_Object*));
8758 memcpy(arg_type_contributors, cl->arg_type_contributors, sz * sizeof(short));
8759 cl->arg_types = arg_types;
8760 cl->arg_type_contributors = arg_type_contributors;
8761 }
8762
8763 if (cl->base_closure && var_map->count) {
8764 int i;
8765 ht = scheme_make_hash_table(SCHEME_hash_ptr);
8766 for (i = 0; i < cl->base_closure->size; i++) {
8767 if (cl->base_closure->vals[i]) {
8768 var = scheme_eq_hash_tree_get(var_map, cl->base_closure->keys[i]);
8769 scheme_hash_set(ht,
8770 (var
8771 ? var
8772 : cl->base_closure->keys[i]),
8773 cl->base_closure->vals[i]);
8774 }
8775 }
8776 cl->base_closure = ht;
8777 }
8778
8779 return (Scheme_Object *)lam2;
8780 }
8781
lambda_body_size_plus_info(Scheme_Lambda * lam,int check_assign,Optimize_Info * info,int * is_leaf)8782 static int lambda_body_size_plus_info(Scheme_Lambda *lam, int check_assign,
8783 Optimize_Info *info, int *is_leaf)
8784 {
8785 int i;
8786 Scheme_IR_Lambda_Info *cl;
8787
8788 cl = lam->ir_info;
8789
8790 if (check_assign) {
8791 /* Don't try to inline if any arguments are mutated: */
8792 for (i = lam->num_params; i--; ) {
8793 if (cl->vars[i]->mutated)
8794 return -1;
8795 }
8796 }
8797
8798 if (is_leaf)
8799 *is_leaf = !cl->has_nonleaf;
8800
8801 return cl->body_size + ((info && info->use_psize) ? cl->body_psize : 0);
8802 }
8803
lambda_has_top_level(Scheme_Lambda * lam)8804 static int lambda_has_top_level(Scheme_Lambda *lam)
8805 {
8806 return lam->ir_info->has_tl;
8807 }
8808
8809 /*========================================================================*/
8810 /* linklets */
8811 /*========================================================================*/
8812
set_code_closure_flags(Scheme_Object * clones,int set_flags,int mask_flags,int just_tentative)8813 static int set_code_closure_flags(Scheme_Object *clones,
8814 int set_flags, int mask_flags,
8815 int just_tentative)
8816 {
8817 Scheme_Object *clone, *orig, *first;
8818 int flags = LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS;
8819
8820 /* The first in a clone pair is the one that is consulted for
8821 references. The second one is the original, and its the one whose
8822 flags are updated by optimization. So consult the original, and set
8823 flags in both. */
8824
8825 while (clones) {
8826 first = SCHEME_CAR(clones);
8827 clone = SCHEME_CAR(first);
8828 orig = SCHEME_CDR(first);
8829
8830 flags = set_one_code_flags(orig, flags,
8831 orig, clone,
8832 set_flags, mask_flags, just_tentative,
8833 0);
8834
8835 clones = SCHEME_CDR(clones);
8836 }
8837
8838 return flags;
8839 }
8840
is_cross_linklet_inline_candidiate(Scheme_Object * e,Optimize_Info * info,int size_override)8841 static Scheme_Object *is_cross_linklet_inline_candidiate(Scheme_Object *e, Optimize_Info *info,
8842 int size_override)
8843 {
8844 if (SCHEME_LAMBDAP(e)) {
8845 if (size_override || (lambda_body_size(e, 1) < CROSS_LINKLET_INLINE_SIZE))
8846 return optimize_clone(0, e, info, empty_eq_hash_tree, 0);
8847 }
8848
8849 return NULL;
8850 }
8851
is_general_lambda(Scheme_Object * e,Optimize_Info * info)8852 static int is_general_lambda(Scheme_Object *e, Optimize_Info *info)
8853 {
8854 /* recognize (begin <omitable>* <proc>) */
8855 if (SCHEME_TYPE(e) == scheme_sequence_type) {
8856 Scheme_Sequence *seq = (Scheme_Sequence *)e;
8857 if (seq->count > 0) {
8858 int i;
8859 for (i = seq->count - 1; i--; ) {
8860 if (!scheme_omittable_expr(seq->array[i], -1, 20, 0, info, NULL))
8861 return 0;
8862 }
8863 }
8864 e = seq->array[seq->count - 1];
8865 }
8866
8867 /* recognize (let ([x <proc>]) x) */
8868 if (SCHEME_TYPE(e) == scheme_ir_let_header_type) {
8869 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)e;
8870 if (!(SCHEME_LET_FLAGS(lh) & SCHEME_LET_RECURSIVE)
8871 && (lh->count == 1)
8872 && (lh->num_clauses == 1)
8873 && SAME_TYPE(SCHEME_TYPE(lh->body), scheme_ir_let_value_type)) {
8874 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
8875 if (SCHEME_LAMBDAP(lv->value))
8876 return SAME_OBJ(lv->body, (Scheme_Object *)lv->vars[0]);
8877 }
8878 }
8879
8880 if (SCHEME_LAMBDAP(e))
8881 return 1;
8882
8883 return 0;
8884 }
8885
install_definition(Scheme_Object * bodies,int pos,Scheme_Object * old_defn,int name_pos,Scheme_Object * rhs)8886 void install_definition(Scheme_Object *bodies, int pos, Scheme_Object *old_defn, int name_pos, Scheme_Object *rhs)
8887 {
8888 Scheme_Object *def;
8889
8890 def = scheme_make_vector(2, NULL);
8891 SCHEME_DEFN_RHS(def) = rhs;
8892 SCHEME_DEFN_VAR_(def, 0) = SCHEME_DEFN_VAR_(old_defn, name_pos);
8893 def->type = scheme_define_values_type;
8894
8895 SCHEME_VEC_ELS(bodies)[pos] = def;
8896 }
8897
split_define_values(Scheme_Object * defn,int n,Scheme_Object * bodies,int offset)8898 int split_define_values(Scheme_Object *defn, int n, Scheme_Object *bodies, int offset)
8899 {
8900 Scheme_Object *e = SCHEME_DEFN_RHS(defn);
8901
8902 if (SAME_TYPE(SCHEME_TYPE(e), scheme_ir_let_header_type)) {
8903 /* This is a tedious case to recognize the pattern
8904 (let ([x rhs] ...) (values x ...))
8905 which might be the result of expansion that involved a local
8906 macro to define the `x's */
8907 Scheme_IR_Let_Header *lh = (Scheme_IR_Let_Header *)e;
8908 if ((lh->count == n) && (lh->num_clauses == n)
8909 && !(SCHEME_LET_FLAGS(lh) & SCHEME_LET_RECURSIVE)) {
8910 Scheme_Object *body = lh->body;
8911 int i;
8912 for (i = 0; i < n; i++) {
8913 if (SAME_TYPE(SCHEME_TYPE(body), scheme_ir_let_value_type)) {
8914 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)body;
8915 if (lv->count == 1) {
8916 if (!scheme_omittable_expr(lv->value, 1, 5, 0, NULL, NULL))
8917 return 0;
8918 body = lv->body;
8919 } else
8920 return 0;
8921 } else
8922 return 0;
8923 }
8924 if ((n == 2) && SAME_TYPE(SCHEME_TYPE(body), scheme_application3_type)) {
8925 Scheme_App3_Rec *app = (Scheme_App3_Rec *)body;
8926 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
8927 if (SAME_OBJ(app->rator, scheme_values_proc)
8928 && SAME_OBJ(app->rand1, (Scheme_Object *)lv->vars[0])
8929 && SAME_OBJ(app->rand2, (Scheme_Object *)((Scheme_IR_Let_Value *)lv->body)->vars[0])) {
8930 if (bodies) {
8931 install_definition(bodies, offset, defn, 0, lv->value);
8932 lv = (Scheme_IR_Let_Value *)lv->body;
8933 install_definition(bodies, offset+1, defn, 1, lv->value);
8934 }
8935 return 1;
8936 }
8937 } else if (SAME_TYPE(SCHEME_TYPE(body), scheme_application_type)
8938 && ((Scheme_App_Rec *)body)->num_args == n) {
8939 Scheme_App_Rec *app = (Scheme_App_Rec *)body;
8940 Scheme_IR_Let_Value *lv = (Scheme_IR_Let_Value *)lh->body;
8941 if (SAME_OBJ(app->args[0], scheme_values_proc)) {
8942 for (i = 0; i < n; i++) {
8943 if (!SAME_TYPE(SCHEME_TYPE(app->args[i+1]), scheme_ir_local_type)
8944 || !SAME_OBJ((Scheme_Object *)lv->vars[0], app->args[i+1]))
8945 return 0;
8946 lv = (Scheme_IR_Let_Value *)lv->body;
8947 }
8948 if (bodies) {
8949 body = lh->body;
8950 for (i = 0; i < n; i++) {
8951 Scheme_IR_Let_Value *lv2 = (Scheme_IR_Let_Value *)body;
8952 install_definition(bodies, offset+i, defn, i, lv2->value);
8953 body = lv2->body;
8954 }
8955 }
8956 return 1;
8957 }
8958 }
8959 }
8960 } else if ((n == 2) && SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) {
8961 Scheme_App3_Rec *app = (Scheme_App3_Rec *)e;
8962 if (SAME_OBJ(app->rator, scheme_values_proc)
8963 && scheme_omittable_expr(app->rand1, 1, 5, 0, NULL, NULL)
8964 && scheme_omittable_expr(app->rand2, 1, 5, 0, NULL, NULL)) {
8965 if (bodies) {
8966 install_definition(bodies, offset, defn, 0, app->rand1);
8967 install_definition(bodies, offset+1, defn, 1, app->rand2);
8968 }
8969 return 1;
8970 }
8971 } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)
8972 && ((Scheme_App_Rec *)e)->num_args == n) {
8973 Scheme_App_Rec *app = (Scheme_App_Rec *)e;
8974 if (SAME_OBJ(app->args[0], scheme_values_proc)) {
8975 int i;
8976 for (i = 0; i < n; i++) {
8977 if (!scheme_omittable_expr(app->args[i+1], 1, 5, 0, NULL, NULL))
8978 return 0;
8979 }
8980 if (bodies) {
8981 for (i = 0; i < n; i++) {
8982 install_definition(bodies, offset+i, defn, i, app->args[i+1]);
8983 }
8984 }
8985 return 1;
8986 }
8987 }
8988
8989 return 0;
8990 }
8991
set_as_fixed(Scheme_Hash_Table * fixed_table,Optimize_Info * info,int pos)8992 static Scheme_Hash_Table *set_as_fixed(Scheme_Hash_Table *fixed_table, Optimize_Info *info, int pos)
8993 {
8994 if (!fixed_table) {
8995 fixed_table = scheme_make_hash_table(SCHEME_hash_ptr);
8996 if (!info->top_level_consts) {
8997 Scheme_Hash_Table *consts;
8998 consts = scheme_make_hash_table(SCHEME_hash_ptr);
8999 info->top_level_consts = consts;
9000 }
9001 scheme_hash_set(info->top_level_consts, scheme_false, (Scheme_Object *)fixed_table);
9002 }
9003
9004 scheme_hash_set(fixed_table, scheme_make_integer(pos), scheme_true);
9005
9006 return fixed_table;
9007 }
9008
scheme_optimize_linklet(Scheme_Linklet * linklet,int enforce_const,int can_inline,int unsafe_mode,Scheme_Object ** _import_keys,Scheme_Object * get_import)9009 Scheme_Linklet *scheme_optimize_linklet(Scheme_Linklet *linklet,
9010 int enforce_const, int can_inline, int unsafe_mode,
9011 Scheme_Object **_import_keys, Scheme_Object *get_import)
9012 {
9013 Scheme_Object *e;
9014 int start_simultaneous = 0, i_m, cnt;
9015 Scheme_Object *cl_first = NULL, *cl_last = NULL;
9016 Scheme_Hash_Table *consts = NULL, *fixed_table = NULL, *re_consts = NULL;
9017 Scheme_Hash_Table *originals = NULL;
9018 int cont, inline_fuel, is_proc_def, any_defns = 0;
9019 Optimize_Info *info;
9020 Optimize_Info *limited_info;
9021 Optimize_Info_Sequence info_seq;
9022 Scheme_Hash_Tree **iu;
9023 /* For now, treat unsafe mode as a hint that cooperation with the validator
9024 is not needed. We may eventually give up on the validator completely. */
9025 int support_validation = !unsafe_mode;
9026
9027 info = optimize_info_create(linklet, enforce_const, can_inline, unsafe_mode);
9028 info->context = (Scheme_Object *)linklet;
9029
9030 /* Less inlining for a large module: */
9031 if (SCHEME_VEC_SIZE(linklet->bodies) > 128)
9032 info->inline_fuel >>= 1;
9033
9034 if (_import_keys) {
9035 Cross_Linklet_Info *cross;
9036 Scheme_Hash_Tree *ht;
9037 int i;
9038
9039 iu = MALLOC_N(Scheme_Hash_Tree*, 1);
9040 *iu = empty_eq_hash_tree;
9041 info->imports_used = iu;
9042
9043 cross = (Cross_Linklet_Info *)scheme_malloc(sizeof(Cross_Linklet_Info));
9044 info->cross = cross;
9045
9046 cross->get_import = get_import;
9047
9048 cross->import_keys = empty_eq_hash_tree;
9049 cross->rev_import_keys = empty_eq_hash_tree;
9050 for (i = 0; i < SCHEME_VEC_SIZE(*_import_keys); i++) {
9051 ht = scheme_hash_tree_set(cross->import_keys,
9052 scheme_make_integer(i),
9053 SCHEME_VEC_ELS(*_import_keys)[i]);
9054 cross->import_keys = ht;
9055 ht = scheme_hash_tree_set(cross->rev_import_keys,
9056 SCHEME_VEC_ELS(*_import_keys)[i],
9057 scheme_make_integer(i));
9058 cross->rev_import_keys = ht;
9059 }
9060 cross->linklets = empty_eq_hash_tree;
9061 cross->import_next_keys = empty_eq_hash_tree;
9062 cross->inline_variants = empty_eq_hash_tree;
9063 cross->import_syms = empty_eq_hash_tree;
9064 }
9065
9066 optimize_info_seq_init(info, &info_seq);
9067
9068 cnt = SCHEME_VEC_SIZE(linklet->bodies);
9069
9070 /* First, flatten `(define-values (x ...) (values e ...))'
9071 to `(define (x) e) ...' when possible. */
9072 {
9073 int inc = 0;
9074 for (i_m = 0; i_m < cnt; i_m++) {
9075 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9076 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9077 int n;
9078 n = SCHEME_DEFN_VAR_COUNT(e);
9079 if (n > 1) {
9080 if (split_define_values(e, n, NULL, 0))
9081 inc += (n - 1);
9082 }
9083 any_defns = 1;
9084 }
9085 }
9086
9087 if (inc > 0) {
9088 Scheme_Object *new_bodies;
9089 int j = 0;
9090 new_bodies = scheme_make_vector(cnt+inc, scheme_false);
9091 for (i_m = 0; i_m < cnt; i_m++) {
9092 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9093 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9094 int n;
9095 n = SCHEME_DEFN_VAR_COUNT(e);
9096 if (n > 1) {
9097 if (split_define_values(e, n, new_bodies, j)) {
9098 j += n;
9099 } else
9100 SCHEME_VEC_ELS(new_bodies)[j++] = e;
9101 } else
9102 SCHEME_VEC_ELS(new_bodies)[j++] = e;
9103 } else
9104 SCHEME_VEC_ELS(new_bodies)[j++] = e;
9105 }
9106 cnt += inc;
9107 linklet->bodies = new_bodies;
9108 }
9109 }
9110
9111 if (any_defns) {
9112 /* Use `limited_info` for optimization decisions that need to be
9113 rediscovered by the validator. The validator knows shape
9114 information for imported variables, and it knows about structure
9115 bindings for later forms. */
9116 limited_info = MALLOC_ONE_RT(Optimize_Info);
9117 #ifdef MZTAG_REQUIRED
9118 limited_info->type = scheme_rt_optimize_info;
9119 #endif
9120 limited_info->linklet = info->linklet;
9121 } else
9122 limited_info = NULL;
9123
9124 if (OPT_ESTIMATE_FUTURE_SIZES && any_defns) {
9125 if (info->enforce_const) {
9126 /* For each identifier bound to a procedure, register an initial
9127 size estimate, which is used to discourage early loop unrolling
9128 at the expense of later inlining. */
9129 for (i_m = 0; i_m < cnt; i_m++) {
9130 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9131 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9132 int n;
9133
9134 n = SCHEME_DEFN_VAR_COUNT(e);
9135 if ((n == 1) && SCHEME_LAMBDAP(SCHEME_DEFN_RHS(e))) {
9136 Scheme_IR_Toplevel *var = SCHEME_DEFN_VAR(e, 0);
9137
9138 if (!(SCHEME_IR_TOPLEVEL_FLAGS(var) & SCHEME_IR_TOPLEVEL_MUTATED)) {
9139 if (!consts)
9140 consts = scheme_make_hash_table(SCHEME_hash_ptr);
9141 scheme_hash_set(consts, scheme_make_integer(var->variable_pos), estimate_closure_size(e));
9142 }
9143 }
9144 }
9145 }
9146
9147 if (consts) {
9148 info->top_level_consts = consts;
9149 consts = NULL;
9150 }
9151 }
9152 }
9153
9154 for (i_m = 0; i_m < cnt; i_m++) {
9155 /* Optimize this expression: */
9156 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9157
9158 is_proc_def = 0;
9159 if (OPT_DISCOURAGE_EARLY_INLINE && info->enforce_const) {
9160 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9161 Scheme_Object *e2;
9162 e2 = SCHEME_DEFN_RHS(e);
9163 if (is_general_lambda(e2, info))
9164 is_proc_def = 1;
9165 }
9166 }
9167
9168 inline_fuel = info->inline_fuel;
9169 if (is_proc_def && OPT_DISCOURAGE_EARLY_INLINE) {
9170 info->use_psize = 1;
9171 if (inline_fuel > 2)
9172 info->inline_fuel = 2;
9173 }
9174 optimize_info_seq_step(info, &info_seq);
9175 e = optimize_expr(e, info, 0);
9176 if (is_proc_def && OPT_DISCOURAGE_EARLY_INLINE) {
9177 info->use_psize = 0;
9178 }
9179 info->inline_fuel = inline_fuel;
9180 SCHEME_VEC_ELS(linklet->bodies)[i_m] = e;
9181
9182 if (info->enforce_const) {
9183 /* If this expression/definition can't have any side effect
9184 (including raising an exception), then continue the group of
9185 simultaneous definitions: */
9186 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9187 int n, cnst = 0, sproc = 0, sprop = 0, has_guard = 0;
9188 Scheme_Object *sstruct = NULL, *parent_identity = NULL;
9189 Simple_Struct_Type_Info stinfo;
9190 Scheme_Object *defn = e;
9191
9192 n = SCHEME_DEFN_VAR_COUNT(defn);
9193 e = SCHEME_DEFN_RHS(defn);
9194
9195 if (support_validation)
9196 limited_info->cross = info->cross;
9197 cont = scheme_omittable_expr(e, n, -1,
9198 (support_validation
9199 /* ignore APPN_FLAG_OMITTABLE, because the
9200 validator won't be able to reconstruct it
9201 in general; also, don't recognize struct-type
9202 functions, since they weren't recognized
9203 as immediate calls */
9204 ? (OMITTABLE_IGNORE_APPN_OMIT
9205 | OMITTABLE_IGNORE_MAKE_STRUCT_TYPE)
9206 : 0),
9207 /* similarly, use `limited_info` instead of `info'
9208 here, because the decision
9209 of omittable should not depend on
9210 information that's only available at
9211 optimization time: */
9212 (support_validation ? limited_info : info),
9213 info);
9214 if (support_validation)
9215 info->cross = limited_info->cross;
9216
9217 if (n == 1) {
9218 if (ir_propagate_ok(e, info, 0, NULL))
9219 cnst = 1;
9220 else if (scheme_is_statically_proc(e, info, OMITTABLE_IGNORE_APPN_OMIT)) {
9221 cnst = 1;
9222 sproc = 1;
9223 }
9224 } else if (scheme_is_simple_make_struct_type(e, n, 0, NULL,
9225 &stinfo, &parent_identity,
9226 info,
9227 NULL, NULL, 0, NULL,
9228 &sstruct,
9229 5)) {
9230 sstruct = scheme_make_pair(sstruct, parent_identity);
9231 cnst = 1;
9232 } else if (scheme_is_simple_make_struct_type_property(e, n, 0,
9233 &has_guard,
9234 info,
9235 NULL, NULL, 0, NULL,
9236 5)) {
9237 sprop = 1;
9238 cnst = 1;
9239 } else
9240 sstruct = NULL;
9241
9242 if (support_validation && (sstruct || sprop) && !cont) {
9243 /* Since the `make-struct-type` or `make-struct-tye-property` form is immediate
9244 enough that the validator can see it, re-check whether we can continue
9245 a group of simultaneously defined variables. */
9246 cont = scheme_omittable_expr(e, n, 5, OMITTABLE_IGNORE_APPN_OMIT, limited_info, NULL);
9247 }
9248
9249 if (cont) {
9250 /* Record for the resolve pass's pruning that definition is omittable */
9251 SCHEME_SET_DEFN_CAN_OMIT(defn);
9252 }
9253
9254 if (cnst) {
9255 Scheme_IR_Toplevel *var;
9256 int i;
9257 for (i = 0; i < n; i++) {
9258 var = SCHEME_DEFN_VAR(defn, i);
9259
9260 if (!(SCHEME_IR_TOPLEVEL_FLAGS(var) & SCHEME_IR_TOPLEVEL_MUTATED)) {
9261 Scheme_Object *e2;
9262
9263 if (sstruct) {
9264 e2 = scheme_make_struct_proc_shape(scheme_get_struct_proc_shape(i, &stinfo),
9265 sstruct);
9266 } else if (sprop) {
9267 e2 = scheme_make_struct_property_proc_shape(scheme_get_struct_property_proc_shape(i, has_guard));
9268 } else if (sproc) {
9269 e2 = scheme_make_noninline_proc(e);
9270 } else if (SCHEME_LAMBDAP(e)) {
9271 e2 = optimize_clone(1, e, info, empty_eq_hash_tree, 0);
9272 if (e2) {
9273 Scheme_Object *pr;
9274 pr = scheme_make_raw_pair(scheme_make_raw_pair(e2, e), NULL);
9275 if (cl_last)
9276 SCHEME_CDR(cl_last) = pr;
9277 else
9278 cl_first = pr;
9279 cl_last = pr;
9280 } else
9281 e2 = scheme_make_noninline_proc(e);
9282 } else {
9283 e2 = e;
9284 }
9285
9286 if (e2) {
9287 consts = info->top_level_consts;
9288 if (!consts) {
9289 consts = scheme_make_hash_table(SCHEME_hash_ptr);
9290 info->top_level_consts = consts;
9291 }
9292 scheme_hash_set(consts, scheme_make_integer(var->variable_pos), e2);
9293
9294 if (sstruct || sprop) {
9295 /* include in `limited_info` */
9296 Scheme_Hash_Table *limited_consts = limited_info->top_level_consts;
9297 if (!limited_consts) {
9298 limited_consts = scheme_make_hash_table(SCHEME_hash_ptr);
9299 limited_info->top_level_consts = limited_consts;
9300 }
9301 scheme_hash_set(limited_consts, scheme_make_integer(var->variable_pos), e2);
9302 }
9303
9304 if (sstruct || (SCHEME_TYPE(e2) > _scheme_ir_values_types_)) {
9305 /* No use re-optimizing */
9306 } else {
9307 if (!re_consts)
9308 re_consts = scheme_make_hash_table(SCHEME_hash_ptr);
9309 scheme_hash_set(re_consts, scheme_make_integer(i_m), scheme_make_integer(var->variable_pos));
9310 }
9311 } else {
9312 /* At least mark it as fixed */
9313 fixed_table = set_as_fixed(fixed_table, info, SCHEME_IR_TOPLEVEL_POS(var));
9314 }
9315 }
9316 }
9317 } else if (cont) {
9318 /* The binding is not inlinable/propagatable, but unless it's
9319 set!ed, it is constant after evaluating the definition. We
9320 map the top-level position to indicate constantness --- immediately
9321 if `cont`, and later if not. */
9322 int i, n = SCHEME_DEFN_VAR_COUNT(defn);
9323 Scheme_IR_Toplevel *var;
9324
9325 for (i = 0; i < n; i++) {
9326 var = SCHEME_DEFN_VAR(defn, i);
9327
9328 /* Test for set!: */
9329 if (!(SCHEME_IR_TOPLEVEL_FLAGS(var) & SCHEME_IR_TOPLEVEL_MUTATED)) {
9330 if (!info->top_level_consts
9331 || !scheme_hash_get(info->top_level_consts, (Scheme_Object *)var)) {
9332 fixed_table = set_as_fixed(fixed_table, info, var->variable_pos);
9333 }
9334 }
9335 }
9336 }
9337 } else {
9338 if (i_m + 1 == cnt)
9339 cont = 0;
9340 else
9341 cont = scheme_omittable_expr(e, -1, -1, 0, NULL, NULL);
9342 }
9343 } else {
9344 cont = 1;
9345 }
9346
9347 if (!cont || (i_m + 1 == cnt)) {
9348 Scheme_Object *prop_later = NULL;
9349 /* If we have new constants, re-optimize to inline: */
9350 if (consts) {
9351 int flags;
9352
9353 /* Same as in letrec: assume LAMBDA_SINGLE_RESULT and
9354 LAMBDA_PRESERVES_MARKS for all, but then assume not for all
9355 if any turn out not (i.e., approximate fix point). */
9356 (void)set_code_closure_flags(cl_first,
9357 LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS | LAMBDA_STATUS_RESULT_TENTATIVE,
9358 0xFFFF,
9359 0);
9360
9361 while (1) {
9362 /* Re-optimize this expression. */
9363 int old_sz, new_sz, orig_fuel;
9364
9365 e = SCHEME_VEC_ELS(linklet->bodies)[start_simultaneous];
9366
9367 if (OPT_DELAY_GROUP_PROPAGATE || OPT_LIMIT_FUNCTION_RESIZE) {
9368 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9369 Scheme_Object *sub_e;
9370 sub_e = SCHEME_DEFN_RHS(e);
9371 old_sz = lambda_body_size(sub_e, 0);
9372 } else
9373 old_sz = 0;
9374 } else
9375 old_sz = 0;
9376
9377 optimize_info_seq_step(info, &info_seq);
9378 orig_fuel = info->inline_fuel;
9379 e = optimize_expr(e, info, 0);
9380 info->inline_fuel = orig_fuel;
9381 SCHEME_VEC_ELS(linklet->bodies)[start_simultaneous] = e;
9382
9383 if (re_consts) {
9384 /* Install optimized closures into constant table ---
9385 unless, maybe, they grow too much: */
9386 Scheme_Object *rpos;
9387 rpos = scheme_hash_get(re_consts, scheme_make_integer(start_simultaneous));
9388 if (rpos) {
9389 Scheme_Object *old_e;
9390
9391 e = SCHEME_DEFN_RHS(e);
9392
9393 old_e = scheme_hash_get(info->top_level_consts, rpos);
9394 if (old_e && SCHEME_LAMBDAP(old_e) && OPT_PRE_OPTIMIZE_FOR_CROSS_LINKLET(1)) {
9395 if (!originals)
9396 originals = scheme_make_hash_table(SCHEME_hash_ptr);
9397 scheme_hash_set(originals, scheme_make_integer(start_simultaneous), old_e);
9398 }
9399
9400 if (!ir_propagate_ok(e, info, 0, NULL)
9401 && scheme_is_statically_proc(e, info, 0)) {
9402 /* If we previously installed a procedure for inlining,
9403 don't replace that with a worse approximation. */
9404 if (SCHEME_LAMBDAP(old_e))
9405 e = NULL;
9406 else
9407 e = scheme_make_noninline_proc(e);
9408 }
9409
9410 if (e) {
9411 if (OPT_DELAY_GROUP_PROPAGATE || OPT_LIMIT_FUNCTION_RESIZE)
9412 new_sz = lambda_body_size(e, 0);
9413 else
9414 new_sz = 0;
9415
9416 if (!old_sz
9417 || (new_sz <= old_sz)
9418 || (!OPT_DELAY_GROUP_PROPAGATE && !OPT_LIMIT_FUNCTION_RESIZE))
9419 scheme_hash_set(info->top_level_consts, rpos, e);
9420 else if (!OPT_LIMIT_FUNCTION_RESIZE
9421 || (new_sz < 4 * old_sz))
9422 prop_later = scheme_make_raw_pair(scheme_make_pair(rpos, e), prop_later);
9423 }
9424 }
9425 }
9426
9427 if (start_simultaneous == i_m)
9428 break;
9429 start_simultaneous++;
9430 }
9431
9432 flags = set_code_closure_flags(cl_first, 0, 0xFFFF, 0);
9433 (void)set_code_closure_flags(cl_first,
9434 (flags & (LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS)),
9435 ~(LAMBDA_SINGLE_RESULT | LAMBDA_PRESERVES_MARKS | LAMBDA_STATUS_MASK),
9436 1);
9437 }
9438
9439 cl_last = cl_first = NULL;
9440 consts = NULL;
9441 re_consts = NULL;
9442 start_simultaneous = i_m + 1;
9443
9444 while (prop_later) {
9445 e = SCHEME_CAR(prop_later);
9446 scheme_hash_set(info->top_level_consts, SCHEME_CAR(e), SCHEME_CDR(e));
9447 prop_later = SCHEME_CDR(prop_later);
9448 }
9449 }
9450
9451 if (!cont) {
9452 /* Now that the definition is evaluated, its variables are
9453 certainly fixed if they're not `set!`ed. */
9454 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9455 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9456 int i, n = SCHEME_DEFN_VAR_COUNT(e);
9457 Scheme_IR_Toplevel *var;
9458
9459 for (i = 0; i < n; i++) {
9460 var = SCHEME_DEFN_VAR(e, i);
9461
9462 /* Test for set!: */
9463 if (!(SCHEME_IR_TOPLEVEL_FLAGS(var) & SCHEME_IR_TOPLEVEL_MUTATED)) {
9464 if (!info->top_level_consts
9465 || !scheme_hash_get(info->top_level_consts, (Scheme_Object *)var)) {
9466 fixed_table = set_as_fixed(fixed_table, info, var->variable_pos);
9467 }
9468 }
9469 }
9470 }
9471 }
9472 }
9473
9474 /* For functions that are potentially inlineable, perhaps
9475 before optimization, insert inline_variant records: */
9476 if (info->enforce_const) {
9477 for (i_m = 0; i_m < cnt; i_m++) {
9478 /* Optimize this expression: */
9479 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9480 if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) {
9481 int size_override;
9482 size_override = SCHEME_DEFN_ALWAYS_INLINEP(e);
9483 if (SCHEME_DEFN_VAR_COUNT(e) == 1) {
9484 Scheme_Object *sub_e, *alt_e;
9485 sub_e = SCHEME_DEFN_RHS(e);
9486 alt_e = is_cross_linklet_inline_candidiate(sub_e, info, 0);
9487 if (!alt_e && originals && OPT_PRE_OPTIMIZE_FOR_CROSS_LINKLET(size_override)) {
9488 alt_e = scheme_hash_get(originals, scheme_make_integer(i_m));
9489 if (SAME_OBJ(alt_e, sub_e) && !size_override)
9490 alt_e = NULL;
9491 else if (alt_e)
9492 alt_e = is_cross_linklet_inline_candidiate(alt_e, info, size_override);
9493 }
9494 if (alt_e) {
9495 Scheme_Object *iv;
9496 iv = scheme_make_vector(3, scheme_false);
9497 iv->type = scheme_inline_variant_type;
9498 SCHEME_VEC_ELS(iv)[0] = sub_e;
9499 SCHEME_VEC_ELS(iv)[1] = alt_e;
9500 SCHEME_DEFN_RHS(e) = iv;
9501 }
9502 }
9503 }
9504 }
9505 }
9506
9507 /* Check one more time for expressions that we can omit: */
9508 {
9509 int can_omit = 0;
9510 for (i_m = 0; i_m < cnt; i_m++) {
9511 /* Optimize this expression: */
9512 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9513 if ((i_m < (cnt - 1)) && scheme_omittable_expr(e, -1, -1, 0, info, NULL)) {
9514 can_omit++;
9515 }
9516 }
9517 if (can_omit) {
9518 Scheme_Object *new_bodies;
9519 int j = 0;
9520 new_bodies = scheme_make_vector(cnt - can_omit, scheme_false);
9521 for (i_m = 0; i_m < cnt; i_m++) {
9522 /* Optimize this expression: */
9523 e = SCHEME_VEC_ELS(linklet->bodies)[i_m];
9524 if ((i_m == (cnt-1)) || !scheme_omittable_expr(e, -1, -1, 0, info, NULL)) {
9525 SCHEME_VEC_ELS(new_bodies)[j++] = e;
9526 }
9527 }
9528 linklet->bodies = new_bodies;
9529 }
9530 cnt -= can_omit;
9531 }
9532
9533 /* Record shapes, if any, of imports as used for optimization; also
9534 reflect import usage, so that the resolve pass can remove unused
9535 imports */
9536 record_optimize_shapes(info, linklet, _import_keys);
9537
9538 return linklet;
9539 }
9540
9541 /*========================================================================*/
9542 /* expressions */
9543 /*========================================================================*/
9544
optimize_k(void)9545 static Scheme_Object *optimize_k(void)
9546 {
9547 Scheme_Thread *p = scheme_current_thread;
9548 Scheme_Object *expr = (Scheme_Object *)p->ku.k.p1;
9549 Optimize_Info *info = (Optimize_Info *)p->ku.k.p2;
9550 int context = p->ku.k.i1;
9551
9552 p->ku.k.p1 = NULL;
9553 p->ku.k.p2 = NULL;
9554
9555 return optimize_expr(expr, info, context);
9556 }
9557
optimize_expr(Scheme_Object * expr,Optimize_Info * info,int context)9558 Scheme_Object *optimize_expr(Scheme_Object *expr, Optimize_Info *info, int context)
9559 {
9560 Scheme_Type type = SCHEME_TYPE(expr);
9561
9562 #ifdef DO_STACK_CHECK
9563 # include "mzstkchk.h"
9564 {
9565 Scheme_Thread *p = scheme_current_thread;
9566
9567 p->ku.k.p1 = (void *)expr;
9568 p->ku.k.p2 = (void *)info;
9569 p->ku.k.i1 = context;
9570
9571 return scheme_handle_stack_overflow(optimize_k);
9572 }
9573 #endif
9574
9575 info->preserves_marks = 1;
9576 info->single_result = 1;
9577 info->escapes = 0;
9578
9579 switch (type) {
9580 case scheme_ir_local_type:
9581 {
9582 Scheme_Object *val;
9583
9584 info->size += 1;
9585
9586 if (SCHEME_VAR(expr)->mutated) {
9587 info->vclock += 1;
9588 register_use(SCHEME_VAR(expr), info);
9589 return expr;
9590 }
9591
9592 val = optimize_info_propagate_local(expr);
9593 if (val) {
9594 info->size -= 1;
9595 return optimize_expr(val, info, context);
9596 }
9597
9598 val = collapse_local(expr, info, context);
9599 if (val)
9600 return val;
9601
9602 if (!(context & OPT_CONTEXT_NO_SINGLE)) {
9603 val = SCHEME_VAR(expr)->optimize.known_val;
9604
9605 if (val && SAME_TYPE(SCHEME_TYPE(val), scheme_once_used_type)) {
9606 Scheme_Once_Used *o = (Scheme_Once_Used *)val;
9607
9608 MZ_ASSERT(!o->moved);
9609 MZ_ASSERT(!SCHEME_VAR(expr)->optimize_outside_binding);
9610
9611 /* In case this variable was tentatively used before: */
9612 SCHEME_VAR(expr)->optimize_used = 0;
9613
9614 if (((o->vclock == info->vclock)
9615 && ((o->aclock == info->aclock)
9616 || !o->spans_k)
9617 && ((context & OPT_CONTEXT_SINGLED)
9618 || single_valued_noncm_expression(o->expr, info, 5)))
9619 || movable_expression(o->expr, info,
9620 o->var->optimize.lambda_depth != info->lambda_depth,
9621 o->kclock != info->kclock,
9622 o->sclock != info->sclock,
9623 0, 5)) {
9624 int save_fuel = info->inline_fuel, save_no_types = info->no_types;
9625 int save_vclock, save_aclock, save_kclock, save_sclock;
9626 info->size -= 1;
9627 info->inline_fuel = -1; /* no more inlining; o->expr was already optimized */
9628 info->no_types = 1; /* cannot used inferred types, in case `val' inferred them */
9629 save_vclock = info->vclock; /* allowed to move => no change to clocks */
9630 save_aclock = info->aclock;
9631 save_kclock = info->kclock;
9632 save_sclock = info->sclock;
9633
9634 o->moved = 1;
9635
9636 val = optimize_expr(o->expr, info, context);
9637
9638 if (info->maybe_values_argument) {
9639 /* Although `val` could be counted as taking 0 time, we advance
9640 the clock conservatively to be consistent with `values`
9641 splitting. */
9642 advance_clocks_for_optimized(val,
9643 &save_vclock, &save_aclock, &save_kclock, &save_sclock,
9644 info,
9645 ADVANCE_CLOCKS_INIT_FUEL);
9646 }
9647
9648 info->inline_fuel = save_fuel;
9649 info->no_types = save_no_types;
9650 info->vclock = save_vclock;
9651 info->aclock = save_aclock;
9652 info->kclock = save_kclock;
9653 info->sclock = save_sclock;
9654 return val;
9655 }
9656 }
9657 }
9658
9659 /* If everything fails, mark it as used. */
9660 if (OPT_CONTEXT_TYPE(context))
9661 SCHEME_VAR(expr)->arg_type = OPT_CONTEXT_TYPE(context);
9662 if (info->kclock > SCHEME_VAR(expr)->optimize.init_kclock)
9663 SCHEME_VAR(expr)->escapes_after_k_tick = 1;
9664 register_use(SCHEME_VAR(expr), info);
9665 return expr;
9666 }
9667 case scheme_application_type:
9668 return optimize_application(expr, info, context);
9669 case scheme_application2_type:
9670 return optimize_application2(expr, info, context);
9671 case scheme_application3_type:
9672 return optimize_application3(expr, info, context);
9673 case scheme_sequence_type:
9674 return optimize_sequence(expr, info, context, 1);
9675 case scheme_branch_type:
9676 return optimize_branch(expr, info, context);
9677 case scheme_with_cont_mark_type:
9678 return optimize_wcm(expr, info, context);
9679 case scheme_ir_lambda_type:
9680 if (context & OPT_CONTEXT_BOOLEAN)
9681 return scheme_true;
9682 else
9683 return optimize_lambda(expr, info, context);
9684 case scheme_ir_let_header_type:
9685 return optimize_lets(expr, info, context);
9686 case scheme_ir_toplevel_type:
9687 info->size += 1;
9688 {
9689 Scheme_Object *c;
9690
9691 while (1) {
9692 c = get_import_inline(info, (Scheme_IR_Toplevel *)expr, -1, 0);
9693 if (!c)
9694 c = get_defn_shape(info, (Scheme_IR_Toplevel *)expr);
9695 c = no_potential_size(c);
9696 if (c && SAME_TYPE(SCHEME_TYPE(c), scheme_ir_toplevel_type))
9697 expr = c;
9698 else
9699 break;
9700 }
9701
9702 if (c) {
9703 if (SAME_OBJ(c, scheme_constant_key)) {
9704 /* can't copy, but constant across instantiations */
9705 expr = scheme_ir_toplevel_to_flagged_toplevel(expr, SCHEME_TOPLEVEL_CONST);
9706 if (context & OPT_CONTEXT_BOOLEAN)
9707 c = scheme_true;
9708 else
9709 c = NULL;
9710 } else if (SAME_OBJ(c, scheme_fixed_key)) {
9711 /* not constant across instantiations, but at least fixed */
9712 expr = scheme_ir_toplevel_to_flagged_toplevel(expr, SCHEME_TOPLEVEL_FIXED);
9713 c = NULL;
9714 }
9715 } else
9716 info->vclock += 1;
9717
9718 if (c) {
9719 if (context & OPT_CONTEXT_BOOLEAN)
9720 return (SCHEME_FALSEP(c) ? scheme_false : scheme_true);
9721
9722 if (scheme_ir_duplicate_ok(c, 0))
9723 return c;
9724
9725 /* We can't inline, but mark the top level as a constant,
9726 so we can direct-jump and avoid null checks in JITed code: */
9727 expr = scheme_ir_toplevel_to_flagged_toplevel(expr, SCHEME_TOPLEVEL_CONST);
9728 }
9729 }
9730 optimize_info_used_top(info);
9731 register_import_used(info, (Scheme_IR_Toplevel *)expr);
9732 return expr;
9733 case scheme_variable_type:
9734 scheme_signal_error("got toplevel in wrong place");
9735 return 0;
9736 case scheme_define_values_type:
9737 return define_values_optimize(expr, info, context);
9738 case scheme_varref_form_type:
9739 return ref_optimize(expr, info, context);
9740 case scheme_set_bang_type:
9741 return set_optimize(expr, info, context);
9742 case scheme_case_lambda_sequence_type:
9743 if (context & OPT_CONTEXT_BOOLEAN)
9744 return scheme_true;
9745 else
9746 return case_lambda_optimize(expr, info, context);
9747 case scheme_begin0_sequence_type:
9748 return begin0_optimize(expr, info, context);
9749 case scheme_apply_values_type:
9750 return apply_values_optimize(expr, info, context);
9751 case scheme_with_immed_mark_type:
9752 return with_immed_mark_optimize(expr, info, context);
9753 default:
9754 info->size += 1;
9755 if ((context & OPT_CONTEXT_BOOLEAN)
9756 && (SCHEME_TYPE(expr) > _scheme_ir_values_types_)
9757 && SCHEME_TRUEP(expr))
9758 return scheme_true;
9759 else
9760 return expr;
9761 }
9762 }
9763
increment_use_count(Scheme_IR_Local * var,int as_rator)9764 static void increment_use_count(Scheme_IR_Local *var, int as_rator)
9765 {
9766 if (var->use_count < SCHEME_USE_COUNT_INF)
9767 var->use_count++;
9768 if (!as_rator && (var->non_app_count < SCHEME_USE_COUNT_INF))
9769 var->non_app_count++;
9770
9771 if (var->optimize.known_val
9772 && var->optimize.clear_known_on_multi_use)
9773 var->optimize.known_val = NULL;
9774 }
9775
optimize_clone_k(void)9776 static Scheme_Object *optimize_clone_k(void)
9777 {
9778 Scheme_Thread *p = scheme_current_thread;
9779 Scheme_Object *expr = (Scheme_Object *)p->ku.k.p1;
9780 Optimize_Info *info = (Optimize_Info *)p->ku.k.p2;
9781 Scheme_Hash_Tree *var_map = (Scheme_Hash_Tree *)p->ku.k.p3;
9782 int single_use = p->ku.k.i1;
9783 int as_rator = p->ku.k.i2;
9784
9785 p->ku.k.p1 = NULL;
9786 p->ku.k.p2 = NULL;
9787 p->ku.k.p3 = NULL;
9788
9789 return optimize_clone(single_use, expr, info, var_map, as_rator);
9790 }
9791
optimize_clone(int single_use,Scheme_Object * expr,Optimize_Info * info,Scheme_Hash_Tree * var_map,int as_rator)9792 Scheme_Object *optimize_clone(int single_use, Scheme_Object *expr, Optimize_Info *info, Scheme_Hash_Tree *var_map, int as_rator)
9793 /* If single_use is 1, then the old copy will be dropped --- so it's ok to "duplicate"
9794 any constant, and local-variable use counts should not be incremented. */
9795 {
9796 int t;
9797
9798 #ifdef DO_STACK_CHECK
9799 # include "mzstkchk.h"
9800 {
9801 Scheme_Thread *p = scheme_current_thread;
9802
9803 p->ku.k.i1 = single_use;
9804 p->ku.k.p1 = (void *)expr;
9805 p->ku.k.p2 = (void *)info;
9806 p->ku.k.p3 = (void *)var_map;
9807 p->ku.k.i2 = as_rator;
9808
9809 return scheme_handle_stack_overflow(optimize_clone_k);
9810 }
9811 #endif
9812
9813 t = SCHEME_TYPE(expr);
9814
9815 switch(t) {
9816 case scheme_ir_local_type:
9817 {
9818 Scheme_Object *v;
9819 v = scheme_eq_hash_tree_get(var_map, expr);
9820 if (v)
9821 return v;
9822 else if (!single_use)
9823 increment_use_count(SCHEME_VAR(expr), as_rator);
9824 return expr;
9825 }
9826 case scheme_application2_type:
9827 {
9828 Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr, *app2;
9829
9830 app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec);
9831 app2->iso.so.type = scheme_application2_type;
9832
9833 expr = optimize_clone(single_use, app->rator, info, var_map, 1);
9834 if (!expr) return NULL;
9835 app2->rator = expr;
9836
9837 expr = optimize_clone(single_use, app->rand, info, var_map, 0);
9838 if (!expr) return NULL;
9839 app2->rand = expr;
9840
9841 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_FLAG_MASK);
9842 if (single_use)
9843 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_POSITION_MASK);
9844
9845 return (Scheme_Object *)app2;
9846 }
9847 case scheme_application_type:
9848 {
9849 Scheme_App_Rec *app = (Scheme_App_Rec *)expr, *app2;
9850 int i;
9851
9852 app2 = scheme_malloc_application(app->num_args + 1);
9853
9854 for (i = app->num_args + 1; i--; ) {
9855 expr = optimize_clone(single_use, app->args[i], info, var_map, !i);
9856 if (!expr) return NULL;
9857 app2->args[i] = expr;
9858 }
9859
9860 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_FLAG_MASK);
9861 if (single_use)
9862 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_POSITION_MASK);
9863
9864 return (Scheme_Object *)app2;
9865 }
9866 case scheme_application3_type:
9867 {
9868 Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr, *app2;
9869
9870 app2 = MALLOC_ONE_TAGGED(Scheme_App3_Rec);
9871 app2->iso.so.type = scheme_application3_type;
9872
9873 expr = optimize_clone(single_use, app->rator, info, var_map, 1);
9874 if (!expr) return NULL;
9875 app2->rator = expr;
9876
9877 expr = optimize_clone(single_use, app->rand1, info, var_map, 0);
9878 if (!expr) return NULL;
9879 app2->rand1 = expr;
9880
9881 expr = optimize_clone(single_use, app->rand2, info, var_map, 0);
9882 if (!expr) return NULL;
9883 app2->rand2 = expr;
9884
9885 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_FLAG_MASK);
9886 if (single_use)
9887 SCHEME_APPN_FLAGS(app2) |= (SCHEME_APPN_FLAGS(app) & APPN_POSITION_MASK);
9888
9889 return (Scheme_Object *)app2;
9890 }
9891 case scheme_ir_let_header_type:
9892 {
9893 Scheme_IR_Let_Header *head = (Scheme_IR_Let_Header *)expr, *head2;
9894 Scheme_Object *body;
9895 Scheme_IR_Let_Value *lv, *lv2, *prev = NULL;
9896 Scheme_IR_Local **vars;
9897 int i;
9898
9899 head2 = MALLOC_ONE_TAGGED(Scheme_IR_Let_Header);
9900 head2->iso.so.type = scheme_ir_let_header_type;
9901 head2->count = head->count;
9902 head2->num_clauses = head->num_clauses;
9903 SCHEME_LET_FLAGS(head2) = SCHEME_LET_FLAGS(head);
9904
9905 /* Build let-value change: */
9906 body = head->body;
9907 for (i = head->num_clauses; i--; ) {
9908 lv = (Scheme_IR_Let_Value *)body;
9909
9910 vars = clone_variable_array(lv->vars, lv->count, &var_map);
9911
9912 lv2 = MALLOC_ONE_TAGGED(Scheme_IR_Let_Value);
9913 SCHEME_IRLV_FLAGS(lv2) |= (SCHEME_IRLV_FLAGS(lv) & 0x1);
9914 lv2->iso.so.type = scheme_ir_let_value_type;
9915 lv2->count = lv->count;
9916 lv2->vars = vars;
9917 lv2->value = lv->value;
9918
9919 if (prev)
9920 prev->body = (Scheme_Object *)lv2;
9921 else
9922 head2->body = (Scheme_Object *)lv2;
9923 prev = lv2;
9924
9925 body = lv->body;
9926 }
9927 if (prev)
9928 prev->body = body;
9929 else
9930 head2->body = body;
9931
9932 body = head2->body;
9933 for (i = head->num_clauses; i--; ) {
9934 lv2 = (Scheme_IR_Let_Value *)body;
9935
9936 expr = optimize_clone(single_use, lv2->value, info, var_map, 0);
9937 if (!expr) return NULL;
9938 lv2->value = expr;
9939
9940 body = lv2->body;
9941 }
9942
9943 expr = optimize_clone(single_use, body, info, var_map, 0);
9944 if (!expr) return NULL;
9945
9946 if (prev)
9947 prev->body = expr;
9948 else
9949 head2->body = expr;
9950
9951 return (Scheme_Object *)head2;
9952 }
9953 case scheme_sequence_type:
9954 case scheme_begin0_sequence_type:
9955 {
9956 Scheme_Sequence *seq = (Scheme_Sequence *)expr, *seq2;
9957 int i;
9958
9959 seq2 = scheme_malloc_sequence(seq->count);
9960 seq2->so.type = seq->so.type;
9961 seq2->count = seq->count;
9962
9963 for (i = seq->count; i--; ) {
9964 expr = optimize_clone(single_use, seq->array[i], info, var_map, 0);
9965 if (!expr) return NULL;
9966 seq2->array[i] = expr;
9967 }
9968
9969 return (Scheme_Object *)seq2;
9970 }
9971 case scheme_branch_type:
9972 {
9973 Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr, *b2;
9974
9975 b2 = MALLOC_ONE_TAGGED(Scheme_Branch_Rec);
9976 b2->so.type = scheme_branch_type;
9977
9978 expr = optimize_clone(single_use, b->test, info, var_map, 0);
9979 if (!expr) return NULL;
9980 b2->test = expr;
9981
9982 expr = optimize_clone(single_use, b->tbranch, info, var_map, 0);
9983 if (!expr) return NULL;
9984 b2->tbranch = expr;
9985
9986 expr = optimize_clone(single_use, b->fbranch, info, var_map, 0);
9987 if (!expr) return NULL;
9988 b2->fbranch = expr;
9989
9990 return (Scheme_Object *)b2;
9991 }
9992 case scheme_with_cont_mark_type:
9993 {
9994 Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)expr, *wcm2;
9995
9996 wcm2 = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark);
9997 wcm2->so.type = scheme_with_cont_mark_type;
9998
9999 expr = optimize_clone(single_use, wcm->key, info, var_map, 0);
10000 if (!expr) return NULL;
10001 wcm2->key = expr;
10002
10003 expr = optimize_clone(single_use, wcm->val, info, var_map, 0);
10004 if (!expr) return NULL;
10005 wcm2->val = expr;
10006
10007 expr = optimize_clone(single_use, wcm->body, info, var_map, 0);
10008 if (!expr) return NULL;
10009 wcm2->body = expr;
10010
10011 return (Scheme_Object *)wcm2;
10012 }
10013 case scheme_ir_lambda_type:
10014 return clone_lambda(single_use, expr, info, var_map);
10015 case scheme_ir_toplevel_type:
10016 return expr;
10017 case scheme_define_values_type:
10018 case scheme_boxenv_type:
10019 return NULL;
10020 case scheme_varref_form_type:
10021 return ref_clone(single_use, expr, info, var_map);
10022 case scheme_set_bang_type:
10023 return set_clone(single_use, expr, info, var_map);
10024 case scheme_apply_values_type:
10025 return apply_values_clone(single_use, expr, info, var_map);
10026 case scheme_with_immed_mark_type:
10027 return with_immed_mark_clone(single_use, expr, info, var_map);
10028 case scheme_case_lambda_sequence_type:
10029 return case_lambda_clone(single_use, expr, info, var_map);
10030 default:
10031 if (t > _scheme_ir_values_types_) {
10032 if (single_use || scheme_ir_duplicate_ok(expr, 0))
10033 return expr;
10034 }
10035 }
10036
10037 return NULL;
10038 }
10039
10040 /*========================================================================*/
10041 /* compile-time env for optimization */
10042 /*========================================================================*/
10043
optimize_info_allocate(Scheme_Linklet * linklet,int enforce_const,int can_inline,int unsafe_mode)10044 static Optimize_Info *optimize_info_allocate(Scheme_Linklet *linklet,
10045 int enforce_const, int can_inline, int unsafe_mode)
10046 {
10047 Optimize_Info *info;
10048
10049 info = MALLOC_ONE_RT(Optimize_Info);
10050 #ifdef MZTAG_REQUIRED
10051 info->type = scheme_rt_optimize_info;
10052 #endif
10053 info->inline_fuel = INITIAL_INLINING_FUEL;
10054 info->flatten_fuel = INITIAL_FLATTENING_FUEL;
10055 info->linklet = linklet;
10056
10057 info->enforce_const = enforce_const;
10058 if (!can_inline)
10059 info->inline_fuel = -1;
10060 info->unsafe_mode = unsafe_mode;
10061
10062 return info;
10063 }
10064
optimize_info_create(Scheme_Linklet * linklet,int enforce_const,int can_inline,int unsafe_mode)10065 static Optimize_Info *optimize_info_create(Scheme_Linklet *linklet,
10066 int enforce_const, int can_inline, int unsafe_mode)
10067 {
10068 Optimize_Info *info;
10069 Scheme_Logger *logger;
10070
10071 info = optimize_info_allocate(linklet, enforce_const, can_inline, unsafe_mode);
10072
10073 logger = (Scheme_Logger *)scheme_get_param(scheme_current_config(), MZCONFIG_LOGGER);
10074 logger = scheme_make_logger(logger, scheme_intern_symbol("optimizer"));
10075 info->logger = logger;
10076
10077 return info;
10078 }
10079
optimize_info_seq_init(Optimize_Info * info,Optimize_Info_Sequence * info_seq)10080 static void optimize_info_seq_init(Optimize_Info *info, Optimize_Info_Sequence *info_seq)
10081 {
10082 info_seq->init_flatten_fuel = info->flatten_fuel;
10083 info_seq->min_flatten_fuel = info->flatten_fuel;
10084 }
10085
optimize_info_seq_step(Optimize_Info * info,Optimize_Info_Sequence * info_seq)10086 static void optimize_info_seq_step(Optimize_Info *info, Optimize_Info_Sequence *info_seq)
10087 {
10088 if (info->flatten_fuel < info_seq->min_flatten_fuel)
10089 info_seq->min_flatten_fuel = info->flatten_fuel;
10090 info->flatten_fuel = info_seq->init_flatten_fuel;
10091 }
10092
optimize_info_seq_done(Optimize_Info * info,Optimize_Info_Sequence * info_seq)10093 static void optimize_info_seq_done(Optimize_Info *info, Optimize_Info_Sequence *info_seq)
10094 {
10095 if (info->flatten_fuel > info_seq->min_flatten_fuel)
10096 info->flatten_fuel = info_seq->min_flatten_fuel;
10097 }
10098
propagate_used_variables(Optimize_Info * info)10099 static void propagate_used_variables(Optimize_Info *info)
10100 {
10101 Scheme_Hash_Table *ht;
10102 Scheme_IR_Local *tvar;
10103 int j;
10104
10105 if (info->next->uses) {
10106 ht = info->uses;
10107 for (j = 0; j < ht->size; j++) {
10108 if (ht->vals[j]) {
10109 tvar = SCHEME_VAR(ht->keys[j]);
10110 if (tvar->optimize.lambda_depth < info->next->lambda_depth)
10111 scheme_hash_set(info->next->uses, (Scheme_Object *)tvar, scheme_true);
10112 }
10113 }
10114 }
10115 }
10116
env_uses_toplevel(Optimize_Info * frame)10117 static int env_uses_toplevel(Optimize_Info *frame)
10118 {
10119 int used;
10120
10121 used = frame->used_toplevel;
10122
10123 if (used) {
10124 /* Propagate use to an enclosing lambda, if any: */
10125 frame = frame->next;
10126 while (frame) {
10127 if (frame->flags & SCHEME_LAMBDA_FRAME) {
10128 frame->used_toplevel = 1;
10129 break;
10130 }
10131 frame = frame->next;
10132 }
10133 }
10134
10135 return used;
10136 }
10137
optimize_info_used_top(Optimize_Info * info)10138 static void optimize_info_used_top(Optimize_Info *info)
10139 {
10140 while (info) {
10141 if (info->flags & SCHEME_LAMBDA_FRAME) {
10142 info->used_toplevel = 1;
10143 break;
10144 }
10145 info = info->next;
10146 }
10147 }
10148
make_once_used(Scheme_Object * val,Scheme_IR_Local * var,int vclock,int aclock,int kclock,int sclock,int spans_k)10149 static Scheme_Once_Used *make_once_used(Scheme_Object *val, Scheme_IR_Local *var,
10150 int vclock, int aclock, int kclock, int sclock, int spans_k)
10151 {
10152 Scheme_Once_Used *o;
10153
10154 /* Procedures should be handled more specifically, because there are
10155 issues with transitive delayed-use registration to handle
10156 `letrec`, where a value that has already been moved can be
10157 marked later as used. */
10158 MZ_ASSERT(!SCHEME_LAMBDAP(val));
10159
10160 o = MALLOC_ONE_TAGGED(Scheme_Once_Used);
10161 o->so.type = scheme_once_used_type;
10162
10163 o->expr = val;
10164 o->var = var;
10165 o->vclock = vclock;
10166 o->aclock = aclock;
10167 o->kclock = kclock;
10168 o->sclock = sclock;
10169 o->spans_k = spans_k;
10170
10171 return o;
10172 }
10173
optimize_any_uses(Optimize_Info * info,Scheme_IR_Let_Value * at_irlv,int n)10174 static int optimize_any_uses(Optimize_Info *info, Scheme_IR_Let_Value *at_irlv, int n)
10175 {
10176 int i, j;
10177 Scheme_IR_Let_Value *irlv = at_irlv;
10178
10179 while (n--) {
10180 MZ_ASSERT(SAME_TYPE(irlv->iso.so.type, scheme_ir_let_value_type));
10181 for (i = irlv->count; i--; ) {
10182 if (irlv->vars[i]->optimize_used)
10183 return 1;
10184 for (j = at_irlv->count; j--; ) {
10185 if (at_irlv->vars[j]->optimize.transitive_uses) {
10186 if (scheme_hash_get(at_irlv->vars[j]->optimize.transitive_uses,
10187 (Scheme_Object *)irlv->vars[i]))
10188 return 1;
10189 }
10190 }
10191 }
10192 irlv = (Scheme_IR_Let_Value *)irlv->body;
10193 }
10194
10195 return 0;
10196 }
10197
optimize_uses_of_mutable_imply_early_alloc(Scheme_IR_Let_Value * at_irlv,int n)10198 static void optimize_uses_of_mutable_imply_early_alloc(Scheme_IR_Let_Value *at_irlv, int n)
10199 {
10200 int i, j;
10201 Scheme_IR_Let_Value *irlv = at_irlv;
10202
10203 /* We we're reinterpreting a `letrec` as `let*`, and when it really
10204 must be `let*` instead of `let`, and when a mutable variable is
10205 involved, then we need to tell the `resolve` pass that the
10206 mutable varaiable's value must be boxed immediately, instead of
10207 delaying to the body of the `let*`. */
10208
10209 while (n--) {
10210 for (i = irlv->count; i--; ) {
10211 if (irlv->vars[i]->mutated) {
10212 int used = 0;
10213 if (irlv->vars[i]->optimize_used)
10214 used = 1;
10215 else {
10216 for (j = at_irlv->count; j--; ) {
10217 if (at_irlv->vars[j]->optimize.transitive_uses) {
10218 if (scheme_hash_get(at_irlv->vars[j]->optimize.transitive_uses,
10219 (Scheme_Object *)irlv->vars[i]))
10220 used = 1;
10221 }
10222 }
10223 }
10224 if (used)
10225 irlv->vars[i]->must_allocate_immediately = 1;
10226 }
10227 }
10228 irlv = (Scheme_IR_Let_Value *)irlv->body;
10229 }
10230 }
10231
register_use(Scheme_IR_Local * var,Optimize_Info * info)10232 static void register_use(Scheme_IR_Local *var, Optimize_Info *info)
10233 {
10234 MZ_ASSERT(SCHEME_VAR(var)->mode == SCHEME_VAR_MODE_OPTIMIZE);
10235 MZ_ASSERT(SCHEME_VAR(var)->use_count);
10236
10237 if (var->optimize.lambda_depth < info->lambda_depth)
10238 scheme_hash_set(info->uses, (Scheme_Object *)var, scheme_true);
10239
10240 if (!var->optimize_used) {
10241 var->optimize_used = 1;
10242
10243 if (info->transitive_use_var
10244 && (var->optimize.lambda_depth
10245 <= info->transitive_use_var->optimize.lambda_depth)) {
10246 Scheme_Hash_Table *ht = info->transitive_use_var->optimize.transitive_uses;
10247
10248 if (!ht) {
10249 ht = scheme_make_hash_table(SCHEME_hash_ptr);
10250 info->transitive_use_var->optimize.transitive_uses = ht;
10251 }
10252 scheme_hash_set(ht, (Scheme_Object *)var, scheme_true);
10253 }
10254 }
10255 }
10256
register_transitive_uses(Scheme_IR_Local * var,Optimize_Info * info)10257 static void register_transitive_uses(Scheme_IR_Local *var, Optimize_Info *info)
10258 {
10259 Scheme_Hash_Table *ht;
10260 Scheme_IR_Local *tvar;
10261 int j;
10262
10263 ht = var->optimize.transitive_uses;
10264
10265 for (j = 0; j < ht->size; j++) {
10266 if (ht->vals[j]) {
10267 tvar = SCHEME_VAR(ht->keys[j]);
10268
10269 if (tvar->optimize.known_val
10270 && SAME_TYPE(SCHEME_TYPE(tvar->optimize.known_val), scheme_once_used_type)
10271 && ((Scheme_Once_Used *)tvar->optimize.known_val)->moved) {
10272 /* variable no longer used, and any transitive uses were
10273 covered by re-optimizing in its use context */
10274 MZ_ASSERT(!tvar->optimize_used);
10275 } else
10276 register_use(tvar, info);
10277 }
10278 }
10279 }
10280
optimize_info_lookup(Scheme_Object * var)10281 static Scheme_Object *optimize_info_lookup(Scheme_Object *var)
10282 {
10283 MZ_ASSERT(SCHEME_VAR(var)->mode == SCHEME_VAR_MODE_OPTIMIZE);
10284 MZ_ASSERT(SCHEME_VAR(var)->use_count);
10285
10286 return SCHEME_VAR(var)->optimize.known_val;
10287 }
10288
optimize_info_propagate_local(Scheme_Object * var)10289 static Scheme_Object *optimize_info_propagate_local(Scheme_Object *var)
10290 {
10291 Scheme_Object *last, *val = var;
10292
10293 last = val; /* Avoid compiler warning */
10294
10295 while (val && SAME_TYPE(SCHEME_TYPE(val), scheme_ir_local_type)) {
10296 MZ_ASSERT(SCHEME_VAR(val)->mode == SCHEME_VAR_MODE_OPTIMIZE);
10297 MZ_ASSERT(SCHEME_VAR(val)->use_count);
10298 last = val;
10299 val = SCHEME_VAR(val)->optimize.known_val;
10300 }
10301
10302 if (!val
10303 || SCHEME_WILL_BE_LAMBDAP(val)
10304 || SCHEME_LAMBDAP(val)
10305 || SAME_TYPE(SCHEME_TYPE(val), scheme_once_used_type)) {
10306 if (SAME_OBJ(last, var))
10307 return NULL;
10308
10309 if (SCHEME_VAR(var)->use_count != 1)
10310 increment_use_count(SCHEME_VAR(last), 0);
10311
10312 return last;
10313 }
10314
10315 return val;
10316 }
10317
optimize_get_predicate(Optimize_Info * info,Scheme_Object * var,int ignore_no_types)10318 Scheme_Object *optimize_get_predicate(Optimize_Info *info, Scheme_Object *var, int ignore_no_types)
10319 {
10320 Scheme_Object *pred;
10321
10322 if (info->no_types && !ignore_no_types) return NULL;
10323
10324 while (info) {
10325 if (info->types) {
10326 pred = scheme_eq_hash_tree_get(info->types, var);
10327 if (pred)
10328 return pred;
10329 }
10330 info = info->next;
10331 }
10332
10333 return NULL;
10334 }
10335
optimize_info_add_frame(Optimize_Info * info,int flags)10336 static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int flags)
10337 {
10338 Optimize_Info *naya;
10339
10340 naya = optimize_info_allocate(info->linklet, 0, 0, 0);
10341 naya->flags = (short)flags;
10342 naya->next = info;
10343 naya->inline_fuel = info->inline_fuel;
10344 naya->flatten_fuel = info->flatten_fuel;
10345 naya->letrec_not_twice = info->letrec_not_twice;
10346 naya->enforce_const = info->enforce_const;
10347 naya->unsafe_mode = info->unsafe_mode;
10348 naya->top_level_consts = info->top_level_consts;
10349 naya->context = info->context;
10350 naya->vclock = info->vclock;
10351 naya->aclock = info->aclock;
10352 naya->kclock = info->kclock;
10353 naya->sclock = info->sclock;
10354 naya->escapes = info->escapes;
10355 naya->init_kclock = info->kclock;
10356 naya->maybe_values_argument = info->maybe_values_argument;
10357 naya->use_psize = info->use_psize;
10358 naya->logger = info->logger;
10359 naya->no_types = info->no_types;
10360 naya->lambda_depth = info->lambda_depth + ((flags & SCHEME_LAMBDA_FRAME) ? 1 : 0);
10361 naya->uses = info->uses;
10362 naya->transitive_use_var = info->transitive_use_var;
10363 naya->cross = info->cross;
10364 naya->imports_used = info->imports_used;
10365
10366 return naya;
10367 }
10368
optimize_info_done(Optimize_Info * info,Optimize_Info * parent)10369 static void optimize_info_done(Optimize_Info *info, Optimize_Info *parent)
10370 {
10371 if (!parent) parent = info->next;
10372
10373 parent->size += info->size;
10374 parent->vclock = info->vclock;
10375 parent->aclock = info->aclock;
10376 parent->kclock = info->kclock;
10377 parent->sclock = info->sclock;
10378 parent->escapes = info->escapes;
10379 parent->psize += info->psize;
10380 parent->flatten_fuel = info->flatten_fuel;
10381 if (info->has_nonleaf)
10382 parent->has_nonleaf = 1;
10383 }
10384
10385
10386 /*========================================================================*/
10387 /* shapes from linklet imports */
10388 /*========================================================================*/
10389
is_procedure_expression(Scheme_Object * e)10390 static int is_procedure_expression(Scheme_Object *e)
10391 {
10392 Scheme_Type t;
10393
10394 if (SCHEME_PROCP(e))
10395 return 1;
10396
10397 t = SCHEME_TYPE(e);
10398
10399 return ((t == scheme_lambda_type)
10400 || (t == scheme_case_lambda_sequence_type));
10401 }
10402
linklet_setup_constants(Scheme_Linklet * linklet)10403 static void linklet_setup_constants(Scheme_Linklet *linklet)
10404 {
10405 int i, cnt, k, defns_start;
10406 Scheme_Object *form, *tl;
10407 Scheme_Hash_Table *ht;
10408
10409 if (linklet->constants)
10410 return;
10411
10412 /* find constants: */
10413 ht = scheme_make_hash_table(SCHEME_hash_ptr);
10414 linklet->constants = ht;
10415
10416 defns_start = 1 + linklet->num_total_imports;
10417
10418 cnt = SCHEME_VEC_SIZE(linklet->bodies);
10419 for (i = 0; i < cnt; i++) {
10420 form = SCHEME_VEC_ELS(linklet->bodies)[i];
10421
10422 if (SAME_TYPE(SCHEME_TYPE(form), scheme_define_values_type)) {
10423 int checked_st = 0, is_st_prop = 0, has_guard = 0;
10424 Scheme_Object *is_st = NULL;
10425 Simple_Struct_Type_Info stinfo;
10426 Scheme_Object *parent_identity;
10427
10428 for (k = SCHEME_DEFN_VAR_COUNT(form); k--; ) {
10429 tl = (Scheme_Object *)SCHEME_DEFN_VAR(form, k);
10430 if (SCHEME_TOPLEVEL_FLAGS(tl) & SCHEME_TOPLEVEL_SEAL) {
10431 int pos = SCHEME_TOPLEVEL_POS(tl) - defns_start;
10432
10433 if (pos < linklet->num_exports) {
10434 Scheme_Object *v;
10435
10436 if (SCHEME_DEFN_VAR_COUNT(form) == 1) {
10437 if (scheme_ir_duplicate_ok(SCHEME_DEFN_RHS(form), 1)) {
10438 /* record simple constant for cross-linklet propagation: */
10439 v = SCHEME_DEFN_RHS(form);
10440 } else if (SAME_TYPE(SCHEME_TYPE(SCHEME_DEFN_RHS(form)), scheme_inline_variant_type)) {
10441 /* record a potentially inlineable function */
10442 v = SCHEME_DEFN_RHS(form);
10443 } else if (is_procedure_expression(SCHEME_VEC_ELS(form)[0])) {
10444 /* record that it's a procedure: */
10445 v = scheme_make_vector(2, scheme_false);
10446 SCHEME_VEC_ELS(v)[0] = SCHEME_DEFN_RHS(form);
10447 } else {
10448 /* record that it's fixed for any given instantiation: */
10449 v = scheme_fixed_key;
10450 }
10451 } else {
10452 if (!checked_st) {
10453 if (scheme_is_simple_make_struct_type(SCHEME_DEFN_RHS(form),
10454 SCHEME_DEFN_VAR_COUNT(form),
10455 CHECK_STRUCT_TYPE_RESOLVED,
10456 NULL, &stinfo, &parent_identity,
10457 NULL, NULL, NULL, 0, linklet,
10458 &is_st,
10459 5)) {
10460 is_st = scheme_make_pair(is_st, parent_identity);
10461 } else {
10462 is_st = NULL;
10463 if (scheme_is_simple_make_struct_type_property(SCHEME_VEC_ELS(form)[0],
10464 SCHEME_VEC_SIZE(form)-1,
10465 CHECK_STRUCT_TYPE_RESOLVED,
10466 &has_guard,
10467 NULL, NULL, NULL, 0, linklet,
10468 5))
10469 is_st_prop = 1;
10470 }
10471 checked_st = 1;
10472 }
10473 if (is_st) {
10474 intptr_t shape;
10475 shape = scheme_get_struct_proc_shape(k, &stinfo);
10476 /* Vector of size 3 => struct shape */
10477 v = scheme_make_vector(3, scheme_false);
10478 SCHEME_VEC_ELS(v)[1] = scheme_make_integer(shape);
10479 SCHEME_VEC_ELS(v)[2] = is_st;
10480 } else if (is_st_prop) {
10481 intptr_t shape;
10482 shape = scheme_get_struct_property_proc_shape(k, has_guard);
10483 /* Vector of size 4 => struct property shape */
10484 v = scheme_make_vector(4, scheme_false);
10485 SCHEME_VEC_ELS(v)[1] = scheme_make_integer(shape);
10486 } else
10487 v = NULL;
10488 }
10489 if (v)
10490 scheme_hash_set(ht, SCHEME_VEC_ELS(linklet->defns)[pos], v);
10491 }
10492 }
10493 }
10494 }
10495 }
10496 }
10497
get_linklet_or_instance_for_import_key(Optimize_Info * info,Scheme_Object * key)10498 static Scheme_Object *get_linklet_or_instance_for_import_key(Optimize_Info *info, Scheme_Object *key)
10499 {
10500 Scheme_Object *v, *next_keys, *a[1];
10501 Cross_Linklet_Info *cross = info->cross;
10502 Scheme_Hash_Tree *ht;
10503
10504 if (!cross || !cross->get_import)
10505 return NULL;
10506
10507 v = scheme_eq_hash_tree_get(cross->linklets, key);
10508 if (!v) {
10509 a[0] = key;
10510 v = scheme_apply_multi(cross->get_import, 1, a);
10511 if (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)
10512 && (scheme_current_thread->ku.multiple.count == 2)) {
10513 v = scheme_current_thread->ku.multiple.array[0];
10514 next_keys = scheme_current_thread->ku.multiple.array[1];
10515 } else {
10516 scheme_wrong_return_arity("compile-linklet",
10517 2,
10518 (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)
10519 ? scheme_current_thread->ku.multiple.count
10520 : 1),
10521 (SAME_OBJ(v, SCHEME_MULTIPLE_VALUES)
10522 ? (Scheme_Object **)v
10523 : scheme_current_thread->ku.multiple.array),
10524 "");
10525 return NULL;
10526 }
10527
10528 ht = scheme_hash_tree_set(cross->linklets, key, v);
10529 cross->linklets = ht;
10530
10531 if (!SCHEME_FALSEP(v)) {
10532 if (!SAME_TYPE(SCHEME_TYPE(v), scheme_linklet_type)
10533 && !SAME_TYPE(SCHEME_TYPE(v), scheme_instance_type))
10534 scheme_wrong_contract("compile-linklet", "(or/c linklet? instance? #f)", -1, 0, &v);
10535
10536 if (!SCHEME_FALSEP(next_keys)
10537 && (!SCHEME_VECTORP(next_keys)
10538 || !SAME_TYPE(SCHEME_TYPE(v), scheme_linklet_type)
10539 || SCHEME_VEC_SIZE(next_keys) != SCHEME_VEC_SIZE(((Scheme_Linklet *)v)->importss)))
10540 scheme_contract_error("compile-linklet",
10541 "result is not #f or a vector of keys that match the result linklet's import count",
10542 (SAME_TYPE(SCHEME_TYPE(v), scheme_linklet_type) ? "linklet" : "instance"), 1, v,
10543 "import count", 1, scheme_make_integer(SCHEME_VEC_SIZE(((Scheme_Linklet *)v)->importss)),
10544 "invalid as vector of keys", 1, next_keys,
10545 NULL);
10546
10547 if (SCHEME_TRUEP(next_keys)) {
10548 ht = scheme_hash_tree_set(cross->import_next_keys, key, next_keys);
10549 cross->import_next_keys = ht;
10550 }
10551 }
10552 }
10553
10554 if (SCHEME_FALSEP(v))
10555 return NULL;
10556
10557 return v;
10558 }
10559
get_import_inline_or_shape(Optimize_Info * info,Scheme_IR_Toplevel * var,int argc,int want_shape,int for_props)10560 static Scheme_Object *get_import_inline_or_shape(Optimize_Info *info, Scheme_IR_Toplevel *var,
10561 int argc, int want_shape, int for_props)
10562 /* Returns either a procedure shape, a value to inline, or (when `for_props`)
10563 a function to be used just for its properties. The
10564 special values scheme_constant_key and scheme_fixed_key may be
10565 returned. If `argc` is less than 0, then scheme_constant_key is
10566 returned for procedures. If `want_shape` or `argc` is less than 0
10567 and a non-NULL value is returned, then `info` records the fact that
10568 shape information is used. */
10569 {
10570 Scheme_Object *key, *v, *name, *l_or_i;
10571 Scheme_Hash_Table *iv_ht;
10572 Scheme_Linklet *linklet;
10573
10574 if (!info->cross || (var->instance_pos < 0))
10575 return NULL;
10576
10577 key = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(var->instance_pos));
10578 if (!key)
10579 return NULL;
10580
10581 l_or_i = get_linklet_or_instance_for_import_key(info, key);
10582
10583 if (!l_or_i)
10584 return NULL;
10585
10586 if ((var->instance_pos < SCHEME_VEC_SIZE(info->linklet->importss))
10587 && (var->variable_pos < SCHEME_VEC_SIZE(SCHEME_VEC_ELS(info->linklet->importss)[var->instance_pos])))
10588 name = SCHEME_VEC_ELS(SCHEME_VEC_ELS(info->linklet->importss)[var->instance_pos])[var->variable_pos];
10589 else {
10590 Scheme_Hash_Tree *ht;
10591 ht = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(info->cross->import_syms,
10592 scheme_make_integer(var->instance_pos));
10593 MZ_ASSERT(ht);
10594 name = scheme_eq_hash_tree_get(ht, scheme_make_integer(var->variable_pos));
10595 }
10596 MZ_ASSERT(name);
10597 MZ_ASSERT(SCHEME_SYMBOLP(name));
10598
10599 if (SAME_TYPE(SCHEME_TYPE(l_or_i), scheme_linklet_type)) {
10600 linklet = (Scheme_Linklet *)l_or_i;
10601
10602 if (!linklet->constants)
10603 linklet_setup_constants(linklet);
10604
10605 if (!want_shape && !for_props && (argc >= 0)) {
10606 /* check for previously unresolved for this linklet: */
10607 iv_ht = (Scheme_Hash_Table *)scheme_eq_hash_tree_get(info->cross->inline_variants, key);
10608 if (iv_ht) {
10609 v = scheme_hash_get(iv_ht, name);
10610 if (v) {
10611 /* We have previously unresolved to `v` */
10612 if (SCHEME_HASHTP(v)) {
10613 /* It's a `case-lambda`, so try to get the right clause */
10614 v = scheme_hash_get((Scheme_Hash_Table *)v, scheme_make_integer(argc));
10615 if (v)
10616 return v;
10617 /* Try to unresolve the right arity */
10618 } else if (SCHEME_FALSEP(v)) {
10619 /* previous unresove attempt failed */
10620 return NULL;
10621 } else
10622 return v;
10623 }
10624 }
10625 /* Otherwise, not yet unresolved (maybe because it doesn't need to be) */
10626 } else
10627 iv_ht = NULL;
10628
10629 v = scheme_hash_get(linklet->constants, name);
10630
10631 if (!v)
10632 return NULL;
10633
10634 if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 2)) {
10635 /* a procedure */
10636 if (want_shape)
10637 v = scheme_get_or_check_procedure_shape(SCHEME_VEC_ELS(v)[0], NULL, 0);
10638 else if (for_props)
10639 return SCHEME_VEC_ELS(v)[0];
10640 else if (argc < 0)
10641 v = scheme_constant_key;
10642 else
10643 v = NULL;
10644 } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_inline_variant_type)) {
10645 /* a procedure that can be inlined (if unresolve succeeds) */
10646 if (for_props) {
10647 return SCHEME_VEC_ELS(v)[0];
10648 } else if (want_shape) {
10649 v = scheme_get_or_check_procedure_shape(v, NULL, 0);
10650 if (v)
10651 info->cross->used_import_shape = 1;
10652 } else if (argc >= 0) {
10653 int has_cases = 0;
10654
10655 v = scheme_unresolve(v, argc, &has_cases, linklet, key, info);
10656
10657 if (!iv_ht) {
10658 Scheme_Hash_Tree *ht;
10659 iv_ht = scheme_make_hash_table(SCHEME_hash_ptr);
10660 ht = scheme_hash_tree_set(info->cross->inline_variants, key, (Scheme_Object *)iv_ht);
10661 info->cross->inline_variants = ht;
10662 }
10663
10664 /* Save unresolved */
10665 if (has_cases) {
10666 Scheme_Hash_Table *cl_ht;
10667 cl_ht = (Scheme_Hash_Table *)scheme_hash_get(iv_ht, name);
10668 if (!cl_ht) {
10669 cl_ht = scheme_make_hash_table(SCHEME_hash_ptr);
10670 scheme_hash_set(iv_ht, name, (Scheme_Object *)cl_ht);
10671 }
10672 scheme_hash_set(cl_ht, scheme_make_integer(argc), v);
10673 } else if (v)
10674 scheme_hash_set(iv_ht, name, v);
10675 else
10676 scheme_hash_set(iv_ht, name, scheme_false); /* record that it won't work */
10677 } else
10678 v = scheme_constant_key;
10679 } else if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 3)) {
10680 if (want_shape)
10681 v = scheme_make_struct_proc_shape(SCHEME_INT_VAL(SCHEME_VEC_ELS(v)[1]),
10682 SCHEME_VEC_ELS(v)[2]);
10683 else if ((argc < 0) || for_props)
10684 v = scheme_constant_key;
10685 else
10686 v = NULL;
10687 } else if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 4)) {
10688 if (want_shape)
10689 v = scheme_make_struct_property_proc_shape(SCHEME_INT_VAL(SCHEME_VEC_ELS(v)[1]));
10690 else if ((argc < 0) || for_props)
10691 v = scheme_constant_key;
10692 else
10693 v = NULL;
10694 }
10695 } else {
10696 Scheme_Bucket *b;
10697 int imprecise = SCHEME_INSTANCE_FLAGS((Scheme_Instance *)l_or_i) & SCHEME_INSTANCE_USE_IMPRECISE;
10698 b = scheme_instance_variable_bucket_or_null(name, (Scheme_Instance *)l_or_i);
10699 if (b && b->val && (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_IS_CONSISTENT)) {
10700 v = b->val;
10701 if (want_shape)
10702 v = get_value_shape(v, imprecise);
10703 else if (argc < 0)
10704 v = scheme_constant_key;
10705 else
10706 v = NULL;
10707 } else
10708 v = NULL;
10709 }
10710
10711 if (v && (want_shape || (argc < 0)))
10712 info->cross->used_import_shape = 1;
10713
10714 return v;
10715 }
10716
scheme_optimize_add_import_variable(Optimize_Info * info,Scheme_Object * linklet_key,Scheme_Object * symbol)10717 Scheme_Object *scheme_optimize_add_import_variable(Optimize_Info *info, Scheme_Object *linklet_key, Scheme_Object *symbol)
10718 /* Called from unresolver (for cross-linklet inlining) to find or add
10719 an imported variable from an existing instance import */
10720 {
10721 Scheme_Object *pos, *var_pos, *vec;
10722 Scheme_Hash_Tree *syms, *ht;
10723 int i;
10724
10725 if (SCHEME_FALSEP(linklet_key))
10726 return NULL;
10727
10728 pos = scheme_eq_hash_tree_get(info->cross->rev_import_keys, linklet_key);
10729 MZ_ASSERT(pos);
10730
10731 syms = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(info->cross->import_syms, pos);
10732 if (!syms) {
10733 syms = empty_eq_hash_tree;
10734 if (SCHEME_INT_VAL(pos) < SCHEME_VEC_SIZE(info->linklet->importss)) {
10735 /* initialize from the linklet that we're optimizing */
10736 vec = SCHEME_VEC_ELS(info->linklet->importss)[SCHEME_INT_VAL(pos)];
10737 for (i = SCHEME_VEC_SIZE(vec); i--; ) {
10738 syms = scheme_hash_tree_set(syms, SCHEME_VEC_ELS(vec)[i], scheme_make_integer(i));
10739 syms = scheme_hash_tree_set(syms, scheme_make_integer(i), SCHEME_VEC_ELS(vec)[i]);
10740 }
10741 } else {
10742 /* must not have imported anything, yet, so the empty table is correct */
10743 }
10744 ht = scheme_hash_tree_set(info->cross->import_syms, pos, (Scheme_Object *)syms);
10745 info->cross->import_syms = ht;
10746 }
10747
10748 var_pos = scheme_eq_hash_tree_get(syms, symbol);
10749 if (!var_pos) {
10750 var_pos = scheme_make_integer(syms->count >> 1);
10751 syms = scheme_hash_tree_set(syms, symbol, var_pos);
10752 syms = scheme_hash_tree_set(syms, var_pos, symbol);
10753 ht = scheme_hash_tree_set(info->cross->import_syms, pos, (Scheme_Object *)syms);
10754 info->cross->import_syms = ht;
10755 }
10756
10757 /* SCHEME_TOPLEVEL_READY is conservative; optimizer can compute a refinement later */
10758 return (Scheme_Object *)scheme_make_ir_toplevel(SCHEME_INT_VAL(pos), SCHEME_INT_VAL(var_pos), SCHEME_TOPLEVEL_READY);
10759 }
10760
scheme_optimize_get_import_key(Optimize_Info * info,Scheme_Object * linklet_key,int instance_pos)10761 Scheme_Object *scheme_optimize_get_import_key(Optimize_Info *info, Scheme_Object *linklet_key, int instance_pos)
10762 /* Called from unresolver (for cross-linklet inlining) to find or add
10763 an imported instance */
10764 {
10765 Scheme_Object *next_keys, *key, *pos;
10766 Scheme_Hash_Tree *ht;
10767
10768 next_keys = scheme_eq_hash_tree_get(info->cross->import_next_keys, linklet_key);
10769 if (!next_keys) {
10770 /* chaining is not supported by the compilation client */
10771 return NULL;
10772 }
10773
10774 MZ_ASSERT(instance_pos < SCHEME_VEC_SIZE(next_keys));
10775
10776 key = SCHEME_VEC_ELS(next_keys)[instance_pos];
10777 pos = scheme_eq_hash_tree_get(info->cross->rev_import_keys, key);
10778 if (!pos) {
10779 /* Add this linklet as an import */
10780 pos = scheme_make_integer(info->cross->import_keys->count);
10781
10782 ht = scheme_hash_tree_set(info->cross->import_keys, pos, key);
10783 info->cross->import_keys = ht;
10784
10785 ht = scheme_hash_tree_set(info->cross->rev_import_keys, key, pos);
10786 info->cross->rev_import_keys = ht;
10787 }
10788
10789 return key;
10790 }
10791
get_import_shape(Optimize_Info * info,Scheme_IR_Toplevel * var)10792 static Scheme_Object *get_import_shape(Optimize_Info *info, Scheme_IR_Toplevel *var)
10793 {
10794 return get_import_inline_or_shape(info, var, -1, 1, 0);
10795 }
10796
get_import_inline(Optimize_Info * info,Scheme_IR_Toplevel * var,int argc,int for_props)10797 static Scheme_Object *get_import_inline(Optimize_Info *info, Scheme_IR_Toplevel *var, int argc, int for_props)
10798 /* argc < 0 => scheme_constant_key for non-copyable procedures */
10799 {
10800 return get_import_inline_or_shape(info, var, argc, 0, for_props);
10801 }
10802
register_import_used(Optimize_Info * info,Scheme_IR_Toplevel * var)10803 static void register_import_used(Optimize_Info *info, Scheme_IR_Toplevel *var)
10804 {
10805 if ((var->instance_pos >= 0) && info->imports_used) {
10806 /* Record that the import is used. The resolve pass can
10807 drop references that have been optimized away. */
10808 Scheme_Hash_Tree *ht;
10809 ht = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(*info->imports_used, scheme_make_integer(var->instance_pos));
10810 if (!ht)
10811 ht = empty_eq_hash_tree;
10812 if (!scheme_eq_hash_tree_get(ht, scheme_make_integer(var->variable_pos))) {
10813 ht = scheme_hash_tree_set(ht, scheme_make_integer(var->variable_pos), scheme_true);
10814 ht = scheme_hash_tree_set(*info->imports_used, scheme_make_integer(var->instance_pos), (Scheme_Object *)ht);
10815 (*info->imports_used) = ht;
10816 }
10817 }
10818 }
10819
record_optimize_shapes(Optimize_Info * info,Scheme_Linklet * linklet,Scheme_Object ** _import_keys)10820 static void record_optimize_shapes(Optimize_Info *info, Scheme_Linklet *linklet, Scheme_Object **_import_keys)
10821 {
10822 int i, j, k, used, total, added_imports = 0, dropped_imports = 0, total_used;
10823 Scheme_Object *shapes, *v, *name;
10824 Scheme_Linklet *in_linklet;
10825 Scheme_Instance *in_instance;
10826 Scheme_Hash_Tree *ht;
10827 Scheme_Bucket *b;
10828
10829 if (info->cross) {
10830 /* Add new imported instances */
10831 if (info->cross->import_keys->count > SCHEME_VEC_SIZE(linklet->importss)) {
10832 added_imports = SCHEME_VEC_SIZE(linklet->importss) - info->cross->import_keys->count;
10833 v = scheme_make_vector(info->cross->import_keys->count, scheme_make_vector(0, NULL));
10834 for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
10835 SCHEME_VEC_ELS(v)[i] = SCHEME_VEC_ELS(linklet->importss)[i];
10836 }
10837 linklet->importss = v;
10838 }
10839
10840 /* Add imported variables for each instance */
10841 for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
10842 ht = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(info->cross->import_syms, scheme_make_integer(i));
10843 if (ht && ((ht->count >> 1) > SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[i]))) {
10844 Scheme_Object *sym;
10845 v = scheme_make_vector((ht->count >> 1), NULL);
10846 SCHEME_VEC_ELS(linklet->importss)[i] = v;
10847
10848 for (j = ht->count >> 1; j--; ) {
10849 sym = scheme_eq_hash_tree_get(ht, scheme_make_integer(j));
10850 MZ_ASSERT(sym);
10851 SCHEME_VEC_ELS(v)[j] = sym;
10852 }
10853 }
10854 }
10855 }
10856
10857 /* Prune unused imports (or, more precisely, tell the resolver how to prune) */
10858 total_used = 0;
10859 total = 0;
10860 for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
10861 used = 0;
10862 k = SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[i]);
10863 total += k;
10864 if (info->imports_used) {
10865 ht = (Scheme_Hash_Tree *)scheme_eq_hash_tree_get(*info->imports_used, scheme_make_integer(i));
10866 if (!ht) ht = empty_eq_hash_tree;
10867 for (j = 0; j < k; j++) {
10868 if (!scheme_eq_hash_tree_get(ht, scheme_make_integer(j))) {
10869 /* Set symbol to #f to communicate non-use to the resolve pass: */
10870 SCHEME_VEC_ELS(SCHEME_VEC_ELS(linklet->importss)[i])[j] = scheme_false;
10871 } else
10872 used++;
10873 }
10874 } else
10875 used += k;
10876 total_used += used;
10877 if (!used && _import_keys
10878 /* When a key is #f or an instance, then dropping is not allowed */
10879 && ((i >= SCHEME_VEC_SIZE(*_import_keys))
10880 || (SCHEME_TRUEP(SCHEME_VEC_ELS(*_import_keys)[i])
10881 && !SAME_TYPE(scheme_instance_type, SCHEME_TYPE(SCHEME_VEC_ELS(*_import_keys)[i]))))) {
10882 dropped_imports++;
10883 /* A number commuicates to the resolve pass that the import
10884 instance had that many variables, but we can drop it
10885 entirely */
10886 SCHEME_VEC_ELS(linklet->importss)[i] = scheme_make_integer(k);
10887 }
10888 }
10889 linklet->num_total_imports = total;
10890
10891 if (dropped_imports || added_imports) {
10892 /* Report a revised set of imports back to the client */
10893 v = scheme_make_vector(SCHEME_VEC_SIZE(linklet->importss) - dropped_imports, NULL);
10894 *_import_keys = v;
10895 used = 0;
10896 for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
10897 if (!SCHEME_INTP(SCHEME_VEC_ELS(linklet->importss)[i])) {
10898 v = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
10899 MZ_ASSERT(v);
10900 SCHEME_VEC_ELS((*_import_keys))[used++] = v;
10901 }
10902 }
10903 MZ_ASSERT(used == (SCHEME_VEC_SIZE(linklet->importss) - dropped_imports));
10904 }
10905
10906 if (info->cross && info->cross->used_import_shape) {
10907 /* The import-shapes vector needs only the imports that will be kept */
10908 shapes = scheme_make_vector(total_used, scheme_false);
10909 linklet->import_shapes = shapes;
10910 k = 0;
10911 for (i = 0; i < SCHEME_VEC_SIZE(linklet->importss); i++) {
10912 if (!SCHEME_INTP(SCHEME_VEC_ELS(linklet->importss)[i])) {
10913 v = scheme_eq_hash_tree_get(info->cross->import_keys, scheme_make_integer(i));
10914 if (v)
10915 v = scheme_eq_hash_tree_get(info->cross->linklets, v);
10916 in_linklet = ((v && SAME_TYPE(SCHEME_TYPE(v), scheme_linklet_type)) ? (Scheme_Linklet *)v : NULL);
10917 in_instance = ((v && SAME_TYPE(SCHEME_TYPE(v), scheme_instance_type)) ? (Scheme_Instance *)v : NULL);
10918 MZ_ASSERT(!in_linklet || SAME_TYPE(in_linklet->so.type, scheme_linklet_type));
10919 MZ_ASSERT(!in_instance || SAME_TYPE(in_instance->iso.so.type, scheme_instance_type));
10920 for (j = 0; j < SCHEME_VEC_SIZE(SCHEME_VEC_ELS(linklet->importss)[i]); j++) {
10921 name = SCHEME_VEC_ELS(SCHEME_VEC_ELS(linklet->importss)[i])[j];
10922 if (SCHEME_TRUEP(name)) {
10923 if (in_linklet && in_linklet->constants) {
10924 v = scheme_hash_get(in_linklet->constants, name);
10925 if (v) {
10926 if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 3)) {
10927 v = scheme_intern_struct_proc_shape(SCHEME_INT_VAL(SCHEME_VEC_ELS(v)[1]));
10928 SCHEME_VEC_ELS(shapes)[k] = v;
10929 } else if (SCHEME_VECTORP(v) && (SCHEME_VEC_SIZE(v) == 4)) {
10930 v = scheme_intern_struct_prop_proc_shape(SCHEME_INT_VAL(SCHEME_VEC_ELS(v)[1]));
10931 SCHEME_VEC_ELS(shapes)[k] = v;
10932 } else if (SCHEME_VECTORP(v)) {
10933 MZ_ASSERT(SCHEME_VEC_SIZE(v) == 2);
10934 v = scheme_get_or_check_procedure_shape(SCHEME_VEC_ELS(v)[0], NULL, 0);
10935 SCHEME_VEC_ELS(shapes)[k] = v;
10936 } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_inline_variant_type)) {
10937 v = scheme_get_or_check_procedure_shape(v, NULL, 0);
10938 SCHEME_VEC_ELS(shapes)[k] = v;
10939 } else if (SAME_OBJ(v, scheme_fixed_key)) {
10940 SCHEME_VEC_ELS(shapes)[k] = scheme_void;
10941 } else {
10942 /* anything else is constant-propagated or irrelevant */
10943 }
10944 }
10945 } else if (in_instance) {
10946 b = scheme_instance_variable_bucket_or_null(name, in_instance);
10947 if (b && b->val && (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_IS_CONSISTENT)) {
10948 int imprecise = SCHEME_INSTANCE_FLAGS(in_instance) & SCHEME_INSTANCE_USE_IMPRECISE;
10949 v = get_value_shape(b->val, imprecise);
10950 if (v) {
10951 if (SAME_TYPE(SCHEME_TYPE(v), scheme_struct_proc_shape_type))
10952 v = scheme_intern_struct_proc_shape(SCHEME_PROC_SHAPE_MODE(v));
10953 else if (SAME_TYPE(SCHEME_TYPE(v), scheme_struct_prop_proc_shape_type))
10954 v = scheme_intern_struct_prop_proc_shape(SCHEME_PROP_PROC_SHAPE_MODE(v));
10955 SCHEME_VEC_ELS(shapes)[k] = v;
10956 } else
10957 SCHEME_VEC_ELS(shapes)[k] = scheme_void;
10958 }
10959 }
10960 k++;
10961 }
10962 }
10963 }
10964 }
10965 MZ_ASSERT(k == total_used);
10966 }
10967 }
10968
get_value_shape(Scheme_Object * v,int imprecise)10969 static Scheme_Object *get_value_shape(Scheme_Object *v, int imprecise)
10970 {
10971 intptr_t s;
10972 Scheme_Object *identity;
10973
10974 s = scheme_get_or_check_structure_shape(v, NULL);
10975 if (s != -1) {
10976 if (SCHEME_STRUCT_TYPEP(v))
10977 identity = v;
10978 else
10979 identity = SCHEME_PRIM_CLOSURE_ELS(v)[0];
10980 return scheme_make_struct_proc_shape(s, identity);
10981 }
10982
10983 s = scheme_get_or_check_structure_property_shape(v, NULL);
10984 if (s != -1)
10985 return scheme_make_struct_property_proc_shape(s);
10986
10987 return scheme_get_or_check_procedure_shape(v, NULL, imprecise);
10988 }
10989
10990 /*========================================================================*/
10991 /* precise GC traversers */
10992 /*========================================================================*/
10993
10994 #ifdef MZ_PRECISE_GC
10995
10996 START_XFORM_SKIP;
10997
10998 #include "mzmark_optimize.inc"
10999
register_traversers(void)11000 static void register_traversers(void)
11001 {
11002 GC_REG_TRAV(scheme_once_used_type, mark_once_used);
11003 GC_REG_TRAV(scheme_rt_optimize_info, mark_optimize_info);
11004 }
11005
11006 END_XFORM_SKIP;
11007
11008 #endif
11009