mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
[Tolk] Refactor: get rid of split_vars, construct valid LET ops
In FunC (and in Tolk before), tensor vars (actually occupying several stack slots) were represented as a single var in terms or IR vars (Ops): > var a = (1, 2); > LET (_i) = (_1, _2) Now, every tensor of N stack slots is represented as N IR vars. > LET (_i, _j) = (_1, _2) This will give an ability to control access to parts of a tensor when implementing `tensorVar.0` syntax.
This commit is contained in:
parent
989629a832
commit
565bc59735
17 changed files with 100 additions and 217 deletions
|
@ -104,9 +104,9 @@ fun testStartBalanceCodegen2() {
|
|||
testDumpDontPolluteStack PROC:<{
|
||||
...
|
||||
DUMPSTK
|
||||
x{6d79} PUSHSLICE // f s _9
|
||||
x{6d79} PUSHSLICE // f s _5
|
||||
STRDUMP DROP
|
||||
SBITS // f _11
|
||||
SBITS // f _6
|
||||
}>
|
||||
"""
|
||||
|
||||
|
|
|
@ -220,11 +220,11 @@ Note, that since 'compute-asm-ltr' became on be default, chaining methods codege
|
|||
1 PUSHINT // _0 _1=1
|
||||
SWAP // _1=1 _0
|
||||
32 STU // _0
|
||||
2 PUSHINT // _0 _5=2
|
||||
SWAP // _5=2 _0
|
||||
2 PUSHINT // _0 _4=2
|
||||
SWAP // _4=2 _0
|
||||
32 STU // _0
|
||||
3 PUSHINT // _0 _9=3
|
||||
SWAP // _9=3 _0
|
||||
3 PUSHINT // _0 _7=3
|
||||
SWAP // _7=3 _0
|
||||
32 STU // _0
|
||||
}>
|
||||
"""
|
||||
|
|
|
@ -332,15 +332,15 @@ These are moments of future optimizations. For now, it's more than enough.
|
|||
DUP // x x
|
||||
IFNOTJMP:<{ // x
|
||||
DROP //
|
||||
1 PUSHINT // _7=1
|
||||
1 PUSHINT // _5=1
|
||||
}> // x
|
||||
DUP // x x
|
||||
IFNOTJMP:<{ // x
|
||||
DROP //
|
||||
1 PUSHINT // _8=1
|
||||
1 PUSHINT // _6=1
|
||||
}> // x
|
||||
100 THROWIFNOT
|
||||
-4 PUSHINT // _12=-4
|
||||
-4 PUSHINT // _9=-4
|
||||
}>
|
||||
"""
|
||||
|
||||
|
|
|
@ -307,7 +307,7 @@ fun main(){}
|
|||
...
|
||||
incrementTwoInPlace CALLDICT // x y sum1
|
||||
-ROT
|
||||
10 PUSHINT // sum1 x y _8=10
|
||||
10 PUSHINT // sum1 x y _10=10
|
||||
incrementTwoInPlace CALLDICT // sum1 x y sum2
|
||||
s1 s3 s0 XCHG3 // x y sum1 sum2
|
||||
}>
|
||||
|
@ -317,8 +317,8 @@ fun main(){}
|
|||
"""
|
||||
load_next PROC:<{
|
||||
// cs
|
||||
32 LDI // _3 cs
|
||||
SWAP // cs _3
|
||||
32 LDI // _4 cs
|
||||
SWAP // cs _4
|
||||
}>
|
||||
"""
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ fun main() {
|
|||
CONS // numbers
|
||||
UNCONS // h numbers
|
||||
DUP // h numbers numbers
|
||||
CAR // h numbers _12
|
||||
CAR // h numbers _13
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
|
@ -133,7 +133,7 @@ fun main() {
|
|||
"""
|
||||
test7 PROC:<{
|
||||
...
|
||||
LDOPTREF // b _18 _17
|
||||
LDOPTREF // b _8 _7
|
||||
DROP // b c
|
||||
ISNULL // b _11
|
||||
10 MULCONST // b _13
|
||||
|
|
|
@ -31,16 +31,6 @@ void TmpVar::dump(std::ostream& os) const {
|
|||
os << " : " << v_type << " (width ";
|
||||
os << v_type->calc_width_on_stack();
|
||||
os << ")";
|
||||
if (coord > 0) {
|
||||
os << " = _" << (coord >> 8) << '.' << (coord & 255);
|
||||
} else if (coord < 0) {
|
||||
int n = (~coord >> 8), k = (~coord & 0xff);
|
||||
if (k) {
|
||||
os << " = (_" << n << ".._" << (n + k - 1) << ")";
|
||||
} else {
|
||||
os << " = ()";
|
||||
}
|
||||
}
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
|
@ -51,7 +41,7 @@ void TmpVar::show(std::ostream& os, int omit_idx) const {
|
|||
return;
|
||||
}
|
||||
}
|
||||
os << '_' << idx;
|
||||
os << '_' << ir_idx;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const TmpVar& var) {
|
||||
|
@ -182,47 +172,6 @@ void VarDescrList::show(std::ostream& os) const {
|
|||
os << " ]\n";
|
||||
}
|
||||
|
||||
void Op::split_vars(const std::vector<TmpVar>& vars) {
|
||||
split_var_list(left, vars);
|
||||
split_var_list(right, vars);
|
||||
for (auto& op : block0) {
|
||||
op.split_vars(vars);
|
||||
}
|
||||
for (auto& op : block1) {
|
||||
op.split_vars(vars);
|
||||
}
|
||||
}
|
||||
|
||||
void Op::split_var_list(std::vector<var_idx_t>& var_list, const std::vector<TmpVar>& vars) {
|
||||
int new_size = 0, changes = 0;
|
||||
for (var_idx_t v : var_list) {
|
||||
int c = vars.at(v).coord;
|
||||
if (c < 0) {
|
||||
++changes;
|
||||
new_size += (~c & 0xff);
|
||||
} else {
|
||||
++new_size;
|
||||
}
|
||||
}
|
||||
if (!changes) {
|
||||
return;
|
||||
}
|
||||
std::vector<var_idx_t> new_var_list;
|
||||
new_var_list.reserve(new_size);
|
||||
for (var_idx_t v : var_list) {
|
||||
int c = vars.at(v).coord;
|
||||
if (c < 0) {
|
||||
int n = (~c >> 8), k = (~c & 0xff);
|
||||
while (k-- > 0) {
|
||||
new_var_list.push_back(n++);
|
||||
}
|
||||
} else {
|
||||
new_var_list.push_back(v);
|
||||
}
|
||||
}
|
||||
var_list = std::move(new_var_list);
|
||||
}
|
||||
|
||||
void Op::show(std::ostream& os, const std::vector<TmpVar>& vars, std::string pfx, int mode) const {
|
||||
if (mode & 2) {
|
||||
os << pfx << " [";
|
||||
|
@ -444,26 +393,22 @@ void CodeBlob::print(std::ostream& os, int flags) const {
|
|||
os << "-------- END ---------\n\n";
|
||||
}
|
||||
|
||||
var_idx_t CodeBlob::create_var(TypePtr var_type, const LocalVarData* v_sym, SrcLocation location) {
|
||||
vars.emplace_back(var_cnt, var_type, v_sym, location);
|
||||
return var_cnt++;
|
||||
std::vector<var_idx_t> CodeBlob::create_var(TypePtr var_type, const LocalVarData* v_sym, SrcLocation loc) {
|
||||
std::vector<var_idx_t> ir_idx;
|
||||
ir_idx.reserve(var_type->calc_width_on_stack());
|
||||
if (const TypeDataTensor* t_tensor = var_type->try_as<TypeDataTensor>()) {
|
||||
for (TypePtr item : t_tensor->items) {
|
||||
std::vector<var_idx_t> nested = create_var(item, v_sym, loc);
|
||||
ir_idx.insert(ir_idx.end(), nested.begin(), nested.end());
|
||||
}
|
||||
|
||||
bool CodeBlob::import_params(FormalArgList&& arg_list) {
|
||||
if (var_cnt || in_var_cnt) {
|
||||
return false;
|
||||
} else if (var_type != TypeDataVoid::create()) {
|
||||
tolk_assert(var_type->calc_width_on_stack() == 1);
|
||||
vars.emplace_back(var_cnt, var_type, v_sym, loc);
|
||||
ir_idx.emplace_back(var_cnt);
|
||||
var_cnt++;
|
||||
}
|
||||
std::vector<var_idx_t> list;
|
||||
for (const auto& par : arg_list) {
|
||||
TypePtr arg_type;
|
||||
const LocalVarData* arg_sym;
|
||||
SrcLocation arg_loc;
|
||||
std::tie(arg_type, arg_sym, arg_loc) = par;
|
||||
list.push_back(create_var(arg_type, arg_sym, arg_loc));
|
||||
}
|
||||
emplace_back(loc, Op::_Import, list);
|
||||
in_var_cnt = var_cnt;
|
||||
return true;
|
||||
tolk_assert(static_cast<int>(ir_idx.size()) == var_type->calc_width_on_stack());
|
||||
return ir_idx;
|
||||
}
|
||||
|
||||
} // namespace tolk
|
||||
|
|
|
@ -26,40 +26,6 @@ namespace tolk {
|
|||
*
|
||||
*/
|
||||
|
||||
int CodeBlob::split_vars(bool strict) {
|
||||
int n = var_cnt, changes = 0;
|
||||
for (int j = 0; j < var_cnt; j++) {
|
||||
TmpVar& var = vars[j];
|
||||
int width_j = var.v_type->calc_width_on_stack();
|
||||
if (strict && width_j < 0) {
|
||||
throw ParseError{var.where, "variable does not have fixed width, cannot manipulate it"};
|
||||
}
|
||||
if (width_j == 1) {
|
||||
continue;
|
||||
}
|
||||
std::vector<TypePtr> comp_types;
|
||||
var.v_type->extract_components(comp_types);
|
||||
tolk_assert(width_j <= 254 && n <= 0x7fff00);
|
||||
tolk_assert((unsigned)width_j == comp_types.size());
|
||||
var.coord = ~((n << 8) + width_j);
|
||||
for (int i = 0; i < width_j; i++) {
|
||||
auto v = create_var(comp_types[i], vars[j].v_sym, vars[j].where);
|
||||
tolk_assert(v == n + i);
|
||||
tolk_assert(vars[v].idx == v);
|
||||
vars[v].coord = ((int)j << 8) + i + 1;
|
||||
}
|
||||
n += width_j;
|
||||
++changes;
|
||||
}
|
||||
if (!changes) {
|
||||
return 0;
|
||||
}
|
||||
for (auto& op : ops) {
|
||||
op.split_vars(vars);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
bool CodeBlob::compute_used_code_vars() {
|
||||
VarDescrList empty_var_info;
|
||||
return compute_used_code_vars(ops, empty_var_info, true);
|
||||
|
|
|
@ -202,8 +202,8 @@ td::Result<std::vector<TypePtr>> deduce_substitutionTs_on_generic_func_call(cons
|
|||
try {
|
||||
GenericSubstitutionsDeduceForFunctionCall deducing(called_fun);
|
||||
for (const LocalVarData& param : called_fun->parameters) {
|
||||
if (param.declared_type->has_genericT_inside() && param.idx < static_cast<int>(arg_types.size())) {
|
||||
deducing.consider_next_condition(param.declared_type, arg_types[param.idx]);
|
||||
if (param.declared_type->has_genericT_inside() && param.param_idx < static_cast<int>(arg_types.size())) {
|
||||
deducing.consider_next_condition(param.declared_type, arg_types[param.param_idx]);
|
||||
}
|
||||
}
|
||||
int idx = deducing.get_first_not_deduced_idx();
|
||||
|
@ -233,7 +233,7 @@ const FunctionData* instantiate_generic_function(SrcLocation loc, const Function
|
|||
std::vector<LocalVarData> parameters;
|
||||
parameters.reserve(fun_ref->get_num_params());
|
||||
for (const LocalVarData& orig_p : fun_ref->parameters) {
|
||||
parameters.emplace_back(orig_p.name, orig_p.loc, replace_genericT_with_deduced(orig_p.declared_type, fun_ref->genericTs, substitutionTs), orig_p.flags, orig_p.idx);
|
||||
parameters.emplace_back(orig_p.name, orig_p.loc, replace_genericT_with_deduced(orig_p.declared_type, fun_ref->genericTs, substitutionTs), orig_p.flags, orig_p.param_idx);
|
||||
}
|
||||
TypePtr declared_return_type = replace_genericT_with_deduced(fun_ref->declared_return_type, fun_ref->genericTs, substitutionTs);
|
||||
const GenericsInstantiation* instantiationTs = new GenericsInstantiation(loc, std::move(substitutionTs));
|
||||
|
|
|
@ -34,15 +34,15 @@
|
|||
namespace tolk {
|
||||
|
||||
struct LValGlobs {
|
||||
std::vector<std::pair<const GlobalVarData*, var_idx_t>> globs;
|
||||
std::vector<std::pair<const GlobalVarData*, std::vector<var_idx_t>>> globs;
|
||||
|
||||
void add_modified_glob(const GlobalVarData* g_sym, var_idx_t local_ir_idx) {
|
||||
globs.emplace_back(g_sym, local_ir_idx);
|
||||
void add_modified_glob(const GlobalVarData* g_sym, std::vector<var_idx_t> local_ir_idx) {
|
||||
globs.emplace_back(g_sym, std::move(local_ir_idx));
|
||||
}
|
||||
|
||||
void gen_ops_set_globs(CodeBlob& code, SrcLocation loc) const {
|
||||
for (const auto& [g_sym, ir_idx] : globs) {
|
||||
Op& op = code.emplace_back(loc, Op::_SetGlob, std::vector<var_idx_t>{}, std::vector<var_idx_t>{ ir_idx }, g_sym);
|
||||
Op& op = code.emplace_back(loc, Op::_SetGlob, std::vector<var_idx_t>{}, ir_idx, g_sym);
|
||||
op.set_impure_flag();
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,9 @@ static std::vector<std::vector<var_idx_t>> pre_compile_tensor_inner(CodeBlob& co
|
|||
|
||||
void on_var_modified(var_idx_t ir_idx, SrcLocation loc, CodeBlob& code) {
|
||||
tolk_assert(is_watched(ir_idx));
|
||||
var_idx_t tmp_idx = code.create_tmp_var(code.vars[ir_idx].v_type, loc);
|
||||
std::vector<var_idx_t> tmp_idx_arr = code.create_tmp_var(code.vars[ir_idx].v_type, loc);
|
||||
tolk_assert(tmp_idx_arr.size() == 1);
|
||||
var_idx_t tmp_idx = tmp_idx_arr[0];
|
||||
code.emplace_back(loc, Op::_Let, std::vector{tmp_idx}, std::vector{ir_idx});
|
||||
for (std::vector<var_idx_t>& prev_vars : res_lists) {
|
||||
std::replace(prev_vars.begin(), prev_vars.end(), ir_idx, tmp_idx);
|
||||
|
@ -143,7 +145,7 @@ static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, AnyExprV lhs, AnyE
|
|||
std::vector<var_idx_t> right = pre_compile_expr(rhs, code);
|
||||
const TypeDataTypedTuple* inferred_tuple = rhs->inferred_type->try_as<TypeDataTypedTuple>();
|
||||
std::vector<TypePtr> types_list = inferred_tuple->items;
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(TypeDataTensor::create(std::move(types_list)), rhs->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(TypeDataTensor::create(std::move(types_list)), rhs->loc);
|
||||
code.emplace_back(lhs->loc, Op::_UnTuple, rvect, std::move(right));
|
||||
LValGlobs globs;
|
||||
std::vector<var_idx_t> left = pre_compile_tensor(code, lhs->as<ast_typed_tuple>()->get_items(), &globs);
|
||||
|
@ -164,7 +166,7 @@ static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, AnyExprV lhs, AnyE
|
|||
|
||||
static std::vector<var_idx_t> gen_op_call(CodeBlob& code, TypePtr ret_type, SrcLocation here,
|
||||
std::vector<var_idx_t>&& args_vars, const FunctionData* fun_ref) {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(ret_type, here)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(ret_type, here);
|
||||
Op& op = code.emplace_back(here, Op::_Call, rvect, std::move(args_vars), fun_ref);
|
||||
if (!fun_ref->is_marked_as_pure()) {
|
||||
op.set_impure_flag();
|
||||
|
@ -175,9 +177,9 @@ static std::vector<var_idx_t> gen_op_call(CodeBlob& code, TypePtr ret_type, SrcL
|
|||
|
||||
static std::vector<var_idx_t> process_symbol(SrcLocation loc, const Symbol* sym, CodeBlob& code, LValGlobs* lval_globs) {
|
||||
if (const auto* glob_ref = sym->try_as<GlobalVarData>()) {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(glob_ref->declared_type, loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(glob_ref->declared_type, loc);
|
||||
if (lval_globs) {
|
||||
lval_globs->add_modified_glob(glob_ref, rvect[0]);
|
||||
lval_globs->add_modified_glob(glob_ref, rvect);
|
||||
return rvect;
|
||||
} else {
|
||||
code.emplace_back(loc, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, glob_ref);
|
||||
|
@ -186,22 +188,25 @@ static std::vector<var_idx_t> process_symbol(SrcLocation loc, const Symbol* sym,
|
|||
}
|
||||
if (const auto* const_ref = sym->try_as<GlobalConstData>()) {
|
||||
if (const_ref->is_int_const()) {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(TypeDataInt::create(), loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(TypeDataInt::create(), loc);
|
||||
code.emplace_back(loc, Op::_IntConst, rvect, const_ref->as_int_const());
|
||||
return rvect;
|
||||
} else {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(TypeDataSlice::create(), loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(TypeDataSlice::create(), loc);
|
||||
code.emplace_back(loc, Op::_SliceConst, rvect, const_ref->as_slice_const());
|
||||
return rvect;
|
||||
}
|
||||
}
|
||||
if (const auto* fun_ref = sym->try_as<FunctionData>()) {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(fun_ref->inferred_full_type, loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(fun_ref->inferred_full_type, loc);
|
||||
code.emplace_back(loc, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, fun_ref);
|
||||
return rvect;
|
||||
}
|
||||
if (const auto* var_ref = sym->try_as<LocalVarData>()) {
|
||||
return {var_ref->idx};
|
||||
#ifdef TOLK_DEBUG
|
||||
tolk_assert(static_cast<int>(var_ref->ir_idx.size()) == var_ref->declared_type->calc_width_on_stack());
|
||||
#endif
|
||||
return var_ref->ir_idx;
|
||||
}
|
||||
throw Fatal("process_symbol");
|
||||
}
|
||||
|
@ -244,7 +249,7 @@ static std::vector<var_idx_t> process_binary_operator(V<ast_binary_operator> v,
|
|||
v_b_ne_0->mutate()->assign_fun_ref(lookup_global_symbol("_!=_")->as<FunctionData>());
|
||||
std::vector<var_idx_t> cond = pre_compile_expr(v->get_lhs(), code);
|
||||
tolk_assert(cond.size() == 1);
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
Op& if_op = code.emplace_back(v->loc, Op::_If, cond);
|
||||
code.push_set_cur(if_op.block0);
|
||||
code.emplace_back(v->loc, Op::_Let, rvect, pre_compile_expr(t == tok_logical_and ? v_b_ne_0 : v_1, code));
|
||||
|
@ -266,7 +271,7 @@ static std::vector<var_idx_t> process_unary_operator(V<ast_unary_operator> v, Co
|
|||
static std::vector<var_idx_t> process_ternary_operator(V<ast_ternary_operator> v, CodeBlob& code) {
|
||||
std::vector<var_idx_t> cond = pre_compile_expr(v->get_cond(), code);
|
||||
tolk_assert(cond.size() == 1);
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
Op& if_op = code.emplace_back(v->loc, Op::_If, cond);
|
||||
code.push_set_cur(if_op.block0);
|
||||
code.emplace_back(v->get_when_true()->loc, Op::_Let, rvect, pre_compile_expr(v->get_when_true(), code));
|
||||
|
@ -299,7 +304,7 @@ static std::vector<var_idx_t> process_function_call(V<ast_function_call> v, Code
|
|||
std::vector<var_idx_t> tfunc = pre_compile_expr(v->get_callee(), code);
|
||||
tolk_assert(tfunc.size() == 1);
|
||||
args_vars.push_back(tfunc[0]);
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
Op& op = code.emplace_back(v->loc, Op::_CallInd, rvect, std::move(args_vars));
|
||||
op.set_impure_flag();
|
||||
return rvect;
|
||||
|
@ -361,8 +366,8 @@ static std::vector<var_idx_t> process_function_call(V<ast_function_call> v, Code
|
|||
}
|
||||
}
|
||||
}
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(real_ret_type, v->loc)};
|
||||
left.push_back(rvect[0]);
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(real_ret_type, v->loc);
|
||||
left.insert(left.end(), rvect.begin(), rvect.end());
|
||||
code.on_var_modification(left, v->loc);
|
||||
code.emplace_back(v->loc, Op::_Let, std::move(left), rvect_apply);
|
||||
local_globs.gen_ops_set_globs(code, v->loc);
|
||||
|
@ -388,21 +393,21 @@ static std::vector<var_idx_t> process_typed_tuple(V<ast_typed_tuple> v, CodeBlob
|
|||
if (lval_globs) { // todo some time, make "var (a, [b,c]) = (1, [2,3])" work
|
||||
v->error("[...] can not be used as lvalue here");
|
||||
}
|
||||
std::vector<var_idx_t> left = std::vector{code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> left = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
std::vector<var_idx_t> right = pre_compile_tensor(code, v->get_items());
|
||||
code.emplace_back(v->loc, Op::_Tuple, left, std::move(right));
|
||||
return left;
|
||||
}
|
||||
|
||||
static std::vector<var_idx_t> process_int_const(V<ast_int_const> v, CodeBlob& code) {
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
code.emplace_back(v->loc, Op::_IntConst, rvect, v->intval);
|
||||
return rvect;
|
||||
}
|
||||
|
||||
static std::vector<var_idx_t> process_string_const(V<ast_string_const> v, CodeBlob& code) {
|
||||
ConstantValue value = eval_const_init_value(v);
|
||||
std::vector<var_idx_t> rvect = {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
std::vector<var_idx_t> rvect = code.create_tmp_var(v->inferred_type, v->loc);
|
||||
if (value.is_int()) {
|
||||
code.emplace_back(v->loc, Op::_IntConst, rvect, value.as_int());
|
||||
} else {
|
||||
|
@ -426,9 +431,9 @@ static std::vector<var_idx_t> process_local_var(V<ast_local_var_lhs> v, CodeBlob
|
|||
return process_symbol(v->loc, v->var_ref, code, nullptr);
|
||||
}
|
||||
|
||||
tolk_assert(v->var_ref->idx == -1);
|
||||
v->var_ref->mutate()->assign_idx(code.create_var(v->inferred_type, v->var_ref, v->loc));
|
||||
return {v->var_ref->idx};
|
||||
tolk_assert(v->var_ref->ir_idx.empty());
|
||||
v->var_ref->mutate()->assign_ir_idx(code.create_var(v->inferred_type, v->var_ref, v->loc));
|
||||
return v->var_ref->ir_idx;
|
||||
}
|
||||
|
||||
static std::vector<var_idx_t> process_local_vars_declaration(V<ast_local_vars_declaration>, CodeBlob&) {
|
||||
|
@ -439,7 +444,7 @@ static std::vector<var_idx_t> process_local_vars_declaration(V<ast_local_vars_de
|
|||
|
||||
static std::vector<var_idx_t> process_underscore(V<ast_underscore> v, CodeBlob& code) {
|
||||
// when _ is used as left side of assignment, like `(cs, _) = cs.loadAndReturn()`
|
||||
return {code.create_tmp_var(v->inferred_type, v->loc)};
|
||||
return code.create_tmp_var(v->inferred_type, v->loc);
|
||||
}
|
||||
|
||||
std::vector<var_idx_t> pre_compile_expr(AnyExprV v, CodeBlob& code, LValGlobs* lval_globs) {
|
||||
|
@ -516,8 +521,8 @@ static void process_assert_statement(V<ast_assert_statement> v, CodeBlob& code)
|
|||
static void process_catch_variable(AnyExprV v_catch_var, CodeBlob& code) {
|
||||
if (auto v_ref = v_catch_var->try_as<ast_reference>(); v_ref && v_ref->sym) { // not underscore
|
||||
const LocalVarData* var_ref = v_ref->sym->as<LocalVarData>();
|
||||
tolk_assert(var_ref->idx == -1);
|
||||
var_ref->mutate()->assign_idx(code.create_var(v_catch_var->inferred_type, var_ref, v_catch_var->loc));
|
||||
tolk_assert(var_ref->ir_idx.empty());
|
||||
var_ref->mutate()->assign_ir_idx(code.create_var(v_catch_var->inferred_type, var_ref, v_catch_var->loc));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,14 +632,13 @@ static void process_throw_statement(V<ast_throw_statement> v, CodeBlob& code) {
|
|||
static void process_return_statement(V<ast_return_statement> v, CodeBlob& code) {
|
||||
std::vector<var_idx_t> return_vars = v->has_return_value() ? pre_compile_expr(v->get_return_value(), code) : std::vector<var_idx_t>{};
|
||||
if (code.fun_ref->does_return_self()) {
|
||||
tolk_assert(return_vars.size() == 1);
|
||||
return_vars = {};
|
||||
}
|
||||
if (code.fun_ref->has_mutate_params()) {
|
||||
std::vector<var_idx_t> mutated_vars;
|
||||
for (const LocalVarData& p_sym: code.fun_ref->parameters) {
|
||||
if (p_sym.is_mutate_parameter()) {
|
||||
mutated_vars.push_back(p_sym.idx);
|
||||
mutated_vars.insert(mutated_vars.end(), p_sym.ir_idx.begin(), p_sym.ir_idx.end());
|
||||
}
|
||||
}
|
||||
return_vars.insert(return_vars.begin(), mutated_vars.begin(), mutated_vars.end());
|
||||
|
@ -647,7 +651,7 @@ static void append_implicit_return_statement(SrcLocation loc_end, CodeBlob& code
|
|||
if (code.fun_ref->has_mutate_params()) {
|
||||
for (const LocalVarData& p_sym: code.fun_ref->parameters) {
|
||||
if (p_sym.is_mutate_parameter()) {
|
||||
mutated_vars.push_back(p_sym.idx);
|
||||
mutated_vars.insert(mutated_vars.end(), p_sym.ir_idx.begin(), p_sym.ir_idx.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -685,11 +689,23 @@ void process_any_statement(AnyV v, CodeBlob& code) {
|
|||
static void convert_function_body_to_CodeBlob(const FunctionData* fun_ref, FunctionBodyCode* code_body) {
|
||||
auto v_body = fun_ref->ast_root->as<ast_function_declaration>()->get_body()->as<ast_sequence>();
|
||||
CodeBlob* blob = new CodeBlob{fun_ref->name, fun_ref->loc, fun_ref};
|
||||
FormalArgList legacy_arg_list;
|
||||
for (const LocalVarData& param : fun_ref->parameters) {
|
||||
legacy_arg_list.emplace_back(param.declared_type, ¶m, param.loc);
|
||||
|
||||
std::vector<var_idx_t> rvect_import;
|
||||
int total_arg_width = 0;
|
||||
for (int i = 0; i < fun_ref->get_num_params(); ++i) {
|
||||
total_arg_width += fun_ref->parameters[i].declared_type->calc_width_on_stack();
|
||||
}
|
||||
blob->import_params(std::move(legacy_arg_list));
|
||||
rvect_import.reserve(total_arg_width);
|
||||
|
||||
for (int i = 0; i < fun_ref->get_num_params(); ++i) {
|
||||
const LocalVarData& param_i = fun_ref->parameters[i];
|
||||
std::vector<var_idx_t> ir_idx = blob->create_var(param_i.declared_type, ¶m_i, param_i.loc);
|
||||
rvect_import.insert(rvect_import.end(), ir_idx.begin(), ir_idx.end());
|
||||
param_i.mutate()->assign_ir_idx(std::move(ir_idx));
|
||||
}
|
||||
blob->emplace_back(fun_ref->loc, Op::_Import, rvect_import);
|
||||
blob->in_var_cnt = blob->var_cnt;
|
||||
tolk_assert(blob->var_cnt == total_arg_width);
|
||||
|
||||
for (AnyV item : v_body->get_items()) {
|
||||
process_any_statement(item, *blob);
|
||||
|
|
|
@ -38,7 +38,7 @@ static void fire_error_cannot_be_used_as_lvalue(AnyV v, const std::string& detai
|
|||
|
||||
GNU_ATTRIBUTE_NORETURN GNU_ATTRIBUTE_COLD
|
||||
static void fire_error_modifying_immutable_variable(AnyExprV v, const LocalVarData* var_ref) {
|
||||
if (var_ref->idx == 0 && var_ref->name == "self") {
|
||||
if (var_ref->param_idx == 0 && var_ref->name == "self") {
|
||||
v->error("modifying `self`, which is immutable by default; probably, you want to declare `mutate self`");
|
||||
} else {
|
||||
v->error("modifying immutable variable `" + var_ref->name + "`");
|
||||
|
|
|
@ -54,11 +54,6 @@ static void generate_output_func(const FunctionData* fun_ref) {
|
|||
std::cerr << "after prune_unreachable: \n";
|
||||
code->print(std::cerr, 0);
|
||||
}
|
||||
code->split_vars(true);
|
||||
if (G.is_verbosity(5)) {
|
||||
std::cerr << "after split_vars: \n";
|
||||
code->print(std::cerr, 0);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
code->compute_used_code_vars();
|
||||
if (G.is_verbosity(4)) {
|
||||
|
|
|
@ -38,11 +38,11 @@ static void fire_error_invalid_mutate_arg_passed(AnyExprV v, const FunctionData*
|
|||
std::string arg_str(arg_expr->type == ast_reference ? arg_expr->as<ast_reference>()->get_name() : "obj");
|
||||
|
||||
// case: `loadInt(cs, 32)`; suggest: `cs.loadInt(32)`
|
||||
if (p_sym.is_mutate_parameter() && !arg_passed_as_mutate && !called_as_method && p_sym.idx == 0 && fun_ref->does_accept_self()) {
|
||||
if (p_sym.is_mutate_parameter() && !arg_passed_as_mutate && !called_as_method && p_sym.param_idx == 0 && fun_ref->does_accept_self()) {
|
||||
v->error("`" + fun_ref->name + "` is a mutating method; consider calling `" + arg_str + "." + fun_ref->name + "()`, not `" + fun_ref->name + "(" + arg_str + ")`");
|
||||
}
|
||||
// case: `cs.mutating_function()`; suggest: `mutating_function(mutate cs)` or make it a method
|
||||
if (p_sym.is_mutate_parameter() && called_as_method && p_sym.idx == 0 && !fun_ref->does_accept_self()) {
|
||||
if (p_sym.is_mutate_parameter() && called_as_method && p_sym.param_idx == 0 && !fun_ref->does_accept_self()) {
|
||||
v->error("function `" + fun_ref->name + "` mutates parameter `" + p_sym.name + "`; consider calling `" + fun_ref->name + "(mutate " + arg_str + ")`, not `" + arg_str + "." + fun_ref->name + "`(); alternatively, rename parameter to `self` to make it a method");
|
||||
}
|
||||
// case: `mutating_function(arg)`; suggest: `mutate arg`
|
||||
|
|
|
@ -93,8 +93,8 @@ void GlobalConstData::assign_resolved_type(TypePtr declared_type) {
|
|||
this->declared_type = declared_type;
|
||||
}
|
||||
|
||||
void LocalVarData::assign_idx(int idx) {
|
||||
this->idx = idx;
|
||||
void LocalVarData::assign_ir_idx(std::vector<int>&& ir_idx) {
|
||||
this->ir_idx = std::move(ir_idx);
|
||||
}
|
||||
|
||||
void LocalVarData::assign_resolved_type(TypePtr declared_type) {
|
||||
|
|
|
@ -59,20 +59,23 @@ struct LocalVarData final : Symbol {
|
|||
|
||||
TypePtr declared_type; // either at declaration `var x:int`, or if omitted, from assigned value `var x=2`
|
||||
int flags;
|
||||
int idx;
|
||||
int param_idx; // 0...N for function parameters, -1 for local vars
|
||||
std::vector<int> ir_idx;
|
||||
|
||||
LocalVarData(std::string name, SrcLocation loc, TypePtr declared_type, int flags, int idx)
|
||||
LocalVarData(std::string name, SrcLocation loc, TypePtr declared_type, int flags, int param_idx)
|
||||
: Symbol(std::move(name), loc)
|
||||
, declared_type(declared_type)
|
||||
, flags(flags)
|
||||
, idx(idx) {
|
||||
, param_idx(param_idx) {
|
||||
}
|
||||
|
||||
bool is_parameter() const { return param_idx >= 0; }
|
||||
|
||||
bool is_immutable() const { return flags & flagImmutable; }
|
||||
bool is_mutate_parameter() const { return flags & flagMutateParameter; }
|
||||
|
||||
LocalVarData* mutate() const { return const_cast<LocalVarData*>(this); }
|
||||
void assign_idx(int idx);
|
||||
void assign_ir_idx(std::vector<int>&& ir_idx);
|
||||
void assign_resolved_type(TypePtr declared_type);
|
||||
void assign_inferred_type(TypePtr inferred_type);
|
||||
};
|
||||
|
|
19
tolk/tolk.h
19
tolk/tolk.h
|
@ -45,17 +45,15 @@ typedef int const_idx_t;
|
|||
|
||||
struct TmpVar {
|
||||
TypePtr v_type;
|
||||
var_idx_t idx;
|
||||
var_idx_t ir_idx;
|
||||
const LocalVarData* v_sym; // points to var defined in code; nullptr for implicitly created tmp vars
|
||||
int coord;
|
||||
SrcLocation where;
|
||||
std::vector<std::function<void(SrcLocation)>> on_modification;
|
||||
|
||||
TmpVar(var_idx_t _idx, TypePtr type, const LocalVarData* v_sym, SrcLocation loc)
|
||||
TmpVar(var_idx_t ir_idx, TypePtr type, const LocalVarData* v_sym, SrcLocation loc)
|
||||
: v_type(type)
|
||||
, idx(_idx)
|
||||
, ir_idx(ir_idx)
|
||||
, v_sym(v_sym)
|
||||
, coord(0)
|
||||
, where(loc) {
|
||||
}
|
||||
|
||||
|
@ -345,8 +343,6 @@ struct Op {
|
|||
void show_var_list(std::ostream& os, const std::vector<VarDescr>& list, const std::vector<TmpVar>& vars) const;
|
||||
static void show_block(std::ostream& os, const Op* block, const std::vector<TmpVar>& vars, std::string pfx = "",
|
||||
int mode = 0);
|
||||
void split_vars(const std::vector<TmpVar>& vars);
|
||||
static void split_var_list(std::vector<var_idx_t>& var_list, const std::vector<TmpVar>& vars);
|
||||
bool compute_used_vars(const CodeBlob& code, bool edit);
|
||||
bool std_compute_used_vars(bool disabled = false);
|
||||
bool set_var_info(const VarDescrList& new_var_info);
|
||||
|
@ -385,9 +381,6 @@ inline ListIterator<const Op> end(const Op* op_list) {
|
|||
return ListIterator<const Op>{};
|
||||
}
|
||||
|
||||
typedef std::tuple<TypePtr, const LocalVarData*, SrcLocation> FormalArg;
|
||||
typedef std::vector<FormalArg> FormalArgList;
|
||||
|
||||
struct AsmOpList;
|
||||
|
||||
struct FunctionBodyCode {
|
||||
|
@ -1115,12 +1108,10 @@ struct CodeBlob {
|
|||
#endif
|
||||
return res;
|
||||
}
|
||||
bool import_params(FormalArgList&& arg_list);
|
||||
var_idx_t create_var(TypePtr var_type, const LocalVarData* v_sym, SrcLocation loc);
|
||||
var_idx_t create_tmp_var(TypePtr var_type, SrcLocation loc) {
|
||||
std::vector<var_idx_t> create_var(TypePtr var_type, const LocalVarData* v_sym, SrcLocation loc);
|
||||
std::vector<var_idx_t> create_tmp_var(TypePtr var_type, SrcLocation loc) {
|
||||
return create_var(var_type, nullptr, loc);
|
||||
}
|
||||
int split_vars(bool strict = false);
|
||||
bool compute_used_code_vars();
|
||||
bool compute_used_code_vars(std::unique_ptr<Op>& ops, const VarDescrList& var_info, bool edit) const;
|
||||
void print(std::ostream& os, int flags = 0) const;
|
||||
|
|
|
@ -537,31 +537,6 @@ bool TypeDataVoid::can_be_casted_with_as_operator(TypePtr cast_to) const {
|
|||
}
|
||||
|
||||
|
||||
// --------------------------------------------
|
||||
// extract_components()
|
||||
//
|
||||
// used in code generation (transforming Ops to other Ops)
|
||||
// to be removed in the future
|
||||
//
|
||||
|
||||
void TypeDataGenericT::extract_components(std::vector<TypePtr>& comp_types) const {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void TypeDataTensor::extract_components(std::vector<TypePtr>& comp_types) const {
|
||||
for (TypePtr item : items) {
|
||||
item->extract_components(comp_types);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeDataUnresolved::extract_components(std::vector<TypePtr>& comp_types) const {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void TypeDataVoid::extract_components(std::vector<TypePtr>& comp_types) const {
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------
|
||||
// parsing type from tokens
|
||||
//
|
||||
|
|
|
@ -97,10 +97,6 @@ public:
|
|||
virtual int calc_width_on_stack() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void extract_components(std::vector<TypePtr>& comp_types) const {
|
||||
comp_types.push_back(this);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -291,7 +287,6 @@ public:
|
|||
bool can_rhs_be_assigned(TypePtr rhs) const override;
|
||||
bool can_be_casted_with_as_operator(TypePtr cast_to) const override;
|
||||
int calc_width_on_stack() const override;
|
||||
void extract_components(std::vector<TypePtr>& comp_types) const override;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -318,7 +313,6 @@ public:
|
|||
void traverse(const TraverserCallbackT& callback) const override;
|
||||
TypePtr replace_children_custom(const ReplacerCallbackT& callback) const override;
|
||||
int calc_width_on_stack() const override;
|
||||
void extract_components(std::vector<TypePtr>& comp_types) const override;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -387,7 +381,6 @@ public:
|
|||
bool can_rhs_be_assigned(TypePtr rhs) const override;
|
||||
bool can_be_casted_with_as_operator(TypePtr cast_to) const override;
|
||||
int calc_width_on_stack() const override;
|
||||
void extract_components(std::vector<TypePtr>& comp_types) const override;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -408,7 +401,6 @@ public:
|
|||
bool can_rhs_be_assigned(TypePtr rhs) const override;
|
||||
bool can_be_casted_with_as_operator(TypePtr cast_to) const override;
|
||||
int calc_width_on_stack() const override;
|
||||
void extract_components(std::vector<TypePtr>& comp_types) const override;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue