diff options
Diffstat (limited to 'src/abstract_hardware_model.cc')
| -rw-r--r-- | src/abstract_hardware_model.cc | 1429 |
1 files changed, 1424 insertions, 5 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index e8ddf95..dde9d28 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -1227,10 +1227,17 @@ void core_t::updateSIMTStack(unsigned warpId, warp_inst_t *inst) { //! Get the warp to be executed using the data taken form the SIMT stack warp_inst_t core_t::getExecuteWarp(unsigned warpId) { unsigned pc, rpc; - m_simt_stack[warpId]->get_pdom_stack_top_info(&pc, &rpc); - warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); - wi.set_active(m_simt_stack[warpId]->get_active_mask()); - return wi; + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->get_pdom_stack_top_info(&pc, &rpc); + warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); + wi.set_active(m_simt_stack[warpId]->get_active_mask()); + return wi; + } else { + m_simt_tables[warpId]->get_pdom_active_split_info(&pc, &rpc); + warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); + wi.set_active(m_simt_tables[warpId]->get_active_mask()); + return wi; + } } void core_t::deleteSIMTStack() { @@ -1251,5 +1258,1417 @@ void core_t::initilizeSIMTStack(unsigned warp_count, unsigned warp_size) { void core_t::get_pdom_stack_top_info(unsigned warpId, unsigned *pc, unsigned *rpc) const { - m_simt_stack[warpId]->get_pdom_stack_top_info(pc, rpc); + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->get_pdom_stack_top_info(pc, rpc); + } else { + m_simt_tables[warpId]->get_pdom_active_split_info(pc, rpc); + } +} + +// ── ITS (AWARE Reconvergence) implementations ─────────────────────────────── + +#define MAX_VIRTUAL_ST_ENTRIES 32 +#define MAX_VIRTUAL_RT_ENTRIES 32 + +// ── simt_splits_table ──────────────────────────────────────────────────────── + +simt_splits_table::simt_splits_table(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const struct memory_config *mem_config, + simt_tables *simt_table) { + m_warp_id = wid; + m_warp_size = warpSize; + m_active_split = (unsigned)-1; + m_num_entries = 0; + m_num_physical_entries = 0; + m_num_transient_entries = 0; + m_max_st_size = config->num_st_entries; + m_warp_size = config->warp_size; + m_config = config; + m_mem_config = mem_config; + m_response_st_entry = -1; + m_spill_st_entry = warp_inst_t(config); + m_fill_st_entry = warp_inst_t(config); + m_spill_st_entry.clear(); + m_fill_st_entry.clear(); + m_simt_tables = simt_table; + m_pending_recvg_entry = simt_splits_table_entry(); + reset(); +} + +void simt_splits_table::reset() { + m_splits_table.clear(); + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + m_splits_table[i] = simt_splits_table_entry(); + while (!m_fifo_queue.empty()) m_fifo_queue.pop_front(); + while (!m_invalid_entries.empty()) m_invalid_entries.pop(); + for (int i = MAX_VIRTUAL_ST_ENTRIES - 1; i >= 0; i--) + m_invalid_entries.push(i); + for (int i = m_warp_size; i >= 0; i--) + m_available_v_id.push(i); +} + +void simt_splits_table::launch(address_type start_pc, + const simt_mask_t &active_mask) { + reset(); + assert(!m_splits_table[0].m_valid); + m_splits_table[0].m_pc = start_pc; + m_splits_table[0].m_calldepth = 1; + m_splits_table[0].m_active_mask = active_mask; + m_splits_table[0].m_type = SPLITS_TABLE_TYPE_CALL; + m_splits_table[0].m_valid = true; + assert(m_invalid_entries.top() == 0); + m_invalid_entries.pop(); + m_active_split = 0; + m_num_entries = 1; + m_num_physical_entries = 1; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + m_fifo_queue.push_back( + fifo_entry(0, gpgpusim_total_cycles, m_fifo_queue.size())); +} + +const simt_mask_t &simt_splits_table::get_active_mask() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_splits_table[m_active_split].m_active_mask.any()); + return m_splits_table[m_active_split].m_active_mask; +} + +const simt_mask_t &simt_splits_table::get_active_mask(unsigned num) { + assert(m_splits_table.find(num) != m_splits_table.end()); + return m_splits_table[num].m_active_mask; +} + +void simt_splits_table::get_pdom_splits_entry_info(unsigned num, unsigned *pc, + unsigned *rpc) { + assert((m_splits_table.find(num) != m_splits_table.end()) && + m_splits_table[0].m_valid); + *pc = m_splits_table[num].m_pc; + *rpc = m_splits_table[num].m_recvg_pc; +} + +void simt_splits_table::get_pdom_active_split_info(unsigned *pc, + unsigned *rpc) { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + *pc = m_splits_table[m_active_split].m_pc; + *rpc = m_splits_table[m_active_split].m_recvg_pc; +} + +unsigned simt_splits_table::get_rpc(unsigned num) { + assert(m_splits_table.find(num) != m_splits_table.end()); + return m_splits_table[num].m_recvg_pc; +} + +void simt_splits_table::set_shader(shader_core_ctx *shader) { + m_shader = shader; +} + +bool simt_splits_table::is_virtualized() { + return m_splits_table[m_active_split].m_virtual; +} + +unsigned simt_splits_table::address_to_entry(warp_inst_t inst) { + if (!inst.empty()) { + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT) / + (MAX_BRU_VIR_PER_SPLIT); + return entry; + } + return (unsigned)-1; +} + +bool simt_splits_table::blocked() { + return m_splits_table[m_active_split].m_blocked; +} + +bool simt_splits_table::push_to_st_response_fifo(unsigned entry) { + if (m_response_st_entry == -1) { + m_response_st_entry = entry; + return true; + } + return false; +} + +unsigned simt_splits_table::get_replacement_candidate() { + unsigned entry = (unsigned)-1; + for (unsigned i = m_fifo_queue.size() - 1; i >= 0; i--) { + fifo_entry replacement_candidate = m_fifo_queue[i]; + entry = replacement_candidate.m_st_entry; + if (!m_splits_table[entry].m_virtual) break; + } + assert(entry != (unsigned)-1); + return entry; +} + +bool simt_splits_table::spill_st_entry() { + if (!m_spill_st_entry.empty()) return false; + assert(m_spill_st_entry.empty()); + + unsigned entry_to_replace = get_replacement_candidate(); + assert(!m_splits_table[entry_to_replace].m_virtual); + m_splits_table[entry_to_replace].m_virtual = true; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + + address_type pc = + (m_warp_id * m_warp_size + entry_to_replace) * MAX_BRU_VIR_PER_SPLIT; + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 12; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_ST_SPILL, ppc, nbytes, true, GPGPU_Context()); + m_spill_st_entry.space = memory_space_t(local_space); + m_spill_st_entry.cache_op = CACHE_WRITE_BACK; + m_spill_st_entry.op = STORE_OP; + m_spill_st_entry.mem_op = NOT_TEX; + m_spill_st_entry.memory_op = bru_st_spill_request; + m_spill_st_entry.pc = ppc; + m_spill_st_entry.occupy(); + m_spill_st_entry.set_warp_id(m_warp_id); + m_spill_st_entry.set_active(0); + m_spill_st_entry.inject_mem_acccesses(acc); + return true; +} + +bool simt_splits_table::fill_st_entry(unsigned entry) { + if (!m_fill_st_entry.empty()) return false; + + address_type pc = + (m_warp_id * m_warp_size + entry) * MAX_BRU_VIR_PER_SPLIT; + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 12; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_ST_FILL, ppc, nbytes, false, GPGPU_Context()); + m_fill_st_entry.space = memory_space_t(local_space); + m_fill_st_entry.cache_op = CACHE_ALL; + m_fill_st_entry.op = LOAD_OP; + m_fill_st_entry.mem_op = NOT_TEX; + m_fill_st_entry.memory_op = bru_st_fill_request; + m_fill_st_entry.pc = ppc; + m_fill_st_entry.inject_mem_acccesses(acc); + m_fill_st_entry.occupy(); + m_fill_st_entry.set_warp_id(m_warp_id); + m_fill_st_entry.set_active(0); + m_splits_table[entry].m_transient = true; + m_num_transient_entries++; + return true; +} + +void simt_splits_table::cycle() { + if (!m_spill_st_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_spill_st_entry, rc_fail, type); + if (done) { + m_spill_st_entry.clear(); + m_spill_st_entry.clear_pending_mem_requests(); + } + } + + if (!m_fill_st_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_fill_st_entry, rc_fail, type); + if (done) { + m_fill_st_entry.clear(); + m_fill_st_entry.clear_pending_mem_requests(); + } + } + + if (m_response_st_entry != -1) { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (spilled) { + assert(m_num_physical_entries < m_max_st_size); + m_splits_table[m_response_st_entry].m_virtual = false; + m_splits_table[m_response_st_entry].m_transient = false; + m_num_transient_entries--; + m_num_physical_entries++; + m_response_st_entry = -1; + } + } else { + assert(m_num_physical_entries < m_max_st_size); + m_splits_table[m_response_st_entry].m_virtual = false; + m_splits_table[m_response_st_entry].m_transient = false; + m_num_transient_entries--; + m_num_physical_entries++; + m_response_st_entry = -1; + } + } + + if (m_pending_recvg_entry.m_valid) { + unsigned entry = insert_new_entry(m_pending_recvg_entry); + if (entry != (unsigned)-1) m_pending_recvg_entry.m_valid = false; + } + + if (m_splits_table[m_active_split].m_blocked || + (!m_splits_table[m_active_split].m_valid && m_fifo_queue.size() > 0)) + push_back(); + + if (m_splits_table[m_active_split].m_virtual && + !m_splits_table[m_active_split].m_transient) + fill_st_entry(m_active_split); +} + +unsigned simt_splits_table::insert_new_entry(simt_splits_table_entry entry, + bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry = entry; + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + assert(m_num_physical_entries < m_max_st_size); + unsigned entry_num = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry_num].m_valid); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry_num, entry.m_pc, entry.m_recvg_pc); + + m_splits_table[entry_num].m_pc = entry.m_pc; + m_splits_table[entry_num].m_recvg_pc = entry.m_recvg_pc; + m_splits_table[entry_num].m_recvg_entry = entry.m_recvg_entry; + m_splits_table[entry_num].m_active_mask = entry.m_active_mask; + m_splits_table[entry_num].m_valid = true; + m_splits_table[entry_num].m_virtual = false; + m_splits_table[entry_num].m_type = entry.m_type; + m_splits_table[entry_num].m_branch_div_cycle = entry.m_branch_div_cycle; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry_num != (unsigned)-1); + m_fifo_queue.push_back( + fifo_entry(entry_num, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry_num; +} + +unsigned simt_splits_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type, + bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_pc = pc; + m_pending_recvg_entry.m_recvg_pc = rpc; + m_pending_recvg_entry.m_recvg_entry = rpc_entry; + m_pending_recvg_entry.m_active_mask = tmp_active_mask; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_type = type; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + unsigned entry = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry].m_valid); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry, pc, rpc); + + m_splits_table[entry].m_pc = pc; + m_splits_table[entry].m_recvg_pc = rpc; + m_splits_table[entry].m_recvg_entry = rpc_entry; + m_splits_table[entry].m_active_mask = tmp_active_mask; + m_splits_table[entry].m_valid = true; + m_splits_table[entry].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry != (unsigned)-1); + m_fifo_queue.push_back( + fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry; +} + +unsigned simt_splits_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type, + bool call_ret, bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_pc = pc; + m_pending_recvg_entry.m_recvg_pc = rpc; + m_pending_recvg_entry.m_recvg_entry = rpc_entry; + m_pending_recvg_entry.m_active_mask = tmp_active_mask; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_type = type; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + unsigned entry = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry].m_valid); + m_splits_table[entry].m_pc = pc; + m_splits_table[entry].m_recvg_pc = rpc; + m_splits_table[entry].m_recvg_entry = rpc_entry; + m_splits_table[entry].m_active_mask = tmp_active_mask; + m_splits_table[entry].m_valid = true; + m_splits_table[entry].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry != (unsigned)-1); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry, pc, rpc); + + // call_ret=true: push to front for LIFO ordering + m_fifo_queue.push_front( + fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry; +} + +void simt_splits_table::push_back() { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + fifo_entry cur_active_split = m_fifo_queue.front(); + assert(cur_active_split.m_st_entry == m_active_split); + m_fifo_queue.pop_front(); + cur_active_split.update_insertion_cycle(gpgpusim_total_cycles, + m_fifo_queue.size()); + m_fifo_queue.push_back(cur_active_split); + fifo_entry new_active_split = m_fifo_queue.front(); + m_active_split = new_active_split.m_st_entry; + + AWARE_DPRINTF("Push current active split %d to back; New active split %d\n", + cur_active_split.m_st_entry, m_active_split); + + if (m_splits_table[m_active_split].m_virtual) { + if (!m_splits_table[m_active_split].m_transient && + !m_splits_table[m_active_split].m_blocked) + fill_st_entry(m_active_split); + } +} + +void simt_splits_table::push_back_once() { + // stub: same as push_back for now + push_back(); +} + +void simt_splits_table::update_active_entry() { + if (m_fifo_queue.size() > 0) { + fifo_entry new_active_entry = m_fifo_queue.front(); + m_active_split = new_active_entry.m_st_entry; + if (new_active_entry.m_blocked || m_splits_table[m_active_split].m_virtual) + push_back(); + assert(m_num_entries > 0); + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_splits_table[m_active_split].m_active_mask.any()); + } +} + +void simt_splits_table::invalidate() { + if (!m_splits_table[m_active_split].m_valid) return; + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_fifo_queue.front().m_st_entry == m_active_split); + assert(!m_splits_table[m_active_split].m_virtual); + + m_splits_table[m_active_split].m_valid = false; + m_fifo_queue.pop_front(); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + m_invalid_entries.push(m_active_split); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); +} + +void simt_splits_table::update_pc(address_type new_pc) { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_fifo_queue.front().m_st_entry == m_active_split); + m_splits_table[m_active_split].m_pc = new_pc; +} + +void simt_splits_table::set_to_blocked() { + m_splits_table[m_active_split].m_blocked = true; +} + +void simt_splits_table::unset_blocked() { + m_splits_table[m_active_split].m_blocked = false; +} + +void simt_splits_table::unset_blocked(unsigned entry) { + m_splits_table[entry].m_blocked = false; +} + +void simt_splits_table::release_blocked() { + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) unset_blocked(i); + for (unsigned i = 0; i < m_fifo_queue.size(); i++) + m_fifo_queue[i].m_blocked = false; +} + +bool simt_splits_table::is_blocked_or_virtual() { + bool blocked = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + blocked &= + (m_splits_table[i].m_blocked || m_splits_table[i].m_virtual); + return (blocked && m_num_entries > 0); +} + +bool simt_splits_table::is_virtual() { + bool virtualized = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + virtualized &= (m_splits_table[i].m_virtual); + return (virtualized && m_num_entries > 0); +} + +bool simt_splits_table::is_blocked() { + bool blocked = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + blocked &= (m_splits_table[i].m_blocked); + return (blocked && m_num_entries > 0); +} + +bool simt_splits_table::split_reaches_barrier(address_type pc) { + m_fifo_queue.front().m_blocked = true; + set_to_blocked(); + update_pc(pc); + return is_blocked(); +} + +unsigned simt_splits_table::get_rpc() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_recvg_pc; +} + +unsigned simt_splits_table::get_rpc_entry() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_recvg_entry; +} + +unsigned simt_splits_table::get_pc() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_pc; +} + +splits_table_entry_type simt_splits_table::get_type() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_type; +} + +bool simt_splits_table::valid() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_valid; +} + +unsigned simt_splits_table::check_simt_splits_table() { + unsigned count = 0; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + for (unsigned j = 0; j < m_warp_size; j++) + if (m_splits_table[i].m_active_mask.test(j)) count++; + return count; +} + +void simt_splits_table::print(FILE *fout) { + printf("max of physical entries = %u\n", m_max_st_size); + printf("num of physical entries = %u\n", m_num_physical_entries); + printf("isBlocked? %u\n", is_blocked()); + if (!m_fifo_queue.empty()) { + fprintf(fout, "fifo- f: %02d\n", m_fifo_queue.front().m_st_entry); + fprintf(fout, "fifo- b: %02d\n", m_fifo_queue.back().m_st_entry); + fprintf(fout, "fifo-sz: %02lu\n", m_fifo_queue.size()); + } + printf("active entry = %u\n", m_active_split); + printf("Pending Recvg Entry valid: %u\n", m_pending_recvg_entry.m_valid); + printf("Response Entry: %d\n", m_response_st_entry); + for (unsigned k = 0; k < MAX_VIRTUAL_ST_ENTRIES; k++) { + simt_splits_table_entry &ste = m_splits_table[k]; + if (!ste.m_valid) continue; + if (ste.m_virtual) printf("Virtual: "); + if (ste.m_transient) printf("Transient: "); + if (ste.m_blocked) printf("Blocked: "); + fprintf(fout, " %1u ", k); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (ste.m_active_mask.test(j) ? '1' : '0')); + fprintf(fout, " pc: 0x%03x", ste.m_pc); + if (ste.m_recvg_pc == (unsigned)-1) + fprintf(fout, " rp: ---- %s\n", (ste.m_valid ? " V " : " N ")); + else + fprintf(fout, " rp: 0x%03x %s\n", ste.m_recvg_pc, + (ste.m_valid ? " V " : " N ")); + } +} + +// ── simt_reconvergence_table ───────────────────────────────────────────────── + +simt_reconvergence_table::simt_reconvergence_table( + unsigned wid, unsigned warpSize, const shader_core_config *config, + const struct memory_config *mem_config, simt_tables *simt_table) { + m_warp_id = wid; + m_warp_size = warpSize; + m_active_reconvergence = (unsigned)-1; + m_num_entries = 0; + m_num_physical_entries = 0; + m_num_transient_entries = 0; + m_max_rec_size = config->num_rec_entries; + m_simt_tables = simt_table; + m_spill_rec_entry = warp_inst_t(config); + m_fill_rec_entry = warp_inst_t(config); + m_pending_update_entry = simt_reconvergence_table_entry(); + m_response_rec_entry = -1; + m_config = config; + m_mem_config = mem_config; + reset(); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::reset() { + m_num_entries = 0; + m_num_physical_entries = 0; + m_recvg_table.clear(); + while (!m_invalid_entries.empty()) m_invalid_entries.pop(); + for (int i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) + m_recvg_table[i] = simt_reconvergence_table_entry(); + for (int i = MAX_VIRTUAL_RT_ENTRIES - 1; i >= 0; i--) + m_invalid_entries.push(i); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +bool simt_reconvergence_table::push_to_rt_response_fifo(unsigned entry) { + if (m_response_rec_entry == -1) { + m_response_rec_entry = entry; + return true; + } + return false; +} + +unsigned simt_reconvergence_table::get_replacement_candidate() { + unsigned oldest_index = (unsigned)-1; + unsigned long long oldest_update = 0; + for (int i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) { + if (m_recvg_table[i].m_valid && !m_recvg_table[i].m_virtual) { + if (oldest_update == 0) { + oldest_index = i; + oldest_update = m_recvg_table[i].m_branch_rec_cycle; + } else if (m_recvg_table[i].m_branch_rec_cycle > oldest_update) { + oldest_index = i; + oldest_update = m_recvg_table[i].m_branch_rec_cycle; + } + } + } + assert(oldest_index != (unsigned)-1); + return oldest_index; +} + +bool simt_reconvergence_table::fill_rec_entry(unsigned entry) { + if (!m_fill_rec_entry.empty()) return false; + + address_type pc = (m_warp_id * m_warp_size + entry) * MAX_BRU_VIR_PER_SPLIT + + (MAX_BRU_VIR_PER_SPLIT / 2); + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 16; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_RT_FILL, ppc, nbytes, false, GPGPU_Context()); + m_fill_rec_entry.space = memory_space_t(local_space); + m_fill_rec_entry.cache_op = CACHE_ALL; + m_fill_rec_entry.op = LOAD_OP; + m_fill_rec_entry.mem_op = NOT_TEX; + m_fill_rec_entry.memory_op = bru_rt_fill_request; + m_fill_rec_entry.pc = ppc; + m_fill_rec_entry.inject_mem_acccesses(acc); + m_fill_rec_entry.occupy(); + m_fill_rec_entry.set_warp_id(m_warp_id); + m_fill_rec_entry.set_active(0); + m_recvg_table[entry].m_transient = true; + m_num_transient_entries++; + return true; +} + +bool simt_reconvergence_table::spill_rec_entry() { + if (!m_spill_rec_entry.empty()) return false; + assert(m_spill_rec_entry.empty()); + + unsigned entry_to_replace = get_replacement_candidate(); + m_recvg_table[entry_to_replace].m_virtual = true; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + + address_type pc = + (m_warp_id * m_warp_size + entry_to_replace) * MAX_BRU_VIR_PER_SPLIT + + (MAX_BRU_VIR_PER_SPLIT / 2); + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 16; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_RT_SPILL, ppc, nbytes, true, GPGPU_Context()); + m_spill_rec_entry.space = memory_space_t(local_space); + m_spill_rec_entry.cache_op = CACHE_WRITE_BACK; + m_spill_rec_entry.op = STORE_OP; + m_spill_rec_entry.mem_op = NOT_TEX; + m_spill_rec_entry.memory_op = bru_rt_spill_request; + m_spill_rec_entry.pc = ppc; + m_spill_rec_entry.occupy(); + m_spill_rec_entry.set_warp_id(m_warp_id); + m_spill_rec_entry.set_active(0); + m_spill_rec_entry.inject_mem_acccesses(acc); + return true; +} + +void simt_reconvergence_table::cycle() { + if (m_pending_update_entry.m_valid && !m_pending_update_entry.m_transient) { + bool sent = fill_rec_entry(m_pending_update_entry.m_recvg_entry); + if (sent) m_pending_update_entry.m_transient = true; + } + + if (!m_spill_rec_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_spill_rec_entry, rc_fail, type); + if (done) { + m_spill_rec_entry.clear(); + m_spill_rec_entry.clear_pending_mem_requests(); + } + } + + if (!m_fill_rec_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_fill_rec_entry, rc_fail, type); + if (done) { + m_fill_rec_entry.clear(); + m_fill_rec_entry.clear_pending_mem_requests(); + } + } + + if (m_response_rec_entry != -1) { + if (m_pending_update_entry.m_recvg_entry == + (unsigned)m_response_rec_entry) { + assert(m_pending_update_entry.m_valid); + simt_mask_t test = m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + bool converged = !test.any(); + bool spacefound = !m_simt_tables->is_pending_reconvergence() || + m_simt_tables->st_space_available(); + if (m_num_physical_entries == m_max_rec_size) { + bool spilled = spill_rec_entry(); + if (spilled && (!converged || (converged && spacefound))) { + m_recvg_table[m_response_rec_entry].m_virtual = false; + m_recvg_table[m_response_rec_entry].m_transient = false; + m_recvg_table[m_response_rec_entry].m_pending_mask = + m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle = + m_pending_update_entry.m_branch_rec_cycle; + m_pending_update_entry.m_valid = false; + m_num_transient_entries--; + m_num_physical_entries++; + if (converged) { + simt_mask_t active_mask = + get_active_mask(m_response_rec_entry); + address_type pc = get_pc(m_response_rec_entry); + address_type rpc = get_rpc(m_response_rec_entry); + unsigned rpc_entry = get_rpc_entry(m_response_rec_entry); + splits_table_entry_type type = get_type(m_response_rec_entry); + invalidate(m_response_rec_entry); + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + m_response_rec_entry = -1; + } + } else { + if (!converged || (converged && spacefound)) { + m_recvg_table[m_response_rec_entry].m_virtual = false; + m_recvg_table[m_response_rec_entry].m_transient = false; + m_recvg_table[m_response_rec_entry].m_pending_mask = + m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle = + m_pending_update_entry.m_branch_rec_cycle; + m_pending_update_entry.m_valid = false; + m_num_transient_entries--; + m_num_physical_entries++; + if (converged) { + simt_mask_t active_mask = + get_active_mask(m_response_rec_entry); + address_type pc = get_pc(m_response_rec_entry); + address_type rpc = get_rpc(m_response_rec_entry); + unsigned rpc_entry = get_rpc_entry(m_response_rec_entry); + splits_table_entry_type type = get_type(m_response_rec_entry); + invalidate(m_response_rec_entry); + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + m_response_rec_entry = -1; + } + } + } else { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + unsigned long long diff = + gpgpusim_total_cycles - + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle; + if (diff > m_config->rec_time_out) { + const simt_mask_t &reconverged_mask = + (~m_recvg_table[m_response_rec_entry].m_pending_mask) & + (m_recvg_table[m_response_rec_entry].m_active_mask); + address_type pc = m_recvg_table[m_response_rec_entry].m_pc; + address_type rpc = m_recvg_table[m_response_rec_entry].m_recvg_pc; + unsigned rpc_entry = m_recvg_table[m_response_rec_entry].m_recvg_entry; + splits_table_entry_type type = + m_recvg_table[m_response_rec_entry].m_type; + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, reconverged_mask, + type, true); + update_masks_upon_time_out(m_response_rec_entry, reconverged_mask); + set_rec_cycle(m_response_rec_entry, gpgpusim_total_cycles); + } + } + } +} + +unsigned simt_reconvergence_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (m_num_physical_entries == m_max_rec_size) { + bool spilled = spill_rec_entry(); + assert(spilled); + } + assert(tmp_active_mask.any()); + int entry_num = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_recvg_table[entry_num].m_valid); + m_recvg_table[entry_num].m_pc = pc; + m_recvg_table[entry_num].m_recvg_pc = rpc; + m_recvg_table[entry_num].m_recvg_entry = rpc_entry; + m_recvg_table[entry_num].m_active_mask = tmp_active_mask; + m_recvg_table[entry_num].m_pending_mask = tmp_active_mask; + m_recvg_table[entry_num].m_valid = true; + m_recvg_table[entry_num].m_branch_rec_cycle = gpgpusim_total_cycles; + m_recvg_table[entry_num].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert(entry_num != (unsigned)-1); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry_num, pc, rpc); + + return entry_num; +} + +void simt_reconvergence_table::update_masks_upon_time_out( + unsigned recvg_entry, const simt_mask_t &reconverged_mask) { + m_recvg_table[recvg_entry].m_active_mask = + m_recvg_table[recvg_entry].m_pending_mask; +} + +unsigned simt_reconvergence_table::address_to_entry(warp_inst_t inst) { + if (!inst.empty()) { + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = + (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT - + MAX_BRU_VIR_PER_SPLIT / 2) / + (MAX_BRU_VIR_PER_SPLIT); + return entry; + } + return (unsigned)-1; +} + +bool simt_reconvergence_table::update_pending_mask( + unsigned recvg_entry, address_type recvg_pc, + const simt_mask_t &tmp_active_mask, bool &suspended) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + assert(m_recvg_table[recvg_entry].m_pc == recvg_pc); + assert(m_recvg_table[recvg_entry].m_valid); + assert(m_recvg_table[recvg_entry].m_pending_mask.any()); + + if (m_recvg_table[recvg_entry].m_virtual) { + suspended = true; + assert(!m_pending_update_entry.m_valid); + if (!m_recvg_table[recvg_entry].m_transient) { + m_pending_update_entry.m_valid = true; + m_pending_update_entry.m_active_mask = tmp_active_mask; + m_pending_update_entry.m_branch_rec_cycle = gpgpusim_total_cycles; + m_pending_update_entry.m_recvg_entry = recvg_entry; + m_pending_update_entry.m_transient = false; + } + } else { + m_recvg_table[recvg_entry].m_branch_rec_cycle = gpgpusim_total_cycles; + m_recvg_table[recvg_entry].m_pending_mask = + m_recvg_table[recvg_entry].m_pending_mask & ~tmp_active_mask; + if (!m_recvg_table[recvg_entry].m_pending_mask.any()) { + invalidate(recvg_entry); + return true; + } + } + return false; } + +const simt_mask_t &simt_reconvergence_table::get_active_mask() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_active_mask; +} + +const simt_mask_t &simt_reconvergence_table::get_active_mask(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_active_mask; +} + +simt_reconvergence_table_entry simt_reconvergence_table::get_recvg_entry( + unsigned num) { + return m_recvg_table[num]; +} + +void simt_reconvergence_table::get_recvg_entry_info(unsigned num, unsigned *pc, + unsigned *rpc) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + *pc = m_recvg_table[num].m_pc; + *rpc = m_recvg_table[num].m_recvg_pc; +} + +void simt_reconvergence_table::get_active_recvg_info(unsigned *pc, + unsigned *rpc) { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + *pc = m_recvg_table[m_active_reconvergence].m_pc; + *rpc = m_recvg_table[m_active_reconvergence].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_rpc_entry() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_recvg_entry; +} + +unsigned simt_reconvergence_table::get_rpc_entry(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_recvg_entry; +} + +splits_table_entry_type simt_reconvergence_table::get_type(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_type; +} + +splits_table_entry_type simt_reconvergence_table::get_type() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_type; +} + +unsigned simt_reconvergence_table::get_rpc() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_rpc(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_pc() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_pc; +} + +unsigned simt_reconvergence_table::get_pc(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_pc; +} + +void simt_reconvergence_table::invalidate() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end() && + m_recvg_table[m_active_reconvergence].m_valid); + m_recvg_table[m_active_reconvergence].m_valid = false; + m_invalid_entries.push(m_active_reconvergence); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::invalidate(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end() && + m_recvg_table[num].m_valid); + m_recvg_table[num].m_valid = false; + m_invalid_entries.push(num); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::set_rec_cycle(unsigned rec_entry, + unsigned long long time) { + m_recvg_table[rec_entry].m_branch_rec_cycle = time; +} + +unsigned simt_reconvergence_table::check_simt_reconvergence_table() { + unsigned count = 0; + for (unsigned i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) + if (m_recvg_table[i].m_valid) + for (unsigned j = 0; j < m_warp_size; j++) + if (!m_recvg_table[i].m_pending_mask.test(j) && + m_recvg_table[i].m_active_mask.test(j)) + count++; + return count; +} + +void simt_reconvergence_table::print(FILE *fout) { + printf("max of physical entries=%u\n", m_max_rec_size); + printf("num of physical entries=%u\n", m_num_physical_entries); + for (unsigned k = 0; k < MAX_VIRTUAL_RT_ENTRIES; k++) { + simt_reconvergence_table_entry &rte = m_recvg_table[k]; + if (!rte.m_valid) continue; + fprintf(fout, " %1u ", k); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (rte.m_active_mask.test(j) ? '1' : '0')); + fprintf(fout, " "); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (rte.m_pending_mask.test(j) ? '1' : '0')); + fprintf(fout, " pc: 0x%03x", rte.m_pc); + if (rte.m_recvg_pc == (unsigned)-1) + fprintf(fout, " rp: ---- %s\n", (rte.m_valid ? " V " : " N ")); + else + fprintf(fout, " rp: 0x%03x %s\n", rte.m_recvg_pc, + (rte.m_valid ? " V " : " N ")); + } +} + +// ── simt_tables ────────────────────────────────────────────────────────────── + +simt_tables::simt_tables(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const memory_config *mem_config) { + m_warp_id = wid; + m_warp_size = warpSize; + m_simt_splits_table = + new simt_splits_table(wid, warpSize, config, mem_config, this); + m_simt_recvg_table = + new simt_reconvergence_table(wid, warpSize, config, mem_config, this); + m_config = config; + m_mem_config = mem_config; + m_shader = NULL; +} + +void simt_tables::reset() { + m_simt_splits_table->reset(); + m_simt_recvg_table->reset(); + m_simt_splits_table->release_blocked(); +} + +void simt_tables::launch(address_type start_pc, + const simt_mask_t &active_mask) { + m_simt_splits_table->launch(start_pc, active_mask); +} + +void simt_tables::check_simt_tables() { + unsigned running = m_simt_splits_table->check_simt_splits_table(); + unsigned converged = m_simt_recvg_table->check_simt_reconvergence_table(); + if (running + converged > 32) { + printf("running=%u\n", running); + printf("converged=%u\n", converged); + abort(); + } +} + +void simt_tables::check_time_out() { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + for (unsigned k = 0; k < m_config->num_rec_entries; k++) { + simt_reconvergence_table_entry recvg_table_entry = + m_simt_recvg_table->get_recvg_entry(k); + if (!recvg_table_entry.m_valid) continue; + const simt_mask_t &reconverged_mask = + (~recvg_table_entry.m_pending_mask) & (recvg_table_entry.m_active_mask); + unsigned long long diff = + gpgpusim_total_cycles - recvg_table_entry.m_branch_rec_cycle; + if (diff > (unsigned long long)m_config->rec_time_out) { + if (recvg_table_entry.m_virtual) { + m_simt_recvg_table->fill_rec_entry(k); + } else { + if (reconverged_mask.any()) { + address_type pc = recvg_table_entry.m_pc; + address_type rpc = recvg_table_entry.m_recvg_pc; + unsigned rpc_entry = recvg_table_entry.m_recvg_entry; + splits_table_entry_type type = recvg_table_entry.m_type; + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, + reconverged_mask, type, true); + m_simt_recvg_table->update_masks_upon_time_out(k, reconverged_mask); + m_simt_recvg_table->set_rec_cycle(k, gpgpusim_total_cycles); + } + } + } + } +} + +void simt_tables::update(simt_mask_t &thread_done, addr_vector_t &next_pc, + address_type recvg_pc, op_type next_inst_op, + unsigned next_inst_size, address_type next_inst_pc, + bool predicated) { + check_simt_tables(); + + simt_mask_t top_active_mask = m_simt_splits_table->get_active_mask(); + simt_mask_t top_active_mask_keep = top_active_mask; + address_type top_recvg_pc = m_simt_splits_table->get_rpc(); + unsigned top_recvg_entry = m_simt_splits_table->get_rpc_entry(); + address_type top_pc = m_simt_splits_table->get_pc(); + assert(top_pc == next_inst_pc); + assert(top_active_mask.any()); + + const address_type null_pc = -1; + bool warp_diverged = false; + address_type new_recvg_pc = null_pc; + unsigned num_divergent_paths = 0; + unsigned new_recvg_entry = top_recvg_entry; + splits_table_entry_type top_type = m_simt_splits_table->get_type(); + + std::map<address_type, simt_mask_t> divergent_paths; + bool do_invalidate = false; + + while (top_active_mask.any()) { + address_type tmp_next_pc = null_pc; + simt_mask_t tmp_active_mask; + for (int i = m_warp_size - 1; i >= 0; i--) { + if (top_active_mask.test(i)) { + if (thread_done.test(i)) { + top_active_mask.reset(i); + } else if (tmp_next_pc == null_pc) { + tmp_next_pc = next_pc[i]; + tmp_active_mask.set(i); + top_active_mask.reset(i); + } else if (tmp_next_pc == next_pc[i]) { + tmp_active_mask.set(i); + top_active_mask.reset(i); + } + } + } + if (tmp_next_pc == null_pc) { + assert(!top_active_mask.any()); + continue; + } + divergent_paths[tmp_next_pc] = tmp_active_mask; + num_divergent_paths++; + } + + address_type not_taken_pc = next_inst_pc + next_inst_size; + assert(num_divergent_paths <= 2); + + for (unsigned i = 0; i < num_divergent_paths; i++) { + address_type tmp_next_pc = null_pc; + simt_mask_t tmp_active_mask; + tmp_active_mask.reset(); + + if (divergent_paths.find(not_taken_pc) != divergent_paths.end()) { + assert(i == 0); + tmp_next_pc = not_taken_pc; + tmp_active_mask = divergent_paths[tmp_next_pc]; + divergent_paths.erase(tmp_next_pc); + } else { + std::map<address_type, simt_mask_t>::iterator it = + divergent_paths.begin(); + tmp_next_pc = it->first; + tmp_active_mask = divergent_paths[tmp_next_pc]; + divergent_paths.erase(tmp_next_pc); + } + + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + + if (!predicated) { + if (next_inst_op == CALL_OPS) { + assert(num_divergent_paths == 1); + new_recvg_entry = m_simt_recvg_table->insert_new_entry( + top_pc, top_recvg_pc, top_recvg_entry, top_active_mask_keep, + top_type); + assert(new_recvg_entry != (unsigned)-1); + m_simt_splits_table->invalidate(); + m_simt_splits_table->update_active_entry(); + + simt_splits_table_entry new_st_entry; + new_st_entry.m_pc = tmp_next_pc; + new_st_entry.m_recvg_entry = new_recvg_entry; + new_st_entry.m_active_mask = tmp_active_mask; + new_st_entry.m_branch_div_cycle = gpgpusim_total_cycles; + new_st_entry.m_type = SPLITS_TABLE_TYPE_CALL; + m_simt_splits_table->insert_new_entry(new_st_entry); + return; + } else if (next_inst_op == RET_OPS && + top_type == SPLITS_TABLE_TYPE_CALL) { + assert(num_divergent_paths == 1); + top_recvg_entry = m_simt_splits_table->get_rpc_entry(); + m_simt_splits_table->invalidate(); + + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(new_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(new_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(new_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(top_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(new_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type, true, true); + m_simt_splits_table->update_active_entry(); + top_recvg_pc = m_simt_splits_table->get_rpc(); + bool suspended = false; + m_simt_recvg_table->update_pending_mask(top_recvg_entry, pc, + active_mask, suspended); + top_recvg_entry = m_simt_splits_table->get_rpc_entry(); + } + } + + if (tmp_next_pc == top_recvg_pc) { + bool suspended = false; + bool reconverged = m_simt_recvg_table->update_pending_mask( + top_recvg_entry, top_recvg_pc, tmp_active_mask, suspended); + if (reconverged && !suspended) { + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(top_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(top_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(top_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(top_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(top_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + if (num_divergent_paths == 1) { + if (!do_invalidate) { + m_simt_splits_table->invalidate(); + do_invalidate = true; + } + } + continue; + } + + if ((num_divergent_paths > 1) && !warp_diverged) { + warp_diverged = true; + new_recvg_pc = recvg_pc; + if (new_recvg_pc != top_recvg_pc) { + new_recvg_entry = m_simt_recvg_table->insert_new_entry( + new_recvg_pc, top_recvg_pc, top_recvg_entry, top_active_mask_keep, + top_type); + } + } + + if (warp_diverged && tmp_next_pc == new_recvg_pc) { + bool suspended = false; + bool reconverged = m_simt_recvg_table->update_pending_mask( + new_recvg_entry, new_recvg_pc, tmp_active_mask, suspended); + if (reconverged && !suspended) { + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(new_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(new_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(new_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(new_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(new_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type); + } + continue; + } + + if (warp_diverged) { + if (!do_invalidate) { + m_simt_splits_table->invalidate(); + do_invalidate = true; + } + m_simt_splits_table->insert_new_entry(tmp_next_pc, new_recvg_pc, + new_recvg_entry, tmp_active_mask, + top_type); + } else { + m_simt_splits_table->update_pc(tmp_next_pc); + if (tmp_next_pc != not_taken_pc) + m_simt_splits_table->push_back(); + } + } + + if (do_invalidate) m_simt_splits_table->update_active_entry(); + + check_simt_tables(); + + m_shader->update_st_size(m_simt_splits_table->num_entries()); + m_shader->update_rt_size(m_simt_recvg_table->num_entries()); +} + +const simt_mask_t &simt_tables::get_active_mask() { + return m_simt_splits_table->get_active_mask(); +} + +void simt_tables::get_pdom_active_split_info(unsigned *pc, unsigned *rpc) { + m_simt_splits_table->get_pdom_active_split_info(pc, rpc); +} + +unsigned simt_tables::get_rp() { return m_simt_splits_table->get_rpc(); } + +bool simt_tables::split_reaches_barrier(address_type pc) { + return m_simt_splits_table->split_reaches_barrier(pc); +} + +void simt_tables::release_barrier() { + m_simt_splits_table->release_blocked(); +} + +bool simt_tables::is_virtualized() { + return m_simt_splits_table->is_virtualized(); +} + +bool simt_tables::is_pending_reconvergence() { + return m_simt_splits_table->is_pending_reconvergence() && + m_simt_recvg_table->is_pending_update(); +} + +bool simt_tables::st_space_available() { + return m_simt_splits_table->st_space_available(); +} + +bool simt_tables::blocked() { return m_simt_splits_table->blocked(); } + +bool simt_tables::is_blocked() { return m_simt_splits_table->is_blocked(); } + +bool simt_tables::valid() { return m_simt_splits_table->valid(); } + +bool simt_tables::push_to_rt_response_fifo(unsigned entry) { + return m_simt_recvg_table->push_to_rt_response_fifo(entry); +} + +bool simt_tables::push_to_st_response_fifo(unsigned entry) { + return m_simt_splits_table->push_to_st_response_fifo(entry); +} + +void simt_tables::set_shader(shader_core_ctx *shader) { + m_shader = shader; + m_simt_splits_table->set_shader(shader); + m_simt_recvg_table->set_shader(shader); +} + +void simt_tables::push_back() { m_simt_splits_table->push_back(); } + +void simt_tables::print(FILE *fp) { + printf("w%02d\n", m_warp_id); + printf("Splits Table:\n"); + m_simt_splits_table->print(fp); + printf("Reconvergence Table:\n"); + m_simt_recvg_table->print(fp); +} + +// ── core_t ITS methods ─────────────────────────────────────────────────────── + +void core_t::initilizeSIMTDivergenceStructures(unsigned warp_count, + unsigned warp_size) { + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack = new simt_stack *[warp_count]; + for (unsigned i = 0; i < warp_count; ++i) + m_simt_stack[i] = new simt_stack(i, warp_size, m_gpu); + } else { + m_simt_tables = new simt_tables *[warp_count]; + for (unsigned i = 0; i < warp_count; ++i) + m_simt_tables[i] = + new simt_tables(i, warp_size, m_gpu->getShaderCoreConfig(), + m_gpu->getMemoryConfig()); + } + m_warp_size = warp_size; + m_warp_count = warp_count; +} + +void core_t::deleteSIMTDivergenceStructures() { + if (m_simt_stack) { + for (unsigned i = 0; i < m_warp_count; ++i) delete m_simt_stack[i]; + delete[] m_simt_stack; + m_simt_stack = NULL; + } + if (m_simt_tables) { + for (unsigned i = 0; i < m_warp_count; ++i) delete m_simt_tables[i]; + delete[] m_simt_tables; + m_simt_tables = NULL; + } +} + +void core_t::updateSIMTDivergenceStructures(unsigned warpId, + warp_inst_t *inst) { + simt_mask_t thread_done; + addr_vector_t next_pc; + unsigned wtid = warpId * m_warp_size; + for (unsigned i = 0; i < m_warp_size; i++) { + if (ptx_thread_done(wtid + i)) { + thread_done.set(i); + next_pc.push_back((address_type)-1); + } else { + if (inst->reconvergence_pc == RECONVERGE_RETURN_PC) + inst->reconvergence_pc = get_return_pc(m_thread[wtid + i]); + next_pc.push_back(m_thread[wtid + i]->get_pc()); + } + } + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->update(thread_done, next_pc, inst->reconvergence_pc, + inst->op, inst->isize, inst->pc); + } else { + AWARE_DPRINTF("Updating SIMT tables for Warp %d\n", warpId); + m_simt_tables[warpId]->update(thread_done, next_pc, inst->reconvergence_pc, + inst->op, inst->isize, inst->pc, + inst->pred != -1); + } +} + +// ── End ITS implementations ────────────────────────────────────────────────── |
