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