mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[FunC] Refactor allow-post-modification, stop producing disabled Op::_Let
Before, #pragma allow-post-modification produced Op::_Let for every tensor entity (which became non-disabled if modification really happened). Although they are stripped off by the compiler and don't affect fif output, they pollute intermediate "AST" representation (ops). Now, Op::_Let is added only if var modification actually happens (which is very uncommon for real-wise code)
This commit is contained in:
parent
1e4b20a061
commit
aee51731ce
2 changed files with 24 additions and 22 deletions
|
@ -269,24 +269,29 @@ std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, con
|
||||||
|
|
||||||
std::vector<var_idx_t> pre_compile_tensor(const std::vector<Expr *>& args, CodeBlob &code,
|
std::vector<var_idx_t> pre_compile_tensor(const std::vector<Expr *>& args, CodeBlob &code,
|
||||||
std::vector<std::pair<SymDef*, var_idx_t>> *lval_globs) {
|
std::vector<std::pair<SymDef*, var_idx_t>> *lval_globs) {
|
||||||
std::vector<std::vector<var_idx_t>> res_lists(args.size());
|
const size_t n = args.size();
|
||||||
|
if (n == 0) { // just `()`
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (n == 1) { // just `(x)`: even if x is modified (e.g. `f(x=x+2)`), there are no next arguments
|
||||||
|
return args[0]->pre_compile(code, lval_globs);
|
||||||
|
}
|
||||||
|
std::vector<std::vector<var_idx_t>> res_lists(n);
|
||||||
|
|
||||||
struct ModifiedVar {
|
struct ModifiedVar {
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
Op* op;
|
std::unique_ptr<Op>* cur_ops; // `LET tmp = v_ij` will be inserted before this
|
||||||
};
|
};
|
||||||
auto modified_vars = std::make_shared<std::vector<ModifiedVar>>();
|
std::vector<ModifiedVar> modified_vars;
|
||||||
for (size_t i = 0; i < args.size(); ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
res_lists[i] = args[i]->pre_compile(code, lval_globs);
|
res_lists[i] = args[i]->pre_compile(code, lval_globs);
|
||||||
for (size_t j = 0; j < res_lists[i].size(); ++j) {
|
for (size_t j = 0; j < res_lists[i].size(); ++j) {
|
||||||
TmpVar& var = code.vars.at(res_lists[i][j]);
|
TmpVar& var = code.vars.at(res_lists[i][j]);
|
||||||
if (!lval_globs && (var.cls & TmpVar::_Named)) {
|
if (!lval_globs && (var.cls & TmpVar::_Named)) {
|
||||||
Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector<var_idx_t>(), std::vector<var_idx_t>());
|
var.on_modification.push_back([&modified_vars, i, j, cur_ops = code.cur_ops, done = false](const SrcLocation &here) mutable {
|
||||||
op->set_disabled();
|
|
||||||
var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable {
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = true;
|
done = true;
|
||||||
modified_vars->push_back({i, j, op});
|
modified_vars.push_back({i, j, cur_ops});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -301,13 +306,16 @@ std::vector<var_idx_t> pre_compile_tensor(const std::vector<Expr *>& args, CodeB
|
||||||
code.vars.at(v).on_modification.pop_back();
|
code.vars.at(v).on_modification.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const ModifiedVar &m : *modified_vars) {
|
for (size_t idx = modified_vars.size(); idx--; ) {
|
||||||
var_idx_t& v = res_lists[m.i][m.j];
|
const ModifiedVar &m = modified_vars[idx];
|
||||||
var_idx_t v2 = code.create_tmp_var(code.vars[v].v_type, code.vars[v].where.get());
|
var_idx_t orig_v = res_lists[m.i][m.j];
|
||||||
m.op->left = {v2};
|
var_idx_t tmp_v = code.create_tmp_var(code.vars[orig_v].v_type, code.vars[orig_v].where.get());
|
||||||
m.op->right = {v};
|
std::unique_ptr<Op> op = std::make_unique<Op>(*code.vars[orig_v].where, Op::_Let);
|
||||||
m.op->set_disabled(false);
|
op->left = {tmp_v};
|
||||||
v = v2;
|
op->right = {orig_v};
|
||||||
|
op->next = std::move((*m.cur_ops));
|
||||||
|
*m.cur_ops = std::move(op);
|
||||||
|
res_lists[m.i][m.j] = tmp_v;
|
||||||
}
|
}
|
||||||
std::vector<var_idx_t> res;
|
std::vector<var_idx_t> res;
|
||||||
for (const auto& list : res_lists) {
|
for (const auto& list : res_lists) {
|
||||||
|
@ -333,10 +341,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, std::vector<std::pair<S
|
||||||
// replace `beginCell()` with `begin_cell()`
|
// replace `beginCell()` with `begin_cell()`
|
||||||
if (func && func->is_just_wrapper_for_another_f()) {
|
if (func && func->is_just_wrapper_for_another_f()) {
|
||||||
// body is { Op::_Import; Op::_Call; Op::_Return; }
|
// body is { Op::_Import; Op::_Call; Op::_Return; }
|
||||||
const Op *op_call = dynamic_cast<SymValCodeFunc*>(func)->code->ops.get();
|
const std::unique_ptr<Op>& op_call = dynamic_cast<SymValCodeFunc*>(func)->code->ops->next;
|
||||||
while (op_call->cl != Op::_Call) {
|
|
||||||
op_call = op_call->next.get();
|
|
||||||
}
|
|
||||||
applied_sym = op_call->fun_ref;
|
applied_sym = op_call->fun_ref;
|
||||||
// a function may call anotherF with shuffled arguments: f(x,y) { return anotherF(y,x) }
|
// a function may call anotherF with shuffled arguments: f(x,y) { return anotherF(y,x) }
|
||||||
// then op_call looks like (_1,_0), so use op_call->right for correct positions in Op::_Call below
|
// then op_call looks like (_1,_0), so use op_call->right for correct positions in Op::_Call below
|
||||||
|
|
|
@ -1431,10 +1431,7 @@ void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td::
|
||||||
func_assert(op_import && op_import->cl == Op::_Import);
|
func_assert(op_import && op_import->cl == Op::_Import);
|
||||||
|
|
||||||
// then Op::_Call (anotherF)
|
// then Op::_Call (anotherF)
|
||||||
// when pragma allow-post-modification, it might be prepended with empty Op::_Let todo I don't like this
|
|
||||||
const Op* op_call = op_import->next.get();
|
const Op* op_call = op_import->next.get();
|
||||||
while (op_call && op_call->cl == Op::_Let && op_call->disabled())
|
|
||||||
op_call = op_call->next.get();
|
|
||||||
if (!op_call || op_call->cl != Op::_Call)
|
if (!op_call || op_call->cl != Op::_Call)
|
||||||
return;
|
return;
|
||||||
func_assert(op_call->left.size() == 1);
|
func_assert(op_call->left.size() == 1);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue