optimize codegen

This commit is contained in:
ValKmjolnir 2023-09-24 00:41:29 +08:00
parent f8ecd2ae53
commit 5e2bb411e5
2 changed files with 80 additions and 67 deletions

View File

@ -37,18 +37,19 @@ void codegen::check_id_exist(identifier* node) {
if (native_function_mapper.count(name)) {
if (local.empty()) {
die("native function should not be used in global scope",
node->get_location());
node->get_location()
);
}
return;
}
if (local_find(name)>=0) {
if (local_symbol_find(name)>=0) {
return;
}
if (upvalue_find(name)>=0) {
if (upvalue_symbol_find(name)>=0) {
return;
}
if (global_find(name)>=0) {
if (global_symbol_find(name)>=0) {
return;
}
die("undefined symbol \"" + name +
@ -106,18 +107,18 @@ void codegen::add_symbol(const std::string& name) {
local.back()[name] = index;
}
i32 codegen::local_find(const std::string& name) {
i32 codegen::local_symbol_find(const std::string& name) {
if (local.empty()) {
return -1;
}
return local.back().count(name)? local.back().at(name):-1;
}
i32 codegen::global_find(const std::string& name) {
i32 codegen::global_symbol_find(const std::string& name) {
return global.count(name)? global.at(name):-1;
}
i32 codegen::upvalue_find(const std::string& name) {
i32 codegen::upvalue_symbol_find(const std::string& name) {
// 32768 level 65536 upvalues
i32 index = -1;
usize size = local.size();
@ -252,9 +253,11 @@ void codegen::func_gen(function* node) {
emit(op_jmp, 0, node->get_location());
auto block = node->get_code_block();
// search symbols first, must use after loading parameters
// or the location of symbols will change and cause fatal error
find_symbol(block);
// add special varibale "arg", which is used to store overflowed args
// but if dynamic parameter is declared, this variable will be useless
// for example:
@ -265,7 +268,7 @@ void codegen::func_gen(function* node) {
// var f = func(a, arg...) {return(arg)}
auto arg = std::string("arg");
// this is used to avoid confliction with defined parameter
while(local_find(arg)>=0) {
while(local_symbol_find(arg)>=0) {
arg = "0" + arg;
}
add_symbol(arg);
@ -308,24 +311,26 @@ void codegen::call_id(identifier* node) {
if (native_function_mapper.count(name)) {
emit(op_callb,
static_cast<u32>(native_function_mapper.at(name)),
node->get_location());
node->get_location()
);
if (local.empty()) {
die("should warp native function in local scope",
node->get_location());
node->get_location()
);
}
return;
}
i32 index;
if ((index=local_find(name))>=0) {
if ((index = local_symbol_find(name))>=0) {
emit(op_calll, index, node->get_location());
return;
}
if ((index=upvalue_find(name))>=0) {
if ((index = upvalue_symbol_find(name))>=0) {
emit(op_upval, index, node->get_location());
return;
}
if ((index=global_find(name))>=0) {
if ((index = global_symbol_find(name))>=0) {
emit(op_callg, index, node->get_location());
return;
}
@ -427,15 +432,15 @@ void codegen::mcall_id(identifier* node) {
}
i32 index;
if ((index=local_find(name))>=0) {
if ((index = local_symbol_find(name))>=0) {
emit(op_mcalll, index, node->get_location());
return;
}
if ((index=upvalue_find(name))>=0) {
if ((index = upvalue_symbol_find(name))>=0) {
emit(op_mupval, index, node->get_location());
return;
}
if ((index=global_find(name))>=0) {
if ((index = global_symbol_find(name))>=0) {
emit(op_mcallg, index, node->get_location());
return;
}
@ -465,9 +470,9 @@ void codegen::single_def(definition_expr* node) {
const auto& str = node->get_variable_name()->get_name();
calc_gen(node->get_value());
if (local.empty()) {
emit(op_loadg, global_find(str), node->get_location());
emit(op_loadg, global_symbol_find(str), node->get_location());
} else {
emit(op_loadl, local_find(str), node->get_location());
emit(op_loadl, local_symbol_find(str), node->get_location());
}
}
@ -490,8 +495,8 @@ void codegen::multi_def(definition_expr* node) {
calc_gen(vals[i]);
const auto& name = identifiers[i]->get_name();
local.empty()?
emit(op_loadg, global_find(name), identifiers[i]->get_location()):
emit(op_loadl, local_find(name), identifiers[i]->get_location());
emit(op_loadg, global_symbol_find(name), identifiers[i]->get_location()):
emit(op_loadl, local_symbol_find(name), identifiers[i]->get_location());
}
return;
}
@ -501,8 +506,8 @@ void codegen::multi_def(definition_expr* node) {
emit(op_callvi, i, node->get_value()->get_location());
const auto& name = identifiers[i]->get_name();
local.empty()?
emit(op_loadg, global_find(name), identifiers[i]->get_location()):
emit(op_loadl, local_find(name), identifiers[i]->get_location());
emit(op_loadg, global_symbol_find(name), identifiers[i]->get_location()):
emit(op_loadl, local_symbol_find(name), identifiers[i]->get_location());
}
emit(op_pop, 0, node->get_location());
}
@ -632,6 +637,20 @@ void codegen::gen_assignment_equal_statement(assignment_expr* node) {
}
}
void codegen::replace_left_assignment_with_load(const span& location) {
// replace mcall with load,
// because mcall needs meq(1) (meq-pop) after it to load,
// but load to mcall-meq-pop in one operand.
// if is not mcall operand, emit meq(1) (meq-pop).
switch(code.back().op) {
case op_mcallg: code.back().op = op_loadg; break;
case op_mcalll: code.back().op = op_loadl; break;
case op_mupval: code.back().op = op_loadu; break;
default: emit(op_meq, 1, location); break;
}
return;
}
void codegen::assignment_statement(assignment_expr* node) {
switch(node->get_assignment_type()) {
case assignment_expr::assign_type::equal:
@ -665,7 +684,9 @@ void codegen::multi_assign_gen(multi_assign* node) {
node->get_tuple()->get_elements().size()>((tuple_expr*)node->get_value())->get_elements().size()) {
die("too many values in multi-assignment", node->get_value()->get_location());
}
i32 size = node->get_tuple()->get_elements().size();
// generate multiple assignment: (a, b, c) = (1, 2, 3);
if (node->get_value()->get_type()==expr_type::ast_tuple) {
for(i32 i = size-1; i>=0; --i) {
calc_gen(((tuple_expr*)node->get_value())->get_elements()[i]);
@ -673,37 +694,24 @@ void codegen::multi_assign_gen(multi_assign* node) {
auto& tuple = node->get_tuple()->get_elements();
for(i32 i = 0; i<size; ++i) {
mcall(tuple[i]);
// multi assign user loadl and loadg to avoid meq's stack--
// use load operands to avoid meq's pop operand
// and this operation changes local and global value directly
if (code.back().op==op_mcalll) {
code.back().op = op_loadl;
} else if (code.back().op==op_mupval) {
code.back().op = op_loadu;
} else if (code.back().op==op_mcallg) {
code.back().op = op_loadg;
} else {
emit(op_meq, 1, tuple[i]->get_location());
}
replace_left_assignment_with_load(tuple[i]->get_location());
}
return;
}
// generate multiple assignment: (a, b, c) = [1, 2, 3];
calc_gen(node->get_value());
auto& tuple = node->get_tuple()->get_elements();
for(i32 i = 0; i<size; ++i) {
emit(op_callvi, i, node->get_value()->get_location());
// multi assign user loadl and loadg to avoid meq's stack--
// and this operation changes local and global value directly
mcall(tuple[i]);
if (code.back().op==op_mcalll) {
code.back().op = op_loadl;
} else if (code.back().op==op_mupval) {
code.back().op = op_loadu;
} else if (code.back().op==op_mcallg) {
code.back().op = op_loadg;
} else {
emit(op_meq, 1, tuple[i]->get_location());
}
// use load operands to avoid meq's pop operand
// and this operation changes local and global value directly
replace_left_assignment_with_load(tuple[i]->get_location());
}
// pop source vector
emit(op_pop, 0, node->get_location());
}
@ -800,38 +808,39 @@ void codegen::for_gen(for_expr* node) {
void codegen::forei_gen(forei_expr* node) {
calc_gen(node->get_value());
emit(op_cnt, 0, node->get_value()->get_location());
usize ptr = code.size();
usize loop_begin = code.size();
if (node->get_loop_type()==forei_expr::forei_loop_type::forindex) {
emit(op_findex, 0, node->get_location());
} else {
emit(op_feach, 0, node->get_location());
}
if (node->get_iterator()->get_name()) { // define a new iterator
if (node->get_iterator()->get_name()) {
// define a new iterator
auto name_node = node->get_iterator()->get_name();
const auto& str = name_node->get_name();
local.empty()?
emit(op_loadg, global_find(str), name_node->get_location()):
emit(op_loadl, local_find(str), name_node->get_location());
} else { // use exist variable as the iterator
emit(op_loadg, global_symbol_find(str), name_node->get_location()):
emit(op_loadl, local_symbol_find(str), name_node->get_location());
} else {
// use exist variable as the iterator
mcall(node->get_iterator()->get_call());
if (code.back().op==op_mcallg) {
code.back().op = op_loadg;
} else if (code.back().op==op_mcalll) {
code.back().op = op_loadl;
} else if (code.back().op==op_mupval) {
code.back().op = op_loadu;
} else {
emit(op_meq, 1, node->get_iterator()->get_location());
}
replace_left_assignment_with_load(node->get_iterator()->get_location());
}
// generate code block
++in_loop_level.back();
block_gen(node->get_code_block());
--in_loop_level.back();
emit(op_jmp, ptr, node->get_location());
code[ptr].num=code.size();
// jump to loop begin
emit(op_jmp, loop_begin, node->get_location());
code[loop_begin].num=code.size();
load_continue_break(code.size()-1, code.size());
emit(op_pop, 0, node->get_value()->get_location());// pop vector
emit(op_pop, 0, node->get_location());// pop iterator
// pop source vector
emit(op_pop, 0, node->get_value()->get_location());
// pop loop iterator
emit(op_pop, 0, node->get_location());
}
void codegen::statement_generation(expr* node) {
@ -1196,14 +1205,16 @@ const error& codegen::compile(parse& parse, linker& import) {
// check global variables size
if (global.size()>=STACK_DEPTH/2) {
err.err("code",
"too many global variables: " + std::to_string(global.size())
"too many global variables: " +
std::to_string(global.size())
);
}
// check generated code size
if (code.size()>0xffffff) {
err.err("code",
"bytecode size overflow: " + std::to_string(code.size())
"bytecode size overflow: " +
std::to_string(code.size())
);
}
return err;
@ -1233,7 +1244,8 @@ void codegen::print(std::ostream& out) {
codestream::set(
const_number_table.data(),
const_string_table.data(),
native_function.data());
native_function.data()
);
for(u32 i = 0; i<code.size(); ++i) {
// print opcode index, opcode name, opcode immediate number
const auto& c = code[i];

View File

@ -79,9 +79,9 @@ private:
void regist_str(const std::string&);
void find_symbol(code_block*);
void add_symbol(const std::string&);
i32 local_find(const std::string&);
i32 global_find(const std::string&);
i32 upvalue_find(const std::string&);
i32 local_symbol_find(const std::string&);
i32 global_symbol_find(const std::string&);
i32 upvalue_symbol_find(const std::string&);
void emit(u8, u32, const span&);
@ -105,6 +105,7 @@ private:
void def_gen(definition_expr*);
void assignment_expression(assignment_expr*);
void gen_assignment_equal_statement(assignment_expr*);
void replace_left_assignment_with_load(const span&);
void assignment_statement(assignment_expr*);
void multi_assign_gen(multi_assign*);
void cond_gen(condition_expr*);