remove a useless compiler transformation

The bytecode compiler used to convert an expresison like

  (<flonum-op> <simple-expr> <complex-expr>)

to

 (let ([id <complex-expr>])
   (<flonum-op> <simple-expr> id))

to help an older version of the JIT avoid boxing the result of
<simple-expr>, but that transformation isn't needed, since the JIT can
keep unboxed values on the stack.

The transformation was complex and apparently buggy.

The changes also include a repair to the JIT for code that the
bytecode compiler formerly wouldn't generate, but which is allowed
bytecode.

Closes PR 13052
This commit is contained in:
Matthew Flatt 2012-08-22 15:48:29 -06:00
parent b7f9c77069
commit c9a7d310ca
4 changed files with 50 additions and 261 deletions

View File

@ -128,6 +128,11 @@ static int is_unboxing_immediate(Scheme_Object *obj, int unsafely)
return 1; return 1;
return unsafely; return unsafely;
case scheme_toplevel_type: case scheme_toplevel_type:
/* Can generalize to allow any toplevel if scheme_generate_pop_unboxed() is fixed */
if ((SCHEME_TOPLEVEL_FLAGS(obj) & SCHEME_TOPLEVEL_FLAGS_MASK) < SCHEME_TOPLEVEL_READY)
return 0;
return unsafely;
break;
case scheme_local_unbox_type: case scheme_local_unbox_type:
return unsafely; return unsafely;
break; break;

View File

@ -1414,8 +1414,7 @@ static int is_nonmutating_primitive(Scheme_Object *rator, int n)
#define IS_NAMED_PRIM(p, nm) (!strcmp(((Scheme_Primitive_Proc *)p)->name, nm)) #define IS_NAMED_PRIM(p, nm) (!strcmp(((Scheme_Primitive_Proc *)p)->name, nm))
int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos, int rotate_mode) int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos)
/* In rotate mode, we really want to know whether any argument wants to be lifted out. */
{ {
if (SCHEME_PRIMP(rator)) { if (SCHEME_PRIMP(rator)) {
if (SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING) { if (SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING) {
@ -1432,12 +1431,9 @@ int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos, int rotate_m
|| IS_NAMED_PRIM(rator, "unsafe-fl>=") || IS_NAMED_PRIM(rator, "unsafe-fl>=")
|| IS_NAMED_PRIM(rator, "unsafe-flmin") || IS_NAMED_PRIM(rator, "unsafe-flmin")
|| IS_NAMED_PRIM(rator, "unsafe-flmax") || IS_NAMED_PRIM(rator, "unsafe-flmax")
|| (!rotate_mode && IS_NAMED_PRIM(rator, "unsafe-fl->fx")) || IS_NAMED_PRIM(rator, "unsafe-fl->fx"))
|| (rotate_mode && IS_NAMED_PRIM(rator, "unsafe-flvector-ref"))
|| (rotate_mode && IS_NAMED_PRIM(rator, "unsafe-fx->fl")))
return 1; return 1;
} else if (SCHEME_PRIM_IS_SOMETIMES_INLINED(rator)) { } else if (SCHEME_PRIM_IS_SOMETIMES_INLINED(rator)) {
if (!rotate_mode) {
if (IS_NAMED_PRIM(rator, "flabs") if (IS_NAMED_PRIM(rator, "flabs")
|| IS_NAMED_PRIM(rator, "flsqrt") || IS_NAMED_PRIM(rator, "flsqrt")
|| IS_NAMED_PRIM(rator, "fltruncate") || IS_NAMED_PRIM(rator, "fltruncate")
@ -1464,11 +1460,10 @@ int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos, int rotate_m
|| IS_NAMED_PRIM(rator, "flmin") || IS_NAMED_PRIM(rator, "flmin")
|| IS_NAMED_PRIM(rator, "flmax")) || IS_NAMED_PRIM(rator, "flmax"))
return 1; return 1;
} if ((argpos == 2)
if ((rotate_mode || (argpos == 2))
&& IS_NAMED_PRIM(rator, "unsafe-flvector-set!")) && IS_NAMED_PRIM(rator, "unsafe-flvector-set!"))
return 1; return 1;
if (!rotate_mode && (argpos == 2) if ((argpos == 2)
&& IS_NAMED_PRIM(rator, "flvector-set!")) && IS_NAMED_PRIM(rator, "flvector-set!"))
return 1; return 1;
} }
@ -1477,7 +1472,7 @@ int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos, int rotate_m
return 0; return 0;
} }
static int produces_unboxed(Scheme_Object *rator, int *non_fl_args, int argc, int for_args) static int produces_unboxed(Scheme_Object *rator, int *non_fl_args, int argc)
{ {
if (SCHEME_PRIMP(rator)) { if (SCHEME_PRIMP(rator)) {
if (SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING) { if (SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_UNSAFE_NONMUTATING) {
@ -1492,13 +1487,7 @@ static int produces_unboxed(Scheme_Object *rator, int *non_fl_args, int argc, in
|| IS_NAMED_PRIM(rator, "unsafe-fl*") || IS_NAMED_PRIM(rator, "unsafe-fl*")
|| IS_NAMED_PRIM(rator, "unsafe-fl/") || IS_NAMED_PRIM(rator, "unsafe-fl/")
|| IS_NAMED_PRIM(rator, "unsafe-flmin") || IS_NAMED_PRIM(rator, "unsafe-flmin")
|| IS_NAMED_PRIM(rator, "unsafe-flmax") || IS_NAMED_PRIM(rator, "unsafe-flmax"))))
|| (for_args
&& (IS_NAMED_PRIM(rator, "unsafe-fl<")
|| IS_NAMED_PRIM(rator, "unsafe-fl<=")
|| IS_NAMED_PRIM(rator, "unsafe-fl=")
|| IS_NAMED_PRIM(rator, "unsafe-fl>")
|| IS_NAMED_PRIM(rator, "unsafe-fl>="))))))
return 1; return 1;
if (((argc == 2) && IS_NAMED_PRIM(rator, "unsafe-flvector-ref")) if (((argc == 2) && IS_NAMED_PRIM(rator, "unsafe-flvector-ref"))
|| ((argc == 1) && IS_NAMED_PRIM(rator, "unsafe-fx->fl"))) { || ((argc == 1) && IS_NAMED_PRIM(rator, "unsafe-fx->fl"))) {
@ -1536,13 +1525,7 @@ static int produces_unboxed(Scheme_Object *rator, int *non_fl_args, int argc, in
|| IS_NAMED_PRIM(rator, "fl/") || IS_NAMED_PRIM(rator, "fl/")
|| IS_NAMED_PRIM(rator, "flmin") || IS_NAMED_PRIM(rator, "flmin")
|| IS_NAMED_PRIM(rator, "flmax") || IS_NAMED_PRIM(rator, "flmax")
|| IS_NAMED_PRIM(rator, "flexpt") || IS_NAMED_PRIM(rator, "flexpt"))
|| (for_args
&& (IS_NAMED_PRIM(rator, "fl<")
|| IS_NAMED_PRIM(rator, "fl<=")
|| IS_NAMED_PRIM(rator, "fl=")
|| IS_NAMED_PRIM(rator, "fl>")
|| IS_NAMED_PRIM(rator, "fl>="))))
return 1; return 1;
if (IS_NAMED_PRIM(rator, "flvector-ref")) { if (IS_NAMED_PRIM(rator, "flvector-ref")) {
if (non_fl_args) *non_fl_args = 1; if (non_fl_args) *non_fl_args = 1;
@ -1554,66 +1537,6 @@ static int produces_unboxed(Scheme_Object *rator, int *non_fl_args, int argc, in
return 0; return 0;
} }
static int is_unboxed_argument(Scheme_Object *rand, int fuel, Optimize_Info *info, int lifted)
{
if (fuel > 0) {
switch (SCHEME_TYPE(rand)) {
case scheme_local_type:
{
/* Ok if not mutable */
int pos = SCHEME_LOCAL_POS(rand);
if (pos < lifted)
return 1;
else if (!optimize_is_mutated(info, pos - lifted))
return 1;
}
break;
case scheme_application_type:
{
Scheme_App_Rec *app = (Scheme_App_Rec *)rand;
int non_fl_args = 0;
if (produces_unboxed(app->args[0], &non_fl_args, app->num_args, 1)) {
int i;
for (i = app->num_args; i--; ) {
fuel--;
if (!is_unboxed_argument(app->args[i+1], fuel, info, lifted))
return 0;
}
return 1;
}
}
break;
case scheme_application2_type:
{
Scheme_App2_Rec *app = (Scheme_App2_Rec *)rand;
int non_fl_args = 0;
if (produces_unboxed(app->rator, &non_fl_args, 1, 1)) {
if (is_unboxed_argument(app->rand, fuel - 1, info, lifted))
return 1;
}
}
break;
case scheme_application3_type:
{
Scheme_App3_Rec *app = (Scheme_App3_Rec *)rand;
int non_fl_args = 0;
if (produces_unboxed(app->rator, &non_fl_args, 2, 1)) {
if (is_unboxed_argument(app->rand1, fuel - 1, info, lifted)
&& is_unboxed_argument(app->rand2, fuel - 2, info, lifted))
return 1;
}
}
break;
default:
if (SCHEME_TYPE(rand) > _scheme_compiled_values_types_)
return 1;
break;
}
}
return 0;
}
int scheme_expr_produces_flonum(Scheme_Object *expr) int scheme_expr_produces_flonum(Scheme_Object *expr)
{ {
while (1) { while (1) {
@ -1621,19 +1544,19 @@ int scheme_expr_produces_flonum(Scheme_Object *expr)
case scheme_application_type: case scheme_application_type:
{ {
Scheme_App_Rec *app = (Scheme_App_Rec *)expr; Scheme_App_Rec *app = (Scheme_App_Rec *)expr;
return produces_unboxed(app->args[0], NULL, app->num_args, 0); return produces_unboxed(app->args[0], NULL, app->num_args);
} }
break; break;
case scheme_application2_type: case scheme_application2_type:
{ {
Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr; Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr;
return produces_unboxed(app->rator, NULL, 1, 0); return produces_unboxed(app->rator, NULL, 1);
} }
break; break;
case scheme_application3_type: case scheme_application3_type:
{ {
Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr; Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr;
return produces_unboxed(app->rator, NULL, 2, 0); return produces_unboxed(app->rator, NULL, 2);
} }
break; break;
case scheme_compiled_let_void_type: case scheme_compiled_let_void_type:
@ -1655,144 +1578,6 @@ int scheme_expr_produces_flonum(Scheme_Object *expr)
} }
} }
static Scheme_Object *check_unbox_rotation(Scheme_Object *_app, Scheme_Object *rator, int count, Optimize_Info *info)
{
Scheme_Object *result = _app, *rand, *new_rand;
Scheme_Let_Header *inner_head = NULL;
Scheme_Compiled_Let_Value *inner = NULL;
int i, lifted = 0;
if (scheme_wants_flonum_arguments(rator, 0, 1)) {
for (i = 0; i < count; i++) {
if (count == 1)
rand = ((Scheme_App2_Rec *)_app)->rand;
else if (count == 2) {
if (i == 0)
rand = ((Scheme_App3_Rec *)_app)->rand1;
else
rand = ((Scheme_App3_Rec *)_app)->rand2;
} else
rand = ((Scheme_App_Rec *)_app)->args[i + 1];
if (!is_unboxed_argument(rand, 32, info, lifted)) {
int delta;
if (SAME_TYPE(SCHEME_TYPE(rand), scheme_compiled_let_void_type)) {
/* Rotate (<unboxed-arg-proc> (let* ([x <arg>]...) <expr>))
to (let* ([x <arg>]...) (<unboxed-arg-proc> <expr>)) */
Scheme_Let_Header *top_head = (Scheme_Let_Header *)rand, *head;
Scheme_Compiled_Let_Value *clv, *prev;
Scheme_Object *e;
int i;
top_head = head = (Scheme_Let_Header *)rand;
prev = NULL;
e = rand;
delta = 0;
while (SAME_TYPE(SCHEME_TYPE(e), scheme_compiled_let_void_type)) {
head = (Scheme_Let_Header *)e;
delta += head->count;
prev = NULL;
clv = (Scheme_Compiled_Let_Value *)head->body;
prev = NULL;
for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) {
prev = clv;
}
e = (Scheme_Object *)clv;
}
if (prev)
new_rand = prev->body;
else
new_rand = head->body;
if (inner)
inner->body = (Scheme_Object *)top_head;
else if (inner_head)
inner_head->body = (Scheme_Object *)top_head;
else
result = (Scheme_Object *)top_head;
inner = prev;
inner_head = head;
} else {
/* Rotate (<unboxed-arg-proc> <arg>) to
(let ([x <arg>]) (<unboxed-arg-proc> x)) */
Scheme_Let_Header *head;
Scheme_Compiled_Let_Value *lv;
int *flags;
head = MALLOC_ONE_TAGGED(Scheme_Let_Header);
head->iso.so.type = scheme_compiled_let_void_type;
head->count = 1;
head->num_clauses = 1;
lv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value);
lv->iso.so.type = scheme_compiled_let_value_type;
lv->count = 1;
lv->position = 0;
lv->value = rand;
flags = (int *)scheme_malloc_atomic(sizeof(int));
flags[0] = (SCHEME_WAS_USED | (1 << SCHEME_USE_COUNT_SHIFT));
if (scheme_wants_flonum_arguments(rator, i, 0))
flags[0] |= SCHEME_WAS_FLONUM_ARGUMENT;
lv->flags = flags;
head->body = (Scheme_Object *)lv;
new_rand = scheme_make_local(scheme_local_type, 0, 0);
if (inner)
inner->body = (Scheme_Object *)head;
else if (inner_head)
inner_head->body = (Scheme_Object *)head;
else
result = (Scheme_Object *)head;
inner = lv;
inner_head = head;
delta = 1;
}
if (delta) {
lifted += delta;
if (count == 1)
((Scheme_App2_Rec *)_app)->rand = scheme_false;
else if (count == 2) {
if (i == 0)
((Scheme_App3_Rec *)_app)->rand1 = scheme_false;
else
((Scheme_App3_Rec *)_app)->rand2 = scheme_false;
} else
((Scheme_App_Rec *)_app)->args[i + 1] = scheme_false;
_app = optimize_shift(_app, delta, 0);
}
if (count == 1)
((Scheme_App2_Rec *)_app)->rand = new_rand;
else if (count == 2) {
if (i == 0)
((Scheme_App3_Rec *)_app)->rand1 = new_rand;
else
((Scheme_App3_Rec *)_app)->rand2 = new_rand;
} else
((Scheme_App_Rec *)_app)->args[i + 1] = new_rand;
if (inner)
inner->body = _app;
else
inner_head->body = _app;
}
}
}
return result;
}
static Scheme_Object *finish_optimize_app(Scheme_Object *o, Optimize_Info *info, int context, int rator_flags) static Scheme_Object *finish_optimize_app(Scheme_Object *o, Optimize_Info *info, int context, int rator_flags)
{ {
switch(SCHEME_TYPE(o)) { switch(SCHEME_TYPE(o)) {
@ -1905,7 +1690,7 @@ static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info
} }
sub_context = 0; sub_context = 0;
if ((i > 0) && scheme_wants_flonum_arguments(app->args[0], i - 1, 0)) if ((i > 0) && scheme_wants_flonum_arguments(app->args[0], i - 1))
sub_context = OPT_CONTEXT_FLONUM_ARG; sub_context = OPT_CONTEXT_FLONUM_ARG;
le = scheme_optimize_expr(app->args[i], info, sub_context); le = scheme_optimize_expr(app->args[i], info, sub_context);
@ -1969,7 +1754,7 @@ static Scheme_Object *finish_optimize_application(Scheme_App_Rec *app, Optimize_
register_flonum_argument_types(app, NULL, NULL, info); register_flonum_argument_types(app, NULL, NULL, info);
return check_unbox_rotation((Scheme_Object *)app, app->args[0], app->num_args, info); return (Scheme_Object *)app;
} }
static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand) static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand)
@ -2043,7 +1828,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf
return le; return le;
} }
if (scheme_wants_flonum_arguments(app->rator, 0, 0)) if (scheme_wants_flonum_arguments(app->rator, 0))
sub_context |= OPT_CONTEXT_FLONUM_ARG; sub_context |= OPT_CONTEXT_FLONUM_ARG;
le = scheme_optimize_expr(app->rand, info, sub_context); le = scheme_optimize_expr(app->rand, info, sub_context);
@ -2188,7 +1973,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz
register_flonum_argument_types(NULL, app, NULL, info); register_flonum_argument_types(NULL, app, NULL, info);
return check_unbox_rotation((Scheme_Object *)app, app->rator, 1, info); return (Scheme_Object *)app;
} }
static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *info, int context) static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *info, int context)
@ -2222,7 +2007,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf
/* 1st arg */ /* 1st arg */
if (scheme_wants_flonum_arguments(app->rator, 0, 0)) if (scheme_wants_flonum_arguments(app->rator, 0))
sub_context |= OPT_CONTEXT_FLONUM_ARG; sub_context |= OPT_CONTEXT_FLONUM_ARG;
le = scheme_optimize_expr(app->rand1, info, sub_context); le = scheme_optimize_expr(app->rand1, info, sub_context);
@ -2230,7 +2015,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf
/* 2nd arg */ /* 2nd arg */
if (scheme_wants_flonum_arguments(app->rator, 1, 0)) if (scheme_wants_flonum_arguments(app->rator, 1))
sub_context |= OPT_CONTEXT_FLONUM_ARG; sub_context |= OPT_CONTEXT_FLONUM_ARG;
else else
sub_context &= ~OPT_CONTEXT_FLONUM_ARG; sub_context &= ~OPT_CONTEXT_FLONUM_ARG;
@ -2403,7 +2188,7 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz
register_flonum_argument_types(NULL, NULL, app, info); register_flonum_argument_types(NULL, NULL, app, info);
return check_unbox_rotation((Scheme_Object *)app, app->rator, 2, info); return (Scheme_Object *)app;
} }
Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e, Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e,

View File

@ -1211,8 +1211,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info)
Scheme_App2_Rec *app = (Scheme_App2_Rec *)((Scheme_Let_One *)body)->body; Scheme_App2_Rec *app = (Scheme_App2_Rec *)((Scheme_Let_One *)body)->body;
if (SAME_TYPE(SCHEME_TYPE(app->rand), scheme_local_type) if (SAME_TYPE(SCHEME_TYPE(app->rand), scheme_local_type)
&& (SCHEME_LOCAL_POS(app->rand) == 1)) { && (SCHEME_LOCAL_POS(app->rand) == 1)) {
if ((SCHEME_TYPE(app->rator) > _scheme_values_types_) if (SCHEME_TYPE(app->rator) > _scheme_values_types_) {
&& !scheme_wants_flonum_arguments(app->rator, 0, 1)) {
/* Move <expr> to app, and drop let-one: */ /* Move <expr> to app, and drop let-one: */
app->rand = ((Scheme_Let_One *)body)->value; app->rand = ((Scheme_Let_One *)body)->value;
scheme_reset_app2_eval_type(app); scheme_reset_app2_eval_type(app);

View File

@ -2708,7 +2708,7 @@ void scheme_optimize_info_never_inline(Optimize_Info *);
Scheme_Object *scheme_toplevel_to_flagged_toplevel(Scheme_Object *tl, int flags); Scheme_Object *scheme_toplevel_to_flagged_toplevel(Scheme_Object *tl, int flags);
int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos, int rotate_mode); int scheme_wants_flonum_arguments(Scheme_Object *rator, int argpos);
int scheme_expr_produces_flonum(Scheme_Object *expr); int scheme_expr_produces_flonum(Scheme_Object *expr);
Scheme_Object *scheme_make_compiled_syntax(Scheme_Syntax *syntax, Scheme_Object *scheme_make_compiled_syntax(Scheme_Syntax *syntax,