From e3942be7767ced192027fcbaa2a4393d89789462 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Tue, 23 Jul 2024 13:08:53 +0200 Subject: [PATCH] Introduces decoder in a seperate class --- src/vm/asmjit/vm_tgc5c.cpp | 90 ++++++++--------------------------- src/vm/interp/vm_tgc5c.cpp | 92 +++++++++--------------------------- src/vm/llvm/vm_tgc5c.cpp | 93 +++++++++--------------------------- src/vm/tcc/vm_tgc5c.cpp | 96 +++++++++----------------------------- 4 files changed, 83 insertions(+), 288 deletions(-) diff --git a/src/vm/asmjit/vm_tgc5c.cpp b/src/vm/asmjit/vm_tgc5c.cpp index d967dc3..00b7f4a 100644 --- a/src/vm/asmjit/vm_tgc5c.cpp +++ b/src/vm/asmjit/vm_tgc5c.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -115,20 +116,11 @@ 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 */ @@ -307,6 +299,9 @@ private: /* instruction DII, encoding '0b0000000000000000' */ {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, }}; + + //needs to be declared after instr_descr + decoder instr_decoder; /* instruction definitions */ /* instruction 0: LUI */ @@ -4740,72 +4735,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) { @@ -4821,7 +4766,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/src/vm/interp/vm_tgc5c.cpp b/src/vm/interp/vm_tgc5c.cpp index 135ab8c..64b716e 100644 --- a/src/vm/interp/vm_tgc5c.cpp +++ b/src/vm/interp/vm_tgc5c.cpp @@ -31,6 +31,7 @@ *******************************************************************************/ // clang-format off +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -146,20 +148,11 @@ private: * start opcode definitions ****************************************************************************/ struct instruction_descriptor { - size_t length; + uint32_t length; uint32_t value; uint32_t mask; typename arch::traits::opcode_e 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 */ {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits::opcode_e::LUI}, @@ -250,6 +243,8 @@ private: {16, 0b1100000000000010, 0b1110000000000011, arch::traits::opcode_e::C__SWSP}, {16, 0b0000000000000000, 0b1111111111111111, arch::traits::opcode_e::DII}, }}; + //needs to be declared after instr_descr + decoder instr_decoder; iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ if(this->core.has_mmu()) { @@ -270,58 +265,6 @@ private: } return iss::Ok; } - - 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; - }); - } - } - - typename arch::traits::opcode_e 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 arch::traits::opcode_e::MAX_OPCODE; - } }; template void debug_fn(CODE_WORD insn) { @@ -347,13 +290,16 @@ constexpr size_t bit_count(uint32_t u) { 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); + }()) {} inline bool is_icount_limit_enabled(finish_cond_e cond){ return (cond & finish_cond_e::ICOUNT_LIMIT) == finish_cond_e::ICOUNT_LIMIT; @@ -390,9 +336,13 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decode_instr(root, instr); + uint32_t inst_index = instr_decoder.decode_instr(instr); + opcode_e inst_id = arch::traits::opcode_e::MAX_OPCODE;; + if(inst_index core.reg.last_branch = 0; + this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); try{ switch(inst_id){ diff --git a/src/vm/llvm/vm_tgc5c.cpp b/src/vm/llvm/vm_tgc5c.cpp index bd86bb8..cee7dd0 100644 --- a/src/vm/llvm/vm_tgc5c.cpp +++ b/src/vm/llvm/vm_tgc5c.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -136,20 +137,11 @@ 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 */ @@ -329,6 +321,9 @@ private: {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, }}; + //needs to be declared after instr_descr + decoder instr_decoder; + /* instruction definitions */ /* instruction 0: LUI */ std::tuple __lui(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){ @@ -4885,58 +4880,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) { @@ -4948,13 +4891,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 @@ -4975,13 +4921,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/src/vm/tcc/vm_tgc5c.cpp b/src/vm/tcc/vm_tgc5c.cpp index afdfbc6..ba61306 100644 --- a/src/vm/tcc/vm_tgc5c.cpp +++ b/src/vm/tcc/vm_tgc5c.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY @@ -137,20 +138,11 @@ 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 */ @@ -329,7 +321,10 @@ private: /* instruction DII, encoding '0b0000000000000000' */ {16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii}, }}; - + + //needs to be declared after instr_descr + decoder instr_decoder; + /* instruction definitions */ /* instruction 0: LUI */ compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){ @@ -3637,59 +3632,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) { @@ -3701,13 +3643,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 @@ -3726,13 +3671,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; }