summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/shader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
-rw-r--r--src/gpgpu-sim/shader.cc269
1 files changed, 251 insertions, 18 deletions
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 9f92215..0897107 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -1087,10 +1087,10 @@ void exec_shader_core_ctx::func_exec_inst(warp_inst_t &inst) {
}
}
-void shader_core_ctx::issue_warp(register_set &pipe_reg_set,
- const warp_inst_t *next_inst,
- const active_mask_t &active_mask,
- unsigned warp_id, unsigned sch_id) {
+warp_inst_t *shader_core_ctx::issue_warp(register_set &pipe_reg_set,
+ const warp_inst_t *next_inst,
+ const active_mask_t &active_mask,
+ unsigned warp_id, unsigned sch_id) {
warp_inst_t **pipe_reg =
pipe_reg_set.get_free(m_config->sub_core_model, sch_id);
assert(pipe_reg);
@@ -1203,6 +1203,45 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set,
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();
+ return *pipe_reg;
+}
+
+void shader_core_ctx::co_issue_warp(warp_inst_t *composite,
+ const warp_inst_t *next_inst,
+ const active_mask_t &active_mask,
+ unsigned warp_id, unsigned sch_id) {
+ // Free the co-issued warp's I-buffer entry
+ m_warp[warp_id]->ibuffer_free();
+ assert(next_inst->valid());
+
+ // Create a temporary instruction for functional execution
+ warp_inst_t temp_inst = *next_inst;
+ temp_inst.issue(active_mask, warp_id,
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle,
+ m_warp[warp_id]->get_dynamic_warp_id(), sch_id,
+ m_warp[warp_id]->get_streamID());
+
+ // Compute SIMD sets for the co-issued instruction
+ temp_inst.compute_simd_sets(m_config->gpgpu_num_simd_sets,
+ m_config->simd_set_width);
+
+ // Functional execution for the co-issued warp's threads
+ func_exec_inst(temp_inst);
+
+ // Update SIMT divergence structures for the co-issued warp
+ updateSIMTDivergenceStructures(warp_id, &temp_inst);
+
+ // Reserve scoreboard for the co-issued warp
+ m_scoreboard->reserveRegisters(&temp_inst);
+
+ // Set next PC for the co-issued warp
+ m_warp[warp_id]->set_next_pc(next_inst->pc + next_inst->isize);
+
+ // Tag the co-issued sets with their source instruction for writeback
+ temp_inst.set_source_inst_on_sets(next_inst);
+
+ // Merge the co-issued instruction's valid sets into the composite
+ composite->merge_simd_sets(temp_inst.get_simd_sets());
}
void shader_core_ctx::issue() {
@@ -1345,6 +1384,12 @@ void scheduler_unit::cycle() {
// waiting for pending register writes
bool issued_inst = false; // of these we issued one
+ // SIMD set co-issue tracking
+ warp_inst_t *co_issue_composite = NULL;
+ exec_unit_type_t co_issue_fu_type = exec_unit_type_t::NONE;
+ register_set *co_issue_reg_set = NULL;
+ unsigned co_issue_primary_warp_id = (unsigned)-1;
+
order_warps();
for (std::vector<shd_warp_t *>::const_iterator iter =
m_next_cycle_prioritized_warps.begin();
@@ -1507,16 +1552,22 @@ void scheduler_unit::cycle() {
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);
+ co_issue_composite = m_shader->issue_warp(
+ *m_sp_out, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::SP;
+ co_issue_reg_set = m_sp_out;
+ co_issue_primary_warp_id = warp_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);
+ co_issue_composite = m_shader->issue_warp(
+ *m_int_out, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::INT;
+ co_issue_reg_set = m_int_out;
+ co_issue_primary_warp_id = warp_id;
issued++;
issued_inst = true;
warp_inst_issued = true;
@@ -1532,8 +1583,11 @@ void scheduler_unit::cycle() {
m_id);
if (dp_pipe_avail) {
- m_shader->issue_warp(*m_dp_out, pI, active_mask, warp_id,
- m_id);
+ co_issue_composite = m_shader->issue_warp(
+ *m_dp_out, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::DP;
+ co_issue_reg_set = m_dp_out;
+ co_issue_primary_warp_id = warp_id;
issued++;
issued_inst = true;
warp_inst_issued = true;
@@ -1552,8 +1606,11 @@ void scheduler_unit::cycle() {
m_id);
if (sfu_pipe_avail) {
- m_shader->issue_warp(*m_sfu_out, pI, active_mask, warp_id,
- m_id);
+ co_issue_composite = m_shader->issue_warp(
+ *m_sfu_out, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::SFU;
+ co_issue_reg_set = m_sfu_out;
+ co_issue_primary_warp_id = warp_id;
issued++;
issued_inst = true;
warp_inst_issued = true;
@@ -1568,8 +1625,11 @@ void scheduler_unit::cycle() {
m_shader->m_config->sub_core_model, m_id);
if (tensor_core_pipe_avail) {
- m_shader->issue_warp(*m_tensor_core_out, pI, active_mask,
- warp_id, m_id);
+ co_issue_composite = m_shader->issue_warp(
+ *m_tensor_core_out, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::TENSOR;
+ co_issue_reg_set = m_tensor_core_out;
+ co_issue_primary_warp_id = warp_id;
issued++;
issued_inst = true;
warp_inst_issued = true;
@@ -1589,8 +1649,11 @@ void scheduler_unit::cycle() {
m_id);
if (spec_pipe_avail) {
- m_shader->issue_warp(*spec_reg_set, pI, active_mask, warp_id,
- m_id);
+ co_issue_composite = m_shader->issue_warp(
+ *spec_reg_set, pI, active_mask, warp_id, m_id);
+ co_issue_fu_type = exec_unit_type_t::SPECIALIZED;
+ co_issue_reg_set = spec_reg_set;
+ co_issue_primary_warp_id = warp_id;
issued++;
issued_inst = true;
warp_inst_issued = true;
@@ -1649,6 +1712,136 @@ void scheduler_unit::cycle() {
}
}
+ // SIMD set co-issue pass: after issuing primary instruction, try to pack
+ // instructions from other warps into unused SIMD sets (same FU type).
+ // Only for non-MEM FUs (LDST excluded from partitioning).
+ if (m_shader->m_config->gpgpu_simd_partitioning && co_issue_composite != NULL &&
+ co_issue_fu_type != exec_unit_type_t::MEM &&
+ co_issue_fu_type != exec_unit_type_t::NONE) {
+ // Count available (unused) sets in the composite
+ unsigned available_sets = 0;
+ const std::vector<simd_set_info> &primary_sets =
+ co_issue_composite->get_simd_sets();
+ for (unsigned s = 0; s < primary_sets.size(); s++) {
+ if (!primary_sets[s].valid) available_sets++;
+ }
+
+ if (available_sets > 0) {
+ printf("SIMD_SETS: cycle %llu, core %u, sched %u: %u sets available "
+ "after primary warp %u\n",
+ m_shader->get_gpu()->gpu_sim_cycle +
+ m_shader->get_gpu()->gpu_tot_sim_cycle,
+ get_sid(), m_id, available_sets, co_issue_primary_warp_id);
+
+ // Scan other warps for co-issue candidates
+ for (std::vector<shd_warp_t *>::const_iterator iter2 =
+ m_next_cycle_prioritized_warps.begin();
+ iter2 != m_next_cycle_prioritized_warps.end() && available_sets > 0;
+ iter2++) {
+ if ((*iter2) == NULL || (*iter2)->done_exit()) continue;
+ unsigned cand_warp_id = (*iter2)->get_warp_id();
+
+ // Skip the primary warp (already issued)
+ if (cand_warp_id == co_issue_primary_warp_id) continue;
+
+ // Check basic eligibility
+ if (warp(cand_warp_id).ibuffer_empty()) continue;
+ if (warp(cand_warp_id).waiting()) continue;
+
+ // AWARE reconvergence eligibility
+ bool simt_ok = true;
+ if (m_shader->m_config->model == AWARE_RECONVERGENCE) {
+ simt_ok = warp(cand_warp_id).valid() &&
+ !warp(cand_warp_id).blocked() &&
+ !warp(cand_warp_id).pending_reconvergence() &&
+ !warp(cand_warp_id).virtualized();
+ }
+ if (!simt_ok) continue;
+
+ const warp_inst_t *cand_inst = warp(cand_warp_id).ibuffer_next_inst();
+ if (!cand_inst) continue;
+ if (!warp(cand_warp_id).ibuffer_next_valid()) continue;
+
+ // Control hazard check
+ unsigned cand_pc, cand_rpc;
+ m_shader->get_pdom_stack_top_info(cand_warp_id, cand_inst, &cand_pc,
+ &cand_rpc);
+ if (cand_pc != cand_inst->pc) continue;
+
+ // Scoreboard check for the candidate warp
+ if (m_scoreboard->checkCollision(cand_warp_id, cand_inst)) continue;
+
+ // Check candidate targets the same FU type as the primary
+ exec_unit_type_t cand_fu_type = exec_unit_type_t::NONE;
+ if ((cand_inst->op == LOAD_OP) || (cand_inst->op == STORE_OP) ||
+ (cand_inst->op == MEMORY_BARRIER_OP) ||
+ (cand_inst->op == TENSOR_CORE_LOAD_OP) ||
+ (cand_inst->op == TENSOR_CORE_STORE_OP)) {
+ cand_fu_type = exec_unit_type_t::MEM;
+ } else if (cand_inst->op == SP_OP ||
+ (cand_inst->op != DP_OP && cand_inst->op != SFU_OP &&
+ cand_inst->op != ALU_SFU_OP &&
+ cand_inst->op != TENSOR_CORE_OP &&
+ cand_inst->op < SPEC_UNIT_START_ID &&
+ m_shader->m_config->gpgpu_num_int_units == 0)) {
+ cand_fu_type = exec_unit_type_t::SP;
+ } else if (cand_inst->op != SP_OP && cand_inst->op != DP_OP &&
+ cand_inst->op != SFU_OP && cand_inst->op != ALU_SFU_OP &&
+ cand_inst->op != TENSOR_CORE_OP &&
+ cand_inst->op < SPEC_UNIT_START_ID &&
+ m_shader->m_config->gpgpu_num_int_units > 0) {
+ cand_fu_type = exec_unit_type_t::INT;
+ } else if (cand_inst->op == DP_OP) {
+ cand_fu_type = exec_unit_type_t::DP;
+ } else if (cand_inst->op == SFU_OP || cand_inst->op == ALU_SFU_OP) {
+ cand_fu_type = exec_unit_type_t::SFU;
+ } else if (cand_inst->op == TENSOR_CORE_OP) {
+ cand_fu_type = exec_unit_type_t::TENSOR;
+ } else if (cand_inst->op >= SPEC_UNIT_START_ID) {
+ cand_fu_type = exec_unit_type_t::SPECIALIZED;
+ }
+ if (cand_fu_type != co_issue_fu_type) continue;
+
+ // Get candidate's active mask and compute its SIMD sets
+ const active_mask_t &cand_mask =
+ m_shader->get_active_mask(cand_warp_id, cand_inst);
+
+ // Build candidate's SIMD set info to check for overlap
+ warp_inst_t cand_temp(m_shader->m_config);
+ cand_temp = *cand_inst;
+ cand_temp.issue(cand_mask, cand_warp_id, 0, 0, 0, 0);
+ cand_temp.compute_simd_sets(m_shader->m_config->gpgpu_num_simd_sets,
+ m_shader->m_config->simd_set_width);
+
+ // Check set overlap with the current composite
+ if (warp_inst_t::simd_sets_overlap(co_issue_composite->get_simd_sets(),
+ cand_temp.get_simd_sets())) {
+ continue; // sets conflict, can't co-issue
+ }
+
+ // Count candidate's sets to verify they fit
+ unsigned cand_sets_needed = cand_temp.num_active_simd_sets();
+ if (cand_sets_needed > available_sets) continue;
+
+ printf("SIMD_SETS: cycle %llu, core %u, sched %u: warp %u "
+ "CO-ISSUED with primary warp %u (%u sets)\n",
+ m_shader->get_gpu()->gpu_sim_cycle +
+ m_shader->get_gpu()->gpu_tot_sim_cycle,
+ get_sid(), m_id, cand_warp_id, co_issue_primary_warp_id,
+ cand_sets_needed);
+
+ // Co-issue: functional execution, SIMT update, scoreboard, merge
+ m_shader->co_issue_warp(co_issue_composite, cand_inst, cand_mask,
+ cand_warp_id, m_id);
+
+ available_sets -= cand_sets_needed;
+
+ // Advance candidate warp's ibuffer
+ warp(cand_warp_id).ibuffer_step();
+ }
+ }
+ }
+
// issue stall statistics:
if (!valid_inst)
m_stats->shader_cycle_distro[0]++; // idle or control hazard
@@ -2063,8 +2256,48 @@ void shader_core_ctx::writeback() {
m_operand_collector.writeback(*pipe_reg);
unsigned warp_id = pipe_reg->warp_id();
- m_scoreboard->releaseRegisters(pipe_reg);
- m_warp[warp_id]->dec_inst_in_pipeline();
+
+ // Per-set writeback: release scoreboard and dec pipeline counter
+ // for each unique warp participating in this composite instruction
+ if (m_config->gpgpu_simd_partitioning && pipe_reg->has_simd_sets()) {
+ std::set<unsigned> unique_warp_ids;
+ const std::vector<simd_set_info> &sets = pipe_reg->get_simd_sets();
+ for (unsigned s = 0; s < sets.size(); s++) {
+ if (!sets[s].valid) continue;
+ unsigned set_warp_id = sets[s].warp_id;
+ unique_warp_ids.insert(set_warp_id);
+ }
+ // Release scoreboard for primary instruction (covers the outer warp_id)
+ m_scoreboard->releaseRegisters(pipe_reg);
+ // Release scoreboard for any co-issued warps (non-primary)
+ for (unsigned wid : unique_warp_ids) {
+ if (wid == warp_id) continue; // already released above
+ // For co-issued warps, release their destination registers
+ // which were reserved in co_issue_warp() via reserveRegisters
+ // on the temporary instruction. The temp used the co-issued
+ // warp's out[] registers, so we need to release those.
+ // Since the composite's outer out[] belongs to the primary warp,
+ // we look at the sets to find co-issued warp registers.
+ for (unsigned s = 0; s < sets.size(); s++) {
+ if (sets[s].valid && sets[s].warp_id == wid &&
+ sets[s].source_inst != NULL) {
+ for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
+ if (sets[s].source_inst->out[r] > 0) {
+ m_scoreboard->releaseRegister(wid, sets[s].source_inst->out[r]);
+ }
+ }
+ }
+ }
+ }
+ // dec_inst_in_pipeline for each unique warp
+ for (unsigned wid : unique_warp_ids) {
+ m_warp[wid]->dec_inst_in_pipeline();
+ }
+ } else {
+ m_scoreboard->releaseRegisters(pipe_reg);
+ m_warp[warp_id]->dec_inst_in_pipeline();
+ }
+
warp_inst_complete(*pipe_reg);
m_gpu->gpu_sim_insn_last_update_sid = m_sid;
m_gpu->gpu_sim_insn_last_update = m_gpu->gpu_sim_cycle;