diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index 9d71ec5b..bba42bd9 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -269,24 +269,29 @@ std::vector pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, con std::vector pre_compile_tensor(const std::vector& args, CodeBlob &code, std::vector> *lval_globs) { - std::vector> 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> res_lists(n); struct ModifiedVar { size_t i, j; - Op* op; + std::unique_ptr* cur_ops; // `LET tmp = v_ij` will be inserted before this }; - auto modified_vars = std::make_shared>(); - for (size_t i = 0; i < args.size(); ++i) { + std::vector modified_vars; + for (size_t i = 0; i < n; ++i) { res_lists[i] = args[i]->pre_compile(code, lval_globs); for (size_t j = 0; j < res_lists[i].size(); ++j) { TmpVar& var = code.vars.at(res_lists[i][j]); if (!lval_globs && (var.cls & TmpVar::_Named)) { - Op *op = &code.emplace_back(nullptr, Op::_Let, std::vector(), std::vector()); - op->set_disabled(); - var.on_modification.push_back([modified_vars, i, j, op, done = false](const SrcLocation &here) mutable { + var.on_modification.push_back([&modified_vars, i, j, cur_ops = code.cur_ops, done = false](const SrcLocation &here) mutable { if (!done) { done = true; - modified_vars->push_back({i, j, op}); + modified_vars.push_back({i, j, cur_ops}); } }); } else { @@ -301,13 +306,16 @@ std::vector pre_compile_tensor(const std::vector& args, CodeB code.vars.at(v).on_modification.pop_back(); } } - for (const ModifiedVar &m : *modified_vars) { - var_idx_t& v = res_lists[m.i][m.j]; - var_idx_t v2 = code.create_tmp_var(code.vars[v].v_type, code.vars[v].where.get()); - m.op->left = {v2}; - m.op->right = {v}; - m.op->set_disabled(false); - v = v2; + for (size_t idx = modified_vars.size(); idx--; ) { + const ModifiedVar &m = modified_vars[idx]; + var_idx_t orig_v = res_lists[m.i][m.j]; + var_idx_t tmp_v = code.create_tmp_var(code.vars[orig_v].v_type, code.vars[orig_v].where.get()); + std::unique_ptr op = std::make_unique(*code.vars[orig_v].where, Op::_Let); + op->left = {tmp_v}; + 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 res; for (const auto& list : res_lists) { @@ -333,10 +341,7 @@ std::vector Expr::pre_compile(CodeBlob& code, std::vectoris_just_wrapper_for_another_f()) { // body is { Op::_Import; Op::_Call; Op::_Return; } - const Op *op_call = dynamic_cast(func)->code->ops.get(); - while (op_call->cl != Op::_Call) { - op_call = op_call->next.get(); - } + const std::unique_ptr& op_call = dynamic_cast(func)->code->ops->next; applied_sym = op_call->fun_ref; // 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 diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 0f17a0c3..c58732f8 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -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); // 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(); - 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) return; func_assert(op_call->left.size() == 1);