feat(library/compiler/llnf): avoid inc/dec operations on persistent objects

inc/dec operations are noop's for persistent objects.
This commit is contained in:
Leonardo de Moura 2019-02-18 20:17:15 -08:00
parent ddab7bcea8
commit feea8ecccd
4 changed files with 76 additions and 54 deletions

View file

@ -51,7 +51,7 @@ do emit $ sformat! "obj* apply_{n}(obj* f, {arg_decls}) {{\n",
emit "unsigned arity = closure_arity(f);\n",
emit "unsigned fixed = closure_num_fixed(f);\n",
emit $ sformat! "if (arity == fixed + {n}) {{\n",
emit $ sformat! " if (!is_shared(f)) {{\n",
emit $ sformat! " if (is_exclusive(f)) {{\n",
emit $ sformat! " switch (arity) {{\n",
max.mrepeat $ λ i, do {
let j := i + 1,
@ -152,7 +152,7 @@ static obj* fix_args(obj* f, unsigned n, obj*const* as) {
obj * r = alloc_closure(closure_fun(f), arity, new_fixed);
obj ** source = closure_arg_cptr(f);
obj ** target = closure_arg_cptr(r);
if (is_shared(f)) {
if (!is_exclusive(f)) {
for (unsigned i = 0; i < fixed; i++, source++, target++) {
*target = *source;
inc(*target);

View file

@ -250,7 +250,7 @@ inline name const & let_name(expr const & e) { lean_assert(is_le
inline expr const & let_type(expr const & e) { lean_assert(is_let(e)); return static_cast<expr const &>(cnstr_get_ref(e, 1)); }
inline expr const & let_value(expr const & e) { lean_assert(is_let(e)); return static_cast<expr const &>(cnstr_get_ref(e, 2)); }
inline expr const & let_body(expr const & e) { lean_assert(is_let(e)); return static_cast<expr const &>(cnstr_get_ref(e, 3)); }
inline bool is_shared(expr const & e) { return is_shared(e.raw()); }
inline bool is_shared(expr const & e) { return !is_exclusive(e.raw()); }
//
// =======================================

View file

@ -1445,8 +1445,9 @@ class explicit_rc_fn {
buffer<expr> m_fvars;
name m_x;
unsigned m_next_idx{1};
name_set m_borrowed; /* Set of variables marked as borrowed. */
name_set m_is_borrowed; /* Set of variables marked as borrowed. */
name_set m_is_scalar; /* Set of variables of type `_obj` that are known to be a boxed scalar value. */
name_set m_is_persistent;
static bool is_jmp(expr const & e) {
return is_llnf_jmp(get_app_fn(e));
@ -1474,10 +1475,28 @@ class explicit_rc_fn {
return r;
}
expr mk_let_decl(expr const & type, expr const & e) {
expr fvar = m_lctx.mk_local_decl(ngen(), next_name(), type, e);
m_fvars.push_back(fvar);
return fvar;
bool is_borrowed(name const & fvar) const {
return m_is_borrowed.contains(fvar);
}
bool is_borrowed(expr const & fvar) const {
return is_borrowed(fvar_name(fvar));
}
bool is_boxed_scalar(name const & fvar) const {
return m_is_scalar.contains(fvar);
}
bool is_boxed_scalar(expr const & fvar) const {
return is_boxed_scalar(fvar_name(fvar));
}
bool is_persistent(name const & fvar) const {
return m_is_persistent.contains(fvar);
}
bool is_persistent(expr const & fvar) const {
return is_persistent(fvar_name(fvar));
}
void collect_live_vars_core(expr e, name_set & visited_jp, name_set & r) {
@ -1604,7 +1623,7 @@ class explicit_rc_fn {
lean_assert(args.size() == borrowed_args.size());
unsigned n = get_num_consumptions(arg, args, borrowed_args);
if (n > 0) { /* arg is consumed by f at least once */
if (m_borrowed.contains(fvar_name(arg)) || /* arg is marked as borrowed, that is, it does not need to be consumed */
if (is_borrowed(arg) || /* arg is marked as borrowed, that is, it does not need to be consumed */
live_obj_vars.contains(fvar_name(arg)) || /* arg is alive after application */
is_borrowed_arg(arg, args, borrowed_args)) { /* arg is also borrowed by f */
/* We must add n increments */
@ -1649,14 +1668,15 @@ class explicit_rc_fn {
expr const & arg = args[i];
if (is_fvar(arg) &&
!is_unboxed(get_type_of(arg)) && /* it is not a unboxed/scalar value */
!m_is_scalar.contains(fvar_name(arg)) && /* it is not known to be a scalar here */
!is_persistent(arg) &&
!is_boxed_scalar(arg) && /* it is not known to be a scalar here */
is_first_occur(arg, i, args)) {
unsigned n = get_num_incs(arg, args, f_borrowed_args, live_obj_vars);
if (n > 0) {
incs.emplace_back(arg, n);
}
/* Check if we need to add a decrement. */
if (!m_borrowed.contains(fvar_name(arg)) && /* arg is not marked as borrowed */
if (!is_borrowed(arg) && /* arg is not marked as borrowed */
!live_obj_vars.contains(fvar_name(arg)) && /* arg is not live after the f-application */
is_borrowed_arg(arg, args, f_borrowed_args)) { /* arg has been borrowed by f */
/* We must add 1 decrement. */
@ -1711,7 +1731,7 @@ class explicit_rc_fn {
expr val = get_value_of(x);
lean_assert(is_app(val) && is_llnf_proj(app_fn(val)));
expr arg = app_arg(val);
if (!m_borrowed.contains(fvar_name(arg)) && /* arg is not marked as borrowed */
if (!is_borrowed(arg) && /* arg is not marked as borrowed */
!live_obj_vars.contains(fvar_name(arg))) { /* arg is not live after projection */
/* We must add decrement. */
add_dec(arg, entries);
@ -1773,7 +1793,8 @@ class explicit_rc_fn {
expr const & arg = args[i];
if (is_fvar(arg) &&
!is_unboxed(get_type_of(arg)) && /* it is not a unboxed/scalar value */
!m_is_scalar.contains(fvar_name(arg)) &&
!is_persistent(arg) &&
!is_boxed_scalar(arg) &&
is_first_occur(arg, i, args)) {
unsigned n = get_num_incs(arg, args, borrowed_args, name_set());
if (n > 0) {
@ -1830,8 +1851,9 @@ class explicit_rc_fn {
/* We must decrement (non-borrowed) variables that are live at `cases_live_vars`, but are not live at `arg_live_vars`. */
cases_live_vars.for_each([&](name const & x_name) {
if (!arg_live_vars.contains(x_name) &&
!m_is_scalar.contains(x_name) &&
!m_borrowed.contains(x_name)) {
!is_persistent(x_name) &&
!is_boxed_scalar(x_name) &&
!is_borrowed(x_name)) {
local_decl x_decl = m_lctx.get_local_decl(x_name);
if (!is_unboxed(x_decl.get_type())) {
expr x = x_decl.mk_ref();
@ -1858,8 +1880,9 @@ class explicit_rc_fn {
return e;
} else if (is_fvar(e)) {
/* If it is marked as borrowed, we should insert `inc`. */
if (m_borrowed.contains(fvar_name(e)) && is_obj(e) &&
!m_is_scalar.contains(fvar_name(e))) {
if (is_borrowed(e) && is_obj(e) &&
!is_persistent(e) &&
!is_boxed_scalar(e)) {
add_inc(e, entries);
}
return e;
@ -1935,7 +1958,7 @@ class explicit_rc_fn {
expr new_fvar = m_lctx.mk_local_decl(ngen(), next_name(), binding_domain(e), binding_info(e));
lean_assert(i < borrowed.size());
if (borrowed[i])
m_borrowed.insert(fvar_name(new_fvar));
m_is_borrowed.insert(fvar_name(new_fvar));
binding_fvars.push_back(new_fvar);
e = binding_body(e);
i++;
@ -1963,7 +1986,7 @@ class explicit_rc_fn {
if (is_lit(val)) {
return false;
} else if (is_constant(val)) {
return !is_llnf_cnstr(val);
return false;
} else if (is_app(val)) {
buffer<expr> args;
expr const & fn = get_app_args(val, args);
@ -2000,20 +2023,27 @@ class explicit_rc_fn {
lit_value(e).get_nat() <= LEAN_MAX_SMALL_NAT);
}
expr mk_fvar(name const & n, expr const & type, expr const & val) {
expr new_fvar = m_lctx.mk_local_decl(ngen(), n, type, val);
m_fvars.push_back(new_fvar);
if (should_mark_as_borrowed(val)) {
m_is_borrowed.insert(fvar_name(new_fvar));
}
if (is_boxed_scalar(type, val)) {
m_is_scalar.insert(fvar_name(new_fvar));
}
if (is_constant(val) && !is_llnf_cnstr(val)) {
m_is_persistent.insert(fvar_name(new_fvar));
}
return new_fvar;
}
/* Make sure `e` is a cases, jmp or fvar */
expr ensure_terminal(expr const & e) {
if (!is_cases_on_app(env(), e) && !is_jmp(e) && !is_fvar(e)) {
/* ensure that `e` is a cases, jmp or fvar */
expr type = ll_infer_type(m_env, m_lctx, e);
expr new_fvar = m_lctx.mk_local_decl(ngen(), "_res", type, e);
if (should_mark_as_borrowed(e)) {
m_borrowed.insert(fvar_name(new_fvar));
}
if (is_boxed_scalar(type, e)) {
m_is_scalar.insert(fvar_name(new_fvar));
}
m_fvars.push_back(new_fvar);
return new_fvar;
return mk_fvar("_res", type, e);
} else {
return e;
}
@ -2033,16 +2063,8 @@ class explicit_rc_fn {
n = next_name();
}
expr type = let_type(e);
expr new_fvar = m_lctx.mk_local_decl(ngen(), n, type, val);
if (should_mark_as_borrowed(val)) {
/* Remark: it is incorrect to mark it at `process`. */
m_borrowed.insert(fvar_name(new_fvar));
}
if (is_boxed_scalar(type, val)) {
m_is_scalar.insert(fvar_name(new_fvar));
}
expr new_fvar = mk_fvar(n, type, val);
fvars.push_back(new_fvar);
m_fvars.push_back(new_fvar);
}
e = let_body(e);
}

View file

@ -19,7 +19,7 @@ static obj* fix_args(obj* f, unsigned n, obj*const* as) {
obj * r = alloc_closure(closure_fun(f), arity, new_fixed);
obj ** source = closure_arg_cptr(f);
obj ** target = closure_arg_cptr(r);
if (is_shared(f)) {
if (!is_exclusive(f)) {
for (unsigned i = 0; i < fixed; i++, source++, target++) {
*target = *source;
inc(*target);
@ -101,7 +101,7 @@ obj* apply_1(obj* f, obj* a1) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 1) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 1: { obj* r = FN1(f)(a1); free_heap_obj(f); return r; }
case 2: { obj* r = FN2(f)(fx(0), a1); free_heap_obj(f); return r; }
@ -159,7 +159,7 @@ obj* apply_2(obj* f, obj* a1, obj* a2) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 2) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 2: { obj* r = FN2(f)(a1, a2); free_heap_obj(f); return r; }
case 3: { obj* r = FN3(f)(fx(0), a1, a2); free_heap_obj(f); return r; }
@ -220,7 +220,7 @@ obj* apply_3(obj* f, obj* a1, obj* a2, obj* a3) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 3) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 3: { obj* r = FN3(f)(a1, a2, a3); free_heap_obj(f); return r; }
case 4: { obj* r = FN4(f)(fx(0), a1, a2, a3); free_heap_obj(f); return r; }
@ -279,7 +279,7 @@ obj* apply_4(obj* f, obj* a1, obj* a2, obj* a3, obj* a4) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 4) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 4: { obj* r = FN4(f)(a1, a2, a3, a4); free_heap_obj(f); return r; }
case 5: { obj* r = FN5(f)(fx(0), a1, a2, a3, a4); free_heap_obj(f); return r; }
@ -336,7 +336,7 @@ obj* apply_5(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 5) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 5: { obj* r = FN5(f)(a1, a2, a3, a4, a5); free_heap_obj(f); return r; }
case 6: { obj* r = FN6(f)(fx(0), a1, a2, a3, a4, a5); free_heap_obj(f); return r; }
@ -391,7 +391,7 @@ obj* apply_6(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6) {
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 6) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 6: { obj* r = FN6(f)(a1, a2, a3, a4, a5, a6); free_heap_obj(f); return r; }
case 7: { obj* r = FN7(f)(fx(0), a1, a2, a3, a4, a5, a6); free_heap_obj(f); return r; }
@ -444,7 +444,7 @@ obj* apply_7(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 7) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 7: { obj* r = FN7(f)(a1, a2, a3, a4, a5, a6, a7); free_heap_obj(f); return r; }
case 8: { obj* r = FN8(f)(fx(0), a1, a2, a3, a4, a5, a6, a7); free_heap_obj(f); return r; }
@ -495,7 +495,7 @@ obj* apply_8(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 8) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 8: { obj* r = FN8(f)(a1, a2, a3, a4, a5, a6, a7, a8); free_heap_obj(f); return r; }
case 9: { obj* r = FN9(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8); free_heap_obj(f); return r; }
@ -544,7 +544,7 @@ obj* apply_9(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 9) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 9: { obj* r = FN9(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9); free_heap_obj(f); return r; }
case 10: { obj* r = FN10(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9); free_heap_obj(f); return r; }
@ -591,7 +591,7 @@ obj* apply_10(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 10) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 10: { obj* r = FN10(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); free_heap_obj(f); return r; }
case 11: { obj* r = FN11(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); free_heap_obj(f); return r; }
@ -636,7 +636,7 @@ obj* apply_11(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 11) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 11: { obj* r = FN11(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); free_heap_obj(f); return r; }
case 12: { obj* r = FN12(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); free_heap_obj(f); return r; }
@ -679,7 +679,7 @@ obj* apply_12(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 12) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 12: { obj* r = FN12(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); free_heap_obj(f); return r; }
case 13: { obj* r = FN13(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); free_heap_obj(f); return r; }
@ -720,7 +720,7 @@ obj* apply_13(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 13) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 13: { obj* r = FN13(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); free_heap_obj(f); return r; }
case 14: { obj* r = FN14(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); free_heap_obj(f); return r; }
@ -759,7 +759,7 @@ obj* apply_14(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 14) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 14: { obj* r = FN14(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); free_heap_obj(f); return r; }
case 15: { obj* r = FN15(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); free_heap_obj(f); return r; }
@ -796,7 +796,7 @@ obj* apply_15(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 15) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 15: { obj* r = FN15(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); free_heap_obj(f); return r; }
case 16: { obj* r = FN16(f)(fx(0), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); free_heap_obj(f); return r; }
@ -831,7 +831,7 @@ obj* apply_16(obj* f, obj* a1, obj* a2, obj* a3, obj* a4, obj* a5, obj* a6, obj*
unsigned arity = closure_arity(f);
unsigned fixed = closure_num_fixed(f);
if (arity == fixed + 16) {
if (!is_shared(f)) {
if (is_exclusive(f)) {
switch (arity) {
case 16: { obj* r = FN16(f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); free_heap_obj(f); return r; }
}