summaryrefslogtreecommitdiff
path: root/src/abstract_hardware_model.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/abstract_hardware_model.cc')
-rw-r--r--src/abstract_hardware_model.cc1429
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 ──────────────────────────────────────────────────