From 051dd5e2d3da35b70b2af709cc86837fa70213bc Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 23 Jul 2024 13:46:10 +0200 Subject: [PATCH] updates templates for decoder in seperate class, adds again generated templates --- gen_input/templates/asmjit/CORENAME.cpp.gtl | 92 +++++-------------- gen_input/templates/llvm/CORENAME.cpp.gtl | 95 +++++--------------- gen_input/templates/tcc/CORENAME.cpp.gtl | 98 +++++---------------- src/vm/asmjit/vm_tgc5c.cpp | 2 +- src/vm/llvm/vm_tgc5c.cpp | 2 +- src/vm/tcc/vm_tgc5c.cpp | 2 +- 6 files changed, 68 insertions(+), 223 deletions(-) diff --git a/gen_input/templates/asmjit/CORENAME.cpp.gtl b/gen_input/templates/asmjit/CORENAME.cpp.gtl index 45c60b7..5749f29 100644 --- a/gen_input/templates/asmjit/CORENAME.cpp.gtl +++ b/gen_input/templates/asmjit/CORENAME.cpp.gtl @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -115,27 +116,21 @@ private: * start opcode definitions ****************************************************************************/ struct instruction_descriptor { - size_t length; + uint32_t length; uint32_t value; uint32_t mask; compile_func op; }; - struct decoding_tree_node{ - std::vector instrs; - std::vector children; - uint32_t submask = std::numeric_limits::max(); - uint32_t value; - decoding_tree_node(uint32_t value) : value(value){} - }; - - decoding_tree_node* root {nullptr}; const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> }}; - + + //needs to be declared after instr_descr + decoder instr_decoder; + /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction ${idx}: ${instr.name} */ continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ @@ -200,72 +195,22 @@ private: gen_instr_epilogue(jh); return BRANCH; } - - //decoding functionality - - void populate_decoding_tree(decoding_tree_node* root){ - //create submask - for(auto instr: root->instrs){ - root->submask &= instr.mask; - } - //put each instr according to submask&encoding into children - for(auto instr: root->instrs){ - bool foundMatch = false; - for(auto child: root->children){ - //use value as identifying trait - if(child->value == (instr.value&root->submask)){ - child->instrs.push_back(instr); - foundMatch = true; - } - } - if(!foundMatch){ - decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); - child->instrs.push_back(instr); - root->children.push_back(child); - } - } - root->instrs.clear(); - //call populate_decoding_tree for all children - if(root->children.size() >1) - for(auto child: root->children){ - populate_decoding_tree(child); - } - else{ - //sort instrs by value of the mask, this works bc we want to have the least restrictive one last - std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { - return instr1.mask > instr2.mask; - }); - } - } - compile_func decode_instr(decoding_tree_node* node, code_word_t word){ - if(!node->children.size()){ - if(node->instrs.size() == 1) return node->instrs[0].op; - for(auto instr : node->instrs){ - if((instr.mask&word) == instr.value) return instr.op; - } - } - else{ - for(auto child : node->children){ - if (child->value == (node->submask&word)){ - return decode_instr(child, word); - } - } - } - return nullptr; - } }; template vm_impl::vm_impl() { this(new ARCH()); } template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) -: vm_base(core, core_id, cluster_id) { - root = new decoding_tree_node(std::numeric_limits::max()); - for(auto instr: instr_descr){ - root->instrs.push_back(instr); - } - populate_decoding_tree(root); -} +: vm_base(core, core_id, cluster_id) +, instr_decoder([this]() { + std::vector g_instr_descr; + g_instr_descr.reserve(instr_descr.size()); + for (uint32_t i = 0; i < instr_descr.size(); ++i) { + generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i}; + g_instr_descr.push_back(new_instr_descr); + } + return std::move(g_instr_descr); + }()) {} template continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) { @@ -281,7 +226,10 @@ continuation_e vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' ++inst_cnt; - auto f = decode_instr(root, instr); + uint32_t inst_index = instr_decoder.decode_instr(instr); + compile_func f = nullptr; + if(inst_index < instr_descr.size()) + f = instr_descr[inst_index].op; if (f == nullptr) f = &this_class::illegal_instruction; return (this->*f)(pc, instr, jh); diff --git a/gen_input/templates/llvm/CORENAME.cpp.gtl b/gen_input/templates/llvm/CORENAME.cpp.gtl index 3d3ebfb..517253a 100644 --- a/gen_input/templates/llvm/CORENAME.cpp.gtl +++ b/gen_input/templates/llvm/CORENAME.cpp.gtl @@ -36,6 +36,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -136,27 +137,21 @@ private: * start opcode definitions ****************************************************************************/ struct instruction_descriptor { - size_t length; + uint32_t length; uint32_t value; uint32_t mask; compile_func op; }; - struct decoding_tree_node{ - std::vector instrs; - std::vector children; - uint32_t submask = std::numeric_limits::max(); - uint32_t value; - decoding_tree_node(uint32_t value) : value(value){} - }; - - decoding_tree_node* root {nullptr}; const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> }}; - + + //needs to be declared after instr_descr + decoder instr_decoder; + /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction ${idx}: ${instr.name} */ std::tuple __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ @@ -219,58 +214,6 @@ private: this->builder.CreateBr(bb); return std::make_tuple(BRANCH, nullptr); } - //decoding functionality - - void populate_decoding_tree(decoding_tree_node* root){ - //create submask - for(auto instr: root->instrs){ - root->submask &= instr.mask; - } - //put each instr according to submask&encoding into children - for(auto instr: root->instrs){ - bool foundMatch = false; - for(auto child: root->children){ - //use value as identifying trait - if(child->value == (instr.value&root->submask)){ - child->instrs.push_back(instr); - foundMatch = true; - } - } - if(!foundMatch){ - decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); - child->instrs.push_back(instr); - root->children.push_back(child); - } - } - root->instrs.clear(); - //call populate_decoding_tree for all children - if(root->children.size() >1) - for(auto child: root->children){ - populate_decoding_tree(child); - } - else{ - //sort instrs by value of the mask, this works bc we want to have the least restrictive one last - std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { - return instr1.mask > instr2.mask; - }); - } - } - compile_func decode_instr(decoding_tree_node* node, code_word_t word){ - if(!node->children.size()){ - if(node->instrs.size() == 1) return node->instrs[0].op; - for(auto instr : node->instrs){ - if((instr.mask&word) == instr.value) return instr.op; - } - } - else{ - for(auto child : node->children){ - if (child->value == (node->submask&word)){ - return decode_instr(child, word); - } - } - } - return nullptr; - } }; template void debug_fn(CODE_WORD instr) { @@ -282,13 +225,16 @@ template vm_impl::vm_impl() { this(new ARCH()); } template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) -: vm_base(core, core_id, cluster_id) { - root = new decoding_tree_node(std::numeric_limits::max()); - for(auto instr:instr_descr){ - root->instrs.push_back(instr); - } - populate_decoding_tree(root); -} +: vm_base(core, core_id, cluster_id) +, instr_decoder([this]() { + std::vector g_instr_descr; + g_instr_descr.reserve(instr_descr.size()); + for (uint32_t i = 0; i < instr_descr.size(); ++i) { + generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i}; + g_instr_descr.push_back(new_instr_descr); + } + return std::move(g_instr_descr); + }()) {} template std::tuple @@ -309,13 +255,16 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, // res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); // } // } else { - auto res = this->core.read(paddr, 4, data); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + auto res = this->core.read(paddr, 4, data); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); // } if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; - auto f = decode_instr(root, instr); + uint32_t inst_index = instr_decoder.decode_instr(instr); + compile_func f = nullptr; + if(inst_index < instr_descr.size()) + f = instr_descr[inst_index].op; if (f == nullptr) { f = &this_class::illegal_instruction; } diff --git a/gen_input/templates/tcc/CORENAME.cpp.gtl b/gen_input/templates/tcc/CORENAME.cpp.gtl index a6e2f64..6f688df 100644 --- a/gen_input/templates/tcc/CORENAME.cpp.gtl +++ b/gen_input/templates/tcc/CORENAME.cpp.gtl @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -130,34 +131,28 @@ protected: auto mask = (1ULL< instrs; - std::vector children; - uint32_t submask = std::numeric_limits::max(); - uint32_t value; - decoding_tree_node(uint32_t value) : value(value){} - }; - - decoding_tree_node* root {nullptr}; const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ {${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%> }}; - + + //needs to be declared after instr_descr + decoder instr_decoder; + /* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %> /* instruction ${idx}: ${instr.name} */ compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ @@ -198,59 +193,6 @@ private: vm_impl::gen_trap_check(tu); return BRANCH; } - - //decoding functionality - - void populate_decoding_tree(decoding_tree_node* root){ - //create submask - for(auto instr: root->instrs){ - root->submask &= instr.mask; - } - //put each instr according to submask&encoding into children - for(auto instr: root->instrs){ - bool foundMatch = false; - for(auto child: root->children){ - //use value as identifying trait - if(child->value == (instr.value&root->submask)){ - child->instrs.push_back(instr); - foundMatch = true; - } - } - if(!foundMatch){ - decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); - child->instrs.push_back(instr); - root->children.push_back(child); - } - } - root->instrs.clear(); - //call populate_decoding_tree for all children - if(root->children.size() >1) - for(auto child: root->children){ - populate_decoding_tree(child); - } - else{ - //sort instrs by value of the mask, this works bc we want to have the least restrictive one last - std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { - return instr1.mask > instr2.mask; - }); - } - } - compile_func decode_instr(decoding_tree_node* node, code_word_t word){ - if(!node->children.size()){ - if(node->instrs.size() == 1) return node->instrs[0].op; - for(auto instr : node->instrs){ - if((instr.mask&word) == instr.value) return instr.op; - } - } - else{ - for(auto child : node->children){ - if (child->value == (node->submask&word)){ - return decode_instr(child, word); - } - } - } - return nullptr; - } }; template void debug_fn(CODE_WORD instr) { @@ -262,13 +204,16 @@ template vm_impl::vm_impl() { this(new ARCH()); } template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) -: vm_base(core, core_id, cluster_id) { - root = new decoding_tree_node(std::numeric_limits::max()); - for(auto instr:instr_descr){ - root->instrs.push_back(instr); - } - populate_decoding_tree(root); -} +: vm_base(core, core_id, cluster_id) +, instr_decoder([this]() { + std::vector g_instr_descr; + g_instr_descr.reserve(instr_descr.size()); + for (uint32_t i = 0; i < instr_descr.size(); ++i) { + generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i}; + g_instr_descr.push_back(new_instr_descr); + } + return std::move(g_instr_descr); + }()) {} template std::tuple @@ -287,13 +232,16 @@ vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, // res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); // } // } else { - auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); - if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); + auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); + if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); // } if (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; - auto f = decode_instr(root, instr); + uint32_t inst_index = instr_decoder.decode_instr(instr); + compile_func f = nullptr; + if(inst_index < instr_descr.size()) + f = instr_descr[inst_index].op; if (f == nullptr) { f = &this_class::illegal_instruction; } diff --git a/src/vm/asmjit/vm_tgc5c.cpp b/src/vm/asmjit/vm_tgc5c.cpp index 00b7f4a..859c65c 100644 --- a/src/vm/asmjit/vm_tgc5c.cpp +++ b/src/vm/asmjit/vm_tgc5c.cpp @@ -302,7 +302,7 @@ private: //needs to be declared after instr_descr decoder instr_decoder; - + /* instruction definitions */ /* instruction 0: LUI */ continuation_e __lui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){ diff --git a/src/vm/llvm/vm_tgc5c.cpp b/src/vm/llvm/vm_tgc5c.cpp index cee7dd0..c5cd06f 100644 --- a/src/vm/llvm/vm_tgc5c.cpp +++ b/src/vm/llvm/vm_tgc5c.cpp @@ -320,7 +320,7 @@ private: /* instruction DII, encoding '0b0000000000000000' */ {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, }}; - + //needs to be declared after instr_descr decoder instr_decoder; diff --git a/src/vm/tcc/vm_tgc5c.cpp b/src/vm/tcc/vm_tgc5c.cpp index ba61306..1969679 100644 --- a/src/vm/tcc/vm_tgc5c.cpp +++ b/src/vm/tcc/vm_tgc5c.cpp @@ -131,7 +131,7 @@ protected: auto mask = (1ULL<