optimize codegen

This commit is contained in:
ValKmjolnir 2023-03-09 23:00:25 +08:00
parent dbc2c365b4
commit 8161f3c514
5 changed files with 113 additions and 191 deletions

View File

@ -71,9 +71,9 @@ test:nasal
@ ./nasal -e test/qrcode.nas @ ./nasal -e test/qrcode.nas
@ ./nasal -t -d test/quick_sort.nas @ ./nasal -t -d test/quick_sort.nas
@ ./nasal -e test/scalar.nas hello world @ ./nasal -e test/scalar.nas hello world
-@ ./nasal -t test/snake.nas --skip @ ./nasal -t test/snake.nas --skip
@ ./nasal -e test/trait.nas @ ./nasal -e test/trait.nas
-@ ./nasal -t test/tetris.nas --skip @ ./nasal -t test/tetris.nas --skip
@ ./nasal -t -d test/turingmachine.nas @ ./nasal -t -d test/turingmachine.nas
@ ./nasal -d test/wavecollapse.nas @ ./nasal -d test/wavecollapse.nas
@ ./nasal test/word_collector.nas test/md5compare.nas @ ./nasal test/word_collector.nas test/md5compare.nas

View File

@ -212,16 +212,13 @@ private:
std::vector<opcode> code; std::vector<opcode> code;
std::list<std::vector<i32>> continue_ptr; std::list<std::vector<i32>> continue_ptr;
std::list<std::vector<i32>> break_ptr; std::list<std::vector<i32>> break_ptr;
// global : max 4095 values // global : max 1023 values
std::unordered_map<string,i32> global; std::unordered_map<string,i32> global;
// local : max 32768 upvalues 65536 values // local : max 32768 upvalues 65536 values
std::list<std::unordered_map<string,i32>> local; std::list<std::unordered_map<string,i32>> local;
// func end stack, reserved for code print
std::stack<u32> fbstk;
std::stack<u32> festk;
bool check_memory_reachable(const ast&); bool check_memory_reachable(const ast&);
void check_id_exist(const ast&);
void die(const string& info,const span& loc) { void die(const string& info,const span& loc) {
err.err("code",loc,info); err.err("code",loc,info);
@ -259,6 +256,7 @@ private:
void load_continue_break(i32,i32); void load_continue_break(i32,i32);
void while_gen(const ast&); void while_gen(const ast&);
void for_gen(const ast&); void for_gen(const ast&);
void expr_gen(const ast&);
void forindex_gen(const ast&); void forindex_gen(const ast&);
void foreach_gen(const ast&); void foreach_gen(const ast&);
void or_gen(const ast&); void or_gen(const ast&);
@ -267,8 +265,6 @@ private:
void calc_gen(const ast&); void calc_gen(const ast&);
void block_gen(const ast&); void block_gen(const ast&);
void ret_gen(const ast&); void ret_gen(const ast&);
void singleop(const u32);
public: public:
codegen(error& e):fileindex(0),err(e),file(nullptr) {} codegen(error& e):fileindex(0),err(e),file(nullptr) {}
const error& compile(const parse&,const linker&); const error& compile(const parse&,const linker&);
@ -296,6 +292,29 @@ bool codegen::check_memory_reachable(const ast& node) {
return true; return true;
} }
void codegen::check_id_exist(const ast& node) {
const string& str=node.str();
for(u32 i=0;builtin[i].name;++i) {
if (builtin[i].name==str) {
if (local.empty()) {
die("useless native function used in global scope",node.location());
}
return;
}
}
if (local_find(str)>=0) {
return;
}
if (upvalue_find(str)>=0) {
return;
}
if (global_find(str)>=0) {
return;
}
die("undefined symbol \""+str+"\", and this symbol is useless here",node.location());
}
void codegen::regist_num(const f64 num) { void codegen::regist_num(const f64 num) {
if (!num_table.count(num)) { if (!num_table.count(num)) {
u32 size=num_table.size(); u32 size=num_table.size();
@ -808,63 +827,7 @@ void codegen::while_gen(const ast& node) {
} }
void codegen::for_gen(const ast& node) { void codegen::for_gen(const ast& node) {
switch(node[0].type()) { expr_gen(node[0]);
case ast_null:break;
case ast_def:def_gen(node[0]);break;
case ast_multi_assign:multi_assign_gen(node[0]);break;
case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(node[0]);
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) {
code.back().num=1;
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().num|=0x80000000;
} else {
gen(op_pop,0,node[0].line());
}
break;
case ast_nil:case ast_num:case ast_str:case ast_bool:break;
case ast_vec:case ast_hash:case ast_func:
case ast_call:
case ast_neg:case ast_lnot:case ast_bnot:
case ast_bitor:case ast_bitxor:case ast_bitand:
case ast_add:case ast_sub:
case ast_mult:case ast_div:
case ast_link:
case ast_cmpeq:case ast_neq:
case ast_leq:case ast_less:
case ast_geq:case ast_grt:
case ast_trino:
calc_gen(node[0]);
if (code.back().op==op_meq) {
code.back().num=1;
} else {
gen(op_pop,0,node[0].line());
}
break;
case ast_equal:
if (node[0][0].type()==ast_id) {
calc_gen(node[0][1]);
mcall_id(node[0][0]);
// only the first mcall_id can use load
if (code.back().op==op_mcalll) {
code.back().op=op_loadl;
} else if (code.back().op==op_mupval) {
code.back().op=op_loadu;
} else {
code.back().op=op_loadg;
}
} else {
calc_gen(node[0]);
if (code.back().op==op_meq) {
code.back().num=1;
} else {
gen(op_pop,0,node[0].line());
}
}
break;
}
usize jmp_place=code.size(); usize jmp_place=code.size();
if (node[1].type()==ast_null) { if (node[1].type()==ast_null) {
gen(op_pnum,num_table[1],node[1].line()); gen(op_pnum,num_table[1],node[1].line());
@ -876,43 +839,50 @@ void codegen::for_gen(const ast& node) {
block_gen(node[3]); block_gen(node[3]);
usize continue_place=code.size(); usize continue_place=code.size();
switch(node[2].type()) { expr_gen(node[2]);
gen(op_jmp,jmp_place,node[2].line());
code[label_exit].num=code.size();
load_continue_break(continue_place,code.size());
}
void codegen::expr_gen(const ast& node) {
switch(node.type()) {
case ast_null:break; case ast_null:break;
case ast_def:def_gen(node[2]);break; case ast_def:def_gen(node);break;
case ast_multi_assign:multi_assign_gen(node[2]);break; case ast_multi_assign:multi_assign_gen(node);break;
case ast_addeq:case ast_subeq: case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq: case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq: case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(node[2]); calc_gen(node);
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) { if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) {
code.back().num=1; code.back().num=1;
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) {
code.back().num|=0x80000000; code.back().num|=0x80000000;
} else { } else {
gen(op_pop,0,node[2].line()); gen(op_pop,0,node.line());
} }
break; break;
case ast_nil:case ast_num:case ast_str:case ast_bool:break; case ast_nil:case ast_num:case ast_str:case ast_bool:break;
case ast_vec:case ast_hash:case ast_func: case ast_vec:case ast_hash:case ast_func:case ast_call:
case ast_call:
case ast_neg:case ast_lnot:case ast_bnot: case ast_neg:case ast_lnot:case ast_bnot:
case ast_bitor:case ast_bitxor:case ast_bitand: case ast_bitor:case ast_bitxor:case ast_bitand:
case ast_add:case ast_sub:case ast_mult: case ast_add:case ast_sub:case ast_mult:case ast_div:case ast_link:
case ast_div:case ast_link: case ast_cmpeq:case ast_neq:
case ast_cmpeq:case ast_neq:case ast_leq: case ast_leq:case ast_less:
case ast_less:case ast_geq:case ast_grt: case ast_geq:case ast_grt:
case ast_trino: case ast_trino:
calc_gen(node[2]); calc_gen(node);
if (code.back().op==op_meq) { if (code.back().op==op_meq) {
code.back().num=1; code.back().num=1;
} else { } else {
gen(op_pop,0,node[2].line()); gen(op_pop,0,node.line());
} }
break; break;
case ast_equal: case ast_equal:
if (node[2][0].type()==ast_id) { if (node[0].type()==ast_id) {
calc_gen(node[2][1]); calc_gen(node[1]);
mcall_id(node[2][0]); mcall_id(node[0]);
// only the first mcall_id can use load // only the first mcall_id can use load
if (code.back().op==op_mcalll) { if (code.back().op==op_mcalll) {
code.back().op=op_loadl; code.back().op=op_loadl;
@ -922,19 +892,15 @@ void codegen::for_gen(const ast& node) {
code.back().op=op_loadg; code.back().op=op_loadg;
} }
} else { } else {
calc_gen(node[2]); calc_gen(node);
if (code.back().op==op_meq) { if (code.back().op==op_meq) {
code.back().num=1; code.back().num=1;
} else { } else {
gen(op_pop,0,node[2].line()); gen(op_pop,0,node.line());
} }
} }
break; break;
} }
gen(op_jmp,jmp_place,node[2].line());
code[label_exit].num=code.size();
load_continue_break(continue_place,code.size());
} }
void codegen::forindex_gen(const ast& node) { void codegen::forindex_gen(const ast& node) {
@ -1170,14 +1136,10 @@ void codegen::calc_gen(const ast& node) {
void codegen::block_gen(const ast& node) { void codegen::block_gen(const ast& node) {
for(auto& tmp:node.child()) { for(auto& tmp:node.child()) {
switch(tmp.type()) { switch(tmp.type()) {
case ast_null: case ast_null:break;
case ast_nil: case ast_id:check_id_exist(tmp);break;
case ast_num: case ast_nil:case ast_num:case ast_str:case ast_bool:break;
case ast_str:
case ast_bool:break;
case ast_file:fileindex=tmp.num();break; // special node type in main block case ast_file:fileindex=tmp.num();break; // special node type in main block
case ast_def:def_gen(tmp);break;
case ast_multi_assign:multi_assign_gen(tmp);break;
case ast_cond:cond_gen(tmp);break; case ast_cond:cond_gen(tmp);break;
case ast_continue: case ast_continue:
continue_ptr.front().push_back(code.size()); continue_ptr.front().push_back(code.size());
@ -1192,70 +1154,21 @@ void codegen::block_gen(const ast& node) {
case ast_forindex: case ast_forindex:
case ast_foreach:loop_gen(tmp);break; case ast_foreach:loop_gen(tmp);break;
case ast_equal: case ast_equal:
if (tmp[0].type()==ast_id) {
calc_gen(tmp[1]);
mcall_id(tmp[0]);
// only the first mcall_id can use load
if (code.back().op==op_mcalll) {
code.back().op=op_loadl;
} else if (code.back().op==op_mupval) {
code.back().op=op_loadu;
} else {
code.back().op=op_loadg;
}
} else {
calc_gen(tmp);
if (code.back().op==op_meq) {
code.back().num=1;
} else {
gen(op_pop,0,tmp.line());
}
}
break;
case ast_addeq:case ast_subeq: case ast_addeq:case ast_subeq:
case ast_multeq:case ast_diveq:case ast_lnkeq: case ast_multeq:case ast_diveq:case ast_lnkeq:
case ast_btandeq:case ast_btoreq:case ast_btxoreq: case ast_btandeq:case ast_btoreq:case ast_btxoreq:
calc_gen(tmp); case ast_vec:case ast_hash:case ast_func:case ast_call:
if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) { case ast_neg:case ast_lnot:case ast_bnot:
code.back().num=1; case ast_bitor:case ast_bitxor:case ast_bitand:
} else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { case ast_add:case ast_sub:case ast_mult:case ast_div:case ast_link:
code.back().num|=0x80000000; case ast_cmpeq:case ast_neq:
} else { case ast_leq:case ast_less:
gen(op_pop,0,tmp.line()); case ast_geq:case ast_grt:
}
break;
case ast_id:
case ast_vec:
case ast_hash:
case ast_func:
case ast_call:
case ast_neg:
case ast_lnot:
case ast_bnot:
case ast_bitor:
case ast_bitxor:
case ast_bitand:
case ast_add:
case ast_sub:
case ast_mult:
case ast_div:
case ast_link:
case ast_cmpeq:
case ast_neq:
case ast_leq:
case ast_less:
case ast_geq:
case ast_grt:
case ast_or: case ast_or:
case ast_and: case ast_and:
case ast_trino: case ast_trino:
calc_gen(tmp); case ast_def:
if (code.back().op==op_meq) { case ast_multi_assign:expr_gen(tmp);break;
code.back().num=1;
} else {
gen(op_pop,0,tmp.line());
}
break;
case ast_ret:ret_gen(tmp);break; case ast_ret:ret_gen(tmp);break;
} }
} }
@ -1283,49 +1196,59 @@ const error& codegen::compile(const parse& parse,const linker& import) {
block_gen(parse.tree()); // generate main block block_gen(parse.tree()); // generate main block
gen(op_exit,0,0); gen(op_exit,0,0);
if (global.size()>=STACK_DEPTH) { if (global.size()>=STACK_DEPTH) {
err.load(file[fileindex]); err.load(file[0]); // load main execute file
err.err("code","too many global variants: "+std::to_string(global.size())); err.err("code","too many global variants: "+std::to_string(global.size()));
} }
if (code.size()>0xffffffff) { if (code.size()>0x00ffffff) {
err.load(file[fileindex]); err.load(file[0]); // load main execute file
err.err("code","too large generated bytecode file: "+std::to_string(code.size())); err.err("code","bytecode size overflow: "+std::to_string(code.size()));
} }
return err; return err;
} }
void codegen::singleop(const u32 index) {
// print opcode index,opcode name,opcode immediate number
const opcode& c=code[index];
if (!festk.empty() && index==festk.top()) {
std::cout<<std::hex<<"<0x"<<fbstk.top()<<std::dec<<">;\n";
if (code[index].op!=op_newf) { // avoid two empty lines
std::cout<<"\n";
}
fbstk.pop();
festk.pop();
}
if (c.op==op_newf) {
std::cout<<std::hex<<"\nfunc <0x"<<index<<std::dec<<">:\n";
for(u32 i=index;i<code.size();++i) {
if (code[i].op==op_jmp) {
fbstk.push(index);
festk.push(code[i].num);
break;
}
}
}
std::cout<<" "<<codestream(c,index,num_res.data(),str_res.data())<<"\n";
}
void codegen::print() { void codegen::print() {
// func end stack, reserved for code print
std::stack<u32> fbstk;
std::stack<u32> festk;
// print const numbers
for(auto& num:num_res) { for(auto& num:num_res) {
std::cout<<" .number "<<num<<"\n"; std::cout<<" .number "<<num<<"\n";
} }
// print const strings
for(auto& str:str_res) { for(auto& str:str_res) {
std::cout<<" .symbol \""<<rawstr(str)<<"\"\n"; std::cout<<" .symbol \""<<rawstr(str)<<"\"\n";
} }
// print code
std::cout<<"\n"; std::cout<<"\n";
for(u32 i=0;i<code.size();++i) { for(u32 i=0;i<code.size();++i) {
singleop(i); // print opcode index, opcode name, opcode immediate number
const opcode& c=code[i];
if (!festk.empty() && i==festk.top()) {
std::cout<<std::hex<<"<0x"<<fbstk.top()<<std::dec<<">;\n";
// avoid two empty lines
if (c.op!=op_newf) {
std::cout<<"\n";
}
fbstk.pop();
festk.pop();
}
// get function begin index and end index
if (c.op==op_newf) {
std::cout<<std::hex<<"\nfunc <0x"<<i<<std::dec<<">:\n";
for(u32 j=i;j<code.size();++j) {
if (code[j].op==op_jmp) {
fbstk.push(i);
festk.push(code[j].num);
break;
}
}
}
// output bytecode
std::cout<<" "<<codestream(c,i,num_res.data(),str_res.data())<<"\n";
} }
} }

View File

@ -144,9 +144,9 @@ void flstream::load(const string& f) {
void error::fatal(const string& stage,const string& info) { void error::fatal(const string& stage,const string& info) {
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n"; std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
if (file.length()) { if (file.length()) {
std::cerr<<cyan<<" --> "<<red<<file<<"\n\n"; std::cerr<<cyan<<" --> "<<red<<file<<reset<<"\n\n";
} else { } else {
std::cerr<<"\n"; std::cerr<<reset<<"\n";
} }
std::exit(1); std::exit(1);
} }
@ -155,9 +155,9 @@ void error::err(const string& stage,const string& info) {
++cnt; ++cnt;
std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n"; std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
if (file.length()) { if (file.length()) {
std::cerr<<cyan<<" --> "<<red<<file<<"\n\n"; std::cerr<<cyan<<" --> "<<red<<file<<reset<<"\n\n";
} else { } else {
std::cerr<<"\n"; std::cerr<<reset<<"\n";
} }
} }

View File

@ -173,18 +173,18 @@ var ansi_escape_sequence=func(){
# move curser left and up # move curser left and up
var bar=process_bar.default_bar("classic3",30); var bar=process_bar.default_bar("classic3",30);
var progress=[0,0,0,0,0,0,0,0]; var progress=[0,0,0,0,0,0,0,0];
var increase=[0.015,0.03,0.02,0.047,0.04,0.045,0.025,0.016]; var increase=[0.03,0.06,0.04,0.094,0.08,0.09,0.05,0.032];
foreach(var i;progress) { foreach(var i;progress) {
print("\e[1000D",bar.bar(i)," ",rightpad(str(int(i*100)),3)," % \n"); print("\e[1000D",bar.bar(i)," ",rightpad(str(int(i*100)),3)," % \n");
} }
for(var i=0;i<1/0.015;i+=1) { for(var i=0;i<1/0.03;i+=1) {
print("\e[1000D","\e["~str(size(progress))~"A"); print("\e[1000D","\e["~str(size(progress))~"A");
forindex(var j;progress) { forindex(var j;progress) {
progress[j]+=increase[j]; progress[j]+=increase[j];
progress[j]=progress[j]>1?1:progress[j]; progress[j]=progress[j]>1?1:progress[j];
print("\e[1000D",bar.bar(progress[j])," ",rightpad(str(int(progress[j]*100)),3)," % \n") print("\e[1000D",bar.bar(progress[j])," ",rightpad(str(int(progress[j]*100)),3)," % \n")
} }
unix.sleep(0.02); unix.sleep(0.01);
} }
} }

View File

@ -97,9 +97,8 @@ var map=func(){
if(os.platform()=="windows") if(os.platform()=="windows")
system("chcp 65001"); system("chcp 65001");
map.new(90); map.new(90);
var interval=1/160;
for(var iter=0;iter<40;iter+=1){ for(var iter=0;iter<40;iter+=1){
map.print(1); map.print(1);
map.next(); map.next();
unix.sleep(interval);
} }