From 8d59181b80697dfc717abcd55da9c899e4cf0d07 Mon Sep 17 00:00:00 2001 From: Inderpreet Singh Date: Wed, 18 Jul 2012 23:17:29 -0800 Subject: Copied in Arun's SIMT stack fix for recursive calls (CL8574) [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 13410] --- CHANGES | 2 ++ src/abstract_hardware_model.cc | 72 ++++++++++++++++++++++++++++++++---------- src/abstract_hardware_model.h | 15 +++++++-- src/cuda-sim/cuda-sim.cc | 17 ++++++++++ src/cuda-sim/ptx_ir.cc | 13 ++++++++ 5 files changed, 101 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 2da61e0..d6ccb25 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,8 @@ Version 3.1.0+edits (development branch) versus 3.1.0 - Cleaner makedepend that doesn't interfere with Makefiles - Print out instructions at branch divergence/reconvergence points - Bug Fixes: + - SIMT stack correctly handles recursive functions by allocating a new stack entry on every + function call - Fixed a bug in executing call_imp and callp_imp with the pure functional simulation mode. - Fixed a couple of memory errors in cuobjdump_to_ptxplus code. - Implemented better support for handling memory operand type modifier diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index 396e45a..b86e750 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -533,24 +533,29 @@ simt_stack::simt_stack( unsigned wid, unsigned warpSize) { m_warp_id=wid; m_warp_size = warpSize; + m_max_stack_size = m_warp_size * 4; // this choice is arbitrary. stack size can grow arbitrarily with deeper call hierarchies. + // TODO: expandable stack implementation m_stack_top = 0; - m_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type)); - m_calldepth = (unsigned int*)calloc(m_warp_size * 2, sizeof(unsigned int)); - m_active_mask = new simt_mask_t[m_warp_size * 2]; - m_recvg_pc = (address_type*)calloc(m_warp_size * 2, sizeof(address_type)); - m_branch_div_cycle = (unsigned long long *)calloc(m_warp_size * 2, sizeof(unsigned long long )); + m_pc = (address_type*)calloc(m_max_stack_size, sizeof(address_type)); + m_calldepth = (unsigned int*)calloc(m_max_stack_size, sizeof(unsigned int)); + m_active_mask = new simt_mask_t[m_max_stack_size]; + m_recvg_pc = (address_type*)calloc(m_max_stack_size, sizeof(address_type)); + m_branch_div_cycle = (unsigned long long *)calloc(m_max_stack_size, sizeof(unsigned long long )); + m_type = (stack_entry_type *) calloc(m_max_stack_size, sizeof(stack_entry_type)); reset(); } void simt_stack::reset() { m_stack_top = 0; - memset(m_pc, -1, m_warp_size * 2 * sizeof(address_type)); - memset(m_calldepth, 0, m_warp_size * 2 * sizeof(unsigned int)); - memset(m_recvg_pc, -1, m_warp_size * 2 * sizeof(address_type)); - memset(m_branch_div_cycle, 0, m_warp_size * 2 * sizeof(unsigned long long )); - for( unsigned i=0; i < 2*m_warp_size; i++ ) + memset(m_pc, -1, m_max_stack_size * sizeof(address_type)); + memset(m_calldepth, 0, m_max_stack_size * sizeof(unsigned int)); + memset(m_recvg_pc, -1, m_max_stack_size * sizeof(address_type)); + memset(m_branch_div_cycle, 0, m_max_stack_size * sizeof(unsigned long long )); + for( unsigned i=0; i < m_max_stack_size; i++ ) { m_active_mask[i].reset(); + m_type[i] = NORMAL; + } } void simt_stack::launch( address_type start_pc, const simt_mask_t &active_mask ) @@ -590,9 +595,9 @@ void simt_stack::print (FILE *fout) const fprintf(fout, "%c", (warp->m_active_mask[k].test(j)?'1':'0') ); fprintf(fout, " pc: 0x%03x", warp->m_pc[k] ); if ( warp->m_recvg_pc[k] == (unsigned)-1 ) { - fprintf(fout," rp: ---- cd: %2u ", warp->m_calldepth[k] ); + fprintf(fout," rp: ---- tp: %s cd: %2u ", (warp->m_type[k]==CALL?"C":"N"), warp->m_calldepth[k] ); } else { - fprintf(fout," rp: %4u cd: %2u ", warp->m_recvg_pc[k], warp->m_calldepth[k] ); + fprintf(fout," rp: %4u tp: %s cd: %2u ", warp->m_recvg_pc[k], (warp->m_type[k]==CALL?"C":"N"), warp->m_calldepth[k] ); } if ( warp->m_branch_div_cycle[k] != 0 ) { fprintf(fout," bd@%6u ", (unsigned) warp->m_branch_div_cycle[k] ); @@ -604,7 +609,7 @@ void simt_stack::print (FILE *fout) const } } -void simt_stack::update( simt_mask_t &thread_done, addr_vector_t &next_pc, address_type recvg_pc ) +void simt_stack::update( simt_mask_t &thread_done, addr_vector_t &next_pc, address_type recvg_pc, op_type next_inst_op ) { int stack_top = m_stack_top; @@ -613,6 +618,7 @@ void simt_stack::update( simt_mask_t &thread_done, addr_vector_t &next_pc, addre simt_mask_t top_active_mask = m_active_mask[stack_top]; address_type top_recvg_pc = m_recvg_pc[stack_top]; address_type top_pc = m_pc[stack_top]; // the pc of the instruction just executed + stack_entry_type top_type = m_type[stack_top]; assert(top_active_mask.any()); @@ -639,9 +645,43 @@ void simt_stack::update( simt_mask_t &thread_done, addr_vector_t &next_pc, addre } } + // HANDLE THE SPECIAL CASES FIRST + if (next_inst_op== CALL_OPS) + { + // Since call is not a divergent instruction, all threads should have executed a call instruction + assert(top_active_mask.any() == false); + stack_top += 1; + + m_active_mask[stack_top] = tmp_active_mask; + m_pc[stack_top]=tmp_next_pc; + m_type[stack_top]= CALL; + m_recvg_pc[stack_top] = -1; + m_stack_top = stack_top; + return; + + } else if(next_inst_op == RET_OPS && top_type==CALL) { + // pop the CALL Entry + assert(top_active_mask.any() == false); + + m_type[stack_top]= NORMAL; // RESET THE STACK ENTRY FOR FUTURE USE + + stack_top -= 1; // REMOVE The top stack entry + m_stack_top = stack_top; + m_pc[stack_top]=tmp_next_pc;// set the PC of the stack top entry to return PC from the call stack; + // Check if the New top of the stack is reconverging + if (tmp_next_pc == m_recvg_pc[stack_top] && m_type[stack_top]!=CALL) + { + assert(m_type[stack_top]==NORMAL); + stack_top -= 1; // REMOVE this entry as well + m_stack_top = stack_top; + } + return; + } + // discard the new entry if its PC matches with reconvergence PC // that automatically reconverges the entry - if (tmp_next_pc == top_recvg_pc) continue; + // If the top stack entry is CALL, dont reconverge. + if (tmp_next_pc == top_recvg_pc && (top_type != CALL)) continue; // this new entry is not converging // if this entry does not include thread from the warp, divergence occurs @@ -674,7 +714,7 @@ void simt_stack::update( simt_mask_t &thread_done, addr_vector_t &next_pc, addre m_stack_top = stack_top - 1; assert(m_stack_top >= 0); - assert(m_stack_top < m_warp_size * 2); + assert(m_stack_top < m_max_stack_size); if (warp_diverged) { ptx_file_line_stats_add_warp_divergence(top_pc, 1); @@ -714,7 +754,7 @@ for (unsigned i = 0; i < warpSize; i++) { next_pc.push_back( m_thread[wtid+i]->get_pc() ); } } -m_simt_stack[warpId]->update(thread_done,next_pc,inst->reconvergence_pc); +m_simt_stack[warpId]->update(thread_done,next_pc,inst->reconvergence_pc, inst->op); } //! Get the warp to be executed using the data taken form the SIMT stack diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index 1fc10b9..4cde89a 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -64,7 +64,9 @@ enum uarch_op_t { STORE_OP, BRANCH_OP, BARRIER_OP, - MEMORY_BARRIER_OP + MEMORY_BARRIER_OP, + CALL_OPS, + RET_OPS }; typedef enum uarch_op_t op_type; @@ -245,7 +247,7 @@ public: 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 ); + void update( simt_mask_t &thread_done, addr_vector_t &next_pc, address_type recvg_pc, op_type next_inst_op ); const simt_mask_t &get_active_mask() const; void get_pdom_stack_top_info( unsigned *pc, unsigned *rpc ) const; @@ -256,12 +258,19 @@ protected: unsigned m_warp_id; unsigned m_stack_top; unsigned m_warp_size; + unsigned m_max_stack_size; address_type *m_pc; simt_mask_t *m_active_mask; address_type *m_recvg_pc; unsigned int *m_calldepth; + enum stack_entry_type { + NORMAL = 0, + CALL + }; + stack_entry_type *m_type; + unsigned long long *m_branch_div_cycle; }; @@ -683,6 +692,7 @@ public: m_per_scalar_thread_valid=false; m_mem_accesses_created=false; m_cache_hit=false; + m_is_printf=false; } virtual ~warp_inst_t(){ } @@ -814,6 +824,7 @@ protected: unsigned long long issue_cycle; unsigned cycles; // used for implementing initiation interval delay bool m_isatomic; + bool m_is_printf; unsigned m_warp_id; const core_config *m_config; active_mask_t m_warp_active_mask; diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index 252b230..e17877b 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -499,6 +499,23 @@ void ptx_instruction::set_opcode_and_latency() case ATOM_OP: op = LOAD_OP; break; case BAR_OP: op = BARRIER_OP; break; case MEMBAR_OP: op = MEMORY_BARRIER_OP; break; + case CALL_OP: + { + if(m_is_printf) + op = ALU_OP; + else + op = CALL_OPS; + break; + } + case CALLP_OP: + { + if(m_is_printf) + op = ALU_OP; + else + op = CALL_OPS; + break; + } + case RET_OP: op = RET_OPS;break; case ADD_OP: case ADDP_OP: case ADDC_OP: case SUB_OP: case SUBC_OP: //ADD,SUB latency switch(get_type()){ diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc index 102ae40..61b45e3 100644 --- a/src/cuda-sim/ptx_ir.cc +++ b/src/cuda-sim/ptx_ir.cc @@ -1162,6 +1162,19 @@ ptx_instruction::ptx_instruction( int opcode, m_source_file = file?file:""; m_source_line = line; m_source = source; + + if (opcode == CALL_OP) { + const operand_info &target = func_addr(); + assert( target.is_function_address() ); + const symbol *func_addr = target.get_symbol(); + const function_info *target_func = func_addr->get_pc(); + std::string fname = target_func->get_name(); + + if (fname =="vprintf"){ + m_is_printf = true; + } + + } } void ptx_instruction::print_insn() const -- cgit v1.3