mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
Add complex assigns to FunC and fix UB (#574)
* Fixed complex funC setglob cases * Forbid modifying local variables after using them in the same tensor * Fix analyzing "while" in func * Update funC version (#9) * Update stress tester * Fix using variable after move Co-authored-by: krigga <krigga7@gmail.com> Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
7347ec0b3b
commit
a1d8a5e4f3
4 changed files with 83 additions and 19 deletions
|
@ -810,6 +810,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
break;
|
||||
}
|
||||
case _While: {
|
||||
auto values0 = values;
|
||||
values = block0->fwd_analyze(values);
|
||||
if (values[left[0]] && values[left[0]]->always_false()) {
|
||||
// block1 never executed
|
||||
|
@ -817,7 +818,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
break;
|
||||
}
|
||||
while (true) {
|
||||
VarDescrList next_values = values | block0->fwd_analyze(block1->fwd_analyze(values));
|
||||
VarDescrList next_values = values | block0->fwd_analyze(values0 | block1->fwd_analyze(values));
|
||||
if (same_values(next_values, values)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -137,13 +137,20 @@ class CodeRepeat(Code):
|
|||
self.c.write(f, indent + 1)
|
||||
print(" " * (indent + 1) + "%s += 1;" % var, file=f)
|
||||
print(" " * indent + "}", file=f)
|
||||
else:
|
||||
elif self.loop_type == 2:
|
||||
var = gen_var_name()
|
||||
print(" " * indent + "int %s = 0;" % var, file=f)
|
||||
print(" " * indent + "do {", file=f)
|
||||
self.c.write(f, indent + 1)
|
||||
print(" " * (indent + 1) + "%s += 1;" % var, file=f)
|
||||
print(" " * indent + "} until (%s >= %d);" % (var, self.n), file=f)
|
||||
else:
|
||||
var = gen_var_name()
|
||||
print(" " * indent + "int %s = %d;" % (var, self.n - 1), file=f)
|
||||
print(" " * indent + "while (%s >= 0) {" % var, file=f)
|
||||
self.c.write(f, indent + 1)
|
||||
print(" " * (indent + 1) + "%s -= 1;" % var, file=f)
|
||||
print(" " * indent + "}", file=f)
|
||||
|
||||
class CodeThrow(Code):
|
||||
def __init__(self):
|
||||
|
@ -199,7 +206,7 @@ def gen_code(xl, xr, with_return, loop_depth=0, try_catch_depth=0, can_throw=Fal
|
|||
for _ in range(random.randint(0, 2)):
|
||||
if random.randint(0, 3) == 0 and loop_depth < 3:
|
||||
c = gen_code(xl, xr, False, loop_depth + 1, try_catch_depth, can_throw)
|
||||
code.append(CodeRepeat(random.randint(0, 3), c, random.randint(0, 2)))
|
||||
code.append(CodeRepeat(random.randint(0, 3), c, random.randint(0, 3)))
|
||||
elif xr - xl > 1:
|
||||
xmid = random.randrange(xl + 1, xr)
|
||||
ret = random.choice((0, 0, 0, 0, 0, 1, 2))
|
||||
|
|
|
@ -39,7 +39,7 @@ extern std::string generated_from;
|
|||
|
||||
constexpr int optimize_depth = 20;
|
||||
|
||||
const std::string func_version{"0.3.0"};
|
||||
const std::string func_version{"0.4.0"};
|
||||
|
||||
enum Keyword {
|
||||
_Eof = -1,
|
||||
|
@ -306,10 +306,16 @@ struct TmpVar {
|
|||
sym_idx_t name;
|
||||
int coord;
|
||||
std::unique_ptr<SrcLocation> where;
|
||||
size_t modify_forbidden = 0;
|
||||
TmpVar(var_idx_t _idx, int _cls, TypeExpr* _type = 0, SymDef* sym = 0, const SrcLocation* loc = 0);
|
||||
void show(std::ostream& os, int omit_idx = 0) const;
|
||||
void dump(std::ostream& os) const;
|
||||
void set_location(const SrcLocation& loc);
|
||||
std::string to_string() const {
|
||||
std::ostringstream s;
|
||||
show(s, 2);
|
||||
return s.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct VarDescr {
|
||||
|
@ -722,6 +728,22 @@ struct CodeBlob {
|
|||
void mark_noreturn();
|
||||
void generate_code(AsmOpList& out_list, int mode = 0);
|
||||
void generate_code(std::ostream& os, int mode = 0, int indent = 0);
|
||||
|
||||
void mark_modify_forbidden(var_idx_t idx) {
|
||||
++vars.at(idx).modify_forbidden;
|
||||
}
|
||||
|
||||
void unmark_modify_forbidden(var_idx_t idx) {
|
||||
assert(vars.at(idx).modify_forbidden > 0);
|
||||
--vars.at(idx).modify_forbidden;
|
||||
}
|
||||
|
||||
void check_modify_forbidden(var_idx_t idx, const SrcLocation& here) const {
|
||||
if (vars.at(idx).modify_forbidden) {
|
||||
throw src::ParseError{here, PSTRING() << "Modifying local variable " << vars[idx].to_string()
|
||||
<< " after using it in the same expression"};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -925,7 +947,7 @@ struct Expr {
|
|||
}
|
||||
int define_new_vars(CodeBlob& code);
|
||||
int predefine_vars();
|
||||
std::vector<var_idx_t> pre_compile(CodeBlob& code, bool lval = false) const;
|
||||
std::vector<var_idx_t> pre_compile(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>* lval_globs = nullptr) const;
|
||||
static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here);
|
||||
var_idx_t new_tmp(CodeBlob& code) const;
|
||||
std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const {
|
||||
|
|
|
@ -221,6 +221,13 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const {
|
|||
return code.create_tmp_var(e_type, &here);
|
||||
}
|
||||
|
||||
void add_set_globs(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>& globs, const SrcLocation& here) {
|
||||
for (const auto& p : globs) {
|
||||
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, std::vector<var_idx_t>{ p.second }, p.first);
|
||||
op.flags |= Op::_Impure;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) {
|
||||
while (lhs->is_type_apply()) {
|
||||
lhs = lhs->args.at(0);
|
||||
|
@ -245,19 +252,18 @@ std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rh
|
|||
return tmp;
|
||||
}
|
||||
auto right = rhs->pre_compile(code);
|
||||
if (lhs->cls == Expr::_GlobVar) {
|
||||
assert(lhs->sym);
|
||||
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, lhs->sym);
|
||||
op.flags |= Op::_Impure;
|
||||
} else {
|
||||
auto left = lhs->pre_compile(code, true);
|
||||
code.emplace_back(here, Op::_Let, std::move(left), right);
|
||||
std::vector<std::pair<SymDef*, var_idx_t>> globs;
|
||||
auto left = lhs->pre_compile(code, &globs);
|
||||
for (var_idx_t v : left) {
|
||||
code.check_modify_forbidden(v, here);
|
||||
}
|
||||
code.emplace_back(here, Op::_Let, std::move(left), right);
|
||||
add_set_globs(code, globs, here);
|
||||
return right;
|
||||
}
|
||||
|
||||
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
||||
if (lval && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply)) {
|
||||
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>* lval_globs) const {
|
||||
if (lval_globs && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply || cls == _GlobVar)) {
|
||||
std::cerr << "lvalue expression constructor is " << cls << std::endl;
|
||||
throw src::Fatal{"cannot compile lvalue expression with unknown constructor"};
|
||||
}
|
||||
|
@ -265,9 +271,15 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
case _Tensor: {
|
||||
std::vector<var_idx_t> res;
|
||||
for (const auto& x : args) {
|
||||
auto add = x->pre_compile(code, lval);
|
||||
auto add = x->pre_compile(code, lval_globs);
|
||||
for (var_idx_t v : add) {
|
||||
code.mark_modify_forbidden(v);
|
||||
}
|
||||
res.insert(res.end(), add.cbegin(), add.cend());
|
||||
}
|
||||
for (var_idx_t v : res) {
|
||||
code.unmark_modify_forbidden(v);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
case _Apply: {
|
||||
|
@ -279,6 +291,9 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
std::vector<std::vector<var_idx_t>> add_list(args.size());
|
||||
for (int i : func->arg_order) {
|
||||
add_list[i] = args[i]->pre_compile(code);
|
||||
for (var_idx_t v : add_list[i]) {
|
||||
code.mark_modify_forbidden(v);
|
||||
}
|
||||
}
|
||||
for (const auto& add : add_list) {
|
||||
res.insert(res.end(), add.cbegin(), add.cend());
|
||||
|
@ -286,9 +301,15 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
} else {
|
||||
for (const auto& x : args) {
|
||||
auto add = x->pre_compile(code);
|
||||
for (var_idx_t v : add) {
|
||||
code.mark_modify_forbidden(v);
|
||||
}
|
||||
res.insert(res.end(), add.cbegin(), add.cend());
|
||||
}
|
||||
}
|
||||
for (var_idx_t v : res) {
|
||||
code.unmark_modify_forbidden(v);
|
||||
}
|
||||
auto rvect = new_tmp_vect(code);
|
||||
auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), sym);
|
||||
if (flags & _IsImpure) {
|
||||
|
@ -297,7 +318,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
return rvect;
|
||||
}
|
||||
case _TypeApply:
|
||||
return args[0]->pre_compile(code, lval);
|
||||
return args[0]->pre_compile(code, lval_globs);
|
||||
case _Var:
|
||||
case _Hole:
|
||||
return {val};
|
||||
|
@ -329,8 +350,13 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
case _Glob:
|
||||
case _GlobVar: {
|
||||
auto rvect = new_tmp_vect(code);
|
||||
code.emplace_back(here, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, sym);
|
||||
return rvect;
|
||||
if (lval_globs) {
|
||||
lval_globs->push_back({ sym, rvect[0] });
|
||||
return rvect;
|
||||
} else {
|
||||
code.emplace_back(here, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, sym);
|
||||
return rvect;
|
||||
}
|
||||
}
|
||||
case _Letop: {
|
||||
return pre_compile_let(code, args.at(0), args.at(1), here);
|
||||
|
@ -338,9 +364,17 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
case _LetFirst: {
|
||||
auto rvect = new_tmp_vect(code);
|
||||
auto right = args[1]->pre_compile(code);
|
||||
auto left = args[0]->pre_compile(code, true);
|
||||
std::vector<std::pair<SymDef*, var_idx_t>> local_globs;
|
||||
if (!lval_globs) {
|
||||
lval_globs = &local_globs;
|
||||
}
|
||||
auto left = args[0]->pre_compile(code, lval_globs);
|
||||
left.push_back(rvect[0]);
|
||||
for (var_idx_t v : left) {
|
||||
code.check_modify_forbidden(v, here);
|
||||
}
|
||||
code.emplace_back(here, Op::_Let, std::move(left), std::move(right));
|
||||
add_set_globs(code, local_globs, here);
|
||||
return rvect;
|
||||
}
|
||||
case _MkTuple: {
|
||||
|
|
Loading…
Reference in a new issue