diff options
Diffstat (limited to 'riscv/processor.cc')
-rw-r--r-- | riscv/processor.cc | 95 |
1 files changed, 46 insertions, 49 deletions
diff --git a/riscv/processor.cc b/riscv/processor.cc index a1cec6c..a813068 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -1064,6 +1064,12 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) throw trap_illegal_instruction(insn.bits()); } +const insn_desc_t insn_desc_t::illegal_instruction = { + 0, 0, + &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, + &::illegal_instruction, &::illegal_instruction, &::illegal_instruction, &::illegal_instruction +}; + reg_t illegal_instruction(processor_t UNUSED *p, insn_t insn, reg_t UNUSED pc) { // The illegal instruction can be longer than ILEN bits, where the tval will @@ -1072,51 +1078,30 @@ reg_t illegal_instruction(processor_t UNUSED *p, insn_t insn, reg_t UNUSED pc) throw trap_illegal_instruction(insn.bits() & 0xffffffffULL); } -static insn_desc_t -propagate_instruction_in_vector(std::vector<insn_desc_t> &instructions, - std::vector<insn_desc_t>::iterator it) { - assert(it != instructions.end()); - insn_desc_t desc = *it; - if (it->mask != 0 && it != instructions.begin() && - std::next(it) != instructions.end()) { - if (it->match != std::prev(it)->match && - it->match != std::next(it)->match) { - // move to front of opcode list to reduce miss penalty - while (--it >= instructions.begin()) - *std::next(it) = *it; - instructions[0] = desc; - } - } - return desc; -} - insn_func_t processor_t::decode_insn(insn_t insn) { // look up opcode in hash table size_t idx = insn.bits() % OPCODE_CACHE_SIZE; - insn_desc_t desc = opcode_cache[idx]; + auto [hit, desc] = opcode_cache[idx].lookup(insn.bits()); bool rve = extension_enabled('E'); - if (unlikely(insn.bits() != desc.match)) { + if (unlikely(!hit)) { // fall back to linear search auto matching = [insn_bits = insn.bits()](const insn_desc_t &d) { return (insn_bits & d.mask) == d.match; }; auto p = std::find_if(custom_instructions.begin(), custom_instructions.end(), matching); - if (p != custom_instructions.end()) { - desc = propagate_instruction_in_vector(custom_instructions, p); - } else { + if (p == custom_instructions.end()) { p = std::find_if(instructions.begin(), instructions.end(), matching); assert(p != instructions.end()); - desc = propagate_instruction_in_vector(instructions, p); } - opcode_cache[idx] = desc; - opcode_cache[idx].match = insn.bits(); + desc = &*p; + opcode_cache[idx].replace(insn.bits(), desc); } - return desc.func(xlen, rve, log_commits_enabled); + return desc->func(xlen, rve, log_commits_enabled); } void processor_t::register_insn(insn_desc_t desc, bool is_custom) { @@ -1131,19 +1116,8 @@ void processor_t::register_insn(insn_desc_t desc, bool is_custom) { void processor_t::build_opcode_map() { - struct cmp { - bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) { - if (lhs.match == rhs.match) - return lhs.mask > rhs.mask; - return lhs.match > rhs.match; - } - }; - - std::sort(instructions.begin(), instructions.end(), cmp()); - std::sort(custom_instructions.begin(), custom_instructions.end(), cmp()); - for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++) - opcode_cache[i] = insn_desc_t::illegal(); + opcode_cache[i].reset(); } void processor_t::register_extension(extension_t *x) { @@ -1165,15 +1139,12 @@ void processor_t::register_base_instructions() { #define DECLARE_INSN(name, match, mask) \ insn_bits_t name##_match = (match), name##_mask = (mask); \ - bool name##_supported = true; + isa_extension_t name##_ext = NUM_ISA_EXTENSIONS; \ + bool name##_overlapping = false; #include "encoding.h" #undef DECLARE_INSN - #define DECLARE_OVERLAP_INSN(name, ext) { name##_supported = isa->extension_enabled(ext); } - #include "overlap_list.h" - #undef DECLARE_OVERLAP_INSN - #define DEFINE_INSN(name) \ extern reg_t fast_rv32i_##name(processor_t*, insn_t, reg_t); \ extern reg_t fast_rv64i_##name(processor_t*, insn_t, reg_t); \ @@ -1182,8 +1153,14 @@ void processor_t::register_base_instructions() extern reg_t logged_rv32i_##name(processor_t*, insn_t, reg_t); \ extern reg_t logged_rv64i_##name(processor_t*, insn_t, reg_t); \ extern reg_t logged_rv32e_##name(processor_t*, insn_t, reg_t); \ - extern reg_t logged_rv64e_##name(processor_t*, insn_t, reg_t); \ - if (name##_supported) { \ + extern reg_t logged_rv64e_##name(processor_t*, insn_t, reg_t); + #include "insn_list.h" + #undef DEFINE_INSN + + // add overlapping instructions first, in order + #define DECLARE_OVERLAP_INSN(name, ext) \ + name##_overlapping = true; \ + if (isa->extension_enabled(ext)) \ register_base_insn((insn_desc_t) { \ name##_match, \ name##_mask, \ @@ -1194,11 +1171,31 @@ void processor_t::register_base_instructions() logged_rv32i_##name, \ logged_rv64i_##name, \ logged_rv32e_##name, \ - logged_rv64e_##name}); \ - } + logged_rv64e_##name}); + #include "overlap_list.h" + #undef DECLARE_OVERLAP_INSN + + // add all other instructions. since they are non-overlapping, the order + // does not affect correctness, but more frequent instructions should + // appear earlier to improve search time on opcode_cache misses. + #define DEFINE_INSN(name) \ + if (!name##_overlapping) \ + register_base_insn((insn_desc_t) { \ + name##_match, \ + name##_mask, \ + fast_rv32i_##name, \ + fast_rv64i_##name, \ + fast_rv32e_##name, \ + fast_rv64e_##name, \ + logged_rv32i_##name, \ + logged_rv64i_##name, \ + logged_rv32e_##name, \ + logged_rv64e_##name}); #include "insn_list.h" + #undef DEFINE_INSN + // terminate instruction list with a catch-all - register_base_insn(insn_desc_t::illegal()); + register_base_insn(insn_desc_t::illegal_instruction); build_opcode_map(); } |