mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
FunC: enable asserts and fix try/catch stack corruption (#699)
* FunC: enable asserts in Release * FunC: Fix analyzing infinite loops * FunC: Allow catch with one tensor argument * FunC: Fix try/catch stack corruption --------- Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
5abfe2337e
commit
583178ccb1
12 changed files with 276 additions and 129 deletions
|
@ -38,6 +38,9 @@ TmpVar::TmpVar(var_idx_t _idx, int _cls, TypeExpr* _type, SymDef* sym, const Src
|
|||
if (!_type) {
|
||||
v_type = TypeExpr::new_hole();
|
||||
}
|
||||
if (cls == _Named) {
|
||||
undefined = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TmpVar::set_location(const SrcLocation& loc) {
|
||||
|
|
|
@ -42,14 +42,14 @@ int CodeBlob::split_vars(bool strict) {
|
|||
}
|
||||
std::vector<TypeExpr*> comp_types;
|
||||
int k = var.v_type->extract_components(comp_types);
|
||||
assert(k <= 254 && n <= 0x7fff00);
|
||||
assert((unsigned)k == comp_types.size());
|
||||
func_assert(k <= 254 && n <= 0x7fff00);
|
||||
func_assert((unsigned)k == comp_types.size());
|
||||
if (k != 1) {
|
||||
var.coord = ~((n << 8) + k);
|
||||
for (int i = 0; i < k; i++) {
|
||||
auto v = create_var(vars[j].cls, comp_types[i], 0, vars[j].where.get());
|
||||
assert(v == n + i);
|
||||
assert(vars[v].idx == v);
|
||||
func_assert(v == n + i);
|
||||
func_assert(vars[v].idx == v);
|
||||
vars[v].name = vars[j].name;
|
||||
vars[v].coord = ((int)j << 8) + i + 1;
|
||||
}
|
||||
|
@ -75,9 +75,9 @@ bool CodeBlob::compute_used_code_vars() {
|
|||
}
|
||||
|
||||
bool CodeBlob::compute_used_code_vars(std::unique_ptr<Op>& ops_ptr, const VarDescrList& var_info, bool edit) const {
|
||||
assert(ops_ptr);
|
||||
func_assert(ops_ptr);
|
||||
if (!ops_ptr->next) {
|
||||
assert(ops_ptr->cl == Op::_Nop);
|
||||
func_assert(ops_ptr->cl == Op::_Nop);
|
||||
return ops_ptr->set_var_info(var_info);
|
||||
}
|
||||
return compute_used_code_vars(ops_ptr->next, var_info, edit) | ops_ptr->compute_used_vars(*this, edit);
|
||||
|
@ -346,7 +346,7 @@ bool Op::std_compute_used_vars(bool disabled) {
|
|||
}
|
||||
|
||||
bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
||||
assert(next);
|
||||
func_assert(next);
|
||||
const VarDescrList& next_var_info = next->var_info;
|
||||
if (cl == _Nop) {
|
||||
return set_var_info_except(next_var_info, left);
|
||||
|
@ -379,7 +379,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
case _Let: {
|
||||
// left = right
|
||||
std::size_t cnt = next_var_info.count_used(left);
|
||||
assert(left.size() == right.size());
|
||||
func_assert(left.size() == right.size());
|
||||
auto l_it = left.cbegin(), r_it = right.cbegin();
|
||||
VarDescrList new_var_info{next_var_info};
|
||||
new_var_info -= left;
|
||||
|
@ -500,7 +500,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
}
|
||||
changes = (new_var_info.size() == n);
|
||||
} while (changes <= edit);
|
||||
assert(left.size() == 1);
|
||||
func_assert(left.size() == 1);
|
||||
bool last = new_var_info.count_used(left) == 0;
|
||||
new_var_info += left;
|
||||
if (last) {
|
||||
|
@ -655,7 +655,7 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
|
|||
ops = std::move(op.block0);
|
||||
return false;
|
||||
}
|
||||
reach = true;
|
||||
reach = (op.cl != Op::_Again);
|
||||
break;
|
||||
}
|
||||
case Op::_TryCatch: {
|
||||
|
@ -684,7 +684,7 @@ void CodeBlob::prune_unreachable_code() {
|
|||
|
||||
void CodeBlob::fwd_analyze() {
|
||||
VarDescrList values;
|
||||
assert(ops && ops->cl == Op::_Import);
|
||||
func_assert(ops && ops->cl == Op::_Import);
|
||||
for (var_idx_t i : ops->left) {
|
||||
values += i;
|
||||
if (vars[i].v_type->is_int()) {
|
||||
|
@ -765,7 +765,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
break;
|
||||
case _Let: {
|
||||
std::vector<VarDescr> old_val;
|
||||
assert(left.size() == right.size());
|
||||
func_assert(left.size() == right.size());
|
||||
for (std::size_t i = 0; i < right.size(); i++) {
|
||||
const VarDescr* ov = values[right[i]];
|
||||
if (!ov && verbosity >= 5) {
|
||||
|
@ -780,7 +780,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
// assert(ov);
|
||||
// func_assert(ov);
|
||||
if (ov) {
|
||||
old_val.push_back(*ov);
|
||||
} else {
|
||||
|
|
109
crypto/func/auto-tests/tests/try-func.fc
Normal file
109
crypto/func/auto-tests/tests/try-func.fc
Normal file
|
@ -0,0 +1,109 @@
|
|||
int foo(int x) method_id(11) {
|
||||
try {
|
||||
if (x == 7) {
|
||||
throw(44);
|
||||
}
|
||||
return x;
|
||||
} catch (_, _) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int foo_inline(int x) inline method_id(12) {
|
||||
try {
|
||||
if (x == 7) {
|
||||
throw(44);
|
||||
}
|
||||
return x;
|
||||
} catch (_, _) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int foo_inlineref(int x) inline_ref method_id(13) {
|
||||
try {
|
||||
if (x == 7) {
|
||||
throw(44);
|
||||
}
|
||||
return x;
|
||||
} catch (_, _) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int test(int x, int y, int z) method_id(1) {
|
||||
y = foo(y);
|
||||
return x * 100 + y * 10 + z;
|
||||
}
|
||||
|
||||
int test_inline(int x, int y, int z) method_id(2) {
|
||||
y = foo_inline(y);
|
||||
return x * 100 + y * 10 + z;
|
||||
}
|
||||
|
||||
int test_inlineref(int x, int y, int z) method_id(3) {
|
||||
y = foo_inlineref(y);
|
||||
return x * 100 + y * 10 + z;
|
||||
}
|
||||
|
||||
int foo_inline_big(
|
||||
int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10,
|
||||
int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20
|
||||
) inline method_id(14) {
|
||||
try {
|
||||
if (x1 == 7) {
|
||||
throw(44);
|
||||
}
|
||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
|
||||
} catch (_, _) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int test_inline_big(int x, int y, int z) method_id(4) {
|
||||
y = foo_inline_big(
|
||||
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
||||
y + 10, y + 11, y + 12, y + 13, y + 14, y + 15, y + 16, y + 17, y + 18, y + 19);
|
||||
return x * 1000000 + y * 1000 + z;
|
||||
}
|
||||
|
||||
int foo_big(
|
||||
int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10,
|
||||
int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20
|
||||
) method_id(15) {
|
||||
try {
|
||||
if (x1 == 7) {
|
||||
throw(44);
|
||||
}
|
||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
|
||||
} catch (_, _) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int test_big(int x, int y, int z) method_id(5) {
|
||||
y = foo_big(
|
||||
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
||||
y + 10, y + 11, y + 12, y + 13, y + 14, y + 15, y + 16, y + 17, y + 18, y + 19);
|
||||
return x * 1000000 + y * 1000 + z;
|
||||
}
|
||||
|
||||
() main() {
|
||||
}
|
||||
|
||||
{-
|
||||
method_id | in | out
|
||||
TESTCASE | 1 | 1 2 3 | 123
|
||||
TESTCASE | 1 | 3 8 9 | 389
|
||||
TESTCASE | 1 | 3 7 9 | 329
|
||||
TESTCASE | 2 | 1 2 3 | 123
|
||||
TESTCASE | 2 | 3 8 9 | 389
|
||||
TESTCASE | 2 | 3 7 9 | 329
|
||||
TESTCASE | 3 | 1 2 3 | 123
|
||||
TESTCASE | 3 | 3 8 9 | 389
|
||||
TESTCASE | 3 | 3 7 9 | 329
|
||||
TESTCASE | 4 | 4 8 9 | 4350009
|
||||
TESTCASE | 4 | 4 7 9 | 4001009
|
||||
TESTCASE | 5 | 4 8 9 | 4350009
|
||||
TESTCASE | 5 | 4 7 9 | 4001009
|
||||
-}
|
|
@ -429,7 +429,7 @@ AsmOp push_const(td::RefInt256 x) {
|
|||
}
|
||||
|
||||
AsmOp compile_add(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const + y.int_const);
|
||||
|
@ -471,7 +471,7 @@ AsmOp compile_add(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
}
|
||||
|
||||
AsmOp compile_sub(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const - y.int_const);
|
||||
|
@ -504,7 +504,7 @@ AsmOp compile_sub(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
}
|
||||
|
||||
AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 1);
|
||||
func_assert(res.size() == 1 && args.size() == 1);
|
||||
VarDescr &r = res[0], &x = args[0];
|
||||
if (x.is_int_const()) {
|
||||
r.set_const(-x.int_const);
|
||||
|
@ -519,7 +519,7 @@ AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args, co
|
|||
}
|
||||
|
||||
AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const & y.int_const);
|
||||
|
@ -532,7 +532,7 @@ AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
}
|
||||
|
||||
AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const | y.int_const);
|
||||
|
@ -545,7 +545,7 @@ AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
}
|
||||
|
||||
AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(x.int_const ^ y.int_const);
|
||||
|
@ -558,7 +558,7 @@ AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
}
|
||||
|
||||
AsmOp compile_not(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 1);
|
||||
func_assert(res.size() == 1 && args.size() == 1);
|
||||
VarDescr &r = res[0], &x = args[0];
|
||||
if (x.is_int_const()) {
|
||||
r.set_const(~x.int_const);
|
||||
|
@ -638,12 +638,12 @@ AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y, const SrcLocat
|
|||
}
|
||||
|
||||
AsmOp compile_mul(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
return compile_mul_internal(res[0], args[0], args[1], where);
|
||||
}
|
||||
|
||||
AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (y.is_int_const()) {
|
||||
auto yv = y.int_const->to_long();
|
||||
|
@ -686,7 +686,7 @@ AsmOp compile_lshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, co
|
|||
|
||||
AsmOp compile_rshift(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where,
|
||||
int round_mode) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (y.is_int_const()) {
|
||||
auto yv = y.int_const->to_long();
|
||||
|
@ -755,13 +755,13 @@ AsmOp compile_div_internal(VarDescr& r, VarDescr& x, VarDescr& y, const SrcLocat
|
|||
}
|
||||
|
||||
AsmOp compile_div(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where, int round_mode) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
return compile_div_internal(res[0], args[0], args[1], where, round_mode);
|
||||
}
|
||||
|
||||
AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const src::SrcLocation& where,
|
||||
int round_mode) {
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
r.set_const(mod(x.int_const, y.int_const, round_mode));
|
||||
|
@ -802,7 +802,7 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const
|
|||
|
||||
AsmOp compile_muldiv(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation& where,
|
||||
int round_mode) {
|
||||
assert(res.size() == 1 && args.size() == 3);
|
||||
func_assert(res.size() == 1 && args.size() == 3);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1], &z = args[2];
|
||||
if (x.is_int_const() && y.is_int_const() && z.is_int_const()) {
|
||||
r.set_const(muldiv(x.int_const, y.int_const, z.int_const, round_mode));
|
||||
|
@ -923,8 +923,8 @@ int compute_compare(const VarDescr& x, const VarDescr& y, int mode) {
|
|||
}
|
||||
|
||||
AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int mode) {
|
||||
assert(mode >= 1 && mode <= 7);
|
||||
assert(res.size() == 1 && args.size() == 2);
|
||||
func_assert(mode >= 1 && mode <= 7);
|
||||
func_assert(res.size() == 1 && args.size() == 2);
|
||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||
if (x.is_int_const() && y.is_int_const()) {
|
||||
int v = compute_compare(x.int_const, y.int_const, mode);
|
||||
|
@ -935,7 +935,7 @@ AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, i
|
|||
}
|
||||
int v = compute_compare(x, y, mode);
|
||||
// std::cerr << "compute_compare(" << x << ", " << y << ", " << mode << ") = " << v << std::endl;
|
||||
assert(v);
|
||||
func_assert(v);
|
||||
if (!(v & (v - 1))) {
|
||||
r.set_const(v - (v >> 2) - 2);
|
||||
x.unused();
|
||||
|
@ -971,7 +971,7 @@ AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, i
|
|||
}
|
||||
|
||||
AsmOp compile_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
|
||||
assert(res.empty() && args.size() == 1);
|
||||
func_assert(res.empty() && args.size() == 1);
|
||||
VarDescr& x = args[0];
|
||||
if (x.is_int_const() && x.int_const->unsigned_fits_bits(11)) {
|
||||
x.unused();
|
||||
|
@ -982,7 +982,7 @@ AsmOp compile_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args, con
|
|||
}
|
||||
|
||||
AsmOp compile_cond_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool mode) {
|
||||
assert(res.empty() && args.size() == 2);
|
||||
func_assert(res.empty() && args.size() == 2);
|
||||
VarDescr &x = args[0], &y = args[1];
|
||||
std::string suff = (mode ? "IF" : "IFNOT");
|
||||
bool skip_cond = false;
|
||||
|
@ -1003,7 +1003,7 @@ AsmOp compile_cond_throw(std::vector<VarDescr>& res, std::vector<VarDescr>& args
|
|||
}
|
||||
|
||||
AsmOp compile_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
|
||||
assert(res.empty() && args.size() == 2);
|
||||
func_assert(res.empty() && args.size() == 2);
|
||||
VarDescr &x = args[1];
|
||||
if (x.is_int_const() && x.int_const->unsigned_fits_bits(11)) {
|
||||
x.unused();
|
||||
|
@ -1014,7 +1014,7 @@ AsmOp compile_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>& args,
|
|||
}
|
||||
|
||||
AsmOp compile_cond_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool mode) {
|
||||
assert(res.empty() && args.size() == 3);
|
||||
func_assert(res.empty() && args.size() == 3);
|
||||
VarDescr &x = args[1], &y = args[2];
|
||||
std::string suff = (mode ? "IF" : "IFNOT");
|
||||
bool skip_cond = false;
|
||||
|
@ -1035,7 +1035,7 @@ AsmOp compile_cond_throw_arg(std::vector<VarDescr>& res, std::vector<VarDescr>&
|
|||
}
|
||||
|
||||
AsmOp compile_bool_const(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool val) {
|
||||
assert(res.size() == 1 && args.empty());
|
||||
func_assert(res.size() == 1 && args.empty());
|
||||
VarDescr& r = res[0];
|
||||
r.set_const(val ? -1 : 0);
|
||||
return AsmOp::Const(val ? "TRUE" : "FALSE");
|
||||
|
@ -1046,7 +1046,7 @@ AsmOp compile_bool_const(std::vector<VarDescr>& res, std::vector<VarDescr>& args
|
|||
// int preload_int(slice s, int len) asm "PLDIX";
|
||||
// int preload_uint(slice s, int len) asm "PLDUX";
|
||||
AsmOp compile_fetch_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool fetch, bool sgnd) {
|
||||
assert(args.size() == 2 && res.size() == 1 + (unsigned)fetch);
|
||||
func_assert(args.size() == 2 && res.size() == 1 + (unsigned)fetch);
|
||||
auto &y = args[1], &r = res.back();
|
||||
r.val = (sgnd ? VarDescr::FiniteInt : VarDescr::FiniteUInt);
|
||||
int v = -1;
|
||||
|
@ -1069,7 +1069,7 @@ AsmOp compile_fetch_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args,
|
|||
// builder store_uint(builder b, int x, int len) asm(x b len) "STUX";
|
||||
// builder store_int(builder b, int x, int len) asm(x b len) "STIX";
|
||||
AsmOp compile_store_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool sgnd) {
|
||||
assert(args.size() == 3 && res.size() == 1);
|
||||
func_assert(args.size() == 3 && res.size() == 1);
|
||||
auto& z = args[2];
|
||||
if (z.is_int_const() && z.int_const > 0 && z.int_const <= 256) {
|
||||
z.unused();
|
||||
|
@ -1079,7 +1079,7 @@ AsmOp compile_store_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args,
|
|||
}
|
||||
|
||||
AsmOp compile_fetch_slice(std::vector<VarDescr>& res, std::vector<VarDescr>& args, bool fetch) {
|
||||
assert(args.size() == 2 && res.size() == 1 + (unsigned)fetch);
|
||||
func_assert(args.size() == 2 && res.size() == 1 + (unsigned)fetch);
|
||||
auto& y = args[1];
|
||||
int v = -1;
|
||||
if (y.is_int_const() && y.int_const > 0 && y.int_const <= 256) {
|
||||
|
@ -1094,7 +1094,7 @@ AsmOp compile_fetch_slice(std::vector<VarDescr>& res, std::vector<VarDescr>& arg
|
|||
|
||||
// <type> <type>_at(tuple t, int index) asm "INDEXVAR";
|
||||
AsmOp compile_tuple_at(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
|
||||
assert(args.size() == 2 && res.size() == 1);
|
||||
func_assert(args.size() == 2 && res.size() == 1);
|
||||
auto& y = args[1];
|
||||
if (y.is_int_const() && y.int_const >= 0 && y.int_const < 16) {
|
||||
y.unused();
|
||||
|
@ -1105,7 +1105,7 @@ AsmOp compile_tuple_at(std::vector<VarDescr>& res, std::vector<VarDescr>& args,
|
|||
|
||||
// int null?(X arg)
|
||||
AsmOp compile_is_null(std::vector<VarDescr>& res, std::vector<VarDescr>& args, const SrcLocation&) {
|
||||
assert(args.size() == 1 && res.size() == 1);
|
||||
func_assert(args.size() == 1 && res.size() == 1);
|
||||
auto &x = args[0], &r = res[0];
|
||||
if (x.always_null() || x.always_not_null()) {
|
||||
x.unused();
|
||||
|
@ -1118,7 +1118,7 @@ AsmOp compile_is_null(std::vector<VarDescr>& res, std::vector<VarDescr>& args, c
|
|||
|
||||
bool compile_run_method(AsmOpList& code, std::vector<VarDescr>& res, std::vector<VarDescr>& args, int n,
|
||||
bool has_value) {
|
||||
assert(args.size() == (unsigned)n + 1 && res.size() == (unsigned)has_value);
|
||||
func_assert(args.size() == (unsigned)n + 1 && res.size() == (unsigned)has_value);
|
||||
auto& x = args[0];
|
||||
if (x.is_int_const() && x.int_const->unsigned_fits_bits(14)) {
|
||||
x.unused();
|
||||
|
|
|
@ -165,7 +165,7 @@ void Stack::push_new_const(var_idx_t idx, const_idx_t cidx) {
|
|||
|
||||
void Stack::assign_var(var_idx_t new_idx, var_idx_t old_idx) {
|
||||
int i = find(old_idx);
|
||||
assert(i >= 0 && "variable not found in stack");
|
||||
func_assert(i >= 0 && "variable not found in stack");
|
||||
if (new_idx != old_idx) {
|
||||
at(i).first = new_idx;
|
||||
modified();
|
||||
|
@ -174,10 +174,10 @@ void Stack::assign_var(var_idx_t new_idx, var_idx_t old_idx) {
|
|||
|
||||
void Stack::do_copy_var(var_idx_t new_idx, var_idx_t old_idx) {
|
||||
int i = find(old_idx);
|
||||
assert(i >= 0 && "variable not found in stack");
|
||||
func_assert(i >= 0 && "variable not found in stack");
|
||||
if (find(old_idx, i + 1) < 0) {
|
||||
issue_push(i);
|
||||
assert(at(0).first == old_idx);
|
||||
func_assert(at(0).first == old_idx);
|
||||
}
|
||||
assign_var(new_idx, old_idx);
|
||||
}
|
||||
|
@ -199,21 +199,21 @@ void Stack::enforce_state(const StackLayout& req_stack) {
|
|||
j = 0;
|
||||
}
|
||||
issue_xchg(j, depth() - i - 1);
|
||||
assert(s[i].first == x);
|
||||
func_assert(s[i].first == x);
|
||||
}
|
||||
while (depth() > k) {
|
||||
issue_pop(0);
|
||||
}
|
||||
assert(depth() == k);
|
||||
func_assert(depth() == k);
|
||||
for (int i = 0; i < k; i++) {
|
||||
assert(s[i].first == req_stack[i]);
|
||||
func_assert(s[i].first == req_stack[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Stack::merge_const(const Stack& req_stack) {
|
||||
assert(s.size() == req_stack.s.size());
|
||||
func_assert(s.size() == req_stack.s.size());
|
||||
for (std::size_t i = 0; i < s.size(); i++) {
|
||||
assert(s[i].first == req_stack.s[i].first);
|
||||
func_assert(s[i].first == req_stack.s[i].first);
|
||||
if (s[i].second != req_stack.s[i].second) {
|
||||
s[i].second = not_const;
|
||||
}
|
||||
|
@ -251,15 +251,15 @@ void Stack::rearrange_top(const StackLayout& top, std::vector<bool> last) {
|
|||
if (last[i]) {
|
||||
// rearrange x to be at s(ss-1)
|
||||
issue_xchg(--ss, j);
|
||||
assert(get(ss).first == x);
|
||||
func_assert(get(ss).first == x);
|
||||
} else {
|
||||
// create a new copy of x
|
||||
issue_push(j);
|
||||
issue_xchg(0, ss);
|
||||
assert(get(ss).first == x);
|
||||
func_assert(get(ss).first == x);
|
||||
}
|
||||
}
|
||||
assert(!ss);
|
||||
func_assert(!ss);
|
||||
}
|
||||
|
||||
void Stack::rearrange_top(var_idx_t top, bool last) {
|
||||
|
@ -269,7 +269,7 @@ void Stack::rearrange_top(var_idx_t top, bool last) {
|
|||
} else {
|
||||
issue_push(i);
|
||||
}
|
||||
assert(get(0).first == top);
|
||||
func_assert(get(0).first == top);
|
||||
}
|
||||
|
||||
bool Op::generate_code_step(Stack& stack) {
|
||||
|
@ -300,7 +300,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
stack.o << push_const(int_const);
|
||||
stack.push_new_const(left[0], cidx);
|
||||
} else {
|
||||
assert(stack.at(i).second == cidx);
|
||||
func_assert(stack.at(i).second == cidx);
|
||||
stack.do_copy_var(left[0], stack[i]);
|
||||
}
|
||||
return true;
|
||||
|
@ -329,7 +329,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
std::string name = sym::symbols.get_name(fun_ref->sym_idx);
|
||||
stack.o << AsmOp::Custom(name + " GETGLOB", 0, 1);
|
||||
if (left.size() != 1) {
|
||||
assert(left.size() <= 15);
|
||||
func_assert(left.size() <= 15);
|
||||
stack.o << AsmOp::UnTuple((int)left.size());
|
||||
}
|
||||
for (auto i : left) {
|
||||
|
@ -337,7 +337,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
}
|
||||
return true;
|
||||
} else {
|
||||
assert(left.size() == 1);
|
||||
func_assert(left.size() == 1);
|
||||
auto p = next->var_info[left[0]];
|
||||
if (!p || p->is_unused() || disabled()) {
|
||||
return true;
|
||||
|
@ -349,10 +349,10 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
// TODO: create and compile a true lambda instead of this (so that arg_order and ret_order would work correctly)
|
||||
std::vector<VarDescr> args0, res;
|
||||
TypeExpr::remove_indirect(func->sym_type);
|
||||
assert(func->get_type()->is_map());
|
||||
func_assert(func->get_type()->is_map());
|
||||
auto wr = func->get_type()->args.at(0)->get_width();
|
||||
auto wl = func->get_type()->args.at(1)->get_width();
|
||||
assert(wl >= 0 && wr >= 0);
|
||||
func_assert(wl >= 0 && wr >= 0);
|
||||
for (int i = 0; i < wl; i++) {
|
||||
res.emplace_back(0);
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
return true;
|
||||
}
|
||||
case _Let: {
|
||||
assert(left.size() == right.size());
|
||||
func_assert(left.size() == right.size());
|
||||
int i = 0;
|
||||
std::vector<bool> active;
|
||||
active.reserve(left.size());
|
||||
|
@ -420,13 +420,13 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
stack.rearrange_top(right, std::move(last));
|
||||
stack.opt_show();
|
||||
int k = (int)stack.depth() - (int)right.size();
|
||||
assert(k >= 0);
|
||||
func_assert(k >= 0);
|
||||
if (cl == _Tuple) {
|
||||
stack.o << AsmOp::Tuple((int)right.size());
|
||||
assert(left.size() == 1);
|
||||
func_assert(left.size() == 1);
|
||||
} else {
|
||||
stack.o << AsmOp::UnTuple((int)left.size());
|
||||
assert(right.size() == 1);
|
||||
func_assert(right.size() == 1);
|
||||
}
|
||||
stack.s.resize(k);
|
||||
for (int i = 0; i < (int)left.size(); i++) {
|
||||
|
@ -442,16 +442,16 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
SymValFunc* func = (fun_ref ? dynamic_cast<SymValFunc*>(fun_ref->value) : nullptr);
|
||||
auto arg_order = (func ? func->get_arg_order() : nullptr);
|
||||
auto ret_order = (func ? func->get_ret_order() : nullptr);
|
||||
assert(!arg_order || arg_order->size() == right.size());
|
||||
assert(!ret_order || ret_order->size() == left.size());
|
||||
func_assert(!arg_order || arg_order->size() == right.size());
|
||||
func_assert(!ret_order || ret_order->size() == left.size());
|
||||
std::vector<var_idx_t> right1;
|
||||
if (args.size()) {
|
||||
assert(args.size() == right.size());
|
||||
func_assert(args.size() == right.size());
|
||||
for (int i = 0; i < (int)right.size(); i++) {
|
||||
int j = arg_order ? arg_order->at(i) : i;
|
||||
const VarDescr& arg = args.at(j);
|
||||
if (!arg.is_unused()) {
|
||||
assert(var_info[arg.idx] && !var_info[arg.idx]->is_unused());
|
||||
func_assert(var_info[arg.idx] && !var_info[arg.idx]->is_unused());
|
||||
right1.push_back(arg.idx);
|
||||
}
|
||||
}
|
||||
|
@ -469,17 +469,25 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
stack.rearrange_top(right1, std::move(last));
|
||||
stack.opt_show();
|
||||
int k = (int)stack.depth() - (int)right1.size();
|
||||
assert(k >= 0);
|
||||
func_assert(k >= 0);
|
||||
for (int i = 0; i < (int)right1.size(); i++) {
|
||||
if (stack.s[k + i].first != right1[i]) {
|
||||
std::cerr << stack.o;
|
||||
}
|
||||
assert(stack.s[k + i].first == right1[i]);
|
||||
func_assert(stack.s[k + i].first == right1[i]);
|
||||
}
|
||||
auto exec_callxargs = [&](int args, int ret) {
|
||||
if (args <= 15 && ret <= 15) {
|
||||
stack.o << exec_arg2_op("CALLXARGS", args, ret, args + 1, ret);
|
||||
} else {
|
||||
func_assert(args <= 254 && ret <= 254);
|
||||
stack.o << AsmOp::Const(PSTRING() << args << " PUSHINT");
|
||||
stack.o << AsmOp::Const(PSTRING() << ret << " PUSHINT");
|
||||
stack.o << AsmOp::Custom("CALLXVARARGS", args + 3, ret);
|
||||
}
|
||||
};
|
||||
if (cl == _CallInd) {
|
||||
// TODO: replace with exec_arg2_op()
|
||||
stack.o << exec_arg2_op("CALLXARGS", (int)right.size() - 1, (int)left.size(), (int)right.size(),
|
||||
(int)left.size());
|
||||
exec_callxargs((int)right.size() - 1, (int)left.size());
|
||||
} else {
|
||||
auto func = dynamic_cast<const SymValAsmFunc*>(fun_ref->value);
|
||||
if (func) {
|
||||
|
@ -493,8 +501,14 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
|
||||
std::string name = sym::symbols.get_name(fun_ref->sym_idx);
|
||||
bool is_inline = (fv && (fv->flags & 3));
|
||||
stack.o << AsmOp::Custom(name + (is_inline ? " INLINECALLDICT" : " CALLDICT"), (int)right.size(),
|
||||
(int)left.size());
|
||||
if (is_inline) {
|
||||
stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size());
|
||||
} else if (fv && fv->code && fv->code->require_callxargs) {
|
||||
stack.o << AsmOp::Custom(name + (" PREPAREDICT"), 0, 2);
|
||||
exec_callxargs((int)right.size() + 1, (int)left.size());
|
||||
} else {
|
||||
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
stack.s.resize(k);
|
||||
|
@ -505,7 +519,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
return true;
|
||||
}
|
||||
case _SetGlob: {
|
||||
assert(fun_ref && dynamic_cast<const SymValGlobVar*>(fun_ref->value));
|
||||
func_assert(fun_ref && dynamic_cast<const SymValGlobVar*>(fun_ref->value));
|
||||
std::vector<bool> last;
|
||||
for (var_idx_t x : right) {
|
||||
last.push_back(var_info[x] && var_info[x]->is_last());
|
||||
|
@ -513,12 +527,12 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
stack.rearrange_top(right, std::move(last));
|
||||
stack.opt_show();
|
||||
int k = (int)stack.depth() - (int)right.size();
|
||||
assert(k >= 0);
|
||||
func_assert(k >= 0);
|
||||
for (int i = 0; i < (int)right.size(); i++) {
|
||||
if (stack.s[k + i].first != right[i]) {
|
||||
std::cerr << stack.o;
|
||||
}
|
||||
assert(stack.s[k + i].first == right[i]);
|
||||
func_assert(stack.s[k + i].first == right[i]);
|
||||
}
|
||||
if (right.size() > 1) {
|
||||
stack.o << AsmOp::Tuple((int)right.size());
|
||||
|
@ -539,7 +553,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
}
|
||||
var_idx_t x = left[0];
|
||||
stack.rearrange_top(x, var_info[x] && var_info[x]->is_last());
|
||||
assert(stack[0] == x);
|
||||
func_assert(stack[0] == x);
|
||||
stack.opt_show();
|
||||
stack.s.pop_back();
|
||||
stack.modified();
|
||||
|
@ -651,7 +665,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
var_idx_t x = left[0];
|
||||
//stack.drop_vars_except(block0->var_info, x);
|
||||
stack.rearrange_top(x, var_info[x] && var_info[x]->is_last());
|
||||
assert(stack[0] == x);
|
||||
func_assert(stack[0] == x);
|
||||
stack.opt_show();
|
||||
stack.s.pop_back();
|
||||
stack.modified();
|
||||
|
@ -877,12 +891,13 @@ void Op::generate_code_all(Stack& stack) {
|
|||
|
||||
void CodeBlob::generate_code(AsmOpList& out, int mode) {
|
||||
Stack stack{out, mode};
|
||||
assert(ops && ops->cl == Op::_Import);
|
||||
func_assert(ops && ops->cl == Op::_Import);
|
||||
auto args = (int)ops->left.size();
|
||||
for (var_idx_t x : ops->left) {
|
||||
stack.push_new_var(x);
|
||||
}
|
||||
ops->generate_code_all(stack);
|
||||
stack.apply_wrappers();
|
||||
stack.apply_wrappers(require_callxargs && (mode & Stack::_InlineAny) ? args : -1);
|
||||
if (!(mode & Stack::_DisableOpt)) {
|
||||
optimize_code(out);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ td::Result<std::string> fs_read_callback(ReadCallback::Kind kind, const char* qu
|
|||
|
||||
void generate_output_func(SymDef* func_sym, std::ostream &outs, std::ostream &errs) {
|
||||
SymValCodeFunc* func_val = dynamic_cast<SymValCodeFunc*>(func_sym->value);
|
||||
assert(func_val);
|
||||
func_assert(func_val);
|
||||
std::string name = sym::symbols.get_name(func_sym->sym_idx);
|
||||
if (verbosity >= 2) {
|
||||
errs << "\n\n=========================\nfunction " << name << " : " << func_val->get_type() << std::endl;
|
||||
|
@ -145,6 +145,9 @@ void generate_output_func(SymDef* func_sym, std::ostream &outs, std::ostream &er
|
|||
if (fv && (fv->flags & 1) && code.ops->noreturn()) {
|
||||
mode |= Stack::_InlineFunc;
|
||||
}
|
||||
if (fv && (fv->flags & 3)) {
|
||||
mode |= Stack::_InlineAny;
|
||||
}
|
||||
code.generate_code(outs, mode, indent + 1);
|
||||
outs << std::string(indent * 2, ' ') << "}>\n";
|
||||
if (verbosity >= 2) {
|
||||
|
@ -163,7 +166,7 @@ int generate_output(std::ostream &outs, std::ostream &errs) {
|
|||
}
|
||||
for (SymDef* func_sym : glob_func) {
|
||||
SymValCodeFunc* func_val = dynamic_cast<SymValCodeFunc*>(func_sym->value);
|
||||
assert(func_val);
|
||||
func_assert(func_val);
|
||||
std::string name = sym::symbols.get_name(func_sym->sym_idx);
|
||||
outs << std::string(indent * 2, ' ');
|
||||
if (func_val->method_id.is_null()) {
|
||||
|
@ -173,7 +176,7 @@ int generate_output(std::ostream &outs, std::ostream &errs) {
|
|||
}
|
||||
}
|
||||
for (SymDef* gvar_sym : glob_vars) {
|
||||
assert(dynamic_cast<SymValGlobVar*>(gvar_sym->value));
|
||||
func_assert(dynamic_cast<SymValGlobVar*>(gvar_sym->value));
|
||||
std::string name = sym::symbols.get_name(gvar_sym->sym_idx);
|
||||
outs << std::string(indent * 2, ' ') << "DECLGLOBVAR " << name << "\n";
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#include "parser/symtable.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#define func_assert(expr) \
|
||||
(bool(expr) ? void(0) \
|
||||
: throw src::Fatal(PSTRING() << "Assertion failed at " << __FILE__ << ":" << __LINE__ << ": " << #expr))
|
||||
|
||||
namespace funC {
|
||||
|
||||
extern int verbosity;
|
||||
|
@ -310,6 +314,7 @@ struct TmpVar {
|
|||
int coord;
|
||||
std::unique_ptr<SrcLocation> where;
|
||||
std::vector<std::function<void(const SrcLocation &)>> on_modification;
|
||||
bool undefined = false;
|
||||
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;
|
||||
|
@ -694,6 +699,7 @@ struct CodeBlob {
|
|||
std::unique_ptr<Op>* cur_ops;
|
||||
std::stack<std::unique_ptr<Op>*> cur_ops_stack;
|
||||
int flags = 0;
|
||||
bool require_callxargs = false;
|
||||
CodeBlob(TypeExpr* ret = nullptr) : var_cnt(0), in_var_cnt(0), op_cnt(0), ret_type(ret), cur_ops(&ops) {
|
||||
}
|
||||
template <typename... Args>
|
||||
|
@ -1177,7 +1183,7 @@ struct AsmOpList {
|
|||
}
|
||||
template <typename... Args>
|
||||
AsmOpList& add(Args&&... args) {
|
||||
list_.emplace_back(std::forward<Args>(args)...);
|
||||
append(AsmOp(std::forward<Args>(args)...));
|
||||
adjust_last();
|
||||
return *this;
|
||||
}
|
||||
|
@ -1564,8 +1570,8 @@ struct Stack {
|
|||
AsmOpList& o;
|
||||
enum {
|
||||
_StkCmt = 1, _CptStkCmt = 2, _DisableOpt = 4, _DisableOut = 128, _Shown = 256,
|
||||
_InlineFunc = 512, _NeedRetAlt = 1024,
|
||||
_ModeSave = _InlineFunc | _NeedRetAlt,
|
||||
_InlineFunc = 512, _NeedRetAlt = 1024, _InlineAny = 2048,
|
||||
_ModeSave = _InlineFunc | _NeedRetAlt | _InlineAny,
|
||||
_Garbage = -0x10000
|
||||
};
|
||||
int mode;
|
||||
|
@ -1612,7 +1618,7 @@ struct Stack {
|
|||
if (i > 255) {
|
||||
throw src::Fatal{"Too deep stack"};
|
||||
}
|
||||
assert(i >= 0 && i < depth() && "invalid stack reference");
|
||||
func_assert(i >= 0 && i < depth() && "invalid stack reference");
|
||||
}
|
||||
void modified() {
|
||||
mode &= ~_Shown;
|
||||
|
@ -1643,14 +1649,24 @@ struct Stack {
|
|||
bool operator==(const Stack& y) const & {
|
||||
return s == y.s;
|
||||
}
|
||||
void apply_wrappers() {
|
||||
void apply_wrappers(int callxargs_count) {
|
||||
bool is_inline = mode & _InlineFunc;
|
||||
if (o.retalt_) {
|
||||
o.insert(0, "SAMEALTSAVE");
|
||||
o.insert(0, "c2 SAVE");
|
||||
if (mode & _InlineFunc) {
|
||||
o.indent_all();
|
||||
o.insert(0, "CONT:<{");
|
||||
o << "}>";
|
||||
}
|
||||
if (callxargs_count != -1 || (is_inline && o.retalt_)) {
|
||||
o.indent_all();
|
||||
o.insert(0, "CONT:<{");
|
||||
o << "}>";
|
||||
if (callxargs_count != -1) {
|
||||
if (callxargs_count <= 15) {
|
||||
o << AsmOp::Custom(PSTRING() << callxargs_count << " -1 CALLXARGS");
|
||||
} else {
|
||||
func_assert(callxargs_count <= 254);
|
||||
o << AsmOp::Custom(PSTRING() << callxargs_count << " PUSHINT -1 PUSHINT CALLXVARARGS");
|
||||
}
|
||||
} else {
|
||||
o << "EXECUTE";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ bool Expr::deduce_type(const Lexem& lem) {
|
|||
return true;
|
||||
}
|
||||
case _VarApply: {
|
||||
assert(args.size() == 2);
|
||||
func_assert(args.size() == 2);
|
||||
TypeExpr* fun_type = TypeExpr::new_map(args[1]->e_type, TypeExpr::new_hole());
|
||||
try {
|
||||
unify(fun_type, args[0]->e_type);
|
||||
|
@ -107,7 +107,7 @@ bool Expr::deduce_type(const Lexem& lem) {
|
|||
return true;
|
||||
}
|
||||
case _Letop: {
|
||||
assert(args.size() == 2);
|
||||
func_assert(args.size() == 2);
|
||||
try {
|
||||
// std::cerr << "in assignment: " << args[0]->e_type << " from " << args[1]->e_type << std::endl;
|
||||
unify(args[0]->e_type, args[1]->e_type);
|
||||
|
@ -122,7 +122,7 @@ bool Expr::deduce_type(const Lexem& lem) {
|
|||
return true;
|
||||
}
|
||||
case _LetFirst: {
|
||||
assert(args.size() == 2);
|
||||
func_assert(args.size() == 2);
|
||||
TypeExpr* rhs_type = TypeExpr::new_tensor({args[0]->e_type, TypeExpr::new_hole()});
|
||||
try {
|
||||
// std::cerr << "in implicit assignment of a modifying method: " << rhs_type << " and " << args[1]->e_type << std::endl;
|
||||
|
@ -140,7 +140,7 @@ bool Expr::deduce_type(const Lexem& lem) {
|
|||
return true;
|
||||
}
|
||||
case _CondExpr: {
|
||||
assert(args.size() == 3);
|
||||
func_assert(args.size() == 3);
|
||||
auto flag_type = TypeExpr::new_atomic(_Int);
|
||||
try {
|
||||
unify(args[0]->e_type, flag_type);
|
||||
|
@ -204,7 +204,7 @@ int Expr::predefine_vars() {
|
|||
}
|
||||
case _Var:
|
||||
if (!sym) {
|
||||
assert(val < 0 && here.defined());
|
||||
func_assert(val < 0 && here.defined());
|
||||
if (prohibited_var_names.count(sym::symbols.get_name(~val))) {
|
||||
throw src::ParseError{
|
||||
here, PSTRING() << "symbol `" << sym::symbols.get_name(~val) << "` cannot be redefined as a variable"};
|
||||
|
@ -274,7 +274,7 @@ std::vector<var_idx_t> pre_compile_tensor(const std::vector<Expr *> args, CodeBl
|
|||
arg_order.resize(args.size());
|
||||
std::iota(arg_order.begin(), arg_order.end(), 0);
|
||||
}
|
||||
assert(args.size() == arg_order.size());
|
||||
func_assert(args.size() == arg_order.size());
|
||||
std::vector<std::vector<var_idx_t>> res_lists(args.size());
|
||||
|
||||
struct ModifiedVar {
|
||||
|
@ -310,7 +310,7 @@ std::vector<var_idx_t> pre_compile_tensor(const std::vector<Expr *> args, CodeBl
|
|||
}
|
||||
for (const auto& list : res_lists) {
|
||||
for (var_idx_t v : list) {
|
||||
assert(!code.vars.at(v).on_modification.empty());
|
||||
func_assert(!code.vars.at(v).on_modification.empty());
|
||||
code.vars.at(v).on_modification.pop_back();
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, std::vector<std::pair<S
|
|||
return pre_compile_tensor(args, code, lval_globs, {});
|
||||
}
|
||||
case _Apply: {
|
||||
assert(sym);
|
||||
func_assert(sym);
|
||||
auto func = dynamic_cast<SymValFunc*>(sym->value);
|
||||
std::vector<var_idx_t> res;
|
||||
if (func && func->arg_order.size() == args.size() && !(code.flags & CodeBlob::_ComputeAsmLtr)) {
|
||||
|
@ -426,7 +426,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, std::vector<std::pair<S
|
|||
}
|
||||
case _CondExpr: {
|
||||
auto cond = args[0]->pre_compile(code);
|
||||
assert(cond.size() == 1);
|
||||
func_assert(cond.size() == 1);
|
||||
auto rvect = new_tmp_vect(code);
|
||||
Op& if_op = code.emplace_back(here, Op::_If, cond);
|
||||
code.push_set_cur(if_op.block0);
|
||||
|
|
|
@ -61,9 +61,9 @@ void Optimizer::apply() {
|
|||
if (!p_ && !q_) {
|
||||
return;
|
||||
}
|
||||
assert(p_ > 0 && p_ <= l_ && q_ >= 0 && q_ <= n && l_ <= n);
|
||||
func_assert(p_ > 0 && p_ <= l_ && q_ >= 0 && q_ <= n && l_ <= n);
|
||||
for (int i = p_; i < l_; i++) {
|
||||
assert(op_[i]);
|
||||
func_assert(op_[i]);
|
||||
op_cons_[i]->car = std::move(op_[i]);
|
||||
op_cons_[i] = nullptr;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ void Optimizer::apply() {
|
|||
code_ = std::move(code_->cdr);
|
||||
}
|
||||
for (int j = q_ - 1; j >= 0; j--) {
|
||||
assert(oq_[j]);
|
||||
func_assert(oq_[j]);
|
||||
oq_[j]->indent = indent_;
|
||||
code_ = AsmOpCons::cons(std::move(oq_[j]), std::move(code_));
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ bool Optimizer::rewrite_const_push_xchgs() {
|
|||
}
|
||||
show_left();
|
||||
auto c_op = std::move(op_[0]);
|
||||
assert(c_op->is_gconst());
|
||||
func_assert(c_op->is_gconst());
|
||||
StackTransform t;
|
||||
q_ = 0;
|
||||
int pos = 0;
|
||||
|
@ -265,31 +265,31 @@ bool Optimizer::rewrite_const_push_xchgs() {
|
|||
if (b > pos) {
|
||||
oq_[q_]->b = b - 1;
|
||||
}
|
||||
assert(apply_op(t, *oq_[q_]));
|
||||
func_assert(apply_op(t, *oq_[q_]));
|
||||
++q_;
|
||||
}
|
||||
} else {
|
||||
assert(op_[i]->is_push(&a));
|
||||
assert(a != pos);
|
||||
func_assert(op_[i]->is_push(&a));
|
||||
func_assert(a != pos);
|
||||
oq_[q_] = std::move(op_[i]);
|
||||
if (a > pos) {
|
||||
oq_[q_]->a = a - 1;
|
||||
}
|
||||
assert(apply_op(t, *oq_[q_]));
|
||||
func_assert(apply_op(t, *oq_[q_]));
|
||||
++q_;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
assert(!pos);
|
||||
func_assert(!pos);
|
||||
t.apply_push_newconst();
|
||||
assert(t <= tr_[p_ - 1]);
|
||||
func_assert(t <= tr_[p_ - 1]);
|
||||
oq_[q_++] = std::move(c_op);
|
||||
show_right();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op) {
|
||||
assert(p > 0 && p <= l_);
|
||||
func_assert(p > 0 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 1;
|
||||
show_left();
|
||||
|
@ -300,7 +300,7 @@ bool Optimizer::rewrite(int p, AsmOp&& new_op) {
|
|||
}
|
||||
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) {
|
||||
assert(p > 1 && p <= l_);
|
||||
func_assert(p > 1 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 2;
|
||||
show_left();
|
||||
|
@ -313,7 +313,7 @@ bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2) {
|
|||
}
|
||||
|
||||
bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3) {
|
||||
assert(p > 2 && p <= l_);
|
||||
func_assert(p > 2 && p <= l_);
|
||||
p_ = p;
|
||||
q_ = 3;
|
||||
show_left();
|
||||
|
@ -328,7 +328,7 @@ bool Optimizer::rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3
|
|||
}
|
||||
|
||||
bool Optimizer::rewrite_nop() {
|
||||
assert(p_ > 0 && p_ <= l_);
|
||||
func_assert(p_ > 0 && p_ <= l_);
|
||||
q_ = 0;
|
||||
show_left();
|
||||
show_right();
|
||||
|
|
|
@ -399,7 +399,7 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) {
|
|||
cur.loc.show_error(std::string{"undefined function `"} + symbols.get_name(func_name) +
|
||||
"`, defining a global function of unknown type");
|
||||
def = sym::define_global_symbol(func_name, 0, cur.loc);
|
||||
assert(def && "cannot define global function");
|
||||
func_assert(def && "cannot define global function");
|
||||
++undef_func_cnt;
|
||||
make_new_glob_func(def, TypeExpr::new_func()); // was: ... ::new_func()
|
||||
return true;
|
||||
|
@ -1111,6 +1111,7 @@ blk_fl::val parse_do_stmt(Lexer& lex, CodeBlob& code) {
|
|||
}
|
||||
|
||||
blk_fl::val parse_try_catch_stmt(Lexer& lex, CodeBlob& code) {
|
||||
code.require_callxargs = true;
|
||||
lex.expect(_Try);
|
||||
Op& try_catch_op = code.emplace_back(lex.cur().loc, Op::_TryCatch);
|
||||
code.push_set_cur(try_catch_op.block0);
|
||||
|
@ -1132,7 +1133,7 @@ blk_fl::val parse_try_catch_stmt(Lexer& lex, CodeBlob& code) {
|
|||
expr->predefine_vars();
|
||||
expr->define_new_vars(code);
|
||||
try_catch_op.left = expr->pre_compile(code);
|
||||
assert(try_catch_op.left.size() == 2);
|
||||
func_assert(try_catch_op.left.size() == 2 || try_catch_op.left.size() == 1);
|
||||
blk_fl::val res1 = parse_block_stmt(lex, code);
|
||||
sym::close_scope(lex);
|
||||
code.close_pop_cur(lex.cur().loc);
|
||||
|
@ -1295,7 +1296,7 @@ SymValAsmFunc* parse_asm_func_body(Lexer& lex, TypeExpr* func_type, const Formal
|
|||
}
|
||||
lex.next();
|
||||
}
|
||||
assert(arg_order.size() == (unsigned)tot_width);
|
||||
func_assert(arg_order.size() == (unsigned)tot_width);
|
||||
}
|
||||
if (lex.tp() == _Mapsto) {
|
||||
lex.expect(_Mapsto);
|
||||
|
@ -1487,7 +1488,7 @@ void parse_func_def(Lexer& lex) {
|
|||
std::cerr << "function " << func_name.str << " : " << func_type << std::endl;
|
||||
}
|
||||
SymDef* func_sym = sym::define_global_symbol(func_name.val, 0, loc);
|
||||
assert(func_sym);
|
||||
func_assert(func_sym);
|
||||
SymValFunc* func_sym_val = dynamic_cast<SymValFunc*>(func_sym->value);
|
||||
if (func_sym->value) {
|
||||
if (func_sym->value->type != SymVal::_Func || !func_sym_val) {
|
||||
|
|
|
@ -183,7 +183,7 @@ bool StackTransform::is_permutation() const {
|
|||
if (!is_valid() || d) {
|
||||
return false;
|
||||
}
|
||||
assert(n <= max_n);
|
||||
func_assert(n <= max_n);
|
||||
std::array<int, max_n> X, Y;
|
||||
for (int i = 0; i < n; i++) {
|
||||
X[i] = A[i].first;
|
||||
|
|
|
@ -132,7 +132,7 @@ void TypeExpr::replace_with(TypeExpr* te2) {
|
|||
}
|
||||
|
||||
bool TypeExpr::remove_indirect(TypeExpr*& te, TypeExpr* forbidden) {
|
||||
assert(te);
|
||||
func_assert(te);
|
||||
while (te->constr == te_Indirect) {
|
||||
te = te->args[0];
|
||||
}
|
||||
|
@ -147,8 +147,8 @@ bool TypeExpr::remove_indirect(TypeExpr*& te, TypeExpr* forbidden) {
|
|||
}
|
||||
|
||||
std::vector<TypeExpr*> TypeExpr::remove_forall(TypeExpr*& te) {
|
||||
assert(te && te->constr == te_ForAll);
|
||||
assert(te->args.size() >= 1);
|
||||
func_assert(te && te->constr == te_ForAll);
|
||||
func_assert(te->args.size() >= 1);
|
||||
std::vector<TypeExpr*> new_vars;
|
||||
for (std::size_t i = 1; i < te->args.size(); i++) {
|
||||
new_vars.push_back(new_hole(1));
|
||||
|
@ -162,8 +162,8 @@ std::vector<TypeExpr*> TypeExpr::remove_forall(TypeExpr*& te) {
|
|||
}
|
||||
|
||||
bool TypeExpr::remove_forall_in(TypeExpr*& te, TypeExpr* te2, const std::vector<TypeExpr*>& new_vars) {
|
||||
assert(te);
|
||||
assert(te2 && te2->constr == te_ForAll);
|
||||
func_assert(te);
|
||||
func_assert(te2 && te2->constr == te_ForAll);
|
||||
if (te->constr == te_Var) {
|
||||
for (std::size_t i = 0; i < new_vars.size(); i++) {
|
||||
if (te == te2->args[i + 1]) {
|
||||
|
@ -277,7 +277,7 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
|
|||
return os << "]";
|
||||
}
|
||||
case te_Map: {
|
||||
assert(args.size() == 2);
|
||||
func_assert(args.size() == 2);
|
||||
if (lex_level > 0) {
|
||||
os << "(";
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
|
|||
return os;
|
||||
}
|
||||
case te_ForAll: {
|
||||
assert(args.size() >= 1);
|
||||
func_assert(args.size() >= 1);
|
||||
if (lex_level > 0) {
|
||||
os << '(';
|
||||
}
|
||||
|
@ -343,11 +343,11 @@ void check_update_widths(TypeExpr* te1, TypeExpr* te2) {
|
|||
check_width_compat(te1, te2);
|
||||
te1->minw = te2->minw = std::max(te1->minw, te2->minw);
|
||||
te1->maxw = te2->maxw = std::min(te1->maxw, te2->maxw);
|
||||
assert(te1->minw <= te1->maxw);
|
||||
func_assert(te1->minw <= te1->maxw);
|
||||
}
|
||||
|
||||
void unify(TypeExpr*& te1, TypeExpr*& te2) {
|
||||
assert(te1 && te2);
|
||||
func_assert(te1 && te2);
|
||||
// std::cerr << "unify( " << te1 << " , " << te2 << " )\n";
|
||||
while (te1->constr == TypeExpr::te_Indirect) {
|
||||
te1 = te1->args[0];
|
||||
|
@ -390,7 +390,7 @@ void unify(TypeExpr*& te1, TypeExpr*& te2) {
|
|||
}
|
||||
if (te1->constr == TypeExpr::te_Unknown) {
|
||||
if (te2->constr == TypeExpr::te_Unknown) {
|
||||
assert(te1->value != te2->value);
|
||||
func_assert(te1->value != te2->value);
|
||||
}
|
||||
if (!TypeExpr::remove_indirect(te2, te1)) {
|
||||
throw UnifyError{te1, te2, "type unification results in an infinite cyclic type"};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue