summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.cc1429
-rw-r--r--src/abstract_hardware_model.h370
-rw-r--r--src/gpgpu-sim/gpu-sim.cc21
-rw-r--r--src/gpgpu-sim/shader.cc260
-rw-r--r--src/gpgpu-sim/shader.h38
5 files changed, 2058 insertions, 60 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 ──────────────────────────────────────────────────
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 06c3082..e96ddc4 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -36,6 +36,10 @@
class gpgpu_sim;
class kernel_info_t;
class gpgpu_context;
+class shader_core_ctx;
+class shader_core_config;
+struct memory_config;
+class simt_tables;
// Set a hard limit of 32 CTAs per shader [cuda only has 8]
#define MAX_CTA_PER_SHADER 32
@@ -96,6 +100,7 @@ enum AdaptiveCache { FIXED = 0, ADAPTIVE_CACHE = 1 };
#ifdef __cplusplus
+#include <stack>
#include <stdio.h>
#include <string.h>
#include <set>
@@ -185,7 +190,15 @@ typedef enum operation_pipeline_t operation_pipeline;
enum mem_operation_t { NOT_TEX, TEX };
typedef enum mem_operation_t mem_operation;
-enum _memory_op_t { no_memory_op = 0, memory_load, memory_store };
+enum _memory_op_t {
+ no_memory_op = 0,
+ bru_st_fill_request,
+ bru_st_spill_request,
+ bru_rt_fill_request,
+ bru_rt_spill_request,
+ memory_load,
+ memory_store
+};
#include <assert.h>
#include <stdlib.h>
@@ -500,12 +513,16 @@ const unsigned long long TOTAL_SHARED_MEM =
MAX_STREAMING_MULTIPROCESSORS * SHARED_MEM_SIZE_MAX;
const unsigned long long TOTAL_LOCAL_MEM =
MAX_STREAMING_MULTIPROCESSORS * MAX_THREAD_PER_SM * LOCAL_MEM_SIZE_MAX;
-const unsigned long long SHARED_GENERIC_START =
- GLOBAL_HEAP_START - TOTAL_SHARED_MEM;
+// BRU virtualization memory region (carved out between global heap and shared mem)
+const unsigned MAX_BRU_VIR_PER_SPLIT = (16 * 2);
+const unsigned long long TOTAL_BRU_VIR =
+ (MAX_STREAMING_MULTIPROCESSORS * MAX_THREAD_PER_SM * MAX_BRU_VIR_PER_SPLIT);
+const unsigned long long BRU_VIR_START = (GLOBAL_HEAP_START - TOTAL_BRU_VIR);
+const unsigned long long SHARED_GENERIC_START = (BRU_VIR_START - TOTAL_SHARED_MEM);
const unsigned long long LOCAL_GENERIC_START =
SHARED_GENERIC_START - TOTAL_LOCAL_MEM;
const unsigned long long STATIC_ALLOC_LIMIT =
- GLOBAL_HEAP_START - (TOTAL_LOCAL_MEM + TOTAL_SHARED_MEM);
+ GLOBAL_HEAP_START - (TOTAL_LOCAL_MEM + TOTAL_SHARED_MEM + TOTAL_BRU_VIR);
#if !defined(__CUDA_RUNTIME_API_H__)
@@ -769,12 +786,13 @@ const unsigned SECTOR_SIZE = 32; // sector is 32 bytes width
typedef std::bitset<SECTOR_CHUNCK_SIZE> mem_access_sector_mask_t;
#define NO_PARTIAL_WRITE (mem_access_byte_mask_t())
-#define MEM_ACCESS_TYPE_TUP_DEF \
- MA_TUP_BEGIN(mem_access_type) \
- MA_TUP(GLOBAL_ACC_R), MA_TUP(LOCAL_ACC_R), MA_TUP(CONST_ACC_R), \
- MA_TUP(TEXTURE_ACC_R), MA_TUP(GLOBAL_ACC_W), MA_TUP(LOCAL_ACC_W), \
- MA_TUP(L1_WRBK_ACC), MA_TUP(L2_WRBK_ACC), MA_TUP(INST_ACC_R), \
- MA_TUP(L1_WR_ALLOC_R), MA_TUP(L2_WR_ALLOC_R), \
+#define MEM_ACCESS_TYPE_TUP_DEF \
+ MA_TUP_BEGIN(mem_access_type) \
+ MA_TUP(GLOBAL_ACC_R), MA_TUP(LOCAL_ACC_R), MA_TUP(CONST_ACC_R), \
+ MA_TUP(TEXTURE_ACC_R), MA_TUP(GLOBAL_ACC_W), MA_TUP(BRU_ST_SPILL), \
+ MA_TUP(BRU_ST_FILL), MA_TUP(BRU_RT_SPILL), MA_TUP(BRU_RT_FILL), \
+ MA_TUP(LOCAL_ACC_W), MA_TUP(L1_WRBK_ACC), MA_TUP(L2_WRBK_ACC), \
+ MA_TUP(INST_ACC_R), MA_TUP(L1_WR_ALLOC_R), MA_TUP(L2_WR_ALLOC_R), \
MA_TUP(NUM_MEM_ACCESS_TYPE) MA_TUP_END(mem_access_type)
#define MA_TUP_BEGIN(X) enum X {
@@ -971,13 +989,31 @@ class inst_t {
virtual void print_insn(FILE *fp) const {
fprintf(fp, " [inst @ pc=0x%04llx] ", pc);
}
+
+ bool is_bru_st_fill_request() const {
+ return (op == LOAD_OP && memory_op == bru_st_fill_request);
+ }
+ bool is_bru_rt_fill_request() const {
+ return (op == LOAD_OP && memory_op == bru_rt_fill_request);
+ }
+ bool is_bru_st_spill_request() const {
+ return (op == STORE_OP && memory_op == bru_st_spill_request);
+ }
+ bool is_bru_rt_spill_request() const {
+ return (op == STORE_OP && memory_op == bru_rt_spill_request);
+ }
+
bool is_load() const {
return (op == LOAD_OP || op == TENSOR_CORE_LOAD_OP ||
- memory_op == memory_load);
+ memory_op == memory_load) &&
+ (memory_op != bru_st_fill_request &&
+ memory_op != bru_rt_fill_request);
}
bool is_store() const {
return (op == STORE_OP || op == TENSOR_CORE_STORE_OP ||
- memory_op == memory_store);
+ memory_op == memory_store) &&
+ (memory_op != bru_st_spill_request &&
+ memory_op != bru_rt_spill_request);
}
bool is_fp() const { return ((sp_op == FP__OP)); } // VIJAY
@@ -1055,7 +1091,21 @@ class inst_t {
virtual void pre_decode() {}
};
-enum divergence_support_t { POST_DOMINATOR = 1, NUM_SIMD_MODEL };
+enum splits_replacement_policy_t {
+ FIFO_BACK = 1,
+ NUM_ST_REPLACEMENT_POLICIES
+};
+
+enum reconvergence_replacement_policy_t {
+ REC_LRU = 1,
+ NUM_REC_REPLACEMENT_POLICIES
+};
+
+enum divergence_support_t {
+ POST_DOMINATOR = 1,
+ AWARE_RECONVERGENCE = 2,
+ NUM_SIMD_MODEL
+};
const unsigned MAX_ACCESSES_PER_INSN_PER_THREAD = 8;
@@ -1178,9 +1228,12 @@ class warp_inst_t : public inst_t {
m_per_scalar_thread[lane_id].callback.thread = thread;
}
void set_active(const active_mask_t &active);
+ void set_active(unsigned lane_id) { m_warp_active_mask.set(lane_id); }
void clear_active(const active_mask_t &inactive);
void set_not_active(unsigned lane_id);
+ void clear_pending_mem_requests() { m_accessq.clear(); }
+ void inject_mem_acccesses(mem_access_t acc) { m_accessq.push_back(acc); }
// accessors
virtual void print_insn(FILE *fp) const {
@@ -1195,6 +1248,9 @@ class warp_inst_t : public inst_t {
return m_warp_issued_mask.count();
} // for instruction counting
bool empty() const { return m_empty; }
+ void occupy() { m_empty = false; }
+ unsigned get_warp_id() const { return m_warp_id; }
+ void set_warp_id(unsigned warp_id) { m_warp_id = warp_id; }
unsigned warp_id() const {
assert(!m_empty);
return m_warp_id;
@@ -1301,6 +1357,285 @@ class checkpoint {
void store_global_mem(class memory_space *mem, char *fname, char *format);
unsigned radnom;
};
+// Debug print macro for ITS (disabled by default)
+#define AWARE_DEBUG_PRINT 1
+#define AWARE_DPRINTF(...) \
+ if (AWARE_DEBUG_PRINT) { \
+ printf(__VA_ARGS__); \
+ fflush(stdout); \
+ }
+
+// ── ITS (AWARE Reconvergence) data structures ──────────────────────────────
+
+#define MAX_ST_SIZE 33
+#define MAX_RT_SIZE 32
+
+enum splits_table_entry_type {
+ SPLITS_TABLE_ENTRY_TYPE_NORMAL = 0,
+ SPLITS_TABLE_TYPE_CALL
+};
+
+struct simt_splits_table_entry {
+ bool m_valid;
+ bool m_blocked;
+ bool m_virtual;
+ bool m_transient;
+ bool m_suspended;
+ address_type m_pc;
+ unsigned int m_calldepth;
+ simt_mask_t m_active_mask;
+ address_type m_recvg_pc;
+ unsigned int m_recvg_entry;
+ unsigned long long m_branch_div_cycle;
+ splits_table_entry_type m_type;
+ simt_splits_table_entry()
+ : m_valid(false), m_blocked(false), m_virtual(false),
+ m_transient(false), m_suspended(false), m_pc(-1), m_calldepth(0),
+ m_active_mask(), m_recvg_pc(-1), m_branch_div_cycle(0),
+ m_type(SPLITS_TABLE_ENTRY_TYPE_NORMAL) {}
+};
+
+struct fifo_entry {
+ bool m_blocked;
+ unsigned m_st_entry;
+ unsigned long long m_insertion_cycle;
+ unsigned m_insertion_distance;
+ fifo_entry() : m_blocked(false), m_st_entry(-1) {}
+ fifo_entry(unsigned num, unsigned long long cycle, unsigned dist)
+ : m_blocked(false), m_st_entry(num), m_insertion_cycle(cycle),
+ m_insertion_distance(dist) {}
+ void update_insertion_cycle(unsigned long long cycle, unsigned dist) {
+ m_insertion_cycle = cycle;
+ m_insertion_distance = dist;
+ }
+};
+
+struct simt_reconvergence_table_entry {
+ bool m_valid;
+ bool m_virtual;
+ bool m_transient;
+ address_type m_pc;
+ unsigned int m_calldepth;
+ simt_mask_t m_active_mask;
+ simt_mask_t m_pending_mask;
+ address_type m_recvg_pc;
+ unsigned int m_recvg_entry;
+ unsigned long long m_branch_rec_cycle;
+ splits_table_entry_type m_type;
+ simt_reconvergence_table_entry()
+ : m_valid(false), m_virtual(false), m_transient(false), m_pc(-1),
+ m_calldepth(0), m_active_mask(), m_recvg_pc(-1),
+ m_branch_rec_cycle(0), m_type(SPLITS_TABLE_ENTRY_TYPE_NORMAL) {}
+};
+
+class simt_splits_table {
+ public:
+ simt_splits_table(unsigned wid, unsigned warpSize,
+ const shader_core_config *config,
+ const struct memory_config *mem_config,
+ simt_tables *simt_table);
+ void reset();
+ void launch(address_type start_pc, const simt_mask_t &active_mask);
+ unsigned 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 = false);
+ unsigned 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 insert_new_entry(simt_splits_table_entry entry, bool recvged = false);
+ bool fill_st_entry(unsigned entry);
+ bool spill_st_entry();
+ void get_pdom_splits_entry_info(unsigned num, unsigned *pc, unsigned *rpc);
+ void get_pdom_active_split_info(unsigned *pc, unsigned *rpc);
+ const simt_mask_t &get_active_mask(unsigned num);
+ const simt_mask_t &get_active_mask();
+ unsigned get_rpc();
+ unsigned get_pc();
+ unsigned get_rpc_entry();
+ splits_table_entry_type get_type();
+ bool valid();
+ unsigned get_rpc(unsigned num);
+ void invalidate();
+ void update_active_entry();
+ void update_pc(address_type new_pc);
+ void set_to_blocked();
+ void unset_blocked();
+ void unset_blocked(unsigned entry);
+ void release_blocked();
+ bool is_blocked();
+ bool is_virtual();
+ bool is_blocked_or_virtual();
+ bool split_reaches_barrier(address_type pc);
+ void push_back();
+ void push_back_once();
+ unsigned check_simt_splits_table();
+ unsigned num_entries() { return m_num_entries; }
+ unsigned getInsertionDist() { return m_fifo_queue.front().m_insertion_distance; }
+ unsigned long long getInsertionCycle() { return m_fifo_queue.front().m_insertion_cycle; }
+ void print(FILE *fp);
+ void cycle();
+ bool branch_unit_avail() { return m_spill_st_entry.empty(); }
+ unsigned get_replacement_candidate();
+ void set_shader(shader_core_ctx *shader);
+ bool push_to_st_response_fifo(unsigned entry);
+ bool is_virtualized();
+ bool is_pending_reconvergence() { return m_pending_recvg_entry.m_valid; }
+ bool st_space_available() { return m_num_physical_entries < m_max_st_size; }
+ bool blocked();
+ unsigned address_to_entry(warp_inst_t inst);
+
+ protected:
+ unsigned m_warp_size;
+ unsigned m_warp_id;
+ unsigned m_max_st_size;
+ unsigned m_num_entries;
+ unsigned m_num_physical_entries;
+ unsigned m_num_transient_entries;
+ std::map<unsigned, simt_splits_table_entry> m_splits_table;
+ std::deque<fifo_entry> m_fifo_queue;
+ std::stack<int> m_invalid_entries;
+ std::stack<int> m_available_v_id;
+ unsigned m_active_split;
+ warp_inst_t m_spill_st_entry;
+ warp_inst_t m_fill_st_entry;
+ int m_response_st_entry;
+ shader_core_ctx *m_shader;
+ const shader_core_config *m_config;
+ const struct memory_config *m_mem_config;
+ simt_tables *m_simt_tables;
+ simt_splits_table_entry m_pending_recvg_entry;
+};
+
+class simt_reconvergence_table {
+ public:
+ simt_reconvergence_table(unsigned wid, unsigned warpSize,
+ const shader_core_config *config,
+ const struct memory_config *mem_config,
+ simt_tables *simt_table);
+ void reset();
+ const simt_mask_t &get_active_mask();
+ const simt_mask_t &get_active_mask(unsigned num);
+ void get_recvg_entry_info(unsigned num, unsigned *pc, unsigned *rpc);
+ void get_active_recvg_info(unsigned *pc, unsigned *rpc);
+ unsigned get_rpc(unsigned num);
+ unsigned get_rpc();
+ unsigned get_rpc_entry(unsigned num);
+ splits_table_entry_type get_type(unsigned num);
+ splits_table_entry_type get_type();
+ unsigned get_rpc_entry();
+ unsigned get_pc(unsigned num);
+ unsigned get_pc();
+ void invalidate();
+ void invalidate(unsigned num);
+ bool update_pending_mask(unsigned top_recvg_entry, address_type top_recvg_pc,
+ const simt_mask_t &tmp_active_mask, bool &suspended);
+ unsigned insert_new_entry(address_type pc, address_type rpc,
+ unsigned rpc_entry,
+ const simt_mask_t &tmp_active_mask,
+ splits_table_entry_type type);
+ void update_masks_upon_time_out(unsigned k,
+ const simt_mask_t &reconverged_mask);
+ void set_rec_cycle(unsigned rec_entry, unsigned long long time);
+ unsigned check_simt_reconvergence_table();
+ simt_reconvergence_table_entry get_recvg_entry(unsigned num);
+ unsigned num_entries() { return m_num_entries; }
+ void print(FILE *fout);
+ void cycle();
+ bool branch_unit_avail() { return m_spill_rec_entry.empty(); }
+ void set_shader(shader_core_ctx *shader) { m_shader = shader; }
+ bool spill_rec_entry();
+ bool fill_rec_entry(unsigned entry);
+ bool is_pending_update() { return m_pending_update_entry.m_valid; }
+ bool push_to_rt_response_fifo(unsigned entry);
+ unsigned get_replacement_candidate();
+ unsigned address_to_entry(warp_inst_t inst);
+
+ protected:
+ unsigned m_warp_id;
+ unsigned m_warp_size;
+ unsigned m_num_entries;
+ unsigned m_num_physical_entries;
+ unsigned m_num_transient_entries;
+ unsigned m_max_rec_size;
+ std::map<int, simt_reconvergence_table_entry> m_recvg_table;
+ std::stack<int> m_invalid_entries;
+ unsigned m_active_reconvergence;
+ const shader_core_config *m_config;
+ shader_core_ctx *m_shader;
+ simt_tables *m_simt_tables;
+ warp_inst_t m_spill_rec_entry;
+ warp_inst_t m_fill_rec_entry;
+ int m_response_rec_entry;
+ simt_reconvergence_table_entry m_pending_update_entry;
+ const struct memory_config *m_mem_config;
+};
+
+class simt_tables {
+ public:
+ simt_tables(unsigned wid, unsigned warpSize,
+ const shader_core_config *config,
+ const memory_config *mem_config);
+ void reset();
+ void launch(address_type start_pc, const simt_mask_t &active_mask);
+ void 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);
+ const simt_mask_t &get_active_mask();
+ void get_pdom_active_split_info(unsigned *pc, unsigned *rpc);
+ unsigned get_rp();
+ void check_simt_tables();
+ void check_time_out();
+ void release_barrier();
+ bool split_reaches_barrier(address_type pc);
+ void print(FILE *fp);
+ unsigned getSTsize() { return m_simt_splits_table->num_entries(); }
+ unsigned getInsertionDist() { return m_simt_splits_table->getInsertionDist(); }
+ unsigned long long getInsertionCycle() { return m_simt_splits_table->getInsertionCycle(); }
+ unsigned getRTsize() { return m_simt_recvg_table->num_entries(); }
+ bool branch_unit_avail() {
+ return m_simt_splits_table->branch_unit_avail() &&
+ m_simt_recvg_table->branch_unit_avail();
+ }
+ bool push_to_st_response_fifo(unsigned entry);
+ bool push_to_rt_response_fifo(unsigned entry);
+ void cycle() {
+ m_simt_splits_table->cycle();
+ m_simt_recvg_table->cycle();
+ }
+ void set_shader(shader_core_ctx *shader);
+ void push_back();
+ bool is_virtualized();
+ bool is_pending_reconvergence();
+ bool st_space_available();
+ bool blocked();
+ bool valid();
+ bool is_blocked();
+ bool fill_rec_entry(unsigned entry) {
+ return m_simt_recvg_table->fill_rec_entry(entry);
+ }
+ bool insert_st_entry(address_type pc, address_type rpc, unsigned rpc_entry,
+ const simt_mask_t &tmp_active_mask,
+ splits_table_entry_type type, bool recvged = false) {
+ return m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry,
+ tmp_active_mask, type, recvged);
+ }
+
+ private:
+ unsigned m_warp_id;
+ unsigned m_warp_size;
+ simt_splits_table *m_simt_splits_table;
+ simt_reconvergence_table *m_simt_recvg_table;
+ const shader_core_config *m_config;
+ const struct memory_config *m_mem_config;
+ shader_core_ctx *m_shader;
+};
+
+// ── End ITS data structures ─────────────────────────────────────────────────
+
/*
* This abstract class used as a base for functional and performance and
* simulation, it has basic functional simulation data structures and
@@ -1313,6 +1648,7 @@ class core_t {
: m_gpu(gpu),
m_kernel(kernel),
m_simt_stack(NULL),
+ m_simt_tables(NULL),
m_thread(NULL),
m_warp_size(warp_size) {
m_warp_count = threads_per_shader / m_warp_size;
@@ -1324,7 +1660,7 @@ class core_t {
assert(m_warp_count * m_warp_size > 0);
m_thread = (ptx_thread_info **)calloc(m_warp_count * m_warp_size,
sizeof(ptx_thread_info *));
- initilizeSIMTStack(m_warp_count, m_warp_size);
+ initilizeSIMTDivergenceStructures(m_warp_count, m_warp_size);
for (unsigned i = 0; i < MAX_CTA_PER_SHADER; i++) {
for (unsigned j = 0; j < MAX_BARRIERS_PER_CTA; j++) {
@@ -1343,8 +1679,11 @@ class core_t {
void execute_warp_inst_t(warp_inst_t &inst, unsigned warpId = (unsigned)-1);
bool ptx_thread_done(unsigned hw_thread_id) const;
virtual void updateSIMTStack(unsigned warpId, warp_inst_t *inst);
+ virtual void updateSIMTDivergenceStructures(unsigned warpId, warp_inst_t *inst);
void initilizeSIMTStack(unsigned warp_count, unsigned warps_size);
void deleteSIMTStack();
+ void initilizeSIMTDivergenceStructures(unsigned warp_count, unsigned warp_size);
+ void deleteSIMTDivergenceStructures();
warp_inst_t getExecuteWarp(unsigned warpId);
void get_pdom_stack_top_info(unsigned warpId, unsigned *pc,
unsigned *rpc) const;
@@ -1369,7 +1708,8 @@ class core_t {
protected:
class gpgpu_sim *m_gpu;
kernel_info_t *m_kernel;
- simt_stack **m_simt_stack; // pdom based reconvergence context for each warp
+ simt_stack **m_simt_stack; // pdom based reconvergence context for each warp
+ simt_tables **m_simt_tables; // ITS (AWARE) reconvergence tables per warp
class ptx_thread_info **m_thread;
unsigned m_warp_size;
unsigned m_warp_count;
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index 9055502..1f7de38 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -327,7 +327,26 @@ void memory_config::reg_options(class OptionParser *opp) {
void shader_core_config::reg_options(class OptionParser *opp) {
option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &model,
- "1 = post-dominator", "1");
+ "1 = post-dominator, 2 = AWARE reconvergence (ITS)",
+ "1");
+ option_parser_register(opp, "-gpgpu_simd_rec_time_out", OPT_INT32,
+ &rec_time_out,
+ "reconvergence timeout (-1 = disabled)", "-1");
+ option_parser_register(opp, "-gpgpu_simd_rec_size", OPT_INT32,
+ &num_rec_entries,
+ "number of physical reconvergence table entries",
+ "32");
+ option_parser_register(opp, "-gpgpu_simd_st_size", OPT_INT32,
+ &num_st_entries,
+ "number of physical splits table entries", "32");
+ option_parser_register(opp, "-gpgpu_simd_rec_replacement", OPT_INT32,
+ &rec_replacement,
+ "reconvergence table replacement policy (1 = LRU)",
+ "1");
+ option_parser_register(opp, "-gpgpu_simd_st_replacement", OPT_INT32,
+ &st_replacement,
+ "splits table replacement policy (1 = FIFO_BACK)",
+ "1");
option_parser_register(
opp, "-gpgpu_shader_core_pipeline", OPT_CSTR,
&gpgpu_shader_core_pipeline_opt,
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 7a4ff37..bcf38d3 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -465,6 +465,9 @@ void shader_core_ctx::create_exec_pipeline() {
for (unsigned i = 0; i < num_result_bus; i++) {
this->m_result_bus.push_back(new std::bitset<MAX_ALU_LATENCY>());
}
+
+ if (m_config->model == AWARE_RECONVERGENCE)
+ updateSIMTDivergenceStructuresInitialization();
}
shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu,
@@ -526,7 +529,11 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread,
for (unsigned i = start_thread / m_config->warp_size;
i < end_thread / m_config->warp_size; ++i) {
m_warp[i]->reset();
- m_simt_stack[i]->reset();
+ if (m_config->model == POST_DOMINATOR) {
+ m_simt_stack[i]->reset();
+ } else {
+ m_simt_tables[i]->reset();
+ }
}
}
@@ -535,23 +542,24 @@ void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread,
int cta_size, kernel_info_t &kernel) {
address_type start_pc = next_pc(start_thread);
unsigned kernel_id = kernel.get_uid();
- if (m_config->model == POST_DOMINATOR) {
- unsigned start_warp = start_thread / m_config->warp_size;
- unsigned warp_per_cta = cta_size / m_config->warp_size;
- unsigned end_warp = end_thread / m_config->warp_size +
- ((end_thread % m_config->warp_size) ? 1 : 0);
- for (unsigned i = start_warp; i < end_warp; ++i) {
- unsigned n_active = 0;
- simt_mask_t active_threads;
- for (unsigned t = 0; t < m_config->warp_size; t++) {
- unsigned hwtid = i * m_config->warp_size + t;
- if (hwtid < end_thread) {
- n_active++;
- assert(!m_active_threads.test(hwtid));
- m_active_threads.set(hwtid);
- active_threads.set(t);
- }
+ unsigned start_warp = start_thread / m_config->warp_size;
+ unsigned warp_per_cta = cta_size / m_config->warp_size;
+ unsigned end_warp = end_thread / m_config->warp_size +
+ ((end_thread % m_config->warp_size) ? 1 : 0);
+ for (unsigned i = start_warp; i < end_warp; ++i) {
+ unsigned n_active = 0;
+ simt_mask_t active_threads;
+ for (unsigned t = 0; t < m_config->warp_size; t++) {
+ unsigned hwtid = i * m_config->warp_size + t;
+ if (hwtid < end_thread) {
+ n_active++;
+ assert(!m_active_threads.test(hwtid));
+ m_active_threads.set(hwtid);
+ active_threads.set(t);
}
+ }
+
+ if (m_config->model == POST_DOMINATOR) {
m_simt_stack[i]->launch(start_pc, active_threads);
if (m_gpu->resume_option == 1 && kernel_id == m_gpu->resume_kernel &&
@@ -570,13 +578,15 @@ void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread,
}
start_pc = pc;
}
-
- m_warp[i]->init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id,
- kernel.get_streamID());
- ++m_dynamic_warp_id;
- m_not_completed += n_active;
- ++m_active_warps;
+ } else {
+ m_simt_tables[i]->launch(start_pc, active_threads);
}
+
+ m_warp[i]->init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id,
+ kernel.get_streamID());
+ ++m_dynamic_warp_id;
+ m_not_completed += n_active;
+ ++m_active_warps;
}
}
@@ -599,7 +609,11 @@ void gpgpu_sim::get_pdom_stack_top_info(unsigned sid, unsigned tid,
void shader_core_ctx::get_pdom_stack_top_info(unsigned tid, unsigned *pc,
unsigned *rpc) const {
unsigned warp_id = tid / m_config->warp_size;
- m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc);
+ if (m_config->model == POST_DOMINATOR) {
+ m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc);
+ } else {
+ m_simt_tables[warp_id]->get_pdom_active_split_info(pc, rpc);
+ }
}
float shader_core_ctx::get_current_occupancy(unsigned long long &active,
@@ -879,12 +893,20 @@ void exec_shader_core_ctx::get_pdom_stack_top_info(unsigned warp_id,
const warp_inst_t *pI,
unsigned *pc,
unsigned *rpc) {
- m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc);
+ if (m_config->model == POST_DOMINATOR) {
+ m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc);
+ } else {
+ m_simt_tables[warp_id]->get_pdom_active_split_info(pc, rpc);
+ }
}
const active_mask_t &exec_shader_core_ctx::get_active_mask(
unsigned warp_id, const warp_inst_t *pI) {
- return m_simt_stack[warp_id]->get_active_mask();
+ if (m_config->model == POST_DOMINATOR) {
+ return m_simt_stack[warp_id]->get_active_mask();
+ } else {
+ return m_simt_tables[warp_id]->get_active_mask();
+ }
}
void shader_core_ctx::decode() {
@@ -974,7 +996,11 @@ void shader_core_ctx::fetch() {
}
// this code fetches instructions from the i-cache or generates memory
- if (!m_warp[warp_id]->functional_done() &&
+ bool simt_conditions = true;
+ if (m_config->model == AWARE_RECONVERGENCE)
+ simt_conditions = !is_virtualized(warp_id);
+
+ if (simt_conditions && !m_warp[warp_id]->functional_done() &&
!m_warp[warp_id]->imiss_pending() &&
m_warp[warp_id]->ibuffer_empty()) {
address_type pc;
@@ -1070,11 +1096,31 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set,
}
}
+ bool split_reaches_barrier = false;
if (next_inst->op == BARRIER_OP) {
m_warp[warp_id]->store_info_of_last_inst_at_barrier(*pipe_reg);
- m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id,
- const_cast<warp_inst_t *>(next_inst));
-
+ if (m_config->model == POST_DOMINATOR) {
+ m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id,
+ const_cast<warp_inst_t *>(next_inst));
+ } else {
+ // AWARE_RECONVERGENCE: warp reaches barrier only when all its splits do
+ split_reaches_barrier = true;
+ bool warp_reaches_barrier =
+ m_simt_tables[warp_id]->split_reaches_barrier(next_inst->pc);
+ if (warp_reaches_barrier) {
+ split_reaches_barrier = false;
+ m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id,
+ const_cast<warp_inst_t *>(next_inst));
+ if (m_barriers.warps_count_at_barrier(m_warp[warp_id]->get_cta_id()) ==
+ 0) {
+ unsigned n = m_config->n_thread_per_shader / m_config->warp_size;
+ for (unsigned i = 0; i < n; i++) {
+ if (m_warp[i]->get_cta_id() == m_warp[warp_id]->get_cta_id())
+ m_simt_tables[i]->release_barrier();
+ }
+ }
+ }
+ }
} else if (next_inst->op == MEMORY_BARRIER_OP) {
m_warp[warp_id]->set_membar();
} else if (next_inst->m_is_ldgdepbar) { // Add for LDGDEPBAR
@@ -1120,10 +1166,11 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set,
}
}
- updateSIMTStack(warp_id, *pipe_reg);
+ updateSIMTDivergenceStructures(warp_id, *pipe_reg);
m_scoreboard->reserveRegisters(*pipe_reg);
m_warp[warp_id]->set_next_pc(next_inst->pc + next_inst->isize);
+ if (split_reaches_barrier) m_simt_tables[warp_id]->push_back();
}
void shader_core_ctx::issue() {
@@ -1299,9 +1346,17 @@ void scheduler_unit::cycle() {
"barrier\n",
(*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id());
- while (!warp(warp_id).waiting() && !warp(warp_id).ibuffer_empty() &&
- (checked < max_issue) && (checked <= issued) &&
- (issued < max_issue)) {
+ bool simt_conditions = true;
+ if (m_shader->m_config->model == AWARE_RECONVERGENCE) {
+ simt_conditions = warp(warp_id).valid() &&
+ !warp(warp_id).blocked() &&
+ !warp(warp_id).pending_reconvergence() &&
+ !warp(warp_id).virtualized();
+ }
+
+ while (simt_conditions && !warp(warp_id).waiting() &&
+ !warp(warp_id).ibuffer_empty() && (checked < max_issue) &&
+ (checked <= issued) && (issued < max_issue)) {
const warp_inst_t *pI = warp(warp_id).ibuffer_next_inst();
// Jin: handle cdp latency;
if (pI && pI->m_is_cdp && warp(warp_id).m_cdp_latency > 0) {
@@ -1415,12 +1470,18 @@ void scheduler_unit::cycle() {
}
if (execute_on_SP) {
+ bool bru_avail = true;
+ if (m_shader->m_config->model == AWARE_RECONVERGENCE &&
+ pI->op == BRANCH_OP)
+ bru_avail = m_shader->branch_unit_avail(warp_id);
+ if (bru_avail) {
m_shader->issue_warp(*m_sp_out, pI, active_mask, warp_id,
m_id);
issued++;
issued_inst = true;
warp_inst_issued = true;
previous_issued_inst_exec_type = exec_unit_type_t::SP;
+ }
} else if (execute_on_INT) {
m_shader->issue_warp(*m_int_out, pI, active_mask, warp_id,
m_id);
@@ -1836,6 +1897,14 @@ void shader_core_ctx::execute() {
}
}
}
+
+ // ITS: advance spill/fill state machines for all warps
+ if (m_config->model == AWARE_RECONVERGENCE) {
+ for (unsigned i = 0; i < m_warp_count; ++i) {
+ AWARE_DPRINTF("Cycling SIMT tables for Shader %d: Warp %d...\n", m_sid, i);
+ m_simt_tables[i]->cycle();
+ }
+ }
}
void ldst_unit::print_cache_stats(FILE *fp, unsigned &dl1_accesses,
@@ -2013,7 +2082,9 @@ mem_stage_stall_type ldst_unit::process_cache_access(
if (status == HIT) {
assert(!read_sent);
inst.accessq_pop_back();
- if (inst.is_load()) {
+ if (inst.is_bru_st_fill_request() || inst.is_bru_rt_fill_request()) {
+ release_virtual_entries(inst);
+ } else if (inst.is_load()) {
for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++)
if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]--;
@@ -2698,10 +2769,41 @@ void ldst_unit::issue(register_set &reg_set) {
pipelined_simd_unit::issue(reg_set);
}
+void ldst_unit::release_virtual_entries(warp_inst_t &inst) {
+ if (inst.is_bru_st_fill_request()) {
+ 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;
+ bool done = m_core->push_to_st_response_fifo(wid, entry);
+ if (done) {
+ inst.clear();
+ inst.clear_pending_mem_requests();
+ }
+ } else {
+ assert(inst.is_bru_rt_fill_request());
+ 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;
+ bool done = m_core->push_to_rt_response_fifo(wid, entry);
+ if (done) {
+ inst.clear();
+ inst.clear_pending_mem_requests();
+ }
+ }
+}
+
void ldst_unit::writeback() {
// process next instruction that is going to writeback
if (!m_next_wb.empty()) {
- if (m_operand_collector->writeback(m_next_wb)) {
+ if (m_next_wb.is_bru_st_fill_request() ||
+ m_next_wb.is_bru_rt_fill_request()) {
+ release_virtual_entries(m_next_wb);
+ } else if (m_operand_collector->writeback(m_next_wb)) {
bool insn_completed = false;
for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
if (m_next_wb.out[r] > 0) {
@@ -3357,7 +3459,10 @@ void shader_core_ctx::display_simt_state(FILE *fout, int mask) const {
if (nactive == 0) {
continue;
}
- m_simt_stack[i]->print(fout);
+ if (m_config->model == POST_DOMINATOR)
+ m_simt_stack[i]->print(fout);
+ else
+ m_simt_tables[i]->print(fout);
}
fprintf(fout, "\n");
}
@@ -3673,6 +3778,12 @@ void shader_core_config::set_pipeline_latency() {
void shader_core_ctx::cycle() {
if (!isactive() && get_not_completed() == 0) return;
+ if (m_config->model == AWARE_RECONVERGENCE && m_config->rec_time_out > 0) {
+ unsigned long long total_cycles =
+ m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
+ if (total_cycles % 10000 == 0) check_time_out();
+ }
+
m_stats->shader_cycles[m_sid]++;
writeback();
execute();
@@ -4114,6 +4225,81 @@ bool shd_warp_t::waiting() {
return false;
}
+// ITS (AWARE Reconvergence) warp eligibility helpers
+bool shd_warp_t::virtualized() {
+ return m_shader->is_virtualized(m_warp_id);
+}
+
+bool shd_warp_t::pending_reconvergence() {
+ return m_shader->pending_reconvergence(m_warp_id);
+}
+
+bool shd_warp_t::blocked() {
+ return m_shader->warp_blocked(m_warp_id);
+}
+
+bool shd_warp_t::valid() {
+ return m_shader->warp_valid(m_warp_id);
+}
+
+// ITS (AWARE Reconvergence) shader_core_ctx methods
+void shader_core_ctx::updateSIMTDivergenceStructuresInitialization() {
+ unsigned n = m_config->n_thread_per_shader / m_config->warp_size;
+ for (unsigned i = 0; i < n; i++) {
+ m_simt_tables[i]->set_shader(this);
+ }
+}
+
+bool shader_core_ctx::push_to_st_response_fifo(unsigned wid, unsigned entry) {
+ return m_simt_tables[wid]->push_to_st_response_fifo(entry);
+}
+
+bool shader_core_ctx::push_to_rt_response_fifo(unsigned wid, unsigned entry) {
+ return m_simt_tables[wid]->push_to_rt_response_fifo(entry);
+}
+
+bool shader_core_ctx::is_virtualized(unsigned wid) {
+ return m_simt_tables[wid]->is_virtualized();
+}
+
+bool shader_core_ctx::pending_reconvergence(unsigned wid) {
+ return m_simt_tables[wid]->is_pending_reconvergence();
+}
+
+bool shader_core_ctx::warp_blocked(unsigned wid) {
+ return m_simt_tables[wid]->blocked();
+}
+
+bool shader_core_ctx::warp_valid(unsigned wid) {
+ return m_simt_tables[wid]->valid();
+}
+
+void shader_core_ctx::update_st_size(unsigned n) {
+ // Stats not tracked in gpgpu-sim base; no-op.
+ (void)n;
+}
+
+void shader_core_ctx::update_rt_size(unsigned n) {
+ // Stats not tracked in gpgpu-sim base; no-op.
+ (void)n;
+}
+
+bool shader_core_ctx::branch_unit_avail(unsigned wid) {
+ return m_simt_tables[wid]->branch_unit_avail();
+}
+
+void shader_core_ctx::check_time_out() {
+ for (unsigned w = 0; w < m_config->max_warps_per_shader; w++) {
+ m_simt_tables[w]->check_time_out();
+ }
+}
+
+bool shader_core_ctx::memory_cycle(warp_inst_t &inst,
+ mem_stage_stall_type &rc_fail,
+ mem_stage_access_type &fail_type) {
+ return m_ldst_unit->memory_cycle(inst, rc_fail, fail_type);
+}
+
void shd_warp_t::print(FILE *fout) const {
if (!done_exit()) {
fprintf(fout,
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 5922d24..bb2ac33 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -177,6 +177,12 @@ class shd_warp_t {
bool waiting(); // not const due to membar
bool hardware_done() const;
+ // ITS (AWARE Reconvergence) warp eligibility helpers
+ bool virtualized();
+ bool pending_reconvergence();
+ bool blocked();
+ bool valid();
+
bool done_exit() const { return m_done_exit; }
void set_done_exit() { m_done_exit = true; }
@@ -1081,6 +1087,12 @@ class barrier_set_t {
// assertions
bool warp_waiting_at_barrier(unsigned warp_id) const;
+ // ITS: count warps from a given CTA that are at barrier
+ unsigned warps_count_at_barrier(int cta_id) {
+ warp_set_t t = m_cta_to_warps[cta_id] & m_warp_at_barrier;
+ return t.count();
+ }
+
// debug
void dump();
@@ -1371,6 +1383,9 @@ class ldst_unit : public pipelined_simd_unit {
void flush();
void invalidate();
void writeback();
+ void release_virtual_entries(warp_inst_t &inst);
+ bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail,
+ mem_stage_access_type &fail_type);
// accessors
virtual unsigned clock_multiplier() const;
@@ -1429,8 +1444,6 @@ class ldst_unit : public pipelined_simd_unit {
mem_stage_access_type &fail_type);
bool texture_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail,
mem_stage_access_type &fail_type);
- bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail,
- mem_stage_access_type &fail_type);
virtual mem_stage_stall_type process_cache_access(
cache_t *cache, new_addr_type address, warp_inst_t &inst,
@@ -1622,6 +1635,12 @@ class shader_core_config : public core_config {
bool gpgpu_clock_gated_reg_file;
bool gpgpu_clock_gated_lanes;
enum divergence_support_t model;
+ // ITS (AWARE Reconvergence) config
+ int rec_time_out; // -1 = no reconvergence timeout
+ int num_rec_entries; // physical entries in reconvergence table
+ int num_st_entries; // physical entries in splits table
+ int rec_replacement; // reconvergence table replacement policy
+ int st_replacement; // splits table replacement policy
unsigned n_thread_per_shader;
unsigned n_regfile_gating_group;
unsigned max_warps_per_shader;
@@ -2423,6 +2442,21 @@ class shader_core_ctx : public core_t {
}
bool check_if_non_released_reduction_barrier(warp_inst_t &inst);
+ // ITS (AWARE Reconvergence) methods
+ bool is_virtualized(unsigned wid);
+ bool pending_reconvergence(unsigned wid);
+ bool warp_blocked(unsigned wid);
+ bool warp_valid(unsigned wid);
+ bool push_to_st_response_fifo(unsigned wid, unsigned entry);
+ bool push_to_rt_response_fifo(unsigned wid, unsigned entry);
+ void update_st_size(unsigned n);
+ void update_rt_size(unsigned n);
+ void check_time_out();
+ bool branch_unit_avail(unsigned wid);
+ bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail,
+ mem_stage_access_type &fail_type);
+ void updateSIMTDivergenceStructuresInitialization();
+
protected:
unsigned inactive_lanes_accesses_sfu(unsigned active_count, double latency) {
return (((32 - active_count) >> 1) * latency) +