summaryrefslogtreecommitdiff
path: root/src/cuda-sim
diff options
context:
space:
mode:
authorAmruth <[email protected]>2018-04-03 11:43:46 -0700
committerAmruth <[email protected]>2018-04-03 11:43:46 -0700
commit26476592e3650e796b51c94dd1a25c162eb1aa64 (patch)
treea12f4f25ba9d6a554c3e95cb189f1f4264ed8db0 /src/cuda-sim
parentdeee9038d3d67e60f106776be3dd0a846dd11df9 (diff)
crash when print() is sent to pdom analysis
Diffstat (limited to 'src/cuda-sim')
-rw-r--r--src/cuda-sim/cuda-sim.cc~2155
-rw-r--r--src/cuda-sim/instructions.cc7
-rw-r--r--src/cuda-sim/instructions.cc~4517
-rw-r--r--src/cuda-sim/ptx_loader.cc~462
4 files changed, 7140 insertions, 1 deletions
diff --git a/src/cuda-sim/cuda-sim.cc~ b/src/cuda-sim/cuda-sim.cc~
new file mode 100644
index 0000000..cfd901f
--- /dev/null
+++ b/src/cuda-sim/cuda-sim.cc~
@@ -0,0 +1,2155 @@
+// Copyright (c) 2009-2011, Tor M. Aamodt, Ali Bakhoda, Wilson W.L. Fung,
+// George L. Yuan, Jimmy Kwa
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "cuda-sim.h"
+
+#include "instructions.h"
+#include "ptx_ir.h"
+#include "ptx.tab.h"
+#include "ptx_sim.h"
+#include <stdio.h>
+
+#include "opcodes.h"
+#include "../statwrapper.h"
+#include <set>
+#include <map>
+#include "../abstract_hardware_model.h"
+#include "memory.h"
+#include "ptx-stats.h"
+#include "ptx_loader.h"
+#include "ptx_parser.h"
+#include "../gpgpu-sim/gpu-sim.h"
+#include "ptx_sim.h"
+#include "../gpgpusim_entrypoint.h"
+#include "decuda_pred_table/decuda_pred_table.h"
+#include "../stream_manager.h"
+#include "cuda_device_runtime.h"
+
+int gpgpu_ptx_instruction_classification;
+void ** g_inst_classification_stat = NULL;
+void ** g_inst_op_classification_stat= NULL;
+int g_ptx_kernel_count = -1; // used for classification stat collection purposes
+int g_debug_execution = 0;
+int g_debug_thread_uid = 0;
+addr_t g_debug_pc = 0xBEEF1518;
+// Output debug information to file options
+
+unsigned g_ptx_sim_num_insn = 0;
+unsigned gpgpu_param_num_shaders = 0;
+
+char *opcode_latency_int, *opcode_latency_fp, *opcode_latency_dp;
+char *opcode_initiation_int, *opcode_initiation_fp, *opcode_initiation_dp;
+char *cdp_latency_str;
+unsigned cdp_latency[5];
+
+void ptx_opcocde_latency_options (option_parser_t opp) {
+ option_parser_register(opp, "-ptx_opcode_latency_int", OPT_CSTR, &opcode_latency_int,
+ "Opcode latencies for integers <ADD,MAX,MUL,MAD,DIV>"
+ "Default 1,1,19,25,145",
+ "1,1,19,25,145");
+ option_parser_register(opp, "-ptx_opcode_latency_fp", OPT_CSTR, &opcode_latency_fp,
+ "Opcode latencies for single precision floating points <ADD,MAX,MUL,MAD,DIV>"
+ "Default 1,1,1,1,30",
+ "1,1,1,1,30");
+ option_parser_register(opp, "-ptx_opcode_latency_dp", OPT_CSTR, &opcode_latency_dp,
+ "Opcode latencies for double precision floating points <ADD,MAX,MUL,MAD,DIV>"
+ "Default 8,8,8,8,335",
+ "8,8,8,8,335");
+ option_parser_register(opp, "-ptx_opcode_initiation_int", OPT_CSTR, &opcode_initiation_int,
+ "Opcode initiation intervals for integers <ADD,MAX,MUL,MAD,DIV>"
+ "Default 1,1,4,4,32",
+ "1,1,4,4,32");
+ option_parser_register(opp, "-ptx_opcode_initiation_fp", OPT_CSTR, &opcode_initiation_fp,
+ "Opcode initiation intervals for single precision floating points <ADD,MAX,MUL,MAD,DIV>"
+ "Default 1,1,1,1,5",
+ "1,1,1,1,5");
+ option_parser_register(opp, "-ptx_opcode_initiation_dp", OPT_CSTR, &opcode_initiation_dp,
+ "Opcode initiation intervals for double precision floating points <ADD,MAX,MUL,MAD,DIV>"
+ "Default 8,8,8,8,130",
+ "8,8,8,8,130");
+ option_parser_register(opp, "-cdp_latency", OPT_CSTR, &cdp_latency_str,
+ "CDP API latency <cudaStreamCreateWithFlags, \
+cudaGetParameterBufferV2_init_perWarp, cudaGetParameterBufferV2_perKernel, \
+cudaLaunchDeviceV2_init_perWarp, cudaLaunchDevicV2_perKernel>"
+ "Default 7200,8000,100,12000,1600",
+ "7200,8000,100,12000,1600");
+}
+
+static address_type get_converge_point(address_type pc);
+
+void gpgpu_t::gpgpu_ptx_sim_bindNameToTexture(const char* name, const struct textureReference* texref, int dim, int readmode, int ext)
+{
+ std::string texname(name);
+ m_NameToTextureRef[texname] = texref;
+ const textureReferenceAttr *texAttr = new textureReferenceAttr(texref, dim, (enum cudaTextureReadMode)readmode, ext);
+ m_TextureRefToAttribute[texref] = texAttr;
+}
+
+const char* gpgpu_t::gpgpu_ptx_sim_findNamefromTexture(const struct textureReference* texref)
+{
+ std::map<std::string, const struct textureReference*>::iterator itr = m_NameToTextureRef.begin();
+ while (itr != m_NameToTextureRef.end()) {
+ if ((*itr).second == texref) {
+ const char *p = ((*itr).first).c_str();
+ return p;
+ }
+ itr++;
+ }
+ return NULL;
+}
+
+unsigned int intLOGB2( unsigned int v ) {
+ unsigned int shift;
+ unsigned int r;
+
+ r = 0;
+
+ shift = (( v & 0xFFFF0000) != 0 ) << 4; v >>= shift; r |= shift;
+ shift = (( v & 0xFF00 ) != 0 ) << 3; v >>= shift; r |= shift;
+ shift = (( v & 0xF0 ) != 0 ) << 2; v >>= shift; r |= shift;
+ shift = (( v & 0xC ) != 0 ) << 1; v >>= shift; r |= shift;
+ shift = (( v & 0x2 ) != 0 ) << 0; v >>= shift; r |= shift;
+
+ return r;
+}
+
+void gpgpu_t::gpgpu_ptx_sim_bindTextureToArray(const struct textureReference* texref, const struct cudaArray* array)
+{
+ m_TextureRefToCudaArray[texref] = array;
+ unsigned int texel_size_bits = array->desc.w + array->desc.x + array->desc.y + array->desc.z;
+ unsigned int texel_size = texel_size_bits/8;
+ unsigned int Tx, Ty;
+ int r;
+
+ printf("GPGPU-Sim PTX: texel size = %d\n", texel_size);
+ printf("GPGPU-Sim PTX: texture cache linesize = %d\n", m_function_model_config.get_texcache_linesize());
+ //first determine base Tx size for given linesize
+ switch (m_function_model_config.get_texcache_linesize()) {
+ case 16: Tx = 4; break;
+ case 32: Tx = 8; break;
+ case 64: Tx = 8; break;
+ case 128: Tx = 16; break;
+ case 256: Tx = 16; break;
+ default:
+ printf("GPGPU-Sim PTX: Line size of %d bytes currently not supported.\n", m_function_model_config.get_texcache_linesize());
+ assert(0);
+ break;
+ }
+ r = texel_size >> 2;
+ //modify base Tx size to take into account size of each texel in bytes
+ while (r != 0) {
+ Tx = Tx >> 1;
+ r = r >> 2;
+ }
+ //by now, got the correct Tx size, calculate correct Ty size
+ Ty = m_function_model_config.get_texcache_linesize()/(Tx*texel_size);
+
+ printf("GPGPU-Sim PTX: Tx = %d; Ty = %d, Tx_numbits = %d, Ty_numbits = %d\n", Tx, Ty, intLOGB2(Tx), intLOGB2(Ty));
+ printf("GPGPU-Sim PTX: Texel size = %d bytes; texel_size_numbits = %d\n", texel_size, intLOGB2(texel_size));
+ printf("GPGPU-Sim PTX: Binding texture to array starting at devPtr32 = 0x%x\n", array->devPtr32);
+ printf("GPGPU-Sim PTX: Texel size = %d bytes\n", texel_size);
+ struct textureInfo* texInfo = (struct textureInfo*) malloc(sizeof(struct textureInfo));
+ texInfo->Tx = Tx;
+ texInfo->Ty = Ty;
+ texInfo->Tx_numbits = intLOGB2(Tx);
+ texInfo->Ty_numbits = intLOGB2(Ty);
+ texInfo->texel_size = texel_size;
+ texInfo->texel_size_numbits = intLOGB2(texel_size);
+ m_TextureRefToTexureInfo[texref] = texInfo;
+}
+
+unsigned g_assemble_code_next_pc=0;
+std::map<unsigned,function_info*> g_pc_to_finfo;
+std::vector<ptx_instruction*> function_info::s_g_pc_to_insn;
+
+#define MAX_INST_SIZE 8 /*bytes*/
+
+void function_info::ptx_assemble()
+{
+ if( m_assembled ) {
+ return;
+ }
+
+ // get the instructions into instruction memory...
+ unsigned num_inst = m_instructions.size();
+ m_instr_mem_size = MAX_INST_SIZE*(num_inst+1);
+ m_instr_mem = new ptx_instruction*[ m_instr_mem_size ];
+
+ printf("GPGPU-Sim PTX: instruction assembly for function \'%s\'... ", m_name.c_str() );
+ fflush(stdout);
+ std::list<ptx_instruction*>::iterator i;
+
+ addr_t PC = g_assemble_code_next_pc; // globally unique address (across functions)
+ // start function on an aligned address
+ for( unsigned i=0; i < (PC%MAX_INST_SIZE); i++ )
+ s_g_pc_to_insn.push_back((ptx_instruction*)NULL);
+ PC += PC%MAX_INST_SIZE;
+ m_start_PC = PC;
+
+ addr_t n=0; // offset in m_instr_mem
+ //Why s_g_pc_to_insn.size() is needed to reserve additional memory for insts? reserve is cumulative.
+ //s_g_pc_to_insn.reserve(s_g_pc_to_insn.size() + MAX_INST_SIZE*m_instructions.size());
+ s_g_pc_to_insn.reserve(MAX_INST_SIZE*m_instructions.size());
+ for ( i=m_instructions.begin(); i != m_instructions.end(); i++ ) {
+ ptx_instruction *pI = *i;
+ if ( pI->is_label() ) {
+ const symbol *l = pI->get_label();
+ labels[l->name()] = n;
+ } else {
+ g_pc_to_finfo[PC] = this;
+ m_instr_mem[n] = pI;
+ s_g_pc_to_insn.push_back(pI);
+ assert(pI == s_g_pc_to_insn[PC]);
+ pI->set_m_instr_mem_index(n);
+ pI->set_PC(PC);
+ assert( pI->inst_size() <= MAX_INST_SIZE );
+ for( unsigned i=1; i < pI->inst_size(); i++ ) {
+ s_g_pc_to_insn.push_back((ptx_instruction*)NULL);
+ m_instr_mem[n+i]=NULL;
+ }
+ n += pI->inst_size();
+ PC += pI->inst_size();
+ }
+ }
+ g_assemble_code_next_pc=PC;
+ for ( unsigned ii=0; ii < n; ii += m_instr_mem[ii]->inst_size() ) { // handle branch instructions
+ ptx_instruction *pI = m_instr_mem[ii];
+ if ( pI->get_opcode() == BRA_OP || pI->get_opcode() == BREAKADDR_OP || pI->get_opcode() == CALLP_OP) {
+ operand_info &target = pI->dst(); //get operand, e.g. target name
+ if ( labels.find(target.name()) == labels.end() ) {
+ printf("GPGPU-Sim PTX: Loader error (%s:%u): Branch label \"%s\" does not appear in assembly code.",
+ pI->source_file(),pI->source_line(), target.name().c_str() );
+ abort();
+ }
+ unsigned index = labels[ target.name() ]; //determine address from name
+ unsigned PC = m_instr_mem[index]->get_PC();
+ m_symtab->set_label_address( target.get_symbol(), PC );
+ target.set_type(label_t);
+ }
+ }
+ m_n = n;
+ printf(" done.\n");
+ fflush(stdout);
+
+ //disable pdom analysis here and do it at runtime
+ printf("GPGPU-Sim PTX: finding reconvergence points for \'%s\'...\n", m_name.c_str() );
+ create_basic_blocks();
+ connect_basic_blocks();
+ bool modified = false;
+ do {
+ find_dominators();
+ find_idominators();
+ modified = connect_break_targets();
+ } while (modified == true);
+
+ if ( g_debug_execution>=50 ) {
+ print_basic_blocks();
+ print_basic_block_links();
+ print_basic_block_dot();
+ }
+ if ( g_debug_execution>=2 ) {
+ print_dominators();
+ }
+ find_postdominators();
+ find_ipostdominators();
+ if ( g_debug_execution>=50 ) {
+ print_postdominators();
+ print_ipostdominators();
+ }
+
+ printf("GPGPU-Sim PTX: pre-decoding instructions for \'%s\'...\n", m_name.c_str() );
+ for ( unsigned ii=0; ii < n; ii += m_instr_mem[ii]->inst_size() ) { // handle branch instructions
+ ptx_instruction *pI = m_instr_mem[ii];
+ pI->pre_decode();
+ }
+ printf("GPGPU-Sim PTX: ... done pre-decoding instructions for \'%s\'.\n", m_name.c_str() );
+ fflush(stdout);
+
+ m_assembled = true;
+}
+
+addr_t shared_to_generic( unsigned smid, addr_t addr )
+{
+ assert( addr < SHARED_MEM_SIZE_MAX );
+ return SHARED_GENERIC_START + smid*SHARED_MEM_SIZE_MAX + addr;
+}
+
+addr_t global_to_generic( addr_t addr )
+{
+ return addr;
+}
+
+bool isspace_shared( unsigned smid, addr_t addr )
+{
+ addr_t start = SHARED_GENERIC_START + smid*SHARED_MEM_SIZE_MAX;
+ addr_t end = SHARED_GENERIC_START + (smid+1)*SHARED_MEM_SIZE_MAX;
+ if( (addr >= end) || (addr < start) )
+ return false;
+ return true;
+}
+
+bool isspace_global( addr_t addr )
+{
+ return (addr >= GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT);
+}
+
+memory_space_t whichspace( addr_t addr )
+{
+ if( (addr >= GLOBAL_HEAP_START) || (addr < STATIC_ALLOC_LIMIT) ) {
+ return global_space;
+ } else if( addr >= SHARED_GENERIC_START ) {
+ return shared_space;
+ } else {
+ return local_space;
+ }
+}
+
+addr_t generic_to_shared( unsigned smid, addr_t addr )
+{
+ assert(isspace_shared(smid,addr));
+ return addr - (SHARED_GENERIC_START + smid*SHARED_MEM_SIZE_MAX);
+}
+
+addr_t local_to_generic( unsigned smid, unsigned hwtid, addr_t addr )
+{
+ assert(addr < LOCAL_MEM_SIZE_MAX);
+ return LOCAL_GENERIC_START + (TOTAL_LOCAL_MEM_PER_SM * smid) + (LOCAL_MEM_SIZE_MAX * hwtid) + addr;
+}
+
+bool isspace_local( unsigned smid, unsigned hwtid, addr_t addr )
+{
+ addr_t start = LOCAL_GENERIC_START + (TOTAL_LOCAL_MEM_PER_SM * smid) + (LOCAL_MEM_SIZE_MAX * hwtid);
+ addr_t end = LOCAL_GENERIC_START + (TOTAL_LOCAL_MEM_PER_SM * smid) + (LOCAL_MEM_SIZE_MAX * (hwtid+1));
+ if( (addr >= end) || (addr < start) )
+ return false;
+ return true;
+}
+
+addr_t generic_to_local( unsigned smid, unsigned hwtid, addr_t addr )
+{
+ assert(isspace_local(smid,hwtid,addr));
+ return addr - (LOCAL_GENERIC_START + (TOTAL_LOCAL_MEM_PER_SM * smid) + (LOCAL_MEM_SIZE_MAX * hwtid));
+}
+
+addr_t generic_to_global( addr_t addr )
+{
+ return addr;
+}
+
+
+void* gpgpu_t::gpu_malloc( size_t size )
+{
+ unsigned long long result = m_dev_malloc;
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, m_dev_malloc );
+ fflush(stdout);
+ }
+ m_dev_malloc += size;
+ if (size%256) m_dev_malloc += (256 - size%256); //align to 256 byte boundaries
+ return(void*) result;
+}
+
+void* gpgpu_t::gpu_mallocarray( size_t size )
+{
+ unsigned long long result = m_dev_malloc;
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, m_dev_malloc );
+ fflush(stdout);
+ }
+ m_dev_malloc += size;
+ if (size%256) m_dev_malloc += (256 - size%256); //align to 256 byte boundaries
+ return(void*) result;
+}
+
+
+void gpgpu_t::memcpy_to_gpu( size_t dst_start_addr, const void *src, size_t count )
+{
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: copying %zu bytes from CPU[0x%Lx] to GPU[0x%Lx] ... ", count, (unsigned long long) src, (unsigned long long) dst_start_addr );
+ fflush(stdout);
+ }
+ char *src_data = (char*)src;
+ for (unsigned n=0; n < count; n ++ )
+ m_global_mem->write(dst_start_addr+n,1, src_data+n,NULL,NULL);
+ if(g_debug_execution >= 3) {
+ printf( " done.\n");
+ fflush(stdout);
+ }
+}
+
+void gpgpu_t::memcpy_from_gpu( void *dst, size_t src_start_addr, size_t count )
+{
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: copying %zu bytes from GPU[0x%Lx] to CPU[0x%Lx] ...", count, (unsigned long long) src_start_addr, (unsigned long long) dst );
+ fflush(stdout);
+ }
+ unsigned char *dst_data = (unsigned char*)dst;
+ for (unsigned n=0; n < count; n ++ )
+ m_global_mem->read(src_start_addr+n,1,dst_data+n);
+ if(g_debug_execution >= 3) {
+ printf( " done.\n");
+ fflush(stdout);
+ }
+}
+
+void gpgpu_t::memcpy_gpu_to_gpu( size_t dst, size_t src, size_t count )
+{
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: copying %zu bytes from GPU[0x%Lx] to GPU[0x%Lx] ...", count,
+ (unsigned long long) src, (unsigned long long) dst );
+ fflush(stdout);
+ }
+ for (unsigned n=0; n < count; n ++ ) {
+ unsigned char tmp;
+ m_global_mem->read(src+n,1,&tmp);
+ m_global_mem->write(dst+n,1, &tmp,NULL,NULL);
+ }
+ if(g_debug_execution >= 3) {
+ printf( " done.\n");
+ fflush(stdout);
+ }
+}
+
+void gpgpu_t::gpu_memset( size_t dst_start_addr, int c, size_t count )
+{
+ if(g_debug_execution >= 3) {
+ printf("GPGPU-Sim PTX: setting %zu bytes of memory to 0x%x starting at 0x%Lx... ",
+ count, (unsigned char) c, (unsigned long long) dst_start_addr );
+ fflush(stdout);
+ }
+ unsigned char c_value = (unsigned char)c;
+ for (unsigned n=0; n < count; n ++ )
+ m_global_mem->write(dst_start_addr+n,1,&c_value,NULL,NULL);
+ if(g_debug_execution >= 3) {
+ printf( " done.\n");
+ fflush(stdout);
+ }
+}
+
+void ptx_print_insn( address_type pc, FILE *fp )
+{
+ std::map<unsigned,function_info*>::iterator f = g_pc_to_finfo.find(pc);
+ if( f == g_pc_to_finfo.end() ) {
+ fprintf(fp,"<no instruction at address 0x%x>", pc );
+ return;
+ }
+ function_info *finfo = f->second;
+ assert( finfo );
+ finfo->print_insn(pc,fp);
+}
+
+std::string ptx_get_insn_str( address_type pc )
+{
+ std::map<unsigned,function_info*>::iterator f = g_pc_to_finfo.find(pc);
+ if( f == g_pc_to_finfo.end() ) {
+ #define STR_SIZE 255
+ char buff[STR_SIZE];
+ buff[STR_SIZE - 1] = '\0';
+ snprintf(buff, STR_SIZE,"<no instruction at address 0x%x>", pc );
+ return std::string(buff);
+ }
+ function_info *finfo = f->second;
+ assert( finfo );
+ return finfo->get_insn_str(pc);
+}
+
+void ptx_instruction::set_fp_or_int_archop(){
+ oprnd_type=UN_OP;
+ if((m_opcode == MEMBAR_OP)||(m_opcode == SSY_OP )||(m_opcode == BRA_OP) || (m_opcode == BAR_OP) || (m_opcode == RET_OP) || (m_opcode == RETP_OP) || (m_opcode == NOP_OP) || (m_opcode == EXIT_OP) || (m_opcode == CALLP_OP) || (m_opcode == CALL_OP)){
+ // do nothing
+ }else if((m_opcode == CVT_OP || m_opcode == SET_OP || m_opcode == SLCT_OP)){
+ if(get_type2()==F16_TYPE || get_type2()==F32_TYPE || get_type2() == F64_TYPE || get_type2() == FF64_TYPE){
+ oprnd_type= FP_OP;
+ }else oprnd_type=INT_OP;
+
+ }else{
+ if(get_type()==F16_TYPE || get_type()==F32_TYPE || get_type() == F64_TYPE || get_type() == FF64_TYPE){
+ oprnd_type= FP_OP;
+ }else oprnd_type=INT_OP;
+ }
+}
+void ptx_instruction::set_mul_div_or_other_archop(){
+ sp_op=OTHER_OP;
+ if((m_opcode != MEMBAR_OP) && (m_opcode != SSY_OP) && (m_opcode != BRA_OP) && (m_opcode != BAR_OP) && (m_opcode != EXIT_OP) && (m_opcode != NOP_OP) && (m_opcode != RETP_OP) && (m_opcode != RET_OP) && (m_opcode != CALLP_OP) && (m_opcode != CALL_OP)){
+ if(get_type()==F32_TYPE || get_type() == F64_TYPE || get_type() == FF64_TYPE){
+ switch(get_opcode()){
+ case MUL_OP:
+ case MAD_OP:
+ sp_op=FP_MUL_OP;
+ break;
+ case DIV_OP:
+ sp_op=FP_DIV_OP;
+ break;
+ case LG2_OP:
+ sp_op=FP_LG_OP;
+ break;
+ case RSQRT_OP:
+ case SQRT_OP:
+ sp_op=FP_SQRT_OP;
+ break;
+ case RCP_OP:
+ sp_op=FP_DIV_OP;
+ break;
+ case SIN_OP:
+ case COS_OP:
+ sp_op=FP_SIN_OP;
+ break;
+ case EX2_OP:
+ sp_op=FP_EXP_OP;
+ break;
+ default:
+ if(op==ALU_OP)
+ sp_op=FP__OP;
+ break;
+
+ }
+ }else {
+ switch(get_opcode()){
+ case MUL24_OP:
+ case MAD24_OP:
+ sp_op=INT_MUL24_OP;
+ break;
+ case MUL_OP:
+ case MAD_OP:
+ if(get_type()==U32_TYPE || get_type()==S32_TYPE || get_type()==B32_TYPE)
+ sp_op=INT_MUL32_OP;
+ else
+ sp_op=INT_MUL_OP;
+ break;
+ case DIV_OP:
+ sp_op=INT_DIV_OP;
+ break;
+ default:
+ if(op==ALU_OP)
+ sp_op=INT__OP;
+ break;
+ }
+ }
+ }
+
+}
+
+
+
+void ptx_instruction::set_bar_type()
+{
+ if(m_opcode==BAR_OP) {
+ switch(m_barrier_op){
+ case SYNC_OPTION:
+ bar_type = SYNC;
+ break;
+ case ARRIVE_OPTION:
+ bar_type = ARRIVE;
+ break;
+ case RED_OPTION:
+ bar_type = RED;
+ switch(m_atomic_spec){
+ case ATOMIC_POPC:
+ red_type = POPC_RED;
+ break;
+ case ATOMIC_AND:
+ red_type = AND_RED;
+ break;
+ case ATOMIC_OR:
+ red_type = OR_RED;
+ break;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+
+void ptx_instruction::set_opcode_and_latency()
+{
+ unsigned int_latency[5];
+ unsigned fp_latency[5];
+ unsigned dp_latency[5];
+ unsigned int_init[5];
+ unsigned fp_init[5];
+ unsigned dp_init[5];
+ /*
+ * [0] ADD,SUB
+ * [1] MAX,Min
+ * [2] MUL
+ * [3] MAD
+ * [4] DIV
+ */
+ sscanf(opcode_latency_int, "%u,%u,%u,%u,%u",
+ &int_latency[0],&int_latency[1],&int_latency[2],
+ &int_latency[3],&int_latency[4]);
+ sscanf(opcode_latency_fp, "%u,%u,%u,%u,%u",
+ &fp_latency[0],&fp_latency[1],&fp_latency[2],
+ &fp_latency[3],&fp_latency[4]);
+ sscanf(opcode_latency_dp, "%u,%u,%u,%u,%u",
+ &dp_latency[0],&dp_latency[1],&dp_latency[2],
+ &dp_latency[3],&dp_latency[4]);
+ sscanf(opcode_initiation_int, "%u,%u,%u,%u,%u",
+ &int_init[0],&int_init[1],&int_init[2],
+ &int_init[3],&int_init[4]);
+ sscanf(opcode_initiation_fp, "%u,%u,%u,%u,%u",
+ &fp_init[0],&fp_init[1],&fp_init[2],
+ &fp_init[3],&fp_init[4]);
+ sscanf(opcode_initiation_dp, "%u,%u,%u,%u,%u",
+ &dp_init[0],&dp_init[1],&dp_init[2],
+ &dp_init[3],&dp_init[4]);
+ sscanf(cdp_latency_str, "%u,%u,%u,%u,%u",
+ &cdp_latency[0],&cdp_latency[1],&cdp_latency[2],
+ &cdp_latency[3],&cdp_latency[4]);
+
+ if(!m_operands.empty()){
+ std::vector<operand_info>::iterator it;
+ for(it=++m_operands.begin();it!=m_operands.end();it++){
+ num_operands++;
+ if((it->is_reg() || it->is_vector())){
+ num_regs++;
+ }
+ }
+ }
+ op = ALU_OP;
+ mem_op= NOT_TEX;
+ initiation_interval = latency = 1;
+ switch( m_opcode ) {
+ case MOV_OP:
+ assert( !(has_memory_read() && has_memory_write()) );
+ if ( has_memory_read() ) op = LOAD_OP;
+ if ( has_memory_write() ) op = STORE_OP;
+ break;
+ case LD_OP: op = LOAD_OP; break;
+ case LDU_OP: op = LOAD_OP; break;
+ case ST_OP: op = STORE_OP; break;
+ case BRA_OP: op = BRANCH_OP; break;
+ case BREAKADDR_OP: op = BRANCH_OP; break;
+ case TEX_OP: op = LOAD_OP; mem_op=TEX; break;
+ 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 || m_is_cdp) {
+ op = ALU_OP;
+ }
+ else
+ op = CALL_OPS;
+ break;
+ }
+ case CALLP_OP:
+ {
+ if(m_is_printf || m_is_cdp) {
+ op = ALU_OP;
+ }
+ else
+ op = CALL_OPS;
+ break;
+ }
+ case RET_OP: case RETP_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()){
+ case F32_TYPE:
+ latency = fp_latency[0];
+ initiation_interval = fp_init[0];
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ latency = dp_latency[0];
+ initiation_interval = dp_init[0];
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ case S32_TYPE:
+ default: //Use int settings for default
+ latency = int_latency[0];
+ initiation_interval = int_init[0];
+ break;
+ }
+ break;
+ case MAX_OP: case MIN_OP:
+ //MAX,MIN latency
+ switch(get_type()){
+ case F32_TYPE:
+ latency = fp_latency[1];
+ initiation_interval = fp_init[1];
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ latency = dp_latency[1];
+ initiation_interval = dp_init[1];
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ case S32_TYPE:
+ default: //Use int settings for default
+ latency = int_latency[1];
+ initiation_interval = int_init[1];
+ break;
+ }
+ break;
+ case MUL_OP:
+ //MUL latency
+ switch(get_type()){
+ case F32_TYPE:
+ latency = fp_latency[2];
+ initiation_interval = fp_init[2];
+ op = ALU_SFU_OP;
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ latency = dp_latency[2];
+ initiation_interval = dp_init[2];
+ op = ALU_SFU_OP;
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ case S32_TYPE:
+ default: //Use int settings for default
+ latency = int_latency[2];
+ initiation_interval = int_init[2];
+ op = SFU_OP;
+ break;
+ }
+ break;
+ case MAD_OP: case MADC_OP: case MADP_OP:
+ //MAD latency
+ switch(get_type()){
+ case F32_TYPE:
+ latency = fp_latency[3];
+ initiation_interval = fp_init[3];
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ latency = dp_latency[3];
+ initiation_interval = dp_init[3];
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ case S32_TYPE:
+ default: //Use int settings for default
+ latency = int_latency[3];
+ initiation_interval = int_init[3];
+ op = SFU_OP;
+ break;
+ }
+ break;
+ case DIV_OP:
+ // Floating point only
+ op = SFU_OP;
+ switch(get_type()){
+ case F32_TYPE:
+ latency = fp_latency[4];
+ initiation_interval = fp_init[4];
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ latency = dp_latency[4];
+ initiation_interval = dp_init[4];
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ case S32_TYPE:
+ default: //Use int settings for default
+ latency = int_latency[4];
+ initiation_interval = int_init[4];
+ break;
+ }
+ break;
+ case SQRT_OP: case SIN_OP: case COS_OP: case EX2_OP: case LG2_OP: case RSQRT_OP: case RCP_OP:
+ //Using double to approximate those
+ latency = dp_latency[2];
+ initiation_interval = dp_init[2];
+ op = SFU_OP;
+ break;
+ case SHFL_OP:
+ latency = 32;
+ initiation_interval = 15;
+ break;
+ default:
+ break;
+ }
+ set_fp_or_int_archop();
+ set_mul_div_or_other_archop();
+
+}
+
+void ptx_thread_info::ptx_fetch_inst( inst_t &inst ) const
+{
+ addr_t pc = get_pc();
+ const ptx_instruction *pI = m_func_info->get_instruction(pc);
+ inst = (const inst_t&)*pI;
+ assert( inst.valid() );
+}
+
+static unsigned datatype2size( unsigned data_type )
+{
+ unsigned data_size;
+ switch ( data_type ) {
+ case B8_TYPE:
+ case S8_TYPE:
+ case U8_TYPE:
+ data_size = 1; break;
+ case B16_TYPE:
+ case S16_TYPE:
+ case U16_TYPE:
+ case F16_TYPE:
+ data_size = 2; break;
+ case B32_TYPE:
+ case S32_TYPE:
+ case U32_TYPE:
+ case F32_TYPE:
+ data_size = 4; break;
+ case B64_TYPE:
+ case BB64_TYPE:
+ case S64_TYPE:
+ case U64_TYPE:
+ case F64_TYPE:
+ case FF64_TYPE:
+ data_size = 8; break;
+ case BB128_TYPE:
+ data_size = 16; break;
+ default: assert(0); break;
+ }
+ return data_size;
+}
+
+void ptx_instruction::pre_decode()
+{
+ pc = m_PC;
+ isize = m_inst_size;
+ for( unsigned i=0; i<4; i++) {
+ out[i] = 0;
+ in[i] = 0;
+ }
+ is_vectorin = 0;
+ is_vectorout = 0;
+ std::fill_n(arch_reg.src, MAX_REG_OPERANDS, -1);
+ std::fill_n(arch_reg.dst, MAX_REG_OPERANDS, -1);
+ pred = 0;
+ ar1 = 0;
+ ar2 = 0;
+ space = m_space_spec;
+ memory_op = no_memory_op;
+ data_size = 0;
+ if ( has_memory_read() || has_memory_write() ) {
+ unsigned to_type = get_type();
+ data_size = datatype2size(to_type);
+ memory_op = has_memory_read() ? memory_load : memory_store;
+ }
+
+ bool has_dst = false ;
+
+ switch ( get_opcode() ) {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break;
+#define OP_W_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break;
+#include "opcodes.def"
+#undef OP_DEF
+#undef OP_W_DEF
+ default:
+ printf( "Execution error: Invalid opcode (0x%x)\n", get_opcode() );
+ break;
+ }
+
+ switch( m_cache_option ) {
+ case CA_OPTION: cache_op = CACHE_ALL; break;
+ case CG_OPTION: cache_op = CACHE_GLOBAL; break;
+ case CS_OPTION: cache_op = CACHE_STREAMING; break;
+ case LU_OPTION: cache_op = CACHE_LAST_USE; break;
+ case CV_OPTION: cache_op = CACHE_VOLATILE; break;
+ case WB_OPTION: cache_op = CACHE_WRITE_BACK; break;
+ case WT_OPTION: cache_op = CACHE_WRITE_THROUGH; break;
+ default:
+ if( m_opcode == LD_OP || m_opcode == LDU_OP )
+ cache_op = CACHE_ALL;
+ else if( m_opcode == ST_OP )
+ cache_op = CACHE_WRITE_BACK;
+ else if( m_opcode == ATOM_OP )
+ cache_op = CACHE_GLOBAL;
+ break;
+ }
+
+ set_opcode_and_latency();
+ set_bar_type();
+ // Get register operands
+ int n=0,m=0;
+ ptx_instruction::const_iterator opr=op_iter_begin();
+ for ( ; opr != op_iter_end(); opr++, n++ ) { //process operands
+ const operand_info &o = *opr;
+ if ( has_dst && n==0 ) {
+ // Do not set the null register "_" as an architectural register
+ if ( o.is_reg() && !o.is_non_arch_reg() ) {
+ out[0] = o.reg_num();
+ arch_reg.dst[0] = o.arch_reg_num();
+ } else if ( o.is_vector() ) {
+ is_vectorin = 1;
+ unsigned num_elem = o.get_vect_nelem();
+ if( num_elem >= 1 ) out[0] = o.reg1_num();
+ if( num_elem >= 2 ) out[1] = o.reg2_num();
+ if( num_elem >= 3 ) out[2] = o.reg3_num();
+ if( num_elem >= 4 ) out[3] = o.reg4_num();
+ for (int i = 0; i < num_elem; i++)
+ arch_reg.dst[i] = o.arch_reg_num(i);
+ }
+ } else {
+ if ( o.is_reg() && !o.is_non_arch_reg() ) {
+ int reg_num = o.reg_num();
+ arch_reg.src[m] = o.arch_reg_num();
+ switch ( m ) {
+ case 0: in[0] = reg_num; break;
+ case 1: in[1] = reg_num; break;
+ case 2: in[2] = reg_num; break;
+ default: break;
+ }
+ m++;
+ } else if ( o.is_vector() ) {
+ //assert(m == 0); //only support 1 vector operand (for textures) right now
+ is_vectorout = 1;
+ unsigned num_elem = o.get_vect_nelem();
+ if( num_elem >= 1 ) in[0] = o.reg1_num();
+ if( num_elem >= 2 ) in[1] = o.reg2_num();
+ if( num_elem >= 3 ) in[2] = o.reg3_num();
+ if( num_elem >= 4 ) in[3] = o.reg4_num();
+ for (int i = 0; i < num_elem; i++)
+ arch_reg.src[i] = o.arch_reg_num(i);
+ m+=4;
+ }
+ }
+ }
+
+ // Get predicate
+ if(has_pred()) {
+ const operand_info &p = get_pred();
+ pred = p.reg_num();
+ }
+
+ // Get address registers inside memory operands.
+ // Assuming only one memory operand per instruction,
+ // and maximum of two address registers for one memory operand.
+ if( has_memory_read() || has_memory_write() ) {
+ ptx_instruction::const_iterator op=op_iter_begin();
+ for ( ; op != op_iter_end(); op++, n++ ) { //process operands
+ const operand_info &o = *op;
+
+ if(o.is_memory_operand()) {
+ // We do not support the null register as a memory operand
+ assert( !o.is_non_arch_reg() );
+
+ // Check PTXPlus-type operand
+ // memory operand with addressing (ex. s[0x4] or g[$r1])
+ if(o.is_memory_operand2()) {
+
+ // memory operand with one address register (ex. g[$r1+0x4] or s[$r2+=0x4])
+ if(o.get_double_operand_type() == 0 || o.get_double_operand_type() == 3){
+ ar1 = o.reg_num();
+ arch_reg.src[4] = o.arch_reg_num();
+ // TODO: address register in $r2+=0x4 should be an output register as well
+ }
+ // memory operand with two address register (ex. s[$r1+$r1] or g[$r1+=$r2])
+ else if(o.get_double_operand_type() == 1 || o.get_double_operand_type() == 2) {
+ ar1 = o.reg1_num();
+ arch_reg.src[4] = o.arch_reg_num();
+ ar2 = o.reg2_num();
+ arch_reg.src[5] = o.arch_reg_num();
+ // TODO: first address register in $r1+=$r2 should be an output register as well
+ }
+ }
+ else if(o.is_immediate_address()){
+
+ }
+ // Regular PTX operand
+ else if (o.get_symbol()->type()->get_key().is_reg()) { // Memory operand contains a register
+ ar1 = o.reg_num();
+ arch_reg.src[4] = o.arch_reg_num();
+ }
+
+ }
+ }
+ }
+
+ // get reconvergence pc
+ reconvergence_pc = get_converge_point(pc);
+
+ m_decoded=true;
+}
+
+void function_info::add_param_name_type_size( unsigned index, std::string name, int type, size_t size, bool ptr, memory_space_t space )
+{
+ unsigned parsed_index;
+ char buffer[2048];
+ snprintf(buffer,2048,"%s_param_%%u", m_name.c_str() );
+ int ntokens = sscanf(name.c_str(),buffer,&parsed_index);
+ if( ntokens == 1 ) {
+ assert( m_ptx_kernel_param_info.find(parsed_index) == m_ptx_kernel_param_info.end() );
+ m_ptx_kernel_param_info[parsed_index] = param_info(name, type, size, ptr, space);
+ } else {
+ assert( m_ptx_kernel_param_info.find(index) == m_ptx_kernel_param_info.end() );
+ m_ptx_kernel_param_info[index] = param_info(name, type, size, ptr, space);
+ }
+}
+
+void function_info::add_param_data( unsigned argn, struct gpgpu_ptx_sim_arg *args )
+{
+ const void *data = args->m_start;
+
+ bool scratchpad_memory_param = false; // Is this parameter in CUDA shared memory or OpenCL local memory
+
+ std::map<unsigned,param_info>::iterator i=m_ptx_kernel_param_info.find(argn);
+ if( i != m_ptx_kernel_param_info.end() ) {
+ if (i->second.is_ptr_shared()) {
+ assert(args->m_start == NULL && "OpenCL parameter pointer to local memory must have NULL as value");
+ scratchpad_memory_param = true;
+ } else {
+ param_t tmp;
+ tmp.pdata = args->m_start;
+ tmp.size = args->m_nbytes;
+ tmp.offset = args->m_offset;
+ tmp.type = 0;
+ i->second.add_data(tmp);
+ i->second.add_offset((unsigned) args->m_offset);
+ }
+ } else {
+ scratchpad_memory_param = true;
+ }
+
+ if (scratchpad_memory_param) {
+ // This should only happen for OpenCL:
+ //
+ // The LLVM PTX compiler in NVIDIA's driver (version 190.29)
+ // does not generate an argument in the function declaration
+ // for __constant arguments.
+ //
+ // The associated constant memory space can be allocated in two
+ // ways. It can be explicitly initialized in the .ptx file where
+ // it is declared. Or, it can be allocated using the clCreateBuffer
+ // on the host. In this later case, the .ptx file will contain
+ // a global declaration of the parameter, but it will have an unknown
+ // array size. Thus, the symbol's address will not be set and we need
+ // to set it here before executing the PTX.
+
+ char buffer[2048];
+ snprintf(buffer,2048,"%s_param_%u",m_name.c_str(),argn);
+
+ symbol *p = m_symtab->lookup(buffer);
+ if( p == NULL ) {
+ printf("GPGPU-Sim PTX: ERROR ** could not locate symbol for \'%s\' : cannot bind buffer\n", buffer);
+ abort();
+ }
+ if( data )
+ p->set_address((addr_t)*(size_t*)data);
+ else {
+ // clSetKernelArg was passed NULL pointer for data...
+ // this is used for dynamically sized shared memory on NVIDIA platforms
+ bool is_ptr_shared = false;
+ if( i != m_ptx_kernel_param_info.end() ) {
+ is_ptr_shared = i->second.is_ptr_shared();
+ }
+
+ if( !is_ptr_shared and !p->is_shared() ) {
+ printf("GPGPU-Sim PTX: ERROR ** clSetKernelArg passed NULL but arg not shared memory\n");
+ abort();
+ }
+ unsigned num_bits = 8*args->m_nbytes;
+ printf("GPGPU-Sim PTX: deferred allocation of shared region for \"%s\" from 0x%x to 0x%x (shared memory space)\n",
+ p->name().c_str(),
+ m_symtab->get_shared_next(),
+ m_symtab->get_shared_next() + num_bits/8 );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ addr_t addr = m_symtab->get_shared_next();
+ addr_t addr_pad = num_bits ? (((num_bits/8) - (addr % (num_bits/8))) % (num_bits/8)) : 0;
+ p->set_address( addr+addr_pad );
+ m_symtab->alloc_shared( num_bits/8 + addr_pad );
+ }
+ }
+}
+
+unsigned function_info::get_args_aligned_size() {
+
+ if(m_args_aligned_size >= 0)
+ return m_args_aligned_size;
+
+ unsigned param_address = 0;
+ unsigned int total_size = 0;
+ for( std::map<unsigned,param_info>::iterator i=m_ptx_kernel_param_info.begin(); i!=m_ptx_kernel_param_info.end(); i++ ) {
+ param_info &p = i->second;
+ std::string name = p.get_name();
+ symbol *param = m_symtab->lookup(name.c_str());
+
+ size_t arg_size = p.get_size() / 8; // size of param in bytes
+ total_size = (total_size + arg_size - 1) / arg_size * arg_size; //aligned
+ p.add_offset(total_size);
+ param->set_address(param_address + total_size);
+ total_size += arg_size;
+ }
+
+ m_args_aligned_size = (total_size + 3) / 4 * 4; //final size aligned to word
+
+ return m_args_aligned_size;
+
+}
+
+
+void function_info::finalize( memory_space *param_mem )
+{
+ unsigned param_address = 0;
+ for( std::map<unsigned,param_info>::iterator i=m_ptx_kernel_param_info.begin(); i!=m_ptx_kernel_param_info.end(); i++ ) {
+ param_info &p = i->second;
+ if (p.is_ptr_shared()) continue; // Pointer to local memory: Should we pass the allocated shared memory address to the param memory space?
+ std::string name = p.get_name();
+ int type = p.get_type();
+ param_t param_value = p.get_value();
+ param_value.type = type;
+ symbol *param = m_symtab->lookup(name.c_str());
+ unsigned xtype = param->type()->get_key().scalar_type();
+ assert(xtype==(unsigned)type);
+ size_t size;
+ size = param_value.size; // size of param in bytes
+ // assert(param_value.offset == param_address);
+ if( size != p.get_size() / 8) {
+ printf("GPGPU-Sim PTX: WARNING actual kernel paramter size = %zu bytes vs. formal size = %zu (using smaller of two)\n",
+ size, p.get_size()/8);
+ size = (size<(p.get_size()/8))?size:(p.get_size()/8);
+ }
+ // copy the parameter over word-by-word so that parameter that crosses a memory page can be copied over
+ //Jin: copy parameter using aligned rules
+ const size_t word_size = 4;
+ param_address = (param_address + size - 1) / size * size; //aligned with size
+ for (size_t idx = 0; idx < size; idx += word_size) {
+ const char *pdata = reinterpret_cast<const char*>(param_value.pdata) + idx; // cast to char * for ptr arithmetic
+ param_mem->write(param_address + idx, word_size, pdata,NULL,NULL);
+ }
+ unsigned offset = p.get_offset();
+ assert(offset == param_address);
+ param->set_address(param_address);
+ param_address += size;
+ }
+}
+
+void function_info::param_to_shared( memory_space *shared_mem, symbol_table *symtab )
+{
+ // TODO: call this only for PTXPlus with GT200 models
+ extern gpgpu_sim* g_the_gpu;
+ if (not g_the_gpu->get_config().convert_to_ptxplus()) return;
+
+ // copies parameters into simulated shared memory
+ for( std::map<unsigned,param_info>::iterator i=m_ptx_kernel_param_info.begin(); i!=m_ptx_kernel_param_info.end(); i++ ) {
+ param_info &p = i->second;
+ if (p.is_ptr_shared()) continue; // Pointer to local memory: Should we pass the allocated shared memory address to the param memory space?
+ std::string name = p.get_name();
+ int type = p.get_type();
+ param_t value = p.get_value();
+ value.type = type;
+ symbol *param = symtab->lookup(name.c_str());
+ unsigned xtype = param->type()->get_key().scalar_type();
+ assert(xtype==(unsigned)type);
+
+ int tmp;
+ size_t size;
+ unsigned offset = p.get_offset();
+ type_info_key::type_decode(xtype,size,tmp);
+
+ // Write to shared memory - offset + 0x10
+ shared_mem->write(offset+0x10,size/8,value.pdata,NULL,NULL);
+ }
+}
+
+
+void function_info::list_param( FILE *fout ) const
+{
+ for( std::map<unsigned,param_info>::const_iterator i=m_ptx_kernel_param_info.begin(); i!=m_ptx_kernel_param_info.end(); i++ ) {
+ const param_info &p = i->second;
+ std::string name = p.get_name();
+ symbol *param = m_symtab->lookup(name.c_str());
+ addr_t param_addr = param->get_address();
+ fprintf(fout, "%s: %#08x\n", name.c_str(), param_addr);
+ }
+ fflush(fout);
+}
+
+template<int activate_level>
+bool ptx_debug_exec_dump_cond(int thd_uid, addr_t pc)
+{
+ if (g_debug_execution >= activate_level) {
+ // check each type of debug dump constraint to filter out dumps
+ if ( (g_debug_thread_uid != 0) && (thd_uid != (unsigned)g_debug_thread_uid) ) {
+ return false;
+ }
+ if ( (g_debug_pc != 0xBEEF1518) && (pc != g_debug_pc) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void init_inst_classification_stat()
+{
+ static std::set<unsigned> init;
+ if( init.find(g_ptx_kernel_count) != init.end() )
+ return;
+ init.insert(g_ptx_kernel_count);
+
+ #define MAX_CLASS_KER 1024
+ char kernelname[MAX_CLASS_KER] ="";
+ if (!g_inst_classification_stat) g_inst_classification_stat = (void**)calloc(MAX_CLASS_KER, sizeof(void*));
+ snprintf(kernelname, MAX_CLASS_KER, "Kernel %d Classification\n",g_ptx_kernel_count );
+ assert( g_ptx_kernel_count < MAX_CLASS_KER ) ; // a static limit on number of kernels increase it if it fails!
+ g_inst_classification_stat[g_ptx_kernel_count] = StatCreate(kernelname,1,20);
+ if (!g_inst_op_classification_stat) g_inst_op_classification_stat = (void**)calloc(MAX_CLASS_KER, sizeof(void*));
+ snprintf(kernelname, MAX_CLASS_KER, "Kernel %d OP Classification\n",g_ptx_kernel_count );
+ g_inst_op_classification_stat[g_ptx_kernel_count] = StatCreate(kernelname,1,100);
+}
+
+static unsigned get_tex_datasize( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &src1 = pI->src1(); //the name of the texture
+ std::string texname = src1.name();
+
+ gpgpu_t *gpu = thread->get_gpu();
+ const struct textureReference* texref = gpu->get_texref(texname);
+ const struct textureInfo* texInfo = gpu->get_texinfo(texref);
+
+ unsigned data_size = texInfo->texel_size;
+ return data_size;
+}
+
+void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id)
+{
+
+ bool skip = false;
+ int op_classification = 0;
+ addr_t pc = next_instr();
+ assert( pc == inst.pc ); // make sure timing model and functional model are in sync
+ const ptx_instruction *pI = m_func_info->get_instruction(pc);
+ set_npc( pc + pI->inst_size() );
+
+
+ try {
+
+ clearRPC();
+ m_last_set_operand_value.u64 = 0;
+
+ if(is_done())
+ {
+ printf("attempted to execute instruction on a thread that is already done.\n");
+ assert(0);
+ }
+
+ if ( g_debug_execution >= 6 || m_gpu->get_config().get_ptx_inst_debug_to_file()) {
+ if ( (g_debug_thread_uid==0) || (get_uid() == (unsigned)g_debug_thread_uid) ) {
+
+ clear_modifiedregs();
+ enable_debug_trace();
+ }
+ }
+
+
+ if( pI->has_pred() ) {
+ const operand_info &pred = pI->get_pred();
+ ptx_reg_t pred_value = get_operand_value(pred, pred, PRED_TYPE, this, 0);
+ if(pI->get_pred_mod() == -1) {
+ skip = (pred_value.pred & 0x0001) ^ pI->get_pred_neg(); //ptxplus inverts the zero flag
+ } else {
+ skip = !pred_lookup(pI->get_pred_mod(), pred_value.pred & 0x000F);
+ }
+ }
+
+ if( skip ) {
+ inst.set_not_active(lane_id);
+ } else {
+ const ptx_instruction *pI_saved = pI;
+ ptx_instruction *pJ = NULL;
+ if( pI->get_opcode() == VOTE_OP ) {
+ pJ = new ptx_instruction(*pI);
+ *((warp_inst_t*)pJ) = inst; // copy active mask information
+ pI = pJ;
+ }
+ switch ( pI->get_opcode() ) {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,this); op_classification = CLASSIFICATION; break;
+#define OP_W_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,get_core(),inst); op_classification = CLASSIFICATION; break;
+#include "opcodes.def"
+#undef OP_DEF
+#undef OP_W_DEF
+ default: printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); break;
+ }
+ delete pJ;
+ pI = pI_saved;
+
+ // Run exit instruction if exit option included
+ if(pI->is_exit())
+ exit_impl(pI,this);
+ }
+
+
+
+ const gpgpu_functional_sim_config &config = m_gpu->get_config();
+
+ // Output instruction information to file and stdout
+ if( config.get_ptx_inst_debug_to_file() != 0 &&
+ (config.get_ptx_inst_debug_thread_uid() == 0 || config.get_ptx_inst_debug_thread_uid() == get_uid()) ) {
+ fprintf(m_gpu->get_ptx_inst_debug_file(),
+ "[thd=%u] : (%s:%u - %s)\n",
+ get_uid(),
+ pI->source_file(), pI->source_line(), pI->get_source() );
+ //fprintf(ptx_inst_debug_file, "has memory read=%d, has memory write=%d\n", pI->has_memory_read(), pI->has_memory_write());
+ fflush(m_gpu->get_ptx_inst_debug_file());
+ }
+
+ if ( ptx_debug_exec_dump_cond<5>(get_uid(), pc) ) {
+ dim3 ctaid = get_ctaid();
+ dim3 tid = get_tid();
+ printf("%u [thd=%u][i=%u] : ctaid=(%u,%u,%u) tid=(%u,%u,%u) icount=%u [pc=%u] (%s:%u - %s) [0x%llx]\n",
+ g_ptx_sim_num_insn,
+ get_uid(),
+ pI->uid(), ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z,
+ get_icount(),
+ pc, pI->source_file(), pI->source_line(), pI->get_source(),
+ m_last_set_operand_value.u64 );
+ fflush(stdout);
+ }
+
+ addr_t insn_memaddr = 0xFEEBDAED;
+ memory_space_t insn_space = undefined_space;
+ _memory_op_t insn_memory_op = no_memory_op;
+ unsigned insn_data_size = 0;
+ if ( (pI->has_memory_read() || pI->has_memory_write()) ) {
+ insn_memaddr = last_eaddr();
+ insn_space = last_space();
+ unsigned to_type = pI->get_type();
+ insn_data_size = datatype2size(to_type);
+ insn_memory_op = pI->has_memory_read() ? memory_load : memory_store;
+ }
+
+ if ( pI->get_opcode() == BAR_OP && pI->barrier_op() == RED_OPTION) {
+ inst.add_callback( lane_id, last_callback().function, last_callback().instruction, this,false /*not atomic*/);
+ }
+
+ if ( pI->get_opcode() == ATOM_OP ) {
+ insn_memaddr = last_eaddr();
+ insn_space = last_space();
+ inst.add_callback( lane_id, last_callback().function, last_callback().instruction, this,true /*atomic*/);
+ unsigned to_type = pI->get_type();
+ insn_data_size = datatype2size(to_type);
+ }
+
+ if (pI->get_opcode() == TEX_OP) {
+ inst.set_addr(lane_id, last_eaddr() );
+ assert( inst.space == last_space() );
+ insn_data_size = get_tex_datasize(pI, this); // texture obtain its data granularity from the texture info
+ }
+
+ // Output register information to file and stdout
+ if( config.get_ptx_inst_debug_to_file()!=0 &&
+ (config.get_ptx_inst_debug_thread_uid()==0||config.get_ptx_inst_debug_thread_uid()==get_uid()) ) {
+ dump_modifiedregs(m_gpu->get_ptx_inst_debug_file());
+ dump_regs(m_gpu->get_ptx_inst_debug_file());
+ }
+
+ if ( g_debug_execution >= 6 ) {
+ if ( ptx_debug_exec_dump_cond<6>(get_uid(), pc) )
+ dump_modifiedregs(stdout);
+ }
+ if ( g_debug_execution >= 10 ) {
+ if ( ptx_debug_exec_dump_cond<10>(get_uid(), pc) )
+ dump_regs(stdout);
+ }
+ update_pc();
+ g_ptx_sim_num_insn++;
+
+ //not using it with functional simulation mode
+ if(!(this->m_functionalSimulationMode))
+ ptx_file_line_stats_add_exec_count(pI);
+
+ if ( gpgpu_ptx_instruction_classification ) {
+ init_inst_classification_stat();
+ unsigned space_type=0;
+ switch ( pI->get_space().get_type() ) {
+ case global_space: space_type = 10; break;
+ case local_space: space_type = 11; break;
+ case tex_space: space_type = 12; break;
+ case surf_space: space_type = 13; break;
+ case param_space_kernel:
+ case param_space_local:
+ space_type = 14; break;
+ case shared_space: space_type = 15; break;
+ case const_space: space_type = 16; break;
+ default:
+ space_type = 0 ;
+ break;
+ }
+ StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], op_classification);
+ if (space_type) StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], ( int )space_type);
+ StatAddSample( g_inst_op_classification_stat[g_ptx_kernel_count], (int) pI->get_opcode() );
+ }
+ if ( (g_ptx_sim_num_insn % 100000) == 0 ) {
+ dim3 ctaid = get_ctaid();
+ dim3 tid = get_tid();
+ printf("GPGPU-Sim PTX: %u instructions simulated : ctaid=(%u,%u,%u) tid=(%u,%u,%u)\n",
+ g_ptx_sim_num_insn, ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z );
+ fflush(stdout);
+ }
+
+ // "Return values"
+ if(!skip) {
+ inst.space = insn_space;
+ inst.set_addr(lane_id, insn_memaddr);
+ inst.data_size = insn_data_size; // simpleAtomicIntrinsics
+ assert( inst.memory_op == insn_memory_op );
+ }
+
+ } catch ( int x ) {
+ printf("GPGPU-Sim PTX: ERROR (%d) executing intruction (%s:%u)\n", x, pI->source_file(), pI->source_line() );
+ printf("GPGPU-Sim PTX: '%s'\n", pI->get_source() );
+ abort();
+ }
+
+}
+
+void set_param_gpgpu_num_shaders(int num_shaders)
+{
+ gpgpu_param_num_shaders = num_shaders;
+}
+
+const struct gpgpu_ptx_sim_info* ptx_sim_kernel_info(const function_info *kernel)
+{
+ return kernel->get_kernel_info();
+}
+
+const warp_inst_t *ptx_fetch_inst( address_type pc )
+{
+ return function_info::pc_to_instruction(pc);
+}
+
+unsigned ptx_sim_init_thread( kernel_info_t &kernel,
+ ptx_thread_info** thread_info,
+ int sid,
+ unsigned tid,
+ unsigned threads_left,
+ unsigned num_threads,
+ core_t *core,
+ unsigned hw_cta_id,
+ unsigned hw_warp_id,
+ gpgpu_t *gpu,
+ bool isInFunctionalSimulationMode)
+{
+ std::list<ptx_thread_info *> &active_threads = kernel.active_threads();
+
+ static std::map<unsigned,memory_space*> shared_memory_lookup;
+ static std::map<unsigned,ptx_cta_info*> ptx_cta_lookup;
+ static std::map<unsigned,ptx_warp_info*> ptx_warp_lookup;
+ static std::map<unsigned,std::map<unsigned,memory_space*> > local_memory_lookup;
+
+ if ( *thread_info != NULL ) {
+ ptx_thread_info *thd = *thread_info;
+ assert( thd->is_done() );
+ if ( g_debug_execution==-1 ) {
+ dim3 ctaid = thd->get_ctaid();
+ dim3 t = thd->get_tid();
+ printf("GPGPU-Sim PTX simulator: thread exiting ctaid=(%u,%u,%u) tid=(%u,%u,%u) uid=%u\n",
+ ctaid.x,ctaid.y,ctaid.z,t.x,t.y,t.z, thd->get_uid() );
+ fflush(stdout);
+ }
+ thd->m_cta_info->register_deleted_thread(thd);
+ delete thd;
+ *thread_info = NULL;
+ }
+
+ if ( !active_threads.empty() ) {
+ assert( active_threads.size() <= threads_left );
+ ptx_thread_info *thd = active_threads.front();
+ active_threads.pop_front();
+ *thread_info = thd;
+ thd->init(gpu, core, sid, hw_cta_id, hw_warp_id, tid, isInFunctionalSimulationMode );
+ return 1;
+ }
+
+ if ( kernel.no_more_ctas_to_run() ) {
+ return 0; //finished!
+ }
+
+ if ( threads_left < kernel.threads_per_cta() ) {
+ return 0;
+ }
+
+ if ( g_debug_execution==-1 ) {
+ printf("GPGPU-Sim PTX simulator: STARTING THREAD ALLOCATION --> \n");
+ fflush(stdout);
+ }
+
+ //initializing new CTA
+ ptx_cta_info *cta_info = NULL;
+ memory_space *shared_mem = NULL;
+
+ unsigned cta_size = kernel.threads_per_cta();
+ unsigned max_cta_per_sm = num_threads/cta_size; // e.g., 256 / 48 = 5
+ assert( max_cta_per_sm > 0 );
+
+ //unsigned sm_idx = (tid/cta_size)*gpgpu_param_num_shaders + sid;
+ unsigned sm_idx = hw_cta_id*gpgpu_param_num_shaders + sid;
+
+ if ( shared_memory_lookup.find(sm_idx) == shared_memory_lookup.end() ) {
+ if ( g_debug_execution >= 1 ) {
+ printf(" <CTA alloc> : sm_idx=%u sid=%u max_cta_per_sm=%u\n",
+ sm_idx, sid, max_cta_per_sm );
+ }
+ char buf[512];
+ snprintf(buf,512,"shared_%u", sid);
+ shared_mem = new memory_space_impl<16*1024>(buf,4);
+ shared_memory_lookup[sm_idx] = shared_mem;
+ cta_info = new ptx_cta_info(sm_idx);
+ ptx_cta_lookup[sm_idx] = cta_info;
+ } else {
+ if ( g_debug_execution >= 1 ) {
+ printf(" <CTA realloc> : sm_idx=%u sid=%u max_cta_per_sm=%u\n",
+ sm_idx, sid, max_cta_per_sm );
+ }
+ shared_mem = shared_memory_lookup[sm_idx];
+ cta_info = ptx_cta_lookup[sm_idx];
+ cta_info->check_cta_thread_status_and_reset();
+ }
+
+ std::map<unsigned,memory_space*> &local_mem_lookup = local_memory_lookup[sid];
+ while( kernel.more_threads_in_cta() ) {
+ dim3 ctaid3d = kernel.get_next_cta_id();
+ unsigned new_tid = kernel.get_next_thread_id();
+ dim3 tid3d = kernel.get_next_thread_id_3d();
+ kernel.increment_thread_id();
+ new_tid += tid;
+ ptx_thread_info *thd = new ptx_thread_info(kernel);
+
+ ptx_warp_info *warp_info = NULL;
+ if ( ptx_warp_lookup.find(hw_warp_id) == ptx_warp_lookup.end() ) {
+ warp_info = new ptx_warp_info();
+ ptx_warp_lookup[hw_warp_id] = warp_info;
+ } else {
+ warp_info = ptx_warp_lookup[hw_warp_id];
+ }
+ thd->m_warp_info = warp_info;
+
+ memory_space *local_mem = NULL;
+ std::map<unsigned,memory_space*>::iterator l = local_mem_lookup.find(new_tid);
+ if ( l != local_mem_lookup.end() ) {
+ local_mem = l->second;
+ } else {
+ char buf[512];
+ snprintf(buf,512,"local_%u_%u", sid, new_tid);
+ local_mem = new memory_space_impl<32>(buf,32);
+ local_mem_lookup[new_tid] = local_mem;
+ }
+ thd->set_info(kernel.entry());
+ thd->set_nctaid(kernel.get_grid_dim());
+ thd->set_ntid(kernel.get_cta_dim());
+ thd->set_ctaid(ctaid3d);
+ thd->set_tid(tid3d);
+ if( kernel.entry()->get_ptx_version().extensions() )
+ thd->cpy_tid_to_reg(tid3d);
+ thd->set_valid();
+ thd->m_shared_mem = shared_mem;
+ function_info *finfo = thd->func_info();
+ symbol_table *st = finfo->get_symtab();
+ thd->func_info()->param_to_shared(thd->m_shared_mem,st);
+ thd->m_cta_info = cta_info;
+ cta_info->add_thread(thd);
+ thd->m_local_mem = local_mem;
+ if ( g_debug_execution==-1 ) {
+ printf("GPGPU-Sim PTX simulator: allocating thread ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n",
+ ctaid3d.x,ctaid3d.y,ctaid3d.z,tid3d.x,tid3d.y,tid3d.z, (unsigned long long)thd );
+ fflush(stdout);
+ }
+ active_threads.push_back(thd);
+ }
+ if ( g_debug_execution==-1 ) {
+ printf("GPGPU-Sim PTX simulator: <-- FINISHING THREAD ALLOCATION\n");
+ fflush(stdout);
+ }
+
+ kernel.increment_cta_id();
+
+ assert( active_threads.size() <= threads_left );
+ *thread_info = active_threads.front();
+ (*thread_info)->init(gpu, core, sid, hw_cta_id, hw_warp_id, tid,isInFunctionalSimulationMode );
+ active_threads.pop_front();
+ return 1;
+}
+
+size_t get_kernel_code_size( class function_info *entry )
+{
+ return entry->get_function_size();
+}
+
+
+kernel_info_t *gpgpu_opencl_ptx_sim_init_grid(class function_info *entry,
+ gpgpu_ptx_sim_arg_list_t args,
+ struct dim3 gridDim,
+ struct dim3 blockDim,
+ gpgpu_t *gpu )
+{
+ kernel_info_t *result = new kernel_info_t(gridDim,blockDim,entry);
+ unsigned argcount=args.size();
+ unsigned argn=1;
+ for( gpgpu_ptx_sim_arg_list_t::iterator a = args.begin(); a != args.end(); a++ ) {
+ entry->add_param_data(argcount-argn,&(*a));
+ argn++;
+ }
+ entry->finalize(result->get_param_memory());
+ g_ptx_kernel_count++;
+ fflush(stdout);
+
+ return result;
+}
+
+#include "../../version"
+#include "detailed_version"
+
+void print_splash()
+{
+ static int splash_printed=0;
+ if ( !splash_printed ) {
+ fprintf(stdout, "\n\n *** %s [build %s] ***\n\n\n", g_gpgpusim_version_string, g_gpgpusim_build_string );
+ splash_printed=1;
+ }
+}
+
+std::map<const void*,std::string> g_const_name_lookup; // indexed by hostVar
+std::map<const void*,std::string> g_global_name_lookup; // indexed by hostVar
+std::set<std::string> g_globals;
+std::set<std::string> g_constants;
+
+void gpgpu_ptx_sim_register_const_variable(void *hostVar, const char *deviceName, size_t size )
+{
+ printf("GPGPU-Sim PTX registering constant %s (%zu bytes) to name mapping\n", deviceName, size );
+ g_const_name_lookup[hostVar] = deviceName;
+}
+
+void gpgpu_ptx_sim_register_global_variable(void *hostVar, const char *deviceName, size_t size )
+{
+ printf("GPGPU-Sim PTX registering global %s hostVar to name mapping\n", deviceName );
+ g_global_name_lookup[hostVar] = deviceName;
+}
+
+void gpgpu_ptx_sim_memcpy_symbol(const char *hostVar, const void *src, size_t count, size_t offset, int to, gpgpu_t *gpu )
+{
+ printf("GPGPU-Sim PTX: starting gpgpu_ptx_sim_memcpy_symbol with hostVar 0x%p\n", hostVar);
+ bool found_sym = false;
+ memory_space_t mem_region = undefined_space;
+ std::string sym_name;
+
+ std::map<const void*,std::string>::iterator c=g_const_name_lookup.find(hostVar);
+ if ( c!=g_const_name_lookup.end() ) {
+ found_sym = true;
+ sym_name = c->second;
+ mem_region = const_space;
+ }
+ std::map<const void*,std::string>::iterator g=g_global_name_lookup.find(hostVar);
+ if ( g!=g_global_name_lookup.end() ) {
+ if ( found_sym ) {
+ printf("Execution error: PTX symbol \"%s\" w/ hostVar=0x%Lx is declared both const and global?\n",
+ sym_name.c_str(), (unsigned long long)hostVar );
+ abort();
+ }
+ found_sym = true;
+ sym_name = g->second;
+ mem_region = global_space;
+ }
+ if( g_globals.find(hostVar) != g_globals.end() ) {
+ found_sym = true;
+ sym_name = hostVar;
+ mem_region = global_space;
+ }
+ if( g_constants.find(hostVar) != g_constants.end() ) {
+ found_sym = true;
+ sym_name = hostVar;
+ mem_region = const_space;
+ }
+
+ if ( !found_sym ) {
+ printf("Execution error: No information for PTX symbol w/ hostVar=0x%Lx\n", (unsigned long long)hostVar );
+ abort();
+ } else printf("GPGPU-Sim PTX: gpgpu_ptx_sim_memcpy_symbol: Found PTX symbol w/ hostVar=0x%Lx\n", (unsigned long long)hostVar );
+ const char *mem_name = NULL;
+ memory_space *mem = NULL;
+
+ std::map<std::string,symbol_table*>::iterator st = g_sym_name_to_symbol_table.find(sym_name.c_str());
+ assert( st != g_sym_name_to_symbol_table.end() );
+ symbol_table *symtab = st->second;
+
+ symbol *sym = symtab->lookup(sym_name.c_str());
+ assert(sym);
+ unsigned dst = sym->get_address() + offset;
+ switch (mem_region.get_type()) {
+ case const_space:
+ mem = gpu->get_global_memory();
+ mem_name = "const";
+ break;
+ case global_space:
+ mem = gpu->get_global_memory();
+ mem_name = "global";
+ break;
+ default:
+ abort();
+ }
+ printf("GPGPU-Sim PTX: gpgpu_ptx_sim_memcpy_symbol: copying %s memory %zu bytes %s symbol %s+%zu @0x%x ...\n",
+ mem_name, count, (to?" to ":"from"), sym_name.c_str(), offset, dst );
+ for ( unsigned n=0; n < count; n++ ) {
+ if( to ) mem->write(dst+n,1,((char*)src)+n,NULL,NULL);
+ else mem->read(dst+n,1,((char*)src)+n);
+ }
+ fflush(stdout);
+}
+
+int g_ptx_sim_mode; // if non-zero run functional simulation only (i.e., no notion of a clock cycle)
+
+extern int ptx_debug;
+
+bool g_cuda_launch_blocking = false;
+
+void read_sim_environment_variables()
+{
+ ptx_debug = 0;
+ g_debug_execution = 0;
+ g_interactive_debugger_enabled = false;
+
+ char *mode = getenv("PTX_SIM_MODE_FUNC");
+ if ( mode )
+ sscanf(mode,"%u", &g_ptx_sim_mode);
+ printf("GPGPU-Sim PTX: simulation mode %d (can change with PTX_SIM_MODE_FUNC environment variable:\n", g_ptx_sim_mode);
+ printf(" 1=functional simulation only, 0=detailed performance simulator)\n");
+ char *dbg_inter = getenv("GPGPUSIM_DEBUG");
+ if ( dbg_inter && strlen(dbg_inter) ) {
+ printf("GPGPU-Sim PTX: enabling interactive debugger\n");
+ fflush(stdout);
+ g_interactive_debugger_enabled = true;
+ }
+ char *dbg_level = getenv("PTX_SIM_DEBUG");
+ if ( dbg_level && strlen(dbg_level) ) {
+ printf("GPGPU-Sim PTX: setting debug level to %s\n", dbg_level );
+ fflush(stdout);
+ sscanf(dbg_level,"%d", &g_debug_execution);
+ }
+ char *dbg_thread = getenv("PTX_SIM_DEBUG_THREAD_UID");
+ if ( dbg_thread && strlen(dbg_thread) ) {
+ printf("GPGPU-Sim PTX: printing debug information for thread uid %s\n", dbg_thread );
+ fflush(stdout);
+ sscanf(dbg_thread,"%d", &g_debug_thread_uid);
+ }
+ char *dbg_pc = getenv("PTX_SIM_DEBUG_PC");
+ if ( dbg_pc && strlen(dbg_pc) ) {
+ printf("GPGPU-Sim PTX: printing debug information for instruction with PC = %s\n", dbg_pc );
+ fflush(stdout);
+ sscanf(dbg_pc,"%d", &g_debug_pc);
+ }
+
+#if CUDART_VERSION > 1010
+ g_override_embedded_ptx = false;
+ char *usefile = getenv("PTX_SIM_USE_PTX_FILE");
+ if (usefile && strlen(usefile)) {
+ printf("GPGPU-Sim PTX: overriding embedded ptx with ptx file (PTX_SIM_USE_PTX_FILE is set)\n");
+ fflush(stdout);
+ g_override_embedded_ptx = true;
+ }
+ char *blocking = getenv("CUDA_LAUNCH_BLOCKING");
+ if( blocking && !strcmp(blocking,"1") ) {
+ g_cuda_launch_blocking = true;
+ }
+#else
+ g_cuda_launch_blocking = true;
+ g_override_embedded_ptx = true;
+#endif
+
+ if ( g_debug_execution >= 40 ) {
+ ptx_debug = 1;
+ }
+}
+
+ptx_cta_info *g_func_cta_info = NULL;
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+/*!
+This function simulates the CUDA code functionally, it takes a kernel_info_t parameter
+which holds the data for the CUDA kernel to be executed
+!*/
+void gpgpu_cuda_ptx_sim_main_func( kernel_info_t &kernel, bool openCL )
+{
+ printf("GPGPU-Sim: Performing Functional Simulation, executing kernel %s...\n",kernel.name().c_str());
+
+ //using a shader core object for book keeping, it is not needed but as most function built for performance simulation need it we use it here
+ extern gpgpu_sim *g_the_gpu;
+ //before we execute, we should do PDOM analysis for functional simulation scenario.
+ function_info *kernel_func_info = kernel.entry();
+ if (kernel_func_info->is_pdom_set()) {
+ printf("GPGPU-Sim PTX: PDOM analysis already done for %s \n", kernel.name().c_str() );
+ } else {
+ printf("GPGPU-Sim PTX: finding reconvergence points for \'%s\'...\n", kernel.name().c_str() );
+ //kernel_func_info->do_pdom();
+ kernel_func_info->set_pdom();
+ }
+
+ //we excute the kernel one CTA (Block) at the time, as synchronization functions work block wise
+ while(!kernel.no_more_ctas_to_run()){
+ functionalCoreSim cta(
+ &kernel,
+ g_the_gpu,
+ g_the_gpu->getShaderCoreConfig()->warp_size
+ );
+ cta.execute();
+
+#if (CUDART_VERSION >= 5000)
+ launch_all_device_kernels();
+#endif
+ }
+
+ //registering this kernel as done
+
+ //openCL kernel simulation calls don't register the kernel so we don't register its exit
+ if(!openCL) {
+ extern stream_manager *g_stream_manager;
+ g_stream_manager->register_finished_kernel(kernel.get_uid());
+ }
+
+ //******PRINTING*******
+ printf( "GPGPU-Sim: Done functional simulation (%u instructions simulated).\n", g_ptx_sim_num_insn );
+ if ( gpgpu_ptx_instruction_classification ) {
+ StatDisp( g_inst_classification_stat[g_ptx_kernel_count]);
+ StatDisp ( g_inst_op_classification_stat[g_ptx_kernel_count]);
+ }
+
+ //time_t variables used to calculate the total simulation time
+ //the start time of simulation is hold by the global variable g_simulation_starttime
+ //g_simulation_starttime is initilized by gpgpu_ptx_sim_init_perf() in gpgpusim_entrypoint.cc upon starting gpgpu-sim
+ time_t end_time, elapsed_time, days, hrs, minutes, sec;
+ end_time = time((time_t *)NULL);
+ elapsed_time = MAX(end_time - g_simulation_starttime, 1);
+
+
+ //calculating and printing simulation time in terms of days, hours, minutes and seconds
+ days = elapsed_time/(3600*24);
+ hrs = elapsed_time/3600 - 24*days;
+ minutes = elapsed_time/60 - 60*(hrs + 24*days);
+ sec = elapsed_time - 60*(minutes + 60*(hrs + 24*days));
+
+ fflush(stderr);
+ printf("\n\ngpgpu_simulation_time = %u days, %u hrs, %u min, %u sec (%u sec)\n",
+ (unsigned)days, (unsigned)hrs, (unsigned)minutes, (unsigned)sec, (unsigned)elapsed_time );
+ printf("gpgpu_simulation_rate = %u (inst/sec)\n", (unsigned)(g_ptx_sim_num_insn / elapsed_time) );
+ fflush(stdout);
+}
+
+void functionalCoreSim::initializeCTA()
+{
+ int ctaLiveThreads=0;
+
+ for(int i=0; i< m_warp_count; i++){
+ m_warpAtBarrier[i]=false;
+ m_liveThreadCount[i]=0;
+ }
+ for(int i=0; i< m_warp_count*m_warp_size;i++)
+ m_thread[i]=NULL;
+
+ //get threads for a cta
+ for(unsigned i=0; i<m_kernel->threads_per_cta();i++) {
+ ptx_sim_init_thread(*m_kernel,&m_thread[i],0,i,m_kernel->threads_per_cta()-i,m_kernel->threads_per_cta(),this,0,i/m_warp_size,(gpgpu_t*)m_gpu, true);
+ assert(m_thread[i]!=NULL && !m_thread[i]->is_done());
+ ctaLiveThreads++;
+ }
+
+ for(int k=0;k<m_warp_count;k++)
+ createWarp(k);
+}
+
+void functionalCoreSim::createWarp(unsigned warpId)
+{
+ simt_mask_t initialMask;
+ unsigned liveThreadsCount=0;
+ initialMask.set();
+ for(int i=warpId*m_warp_size; i<warpId*m_warp_size+m_warp_size;i++){
+ if(m_thread[i]==NULL) initialMask.reset(i-warpId*m_warp_size);
+ else liveThreadsCount++;
+ }
+
+ assert(m_thread[warpId*m_warp_size]!=NULL);
+ m_simt_stack[warpId]->launch(m_thread[warpId*m_warp_size]->get_pc(),initialMask);
+ m_liveThreadCount[warpId]= liveThreadsCount;
+}
+
+void functionalCoreSim::execute()
+ {
+ initializeCTA();
+
+ //start executing the CTA
+ while(true){
+ bool someOneLive= false;
+ bool allAtBarrier = true;
+ for(unsigned i=0;i<m_warp_count;i++){
+ executeWarp(i,allAtBarrier,someOneLive);
+ }
+ if(!someOneLive) break;
+ if(allAtBarrier){
+ for(unsigned i=0;i<m_warp_count;i++)
+ m_warpAtBarrier[i]=false;
+ }
+ }
+ }
+
+void functionalCoreSim::executeWarp(unsigned i, bool &allAtBarrier, bool & someOneLive)
+{
+ if(!m_warpAtBarrier[i] && m_liveThreadCount[i]!=0){
+ warp_inst_t inst =getExecuteWarp(i);
+ execute_warp_inst_t(inst,i);
+ if(inst.isatomic()) inst.do_atomic(true);
+ if(inst.op==BARRIER_OP || inst.op==MEMORY_BARRIER_OP ) m_warpAtBarrier[i]=true;
+ updateSIMTStack( i, &inst );
+ }
+ if(m_liveThreadCount[i]>0) someOneLive=true;
+ if(!m_warpAtBarrier[i]&& m_liveThreadCount[i]>0) allAtBarrier = false;
+}
+
+unsigned translate_pc_to_ptxlineno(unsigned pc)
+{
+ // this function assumes that the kernel fits inside a single PTX file
+ // function_info *pFunc = g_func_info; // assume that the current kernel is the one in query
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+ unsigned ptx_line_number = pInsn->source_line();
+
+ return ptx_line_number;
+}
+
+// ptxinfo parser
+
+extern std::map<unsigned,const char*> get_duplicate();
+
+int g_ptxinfo_error_detected;
+
+static char *g_ptxinfo_kname = NULL;
+static struct gpgpu_ptx_sim_info g_ptxinfo;
+static std::map<unsigned,const char*> g_duplicate;
+static const char *g_last_dup_type;
+
+const char *get_ptxinfo_kname()
+{
+ return g_ptxinfo_kname;
+}
+
+void print_ptxinfo()
+{
+ if(! get_ptxinfo_kname()){
+ printf ("GPGPU-Sim PTX: Binary info : gmem=%u, cmem=%u\n",
+ g_ptxinfo.gmem,
+ g_ptxinfo.cmem);
+ }
+ if(get_ptxinfo_kname()){
+ printf ("GPGPU-Sim PTX: Kernel \'%s\' : regs=%u, lmem=%u, smem=%u, cmem=%u\n",
+ get_ptxinfo_kname(),
+ g_ptxinfo.regs,
+ g_ptxinfo.lmem,
+ g_ptxinfo.smem,
+ g_ptxinfo.cmem );
+ }
+}
+
+
+struct gpgpu_ptx_sim_info get_ptxinfo()
+{
+ return g_ptxinfo;
+}
+
+std::map<unsigned,const char*> get_duplicate()
+{
+ return g_duplicate;
+}
+
+void ptxinfo_linenum( unsigned linenum )
+{
+ g_duplicate[linenum] = g_last_dup_type;
+}
+
+void ptxinfo_dup_type( const char *dup_type )
+{
+ g_last_dup_type = dup_type;
+}
+
+void ptxinfo_function(const char *fname )
+{
+ clear_ptxinfo();
+ g_ptxinfo_kname = strdup(fname);
+}
+
+void ptxinfo_regs( unsigned nregs )
+{
+ g_ptxinfo.regs=nregs;
+}
+
+void ptxinfo_lmem( unsigned declared, unsigned system )
+{
+ g_ptxinfo.lmem=declared+system;
+}
+
+void ptxinfo_gmem( unsigned declared, unsigned system )
+{
+ g_ptxinfo.gmem=declared+system;
+}
+
+void ptxinfo_smem( unsigned declared, unsigned system )
+{
+ g_ptxinfo.smem=declared+system;
+}
+
+void ptxinfo_cmem( unsigned nbytes, unsigned bank )
+{
+ g_ptxinfo.cmem+=nbytes;
+}
+
+void clear_ptxinfo()
+{
+ free(g_ptxinfo_kname);
+ g_ptxinfo_kname=NULL;
+ g_ptxinfo.regs=0;
+ g_ptxinfo.lmem=0;
+ g_ptxinfo.smem=0;
+ g_ptxinfo.cmem=0;
+ g_ptxinfo.gmem=0;
+ g_ptxinfo.ptx_version=0;
+ g_ptxinfo.sm_target=0;
+}
+
+
+void ptxinfo_opencl_addinfo( std::map<std::string,function_info*> &kernels )
+{
+
+ if(! g_ptxinfo_kname) {
+ printf ("GPGPU-Sim PTX: Binary info : gmem=%u, cmem=%u\n",
+ g_ptxinfo.gmem,
+ g_ptxinfo.cmem);
+ clear_ptxinfo();
+ return;
+ }
+
+ if( !strcmp("__cuda_dummy_entry__",g_ptxinfo_kname) ) {
+ // this string produced by ptxas for empty ptx files (e.g., bandwidth test)
+ clear_ptxinfo();
+ return;
+ }
+ std::map<std::string,function_info*>::iterator k=kernels.find(g_ptxinfo_kname);
+ if( k==kernels.end() ) {
+ printf ("GPGPU-Sim PTX: ERROR ** implementation for '%s' not found.\n", g_ptxinfo_kname );
+ abort();
+ } else {
+ printf ("GPGPU-Sim PTX: Kernel \'%s\' : regs=%u, lmem=%u, smem=%u, cmem=%u\n",
+ g_ptxinfo_kname,
+ g_ptxinfo.regs,
+ g_ptxinfo.lmem,
+ g_ptxinfo.smem,
+ g_ptxinfo.cmem );
+ function_info *finfo = k->second;
+ assert(finfo!=NULL);
+ finfo->set_kernel_info( g_ptxinfo );
+ }
+ clear_ptxinfo();
+}
+
+struct rec_pts {
+ gpgpu_recon_t *s_kernel_recon_points;
+ int s_num_recon;
+};
+
+struct std::map<function_info*,rec_pts> g_rpts;
+
+struct rec_pts find_reconvergence_points( function_info *finfo )
+{
+ rec_pts tmp;
+ std::map<function_info*,rec_pts>::iterator r=g_rpts.find(finfo);
+
+ if( r==g_rpts.end() ) {
+ int num_recon = finfo->get_num_reconvergence_pairs();
+
+ gpgpu_recon_t *kernel_recon_points = (struct gpgpu_recon_t*) calloc(num_recon, sizeof(struct gpgpu_recon_t));
+ finfo->get_reconvergence_pairs(kernel_recon_points);
+ printf("GPGPU-Sim PTX: reconvergence points for %s...\n", finfo->get_name().c_str() );
+ for (int i=0;i<num_recon;i++) {
+ printf("GPGPU-Sim PTX: %2u (potential) branch divergence @ ", i+1 );
+ kernel_recon_points[i].source_inst->print_insn();
+ printf("\n");
+ printf("GPGPU-Sim PTX: immediate post dominator @ " );
+ if( kernel_recon_points[i].target_inst )
+ kernel_recon_points[i].target_inst->print_insn();
+ printf("\n");
+ }
+ printf("GPGPU-Sim PTX: ... end of reconvergence points for %s\n", finfo->get_name().c_str() );
+
+ tmp.s_kernel_recon_points = kernel_recon_points;
+ tmp.s_num_recon = num_recon;
+ g_rpts[finfo] = tmp;
+ } else {
+ tmp = r->second;
+ }
+ return tmp;
+}
+
+address_type get_return_pc( void *thd )
+{
+ // function call return
+ ptx_thread_info *the_thread = (ptx_thread_info*)thd;
+ assert( the_thread != NULL );
+ return the_thread->get_return_PC();
+}
+
+address_type get_converge_point( address_type pc )
+{
+ // the branch could encode the reconvergence point and/or a bit that indicates the
+ // reconvergence point is the return PC on the call stack in the case the branch has
+ // no immediate postdominator in the function (i.e., due to multiple return points).
+
+ std::map<unsigned,function_info*>::iterator f=g_pc_to_finfo.find(pc);
+ assert( f != g_pc_to_finfo.end() );
+ function_info *finfo = f->second;
+ rec_pts tmp = find_reconvergence_points(finfo);
+
+ int i=0;
+ for (; i < tmp.s_num_recon; ++i) {
+ if (tmp.s_kernel_recon_points[i].source_pc == pc) {
+ if( tmp.s_kernel_recon_points[i].target_pc == (unsigned) -2 ) {
+ return RECONVERGE_RETURN_PC;
+ } else {
+ return tmp.s_kernel_recon_points[i].target_pc;
+ }
+ }
+ }
+ return NO_BRANCH_DIVERGENCE;
+}
+
+void functionalCoreSim::warp_exit( unsigned warp_id )
+{
+ for(int i=0;i<m_warp_count*m_warp_size;i++){
+ if(m_thread[i]!=NULL){
+ m_thread[i]->m_cta_info->register_deleted_thread(m_thread[i]);
+ delete m_thread[i];
+ }
+ }
+}
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
index 5d97287..0025c52 100644
--- a/src/cuda-sim/instructions.cc
+++ b/src/cuda-sim/instructions.cc
@@ -1471,7 +1471,12 @@ void call_impl( const ptx_instruction *pI, ptx_thread_info *thread )
printf("GPGPU-Sim PTX: PDOM analysis already done for %s \n", target_func->get_name().c_str() );
} else {
printf("GPGPU-Sim PTX: finding reconvergence points for \'%s\'...\n", target_func->get_name().c_str() );
- target_func->do_pdom();
+ /*
+ * Some of the instructions like printf() gives the gpgpusim the wrong impression that it is a function call.
+ * As printf() doesnt have a body like functions do, doing pdom analysis for printf() causes a crash.
+ */
+ if (target_func->get_function_size() >0)
+ target_func->do_pdom();
target_func->set_pdom();
}
diff --git a/src/cuda-sim/instructions.cc~ b/src/cuda-sim/instructions.cc~
new file mode 100644
index 0000000..0e6f530
--- /dev/null
+++ b/src/cuda-sim/instructions.cc~
@@ -0,0 +1,4517 @@
+// Copyright (c) 2009-2011, Tor M. Aamodt, Wilson W.L. Fung, Ali Bakhoda,
+// Jimmy Kwa, George L. Yuan
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "instructions.h"
+#include "ptx_ir.h"
+#include "opcodes.h"
+#include "ptx_sim.h"
+#include "ptx.tab.h"
+#include <stdlib.h>
+#include <math.h>
+#include <fenv.h>
+#include "cuda-math.h"
+#include "../abstract_hardware_model.h"
+#include "ptx_loader.h"
+#include "cuda_device_printf.h"
+#include "../gpgpu-sim/gpu-sim.h"
+#include "../gpgpu-sim/shader.h"
+
+//Jin: include device runtime for CDP
+#include "cuda_device_runtime.h"
+
+#include <stdarg.h>
+
+unsigned ptx_instruction::g_num_ptx_inst_uid=0;
+
+const char *g_opcode_string[NUM_OPCODES] = {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) STR,
+#define OP_W_DEF(OP,FUNC,STR,DST,CLASSIFICATION) STR,
+#include "opcodes.def"
+#undef OP_DEF
+#undef OP_W_DEF
+};
+
+void inst_not_implemented( const ptx_instruction * pI ) ;
+ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, operand_info dstInfo, unsigned type, ptx_thread_info *thread);
+
+void sign_extend( ptx_reg_t &data, unsigned src_size, const operand_info &dst );
+
+void ptx_thread_info::set_reg( const symbol *reg, const ptx_reg_t &value )
+{
+ assert( reg != NULL );
+ if( reg->name() == "_" ) return;
+ assert( !m_regs.empty() );
+ assert( reg->uid() > 0 );
+ m_regs.back()[ reg ] = value;
+ if (m_enable_debug_trace )
+ m_debug_trace_regs_modified.back()[ reg ] = value;
+ m_last_set_operand_value = value;
+}
+
+ptx_reg_t ptx_thread_info::get_reg( const symbol *reg )
+{
+ static bool unfound_register_warned = false;
+ assert( reg != NULL );
+ assert( !m_regs.empty() );
+ reg_map_t::iterator regs_iter = m_regs.back().find(reg);
+ if (regs_iter == m_regs.back().end()) {
+ assert( reg->type()->get_key().is_reg() );
+ const std::string &name = reg->name();
+ unsigned call_uid = m_callstack.back().m_call_uid;
+ ptx_reg_t uninit_reg;
+ uninit_reg.u32 = 0x0;
+ set_reg(reg, uninit_reg); // give it a value since we are going to warn the user anyway
+ std::string file_loc = get_location();
+ if( !unfound_register_warned ) {
+ printf("GPGPU-Sim PTX: WARNING (%s) ** reading undefined register \'%s\' (cuid:%u). Setting to 0X00000000. This is okay if you are simulating the native ISA"
+ "\n",
+ file_loc.c_str(), name.c_str(), call_uid );
+ unfound_register_warned = true;
+ }
+ regs_iter = m_regs.back().find(reg);
+ }
+ if (m_enable_debug_trace )
+ m_debug_trace_regs_read.back()[ reg ] = regs_iter->second;
+ return regs_iter->second;
+}
+
+ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_info dstInfo, unsigned opType, ptx_thread_info *thread, int derefFlag )
+{
+ ptx_reg_t result, tmp;
+
+
+ if(op.get_double_operand_type() == 0) {
+ if(((opType != BB128_TYPE) && (opType != BB64_TYPE) && (opType != FF64_TYPE)) || (op.get_addr_space() != undefined_space)) {
+ if ( op.is_reg() ) {
+ result = get_reg( op.get_symbol() );
+ } else if ( op.is_builtin()) {
+ result.u32 = get_builtin( op.get_int(), op.get_addr_offset() );
+ } else if(op.is_immediate_address()){
+ result.u64 = op.get_addr_offset();
+ } else if ( op.is_memory_operand() ) {
+ // a few options here...
+ const symbol *sym = op.get_symbol();
+ const type_info *type = sym->type();
+ const type_info_key &info = type->get_key();
+
+ if ( info.is_reg() ) {
+ const symbol *name = op.get_symbol();
+ result.u64 = get_reg(name).u64 + op.get_addr_offset();
+ } else if ( info.is_param_kernel() ) {
+ result.u64 = sym->get_address() + op.get_addr_offset();
+ } else if ( info.is_param_local() ) {
+ result.u64 = sym->get_address() + op.get_addr_offset();
+ } else if ( info.is_global() ) {
+ assert( op.get_addr_offset() == 0 );
+ result.u64 = sym->get_address();
+ } else if ( info.is_local() ) {
+ result.u64 = sym->get_address() + op.get_addr_offset();
+ } else if ( info.is_const() ) {
+ result.u64 = sym->get_address() + op.get_addr_offset();
+ } else if ( op.is_shared() ) {
+ result.u64 = op.get_symbol()->get_address() + op.get_addr_offset();
+ } else {
+ const char *name = op.name().c_str();
+ printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown memory operand type for %s\n", name );
+ abort();
+ }
+
+ } else if ( op.is_literal() ) {
+ result = op.get_literal_value();
+ } else if ( op.is_label() ) {
+ result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_shared() ) {
+ result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_const() ) {
+ result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_global() ) {
+ result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_local() ) {
+ result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_function_address() ) {
+ result.u64 = (size_t)op.get_symbol()->get_pc();
+ } else {
+ const char *name = op.name().c_str();
+ printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown operand type for %s\n", name );
+ assert(0);
+ }
+
+ if(op.get_operand_lohi() == 1)
+ result.u64 = result.u64 & 0xFFFF;
+ else if(op.get_operand_lohi() == 2)
+ result.u64 = (result.u64>>16) & 0xFFFF;
+ } else if (opType == BB128_TYPE) {
+ // b128
+ result.u128.lowest = get_reg( op.vec_symbol(0) ).u32;
+ result.u128.low = get_reg( op.vec_symbol(1) ).u32;
+ result.u128.high = get_reg( op.vec_symbol(2) ).u32;
+ result.u128.highest = get_reg( op.vec_symbol(3) ).u32;
+ } else {
+ // bb64 or ff64
+ result.bits.ls = get_reg( op.vec_symbol(0) ).u32;
+ result.bits.ms = get_reg( op.vec_symbol(1) ).u32;
+ }
+ } else if (op.get_double_operand_type() == 1) {
+ ptx_reg_t firstHalf, secondHalf;
+ firstHalf.u64 = get_reg( op.vec_symbol(0) ).u64;
+ secondHalf.u64 = get_reg( op.vec_symbol(1) ).u64;
+ if(op.get_operand_lohi() == 1)
+ secondHalf.u64 = secondHalf.u64 & 0xFFFF;
+ else if(op.get_operand_lohi() == 2)
+ secondHalf.u64 = (secondHalf.u64>>16) & 0xFFFF;
+ result.u64 = firstHalf.u64 + secondHalf.u64;
+ } else if (op.get_double_operand_type() == 2) {
+ // s[reg1 += reg2]
+ // reg1 is incremented after value is returned: the value returned is s[reg1]
+ ptx_reg_t firstHalf, secondHalf;
+ firstHalf.u64 = get_reg(op.vec_symbol(0)).u64;
+ secondHalf.u64 = get_reg(op.vec_symbol(1)).u64;
+ if(op.get_operand_lohi() == 1)
+ secondHalf.u64 = secondHalf.u64 & 0xFFFF;
+ else if(op.get_operand_lohi() == 2)
+ secondHalf.u64 = (secondHalf.u64>>16) & 0xFFFF;
+ result.u64 = firstHalf.u64;
+ firstHalf.u64 = firstHalf.u64 + secondHalf.u64;
+ set_reg(op.vec_symbol(0),firstHalf);
+ } else if (op.get_double_operand_type() == 3) {
+ // s[reg += immediate]
+ // reg is incremented after value is returned: the value returned is s[reg]
+ ptx_reg_t firstHalf;
+ firstHalf.u64 = get_reg(op.get_symbol()).u64;
+ result.u64 = firstHalf.u64;
+ firstHalf.u64 = firstHalf.u64 + op.get_addr_offset();
+ set_reg(op.get_symbol(),firstHalf);
+ }
+
+ ptx_reg_t finalResult;
+ memory_space *mem = NULL;
+ size_t size=0;
+ int t=0;
+ finalResult.u64=0;
+
+ //complete other cases for reading from memory, such as reading from other const memory
+ if((op.get_addr_space() == global_space)&&(derefFlag)) {
+ // global memory - g[4], g[$r0]
+ mem = thread->get_global_memory();
+ type_info_key::type_decode(opType,size,t);
+ mem->read(result.u32,size/8,&finalResult.u128);
+ thread->m_last_effective_address = result.u32;
+ thread->m_last_memory_space = global_space;
+
+ if( opType == S16_TYPE || opType == S32_TYPE )
+ sign_extend(finalResult,size,dstInfo);
+ } else if((op.get_addr_space() == shared_space)&&(derefFlag)) {
+ // shared memory - s[4], s[$r0]
+ mem = thread->m_shared_mem;
+ type_info_key::type_decode(opType,size,t);
+ mem->read(result.u32,size/8,&finalResult.u128);
+ thread->m_last_effective_address = result.u32;
+ thread->m_last_memory_space = shared_space;
+
+ if( opType == S16_TYPE || opType == S32_TYPE )
+ sign_extend(finalResult,size,dstInfo);
+ } else if((op.get_addr_space() == const_space)&&(derefFlag)) {
+ // const memory - ce0c1[4], ce0c1[$r0]
+ mem = thread->get_global_memory();
+ type_info_key::type_decode(opType,size,t);
+ mem->read((result.u32 + op.get_const_mem_offset()),size/8,&finalResult.u128);
+ thread->m_last_effective_address = result.u32;
+ thread->m_last_memory_space = const_space;
+ if( opType == S16_TYPE || opType == S32_TYPE )
+ sign_extend(finalResult,size,dstInfo);
+ } else if((op.get_addr_space() == local_space)&&(derefFlag)) {
+ // local memory - l0[4], l0[$r0]
+ mem = thread->m_local_mem;
+ type_info_key::type_decode(opType,size,t);
+ mem->read(result.u32,size/8,&finalResult.u128);
+ thread->m_last_effective_address = result.u32;
+ thread->m_last_memory_space = local_space;
+ if( opType == S16_TYPE || opType == S32_TYPE )
+ sign_extend(finalResult,size,dstInfo);
+ } else {
+ finalResult = result;
+ }
+
+ if((op.get_operand_neg() == true)&&(derefFlag)) {
+ switch( opType ) {
+ // Default to f32 for now, need to add support for others
+ case S8_TYPE:
+ case U8_TYPE:
+ case B8_TYPE:
+ finalResult.s8 = -finalResult.s8;
+ break;
+ case S16_TYPE:
+ case U16_TYPE:
+ case B16_TYPE:
+ finalResult.s16 = -finalResult.s16;
+ break;
+ case S32_TYPE:
+ case U32_TYPE:
+ case B32_TYPE:
+ finalResult.s32 = -finalResult.s32;
+ break;
+ case S64_TYPE:
+ case U64_TYPE:
+ case B64_TYPE:
+ finalResult.s64 = -finalResult.s64;
+ break;
+ case F16_TYPE:
+ finalResult.f16 = -finalResult.f16;
+ break;
+ case F32_TYPE:
+ finalResult.f32 = -finalResult.f32;
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ finalResult.f64 = -finalResult.f64;
+ break;
+ default:
+ assert(0);
+ }
+
+ }
+
+ return finalResult;
+
+}
+
+unsigned get_operand_nbits( const operand_info &op )
+{
+ if ( op.is_reg() ) {
+ const symbol *sym = op.get_symbol();
+ const type_info *typ = sym->type();
+ type_info_key t = typ->get_key();
+ switch( t.scalar_type() ) {
+ case PRED_TYPE:
+ return 1;
+ case B8_TYPE: case S8_TYPE: case U8_TYPE:
+ return 8;
+ case S16_TYPE: case U16_TYPE: case F16_TYPE: case B16_TYPE:
+ return 16;
+ case S32_TYPE: case U32_TYPE: case F32_TYPE: case B32_TYPE:
+ return 32;
+ case S64_TYPE: case U64_TYPE: case F64_TYPE: case B64_TYPE:
+ return 64;
+ default:
+ printf("ERROR: unknown register type\n");
+ fflush(stdout);
+ abort();
+ }
+ } else {
+ printf("ERROR: Need to implement get_operand_nbits() for currently unsupported operand_info type\n");
+ fflush(stdout);
+ abort();
+ }
+
+ return 0;
+}
+
+void ptx_thread_info::get_vector_operand_values( const operand_info &op, ptx_reg_t* ptx_regs, unsigned num_elements )
+{
+ assert( op.is_vector() );
+ assert( num_elements <= 4 ); // max 4 elements in a vector
+
+ for (int idx = num_elements - 1; idx >= 0; --idx) {
+ const symbol *sym = NULL;
+ sym = op.vec_symbol(idx);
+ if( strcmp(sym->name().c_str(),"_") != 0) {
+ reg_map_t::iterator reg_iter = m_regs.back().find(sym);
+ assert( reg_iter != m_regs.back().end() );
+ ptx_regs[idx] = reg_iter->second;
+ }
+ }
+}
+
+void sign_extend( ptx_reg_t &data, unsigned src_size, const operand_info &dst )
+{
+ if( !dst.is_reg() )
+ return;
+ unsigned dst_size = get_operand_nbits( dst );
+ if( src_size >= dst_size )
+ return;
+ // src_size < dst_size
+ unsigned long long mask = 1;
+ mask <<= (src_size-1);
+ if( (mask & data.u64) == 0 ) {
+ // no need to sign extend
+ return;
+ }
+ // need to sign extend
+ mask = 1;
+ mask <<= dst_size-src_size;
+ mask -= 1;
+ mask <<= src_size;
+ data.u64 |= mask;
+}
+
+void ptx_thread_info::set_operand_value( const operand_info &dst, const ptx_reg_t &data, unsigned type, ptx_thread_info *thread, const ptx_instruction *pI, int overflow, int carry )
+{
+ thread->set_operand_value( dst, data, type, thread, pI );
+
+ if (dst.get_double_operand_type() == -2)
+ {
+ ptx_reg_t predValue;
+
+ const symbol *sym = dst.vec_symbol(0);
+ predValue.u64 = (m_regs.back()[ sym ].u64) & ~(0x0C);
+ predValue.u64 |= ((overflow & 0x01)<<3);
+ predValue.u64 |= ((carry & 0x01)<<2);
+
+ set_reg(sym,predValue);
+ }
+ else if (dst.get_double_operand_type() == 0)
+ {
+ //intentionally do nothing
+ }
+ else
+ {
+ printf("Unexpected double destination\n");
+ assert(0);
+ }
+
+}
+
+void ptx_thread_info::set_operand_value( const operand_info &dst, const ptx_reg_t &data, unsigned type, ptx_thread_info *thread, const ptx_instruction *pI )
+{
+ ptx_reg_t dstData;
+ memory_space *mem = NULL;
+ size_t size;
+ int t;
+
+ type_info_key::type_decode(type,size,t);
+
+ /*complete this section for other cases*/
+ if(dst.get_addr_space() == undefined_space)
+ {
+ ptx_reg_t setValue;
+ setValue.u64 = data.u64;
+
+ // Double destination in set instruction ($p0|$p1) - second is negation of first
+ if (dst.get_double_operand_type() == -1)
+ {
+ ptx_reg_t setValue2;
+ const symbol *name1 = dst.vec_symbol(0);
+ const symbol *name2 = dst.vec_symbol(1);
+
+ if ( (type==F16_TYPE)||(type==F32_TYPE)||(type==F64_TYPE)||(type==FF64_TYPE) ) {
+ setValue2.f32 = (setValue.u64==0)?1.0f:0.0f;
+ } else {
+ setValue2.u32 = (setValue.u64==0)?0xFFFFFFFF:0;
+ }
+
+ set_reg(name1,setValue);
+ set_reg(name2,setValue2);
+ }
+
+ // Double destination in cvt,shr,mul,etc. instruction ($p0|$r4) - second register operand receives data, first predicate operand
+ // is set as $p0=($r4!=0)
+ // Also for Double destination in set instruction ($p0/$r1)
+ else if ((dst.get_double_operand_type() == -2)||(dst.get_double_operand_type() == -3))
+ {
+ ptx_reg_t predValue;
+ const symbol *predName = dst.vec_symbol(0);
+ const symbol *regName = dst.vec_symbol(1);
+ predValue.u64 = 0;
+
+ switch ( type ) {
+ case S8_TYPE:
+ if((setValue.s8 & 0x7F) == 0)
+ predValue.u64 |= 1;
+ break;
+ case S16_TYPE:
+ if((setValue.s16 & 0x7FFF) == 0)
+ predValue.u64 |= 1;
+ break;
+ case S32_TYPE:
+ if((setValue.s32 & 0x7FFFFFFF) == 0)
+ predValue.u64 |= 1;
+ break;
+ case S64_TYPE:
+ if((setValue.s64 & 0x7FFFFFFFFFFFFFFF) == 0)
+ predValue.u64 |= 1;
+ break;
+ case U8_TYPE:
+ case B8_TYPE:
+ if(setValue.u8 == 0)
+ predValue.u64 |= 1;
+ break;
+ case U16_TYPE:
+ case B16_TYPE:
+ if(setValue.u16 == 0)
+ predValue.u64 |= 1;
+ break;
+ case U32_TYPE:
+ case B32_TYPE:
+ if(setValue.u32 == 0)
+ predValue.u64 |= 1;
+ break;
+ case U64_TYPE:
+ case B64_TYPE:
+ if(setValue.u64 == 0)
+ predValue.u64 |= 1;
+ break;
+ case F16_TYPE:
+ if(setValue.f16 == 0)
+ predValue.u64 |= 1;
+ break;
+ case F32_TYPE:
+ if(setValue.f32 == 0)
+ predValue.u64 |= 1;
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ if(setValue.f64 == 0)
+ predValue.u64 |= 1;
+ break;
+ default: assert(0); break;
+ }
+
+
+ if ( (type==S8_TYPE)||(type==S16_TYPE)||(type==S32_TYPE)||(type==S64_TYPE)||
+ (type==U8_TYPE)||(type==U16_TYPE)||(type==U32_TYPE)||(type==U64_TYPE)||
+ (type==B8_TYPE)||(type==B16_TYPE)||(type==B32_TYPE)||(type==B64_TYPE)) {
+ if((setValue.u32 & (1<<(size-1))) != 0)
+ predValue.u64 |= 1<<1;
+ }
+ if ( type==F32_TYPE ) {
+ if(setValue.f32 < 0)
+ predValue.u64 |= 1<<1;
+ }
+
+ if(dst.get_operand_lohi() == 1)
+ {
+ setValue.u64 = ((m_regs.back()[ regName ].u64) & (~(0xFFFF))) + (data.u64 & 0xFFFF);
+ }
+ else if(dst.get_operand_lohi() == 2)
+ {
+ setValue.u64 = ((m_regs.back()[ regName ].u64) & (~(0xFFFF0000))) + ((data.u64<<16) & 0xFFFF0000);
+ }
+
+ set_reg(predName,predValue);
+ set_reg(regName,setValue);
+ }
+ else if (type == BB128_TYPE)
+ {
+ //b128 stuff here.
+ ptx_reg_t setValue2, setValue3, setValue4;
+ setValue.u64 = 0;
+ setValue2.u64 = 0;
+ setValue3.u64 = 0;
+ setValue4.u64 = 0;
+ setValue.u32 = data.u128.lowest;
+ setValue2.u32 = data.u128.low;
+ setValue3.u32 = data.u128.high;
+ setValue4.u32 = data.u128.highest;
+
+ const symbol *name1, *name2, *name3, *name4 = NULL;
+
+ name1 = dst.vec_symbol(0);
+ name2 = dst.vec_symbol(1);
+ name3 = dst.vec_symbol(2);
+ name4 = dst.vec_symbol(3);
+
+ set_reg(name1,setValue);
+ set_reg(name2,setValue2);
+ set_reg(name3,setValue3);
+ set_reg(name4,setValue4);
+ }
+ else if (type == BB64_TYPE || type == FF64_TYPE)
+ {
+ //ptxplus version of storing 64 bit values to registers stores to two adjacent registers
+ ptx_reg_t setValue2;
+ setValue.u32 = 0;
+ setValue2.u32 = 0;
+
+ setValue.u32 = data.bits.ls;
+ setValue2.u32 = data.bits.ms;
+
+ const symbol *name1, *name2 = NULL;
+
+ name1 = dst.vec_symbol(0);
+ name2 = dst.vec_symbol(1);
+
+ set_reg(name1,setValue);
+ set_reg(name2,setValue2);
+ }
+ else
+ {
+ if(dst.get_operand_lohi() == 1)
+ {
+ setValue.u64 = ((m_regs.back()[ dst.get_symbol() ].u64) & (~(0xFFFF))) + (data.u64 & 0xFFFF);
+ }
+ else if(dst.get_operand_lohi() == 2)
+ {
+ setValue.u64 = ((m_regs.back()[ dst.get_symbol() ].u64) & (~(0xFFFF0000))) + ((data.u64<<16) & 0xFFFF0000);
+ }
+ set_reg(dst.get_symbol(),setValue);
+ }
+ }
+
+ // global memory - g[4], g[$r0]
+ else if(dst.get_addr_space() == global_space)
+ {
+ dstData = thread->get_operand_value(dst, dst, type, thread, 0);
+ mem = thread->get_global_memory();
+ type_info_key::type_decode(type,size,t);
+
+ mem->write(dstData.u32,size/8,&data.u128,thread,pI);
+ thread->m_last_effective_address = dstData.u32;
+ thread->m_last_memory_space = global_space;
+ }
+
+ // shared memory - s[4], s[$r0]
+ else if(dst.get_addr_space() == shared_space)
+ {
+ dstData = thread->get_operand_value(dst, dst, type, thread, 0);
+ mem = thread->m_shared_mem;
+ type_info_key::type_decode(type,size,t);
+
+ mem->write(dstData.u32,size/8,&data.u128,thread,pI);
+ thread->m_last_effective_address = dstData.u32;
+ thread->m_last_memory_space = shared_space;
+ }
+
+ // local memory - l0[4], l0[$r0]
+ else if(dst.get_addr_space() == local_space)
+ {
+ dstData = thread->get_operand_value(dst, dst, type, thread, 0);
+ mem = thread->m_local_mem;
+ type_info_key::type_decode(type,size,t);
+
+ mem->write(dstData.u32,size/8,&data.u128,thread,pI);
+ thread->m_last_effective_address = dstData.u32;
+ thread->m_last_memory_space = local_space;
+ }
+
+ else
+ {
+ printf("Destination stores to unknown location.");
+ assert(0);
+ }
+
+
+}
+
+void ptx_thread_info::set_vector_operand_values( const operand_info &dst,
+ const ptx_reg_t &data1,
+ const ptx_reg_t &data2,
+ const ptx_reg_t &data3,
+ const ptx_reg_t &data4 )
+{
+ unsigned num_elements = dst.get_vect_nelem();
+ if (num_elements > 0) {
+ set_reg(dst.vec_symbol(0), data1);
+ if (num_elements > 1) {
+ set_reg(dst.vec_symbol(1), data2);
+ if (num_elements > 2) {
+ set_reg(dst.vec_symbol(2), data3);
+ if (num_elements > 3) {
+ set_reg(dst.vec_symbol(3), data4);
+ }
+ }
+ }
+ }
+
+ m_last_set_operand_value = data1;
+}
+
+#define my_abs(a) (((a)<0)?(-a):(a))
+
+#define MY_MAX_I(a,b) (a > b) ? a : b
+#define MY_MAX_F(a,b) isNaN(a) ? b : isNaN(b) ? a : (a > b) ? a : b
+
+#define MY_MIN_I(a,b) (a < b) ? a : b
+#define MY_MIN_F(a,b) isNaN(a) ? b : isNaN(b) ? a : (a < b) ? a : b
+
+#define MY_INC_I(a,b) (a >= b) ? 0 : a+1
+#define MY_DEC_I(a,b) ((a == 0) || (a > b)) ? b : a-1
+
+#define MY_CAS_I(a,b,c) (a == b) ? c : a
+
+#define MY_EXCH(a,b) b
+
+void abs_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case S16_TYPE: d.s16 = my_abs(a.s16); break;
+ case S32_TYPE: d.s32 = my_abs(a.s32); break;
+ case S64_TYPE: d.s64 = my_abs(a.s64); break;
+ case U16_TYPE: d.s16 = my_abs(a.u16); break;
+ case U32_TYPE: d.s32 = my_abs(a.u32); break;
+ case U64_TYPE: d.s64 = my_abs(a.u64); break;
+ case F32_TYPE: d.f32 = my_abs(a.f32); break;
+ case F64_TYPE: case FF64_TYPE: d.f64 = my_abs(a.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void addp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ //PTXPlus add instruction with carry (carry is kept in a predicate) register
+ ptx_reg_t src1_data, src2_data, src3_data, data;
+ int overflow = 0;
+ int carry = 0;
+
+ const operand_info &dst = pI->dst(); //get operand info of sources and destination
+ const operand_info &src1 = pI->src1(); //use them to determine that they are of type 'register'
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ src3_data = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+ unsigned rounding_mode = pI->rounding_mode();
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+
+ //performs addition. Sets carry and overflow if needed.
+ //src3_data.pred&0x4 is the carry flag
+ switch ( i_type ) {
+ case S8_TYPE:
+ data.s64 = (src1_data.s64 & 0x0000000FF) + (src2_data.s64 & 0x0000000FF) + (src3_data.pred & 0x4);
+ if(((src1_data.s64 & 0x80)-(src2_data.s64 & 0x80)) == 0) {overflow=((src1_data.s64 & 0x80)-(data.s64 & 0x80))==0?0:1; }
+ carry = (data.u64 & 0x000000100)>>8;
+ break;
+ case S16_TYPE:
+ data.s64 = (src1_data.s64 & 0x00000FFFF) + (src2_data.s64 & 0x00000FFFF) + (src3_data.pred & 0x4);
+ if(((src1_data.s64 & 0x8000)-(src2_data.s64 & 0x8000)) == 0) {overflow=((src1_data.s64 & 0x8000)-(data.s64 & 0x8000))==0?0:1; }
+ carry = (data.u64 & 0x000010000)>>16;
+ break;
+ case S32_TYPE:
+ data.s64 = (src1_data.s64 & 0x0FFFFFFFF) + (src2_data.s64 & 0x0FFFFFFFF) + (src3_data.pred & 0x4);
+ if(((src1_data.s64 & 0x80000000)-(src2_data.s64 & 0x80000000)) == 0) {overflow=((src1_data.s64 & 0x80000000)-(data.s64 & 0x80000000))==0?0:1; }
+ carry = (data.u64 & 0x100000000)>>32;
+ break;
+ case S64_TYPE:
+ data.s64 = src1_data.s64 + src2_data.s64 + (src3_data.pred & 0x4);
+ break;
+ case U8_TYPE:
+ data.u64 = (src1_data.u64 & 0xFF) + (src2_data.u64 & 0xFF) + (src3_data.pred & 0x4);
+ carry = (data.u64 & 0x100)>>8;
+ break;
+ case U16_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFF) + (src2_data.u64 & 0xFFFF) + (src3_data.pred & 0x4);
+ carry = (data.u64 & 0x10000)>>16;
+ break;
+ case U32_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFFFFFF) + (src2_data.u64 & 0xFFFFFFFF) + (src3_data.pred & 0x4);
+ carry = (data.u64 & 0x100000000)>>32;
+ break;
+ case U64_TYPE:
+ data.s64 = src1_data.s64 + src2_data.s64 + (src3_data.pred & 0x4);
+ break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = src1_data.f32 + src2_data.f32; break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 + src2_data.f64; break;
+ default: assert(0); break;
+ }
+ fesetround( orig_rm );
+
+ thread->set_operand_value(dst, data, i_type, thread, pI, overflow, carry );
+}
+
+void add_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+ int overflow = 0;
+ int carry = 0;
+
+ const operand_info &dst = pI->dst(); //get operand info of sources and destination
+ const operand_info &src1 = pI->src1(); //use them to determine that they are of type 'register'
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ unsigned rounding_mode = pI->rounding_mode();
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+
+ //performs addition. Sets carry and overflow if needed.
+ switch ( i_type ) {
+ case S8_TYPE:
+ data.s64 = (src1_data.s64 & 0x0000000FF) + (src2_data.s64 & 0x0000000FF);
+ if(((src1_data.s64 & 0x80)-(src2_data.s64 & 0x80)) == 0) {overflow=((src1_data.s64 & 0x80)-(data.s64 & 0x80))==0?0:1; }
+ carry = (data.u64 & 0x000000100)>>8;
+ break;
+ case S16_TYPE:
+ data.s64 = (src1_data.s64 & 0x00000FFFF) + (src2_data.s64 & 0x00000FFFF);
+ if(((src1_data.s64 & 0x8000)-(src2_data.s64 & 0x8000)) == 0) {overflow=((src1_data.s64 & 0x8000)-(data.s64 & 0x8000))==0?0:1; }
+ carry = (data.u64 & 0x000010000)>>16;
+ break;
+ case S32_TYPE:
+ data.s64 = (src1_data.s64 & 0x0FFFFFFFF) + (src2_data.s64 & 0x0FFFFFFFF);
+ if(((src1_data.s64 & 0x80000000)-(src2_data.s64 & 0x80000000)) == 0) {overflow=((src1_data.s64 & 0x80000000)-(data.s64 & 0x80000000))==0?0:1; }
+ carry = (data.u64 & 0x100000000)>>32;
+ break;
+ case S64_TYPE:
+ data.s64 = src1_data.s64 + src2_data.s64;
+ break;
+ case U8_TYPE:
+ data.u64 = (src1_data.u64 & 0xFF) + (src2_data.u64 & 0xFF);
+ carry = (data.u64 & 0x100)>>8;
+ break;
+ case U16_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFF) + (src2_data.u64 & 0xFFFF);
+ carry = (data.u64 & 0x10000)>>16;
+ break;
+ case U32_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFFFFFF) + (src2_data.u64 & 0xFFFFFFFF);
+ carry = (data.u64 & 0x100000000)>>32;
+ break;
+ case U64_TYPE:
+ data.u64 = src1_data.u64 + src2_data.u64;
+ break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = src1_data.f32 + src2_data.f32; break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 + src2_data.f64; break;
+ default: assert(0); break;
+ }
+ fesetround( orig_rm );
+
+ thread->set_operand_value(dst, data, i_type, thread, pI, overflow, carry );
+}
+
+void addc_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void and_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = ~(~(src1_data.pred) & ~(src2_data.pred));
+ else
+ data.u64 = src1_data.u64 & src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void andn_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ switch ( i_type ) {
+ case B16_TYPE: src2_data.u16 = ~src2_data.u16; break;
+ case B32_TYPE: src2_data.u32 = ~src2_data.u32; break;
+ case B64_TYPE: src2_data.u64 = ~src2_data.u64; break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ data.u64 = src1_data.u64 & src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void bar_callback( const inst_t* inst, ptx_thread_info* thread)
+{
+ unsigned ctaid = thread->get_cta_uid();
+ unsigned barid = inst->bar_id;
+ unsigned value = thread->get_reduction_value(ctaid,barid);
+ const ptx_instruction *pI = dynamic_cast<const ptx_instruction*>(inst);
+ const operand_info &dst = pI->dst();
+ ptx_reg_t data;
+ data.u32 = value;
+ thread->set_operand_value(dst,value, U32_TYPE, thread, pI);
+}
+
+void atom_callback( const inst_t* inst, ptx_thread_info* thread)
+{
+ const ptx_instruction *pI = dynamic_cast<const ptx_instruction*>(inst);
+
+ // "Decode" the output type
+ unsigned to_type = pI->get_type();
+ size_t size;
+ int t;
+ type_info_key::type_decode(to_type, size, t);
+
+ // Set up operand variables
+ ptx_reg_t data; // d
+ ptx_reg_t src1_data; // a
+ ptx_reg_t src2_data; // b
+ ptx_reg_t op_result; // temp variable to hold operation result
+
+ bool data_ready = false;
+
+ // Get operand info of sources and destination
+ const operand_info &dst = pI->dst(); // d
+ const operand_info &src1 = pI->src1(); // a
+ const operand_info &src2 = pI->src2(); // b
+
+ // Get operand values
+ src1_data = thread->get_operand_value(src1, src1, to_type, thread, 1); // a
+ if (dst.get_symbol()->type()){
+ src2_data = thread->get_operand_value(src2, dst, to_type, thread, 1); // b
+ } else {
+ //This is the case whent he first argument (dest) is '_'
+ src2_data = thread->get_operand_value(src2, src1, to_type, thread, 1); // b
+ }
+
+ // Check state space
+ addr_t effective_address = src1_data.u64;
+ memory_space_t space = pI->get_space();
+ if (space == undefined_space) {
+ // generic space - determine space via address
+ if( whichspace(effective_address) == global_space ) {
+ effective_address = generic_to_global(effective_address);
+ space = global_space;
+ } else if( whichspace(effective_address) == shared_space ) {
+ unsigned smid = thread->get_hw_sid();
+ effective_address = generic_to_shared(smid,effective_address);
+ space = shared_space;
+ } else {
+ abort();
+ }
+ }
+ assert( space == global_space || space == shared_space );
+
+ memory_space *mem = NULL;
+ if(space == global_space)
+ mem = thread->get_global_memory();
+ else if(space == shared_space)
+ mem = thread->m_shared_mem;
+ else
+ abort();
+
+ // Copy value pointed to in operand 'a' into register 'd'
+ // (i.e. copy src1_data to dst)
+ mem->read(effective_address,size/8,&data.s64);
+ if (dst.get_symbol()->type()){
+ thread->set_operand_value(dst, data, to_type, thread, pI); // Write value into register 'd'
+ }
+
+ // Get the atomic operation to be performed
+ unsigned m_atomic_spec = pI->get_atomic();
+
+ switch ( m_atomic_spec ) {
+ // AND
+ case ATOMIC_AND:
+ {
+
+ switch ( to_type ) {
+ case B32_TYPE:
+ case U32_TYPE:
+ op_result.u32 = data.u32 & src2_data.u32;
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = data.s32 & src2_data.s32;
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch (%x) with instruction\natom.AND only accepts b32\n", to_type);
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // OR
+ case ATOMIC_OR:
+ {
+
+ switch ( to_type ) {
+ case B32_TYPE:
+ case U32_TYPE:
+ op_result.u32 = data.u32 | src2_data.u32;
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = data.s32 | src2_data.s32;
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch (%x) with instruction\natom.OR only accepts b32\n", to_type);
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // XOR
+ case ATOMIC_XOR:
+ {
+
+ switch ( to_type ) {
+ case B32_TYPE:
+ case U32_TYPE:
+ op_result.u32 = data.u32 ^ src2_data.u32;
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = data.s32 ^ src2_data.s32;
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch (%x) with instruction\natom.XOR only accepts b32\n", to_type);
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // CAS
+ case ATOMIC_CAS:
+ {
+
+ ptx_reg_t src3_data;
+ const operand_info &src3 = pI->src3();
+ src3_data = thread->get_operand_value(src3, dst, to_type, thread, 1);
+
+ switch ( to_type ) {
+ case B32_TYPE:
+ case U32_TYPE:
+ op_result.u32 = MY_CAS_I(data.u32, src2_data.u32, src3_data.u32);
+ data_ready = true;
+ break;
+ case B64_TYPE:
+ case U64_TYPE:
+ op_result.u64 = MY_CAS_I(data.u64, src2_data.u64, src3_data.u64);
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = MY_CAS_I(data.s32, src2_data.s32, src3_data.s32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch (%x) with instruction\natom.CAS only accepts b32 and b64\n", to_type);
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // EXCH
+ case ATOMIC_EXCH:
+ {
+ switch ( to_type ) {
+ case B32_TYPE:
+ case U32_TYPE:
+ op_result.u32 = MY_EXCH(data.u32, src2_data.u32);
+ data_ready = true;
+ break;
+ case B64_TYPE:
+ case U64_TYPE:
+ op_result.u64 = MY_EXCH(data.u64, src2_data.u64);
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = MY_EXCH(data.s32, src2_data.s32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch (%x) with instruction\natom.EXCH only accepts b32\n", to_type);
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // ADD
+ case ATOMIC_ADD:
+ {
+
+ switch ( to_type ) {
+ case U32_TYPE:
+ op_result.u32 = data.u32 + src2_data.u32;
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = data.s32 + src2_data.s32;
+ data_ready = true;
+ break;
+ case U64_TYPE:
+ op_result.u64 = data.u64 + src2_data.u64;
+ data_ready = true;
+ break;
+ case F32_TYPE:
+ op_result.f32 = data.f32 + src2_data.f32;
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.ADD only accepts u32, s32, u64, and f32\n");
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // INC
+ case ATOMIC_INC:
+ {
+ switch ( to_type ) {
+ case U32_TYPE:
+ op_result.u32 = MY_INC_I(data.u32, src2_data.u32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.INC only accepts u32 and s32\n");
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // DEC
+ case ATOMIC_DEC:
+ {
+ switch ( to_type ) {
+ case U32_TYPE:
+ op_result.u32 = MY_DEC_I(data.u32, src2_data.u32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.DEC only accepts u32 and s32\n");
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // MIN
+ case ATOMIC_MIN:
+ {
+ switch ( to_type ) {
+ case U32_TYPE:
+ op_result.u32 = MY_MIN_I(data.u32, src2_data.u32);
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = MY_MIN_I(data.s32, src2_data.s32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.MIN only accepts u32 and s32\n");
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // MAX
+ case ATOMIC_MAX:
+ {
+ switch ( to_type ) {
+ case U32_TYPE:
+ op_result.u32 = MY_MAX_I(data.u32, src2_data.u32);
+ data_ready = true;
+ break;
+ case S32_TYPE:
+ op_result.s32 = MY_MAX_I(data.s32, src2_data.s32);
+ data_ready = true;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.MAX only accepts u32 and s32\n");
+ assert(0);
+ break;
+ }
+
+ break;
+ }
+ // DEFAULT
+ default:
+ {
+ assert(0);
+ break;
+ }
+ }
+
+ // Write operation result into memory
+ // (i.e. copy src1_data to dst)
+ if ( data_ready ) {
+ mem->write(effective_address,size/8,&op_result.s64,thread,pI);
+ } else {
+ printf("Execution error: data_ready not set\n");
+ assert(0);
+ }
+}
+
+// atom_impl will now result in a callback being called in mem_ctrl_pop (gpu-sim.c)
+void atom_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ // SYNTAX
+ // atom.space.operation.type d, a, b[, c]; (now read in callback)
+
+ // obtain memory space of the operation
+ memory_space_t space = pI->get_space();
+
+ // get the memory address
+ const operand_info &src1 = pI->src1();
+ // const operand_info &dst = pI->dst(); // not needed for effective address calculation
+ unsigned i_type = pI->get_type();
+ ptx_reg_t src1_data;
+ src1_data = thread->get_operand_value(src1, src1, i_type, thread, 1);
+ addr_t effective_address = src1_data.u64;
+
+ addr_t effective_address_final;
+
+ // handle generic memory space by converting it to global
+ if ( space == undefined_space ) {
+ if( whichspace(effective_address) == global_space ) {
+ effective_address_final = generic_to_global(effective_address);
+ space = global_space;
+ } else if( whichspace(effective_address) == shared_space ) {
+ unsigned smid = thread->get_hw_sid();
+ effective_address_final = generic_to_shared(smid,effective_address);
+ space = shared_space;
+ } else {
+ abort();
+ }
+ } else {
+ assert( space == global_space || space == shared_space );
+ effective_address_final = effective_address;
+ }
+
+ // Check state space
+ assert( space == global_space || space == shared_space );
+
+ thread->m_last_effective_address = effective_address_final;
+ thread->m_last_memory_space = space;
+ thread->m_last_dram_callback.function = atom_callback;
+ thread->m_last_dram_callback.instruction = pI;
+}
+
+void bar_impl( const ptx_instruction *pIin, ptx_thread_info *thread )
+{
+ ptx_instruction * pI = const_cast<ptx_instruction *>(pIin);
+ unsigned bar_op = pI->barrier_op();
+ unsigned red_op = pI->get_atomic();
+ unsigned ctaid = thread->get_cta_uid();
+
+ switch(bar_op){
+ case SYNC_OPTION:
+ {
+ if(pI->get_num_operands()>1){
+ const operand_info &op0 = pI->dst();
+ const operand_info &op1 = pI->src1();
+ ptx_reg_t op0_data;
+ ptx_reg_t op1_data;
+ op0_data = thread->get_operand_value(op0, op0, U32_TYPE, thread, 1);
+ op1_data = thread->get_operand_value(op1, op1, U32_TYPE, thread, 1);
+ pI->set_bar_id(op0_data.u32);
+ pI->set_bar_count(op1_data.u32);
+ }else{
+ const operand_info &op0 = pI->dst();
+ ptx_reg_t op0_data;
+ op0_data = thread->get_operand_value(op0, op0, U32_TYPE, thread, 1);
+ pI->set_bar_id(op0_data.u32);
+ }
+ break;
+ }
+ case ARRIVE_OPTION:
+ {
+ const operand_info &op0 = pI->dst();
+ const operand_info &op1 = pI->src1();
+ ptx_reg_t op0_data;
+ ptx_reg_t op1_data;
+ op0_data = thread->get_operand_value(op0, op0, U32_TYPE, thread, 1);
+ op1_data = thread->get_operand_value(op1, op1, U32_TYPE, thread, 1);
+ pI->set_bar_id(op0_data.u32);
+ pI->set_bar_count(op1_data.u32);
+ break;
+ }
+ case RED_OPTION:
+ {
+ if(pI->get_num_operands()>3){
+ const operand_info &op1 = pI->src1();
+ const operand_info &op2 = pI->src2();
+ const operand_info &op3 = pI->src3();
+ ptx_reg_t op1_data;
+ ptx_reg_t op2_data;
+ ptx_reg_t op3_data;
+ op1_data = thread->get_operand_value(op1, op1, U32_TYPE, thread, 1);
+ op2_data = thread->get_operand_value(op2, op2, U32_TYPE, thread, 1);
+ op3_data = thread->get_operand_value(op3, op3, PRED_TYPE, thread, 1);
+ op3_data.u32=!(op3_data.pred & 0x0001);
+ pI->set_bar_id(op1_data.u32);
+ pI->set_bar_count(op2_data.u32);
+ switch(red_op){
+ case ATOMIC_POPC:
+ thread->popc_reduction(ctaid,op1_data.u32,op3_data.u32);
+ break;
+ case ATOMIC_AND:
+ thread->and_reduction(ctaid,op1_data.u32,op3_data.u32);
+ break;
+ case ATOMIC_OR:
+ thread->or_reduction(ctaid,op1_data.u32,op3_data.u32);
+ break;
+ default:
+ abort();
+ break;
+ }
+ }else{
+ const operand_info &op1 = pI->src1();
+ const operand_info &op2 = pI->src2();
+ ptx_reg_t op1_data;
+ ptx_reg_t op2_data;
+ op1_data = thread->get_operand_value(op1, op1, U32_TYPE, thread, 1);
+ op2_data = thread->get_operand_value(op2, op2, PRED_TYPE, thread, 1);
+ op2_data.u32=!(op2_data.pred & 0x0001);
+ pI->set_bar_id(op1_data.u32);
+ switch(red_op){
+ case ATOMIC_POPC:
+ thread->popc_reduction(ctaid,op1_data.u32,op2_data.u32);
+ break;
+ case ATOMIC_AND:
+ thread->and_reduction(ctaid,op1_data.u32,op2_data.u32);
+ break;
+ case ATOMIC_OR:
+ thread->or_reduction(ctaid,op1_data.u32,op2_data.u32);
+ break;
+ default:
+ abort();
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ abort();
+ break;
+ }
+
+ thread->m_last_dram_callback.function = bar_callback;
+ thread->m_last_dram_callback.instruction = pIin;
+}
+
+void bfe_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ unsigned i_type = pI->get_type();
+ unsigned msb = (i_type == U32_TYPE || i_type == S32_TYPE) ? 31 : 63;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ ptx_reg_t a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ ptx_reg_t c = thread->get_operand_value(src3, dst, i_type, thread, 1);
+ unsigned pos = b.u32 & 0xFF;
+ unsigned len = c.u32 & 0xFF;
+ unsigned d = 0;
+ switch (i_type)
+ {
+ case U32_TYPE:
+ {
+ unsigned mask;
+ d = a.u32 >> pos;
+ mask = 0xFFFFFFFF >> (32 - len);
+ d &= mask;
+ break;
+ }
+ case U64_TYPE:
+ {
+ unsigned long mask;
+ d = a.u64 >> pos;
+ mask = 0xFFFFFFFFFFFFFFFF >> (64 - len);
+ d &= mask;
+ break;
+ }
+ case S32_TYPE:
+ {
+ unsigned mask;
+ unsigned min = MY_MIN_I(pos + len - 1, msb);
+ unsigned sbit = len == 0 ? 0 : (a.s32 >> min) & 0x1;
+ d = a.s32 >> pos;
+ if (sbit > 0)
+ {
+ mask = 0xFFFFFFFF << len;
+ d |= mask;
+ }
+ else
+ {
+ mask = 0xFFFFFFFF >> (32 - len);
+ d &= mask;
+ }
+ break;
+ }
+ case S64_TYPE:
+ {
+ unsigned long mask;
+ unsigned min = MY_MIN_I(pos + len - 1, msb);
+ unsigned sbit = len == 0 ? 0 : (a.s64 >> min) & 0x1;
+ d = a.s64 >> pos;
+ if (sbit > 0)
+ {
+ mask = 0xFFFFFFFFFFFFFFFF << len;
+ d |= mask;
+ }
+ else
+ {
+ mask = 0xFFFFFFFFFFFFFFFF >> (64 - len);
+ d &= mask;
+ }
+ break;
+ }
+ default:
+ printf("Operand type not supported for BFE instruction.\n");
+ abort();
+ return;
+ }
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void bfi_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void bfind_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void bra_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &target = pI->dst();
+ ptx_reg_t target_pc = thread->get_operand_value(target, target, U32_TYPE, thread, 1);
+
+ thread->m_branch_taken = true;
+ thread->set_npc(target_pc);
+}
+
+void brx_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &target = pI->dst();
+ ptx_reg_t target_pc = thread->get_operand_value(target, target, U32_TYPE, thread, 1);
+
+ thread->m_branch_taken = true;
+ thread->set_npc(target_pc);
+}
+
+void break_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &target = thread->pop_breakaddr();
+ ptx_reg_t target_pc = thread->get_operand_value(target, target, U32_TYPE, thread, 1);
+
+ thread->m_branch_taken = true;
+ thread->set_npc(target_pc);
+}
+
+void breakaddr_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &target = pI->dst();
+ thread->push_breakaddr(target);
+ assert(pI->has_pred() == false); // pdom analysis cannot handle if this instruction is predicated
+}
+
+void brev_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void brkpt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void call_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ static unsigned call_uid_next = 1;
+
+ const operand_info &target = pI->func_addr();
+ assert( target.is_function_address() );
+ const symbol *func_addr = target.get_symbol();
+ function_info *target_func = func_addr->get_pc();
+ if (target_func->is_pdom_set()) {
+ printf("GPGPU-Sim PTX: PDOM analysis already done for %s \n", target_func->get_name().c_str() );
+ } else {
+ printf("GPGPU-Sim PTX: finding reconvergence points for \'%s\'...\n", target_func->get_name().c_str() );
+ if (target_func->get_function_size() >0)
+ target_func->do_pdom();
+ target_func->set_pdom();
+ }
+
+ // check that number of args and return match function requirements
+ if( pI->has_return() ^ target_func->has_return() ) {
+ printf("GPGPU-Sim PTX: Execution error - mismatch in number of return values between\n"
+ " call instruction and function declaration\n");
+ abort();
+ }
+ unsigned n_return = target_func->has_return();
+ unsigned n_args = target_func->num_args();
+ unsigned n_operands = pI->get_num_operands();
+
+ if( n_operands != (n_return+1+n_args) ) {
+ printf("GPGPU-Sim PTX: Execution error - mismatch in number of arguements between\n"
+ " call instruction and function declaration\n");
+ abort();
+ }
+
+ // handle intrinsic functions
+ std::string fname = target_func->get_name();
+ if( fname == "vprintf" ) {
+ gpgpusim_cuda_vprintf(pI, thread, target_func);
+ return;
+ }
+
+#if (CUDART_VERSION >= 5000)
+ //Jin: handle device runtime apis for CDP
+ else if(fname == "cudaGetParameterBufferV2") {
+ gpgpusim_cuda_getParameterBufferV2(pI, thread, target_func);
+ return;
+ }
+ else if(fname == "cudaLaunchDeviceV2") {
+ gpgpusim_cuda_launchDeviceV2(pI, thread, target_func);
+ return;
+ }
+ else if(fname == "cudaStreamCreateWithFlags") {
+ gpgpusim_cuda_streamCreateWithFlags(pI, thread, target_func);
+ return;
+ }
+#endif
+
+ // read source arguements into register specified in declaration of function
+ arg_buffer_list_t arg_values;
+ copy_args_into_buffer_list(pI, thread, target_func, arg_values);
+
+ // record local for return value (we only support a single return value)
+ const symbol *return_var_src = NULL;
+ const symbol *return_var_dst = NULL;
+ if( target_func->has_return() ) {
+ return_var_dst = pI->dst().get_symbol();
+ return_var_src = target_func->get_return_var();
+ }
+
+ gpgpu_sim *gpu = thread->get_gpu();
+ unsigned callee_pc=0, callee_rpc=0;
+ if( gpu->simd_model() == POST_DOMINATOR ) {
+ thread->get_core()->get_pdom_stack_top_info(thread->get_hw_wid(),&callee_pc,&callee_rpc);
+ assert( callee_pc == thread->get_pc() );
+ }
+
+ thread->callstack_push(callee_pc + pI->inst_size(), callee_rpc, return_var_src, return_var_dst, call_uid_next++);
+
+ copy_buffer_list_into_frame(thread, arg_values);
+
+ thread->set_npc(target_func);
+}
+
+//Ptxplus version of call instruction. Jumps to a label not a different Kernel.
+void callp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+
+ static unsigned call_uid_next = 1;
+
+ const operand_info &target = pI->dst();
+ ptx_reg_t target_pc = thread->get_operand_value(target, target, U32_TYPE, thread, 1);
+
+ const symbol *return_var_src = NULL;
+ const symbol *return_var_dst = NULL;
+
+ gpgpu_sim *gpu = thread->get_gpu();
+ unsigned callee_pc=0, callee_rpc=0;
+ if( gpu->simd_model() == POST_DOMINATOR ) {
+ thread->get_core()->get_pdom_stack_top_info(thread->get_hw_wid(),&callee_pc,&callee_rpc);
+ assert( callee_pc == thread->get_pc() );
+ }
+
+ thread->callstack_push_plus(callee_pc + pI->inst_size(), callee_rpc, return_var_src, return_var_dst, call_uid_next++);
+ thread->set_npc(target_pc);
+}
+
+void clz_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ int max;
+ unsigned long long mask;
+ d.u64 = 0;
+
+ switch ( i_type ) {
+ case B32_TYPE:
+ max = 32;
+ mask = 0x80000000;
+ break;
+ case B64_TYPE:
+ max = 64;
+ mask = 0x8000000000000000;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ while ((d.u32 < max) && ((a.u64&mask) == 0) ) {
+ d.u32++;
+ a.u64 = a.u64 << 1;
+ }
+
+ thread->set_operand_value(dst,d, B32_TYPE, thread, pI);
+}
+
+void cnot_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ switch ( i_type ) {
+ case PRED_TYPE: d.pred = ((a.pred & 0x0001) == 0)?1:0; break;
+ case B16_TYPE: d.u16 = (a.u16 == 0)?1:0; break;
+ case B32_TYPE: d.u32 = (a.u32 == 0)?1:0; break;
+ case B64_TYPE: d.u64 = (a.u64 == 0)?1:0; break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void cos_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ d.f32 = cos(a.f32);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+ptx_reg_t chop( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ switch ( to_width ) {
+ case 8: x.mask_and(0,0xFF); break;
+ case 16: x.mask_and(0,0xFFFF); break;
+ case 32: x.mask_and(0,0xFFFFFFFF); break;
+ case 64: break;
+ default: assert(0);
+ }
+ return x;
+}
+
+ptx_reg_t sext( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ x=chop(x,0,from_width,0,rounding_mode,saturation_mode);
+ switch ( from_width ) {
+ case 8: if ( x.get_bit(7) ) x.mask_or(0xFFFFFFFF,0xFFFFFF00);break;
+ case 16:if ( x.get_bit(15) ) x.mask_or(0xFFFFFFFF,0xFFFF0000);break;
+ case 32: if ( x.get_bit(31) ) x.mask_or(0xFFFFFFFF,0x00000000);break;
+ case 64: break;
+ default: assert(0);
+ }
+ return x;
+}
+
+// sign extend depending on the destination register size - hack to get SobelFilter working in CUDA 4.2
+ptx_reg_t sexd( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ x=chop(x,0,from_width,0,rounding_mode,saturation_mode);
+ switch ( to_width ) {
+ case 8: if ( x.get_bit(7) ) x.mask_or(0xFFFFFFFF,0xFFFFFF00);break;
+ case 16:if ( x.get_bit(15) ) x.mask_or(0xFFFFFFFF,0xFFFF0000);break;
+ case 32: if ( x.get_bit(31) ) x.mask_or(0xFFFFFFFF,0x00000000);break;
+ case 64: break;
+ default: assert(0);
+ }
+ return x;
+}
+
+ptx_reg_t zext( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ return chop(x,0,from_width,0,rounding_mode,saturation_mode);
+}
+
+int saturatei(int a, int max, int min)
+{
+ if (a > max) a = max;
+ else if (a < min) a = min;
+ return a;
+}
+
+unsigned int saturatei(unsigned int a, unsigned int max)
+{
+ if (a > max) a = max;
+ return a;
+}
+
+ptx_reg_t f2x( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ assert( from_width == 32);
+
+ enum cuda_math::cudaRoundMode mode = cuda_math::cudaRoundZero;
+ switch (rounding_mode) {
+ case RZI_OPTION: mode = cuda_math::cudaRoundZero; break;
+ case RNI_OPTION: mode = cuda_math::cudaRoundNearest; break;
+ case RMI_OPTION: mode = cuda_math::cudaRoundMinInf; break;
+ case RPI_OPTION: mode = cuda_math::cudaRoundPosInf; break;
+ default: break;
+ }
+
+ ptx_reg_t y;
+ if ( to_sign == 1 ) { // convert to 64-bit number first?
+ int tmp = cuda_math::float2int(x.f32, mode);
+ if ((x.u32 & 0x7f800000) == 0)
+ tmp = 0; // round denorm. FP to 0
+ if (saturation_mode && to_width < 32) {
+ tmp = saturatei(tmp, (1<<to_width) - 1, -(1<<to_width));
+ }
+ switch ( to_width ) {
+ case 8: y.s8 = (char)tmp; break;
+ case 16: y.s16 = (short)tmp; break;
+ case 32: y.s32 = (int)tmp; break;
+ case 64: y.s64 = (long long)tmp; break;
+ default: assert(0); break;
+ }
+ } else if ( to_sign == 0 ) {
+ unsigned int tmp = cuda_math::float2uint(x.f32, mode);
+ if ((x.u32 & 0x7f800000) == 0)
+ tmp = 0; // round denorm. FP to 0
+ if (saturation_mode && to_width < 32) {
+ tmp = saturatei(tmp, (1<<to_width) - 1);
+ }
+ switch ( to_width ) {
+ case 8: y.u8 = (unsigned char)tmp; break;
+ case 16: y.u16 = (unsigned short)tmp; break;
+ case 32: y.u32 = (unsigned int)tmp; break;
+ case 64: y.u64 = (unsigned long long)tmp; break;
+ default: assert(0); break;
+ }
+ } else {
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32: assert(0); break; // handled by f2f
+ case 64:
+ y.f64 = x.f32;
+ break;
+ default: assert(0); break;
+ }
+ }
+ return y;
+}
+
+double saturated2i (double a, double max, double min) {
+ if (a > max) a = max;
+ else if (a < min) a = min;
+ return a;
+}
+
+ptx_reg_t d2x( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ assert( from_width == 64);
+
+ double tmp;
+ switch (rounding_mode) {
+ case RZI_OPTION: tmp = trunc(x.f64); break;
+ case RNI_OPTION: tmp = nearbyint(x.f64); break;
+ case RMI_OPTION: tmp = floor(x.f64); break;
+ case RPI_OPTION: tmp = ceil(x.f64); break;
+ default: tmp = x.f64; break;
+ }
+
+ ptx_reg_t y;
+ if ( to_sign == 1 ) {
+ tmp = saturated2i(tmp, ((1<<(to_width - 1)) - 1), (1<<(to_width - 1)) );
+ switch ( to_width ) {
+ case 8: y.s8 = (char)tmp; break;
+ case 16: y.s16 = (short)tmp; break;
+ case 32: y.s32 = (int)tmp; break;
+ case 64: y.s64 = (long long)tmp; break;
+ default: assert(0); break;
+ }
+ } else if ( to_sign == 0 ) {
+ tmp = saturated2i(tmp, ((1<<(to_width - 1)) - 1), 0);
+ switch ( to_width ) {
+ case 8: y.u8 = (unsigned char)tmp; break;
+ case 16: y.u16 = (unsigned short)tmp; break;
+ case 32: y.u32 = (unsigned int)tmp; break;
+ case 64: y.u64 = (unsigned long long)tmp; break;
+ default: assert(0); break;
+ }
+ } else {
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32:
+ y.f32 = x.f64;
+ break;
+ case 64:
+ y.f64 = x.f64; // should be handled by d2d
+ break;
+ default: assert(0); break;
+ }
+ }
+ return y;
+}
+
+ptx_reg_t s2f( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ ptx_reg_t y;
+
+ if (from_width < 64) { // 32-bit conversion
+ y = sext(x,from_width,32,0,rounding_mode,saturation_mode);
+
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32:
+ switch (rounding_mode) {
+ case RZ_OPTION: y.f32 = cuda_math::__int2float_rz(y.s32); break;
+ case RN_OPTION: y.f32 = cuda_math::__int2float_rn(y.s32); break;
+ case RM_OPTION: y.f32 = cuda_math::__int2float_rd(y.s32); break;
+ case RP_OPTION: y.f32 = cuda_math::__int2float_ru(y.s32); break;
+ default: break;
+ }
+ break;
+ case 64: y.f64 = y.s32; break; // no rounding needed
+ default: assert(0); break;
+ }
+ } else {
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32:
+ switch (rounding_mode) {
+ case RZ_OPTION: y.f32 = cuda_math::__ll2float_rz(y.s64); break;
+ case RN_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
+ case RM_OPTION: y.f32 = cuda_math::__ll2float_rd(y.s64); break;
+ case RP_OPTION: y.f32 = cuda_math::__ll2float_ru(y.s64); break;
+ default: break;
+ }
+ break;
+ case 64: y.f64 = y.s64; break; // no internal implementation found
+ default: assert(0); break;
+ }
+ }
+
+ // saturating an integer to 1 or 0?
+ return y;
+}
+
+ptx_reg_t u2f( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ ptx_reg_t y;
+
+ if (from_width < 64) { // 32-bit conversion
+ y = zext(x,from_width,32,0,rounding_mode,saturation_mode);
+
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32:
+ switch (rounding_mode) {
+ case RZ_OPTION: y.f32 = cuda_math::__uint2float_rz(y.u32); break;
+ case RN_OPTION: y.f32 = cuda_math::__uint2float_rn(y.u32); break;
+ case RM_OPTION: y.f32 = cuda_math::__uint2float_rd(y.u32); break;
+ case RP_OPTION: y.f32 = cuda_math::__uint2float_ru(y.u32); break;
+ default: break;
+ }
+ break;
+ case 64: y.f64 = y.u32; break; // no rounding needed
+ default: assert(0); break;
+ }
+ } else {
+ switch ( to_width ) {
+ case 16: assert(0); break;
+ case 32:
+ switch (rounding_mode) {
+ case RZ_OPTION: y.f32 = cuda_math::__ull2float_rn(y.u64); break;
+ case RN_OPTION: y.f32 = cuda_math::__ull2float_rn(y.u64); break;
+ case RM_OPTION: y.f32 = cuda_math::__ull2float_rn(y.u64); break;
+ case RP_OPTION: y.f32 = cuda_math::__ull2float_rn(y.u64); break;
+ default: break;
+ }
+ break;
+ case 64: y.f64 = y.u64; break; // no internal implementation found
+ default: assert(0); break;
+ }
+ }
+
+ // saturating an integer to 1 or 0?
+ return y;
+}
+
+ptx_reg_t f2f( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ ptx_reg_t y;
+ switch ( rounding_mode ) {
+ case RZI_OPTION:
+ y.f32 = truncf(x.f32);
+ break;
+ case RNI_OPTION:
+#if CUDART_VERSION >= 3000
+ y.f32 = nearbyintf(x.f32);
+#else
+ y.f32 = cuda_math::__internal_nearbyintf(x.f32);
+#endif
+ break;
+ case RMI_OPTION:
+ if ((x.u32 & 0x7f800000) == 0) {
+ y.u32 = x.u32 & 0x80000000; // round denorm. FP to 0, keeping sign
+ } else {
+ y.f32 = floorf(x.f32);
+ }
+ break;
+ case RPI_OPTION:
+ if ((x.u32 & 0x7f800000) == 0) {
+ y.u32 = x.u32 & 0x80000000; // round denorm. FP to 0, keeping sign
+ } else {
+ y.f32 = ceilf(x.f32);
+ }
+ break;
+ default:
+ if ((x.u32 & 0x7f800000) == 0) {
+ y.u32 = x.u32 & 0x80000000; // round denorm. FP to 0, keeping sign
+ } else {
+ y.f32 = x.f32;
+ }
+ break;
+ }
+#if CUDART_VERSION >= 3000
+ if (isnanf(y.f32))
+#else
+ if (cuda_math::__cuda___isnanf(y.f32))
+#endif
+ {
+ y.u32 = 0x7fffffff;
+ } else if (saturation_mode) {
+ y.f32 = cuda_math::__saturatef(y.f32);
+ }
+
+ return y;
+}
+
+ptx_reg_t d2d( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign, int rounding_mode, int saturation_mode )
+{
+ ptx_reg_t y;
+ switch ( rounding_mode ) {
+ case RZI_OPTION:
+ y.f64 = trunc(x.f64);
+ break;
+ case RNI_OPTION:
+#if CUDART_VERSION >= 3000
+ y.f64 = nearbyint(x.f64);
+#else
+ y.f64 = cuda_math::__internal_nearbyintf(x.f64);
+#endif
+ break;
+ case RMI_OPTION:
+ y.f64 = floor(x.f64);
+ break;
+ case RPI_OPTION:
+ y.f64 = ceil(x.f64);
+ break;
+ default:
+ y.f64 = x.f64;
+ break;
+ }
+ if (std::isnan(y.f64)) {
+ y.u64 = 0xfff8000000000000ull;
+ } else if (saturation_mode) {
+ y.f64 = cuda_math::__saturatef(y.f64);
+ }
+ return y;
+}
+
+ptx_reg_t (*g_cvt_fn[11][11])( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
+ int rounding_mode, int saturation_mode ) = {
+ { NULL, sext, sext, sext, NULL, sext, sext, sext, s2f, s2f, s2f},
+ { chop, NULL, sext, sext, chop, NULL, sext, sext, s2f, s2f, s2f},
+ { chop, sexd, NULL, sext, chop, chop, NULL, sext, s2f, s2f, s2f},
+ { chop, chop, chop, NULL, chop, chop, chop, NULL, s2f, s2f, s2f},
+ { NULL, zext, zext, zext, NULL, zext, zext, zext, u2f, u2f, u2f},
+ { chop, NULL, zext, zext, chop, NULL, zext, zext, u2f, u2f, u2f},
+ { chop, chop, NULL, zext, chop, chop, NULL, zext, u2f, u2f, u2f},
+ { chop, chop, chop, NULL, chop, chop, chop, NULL, u2f, u2f, u2f},
+ { f2x , f2x , f2x , f2x , f2x , f2x , f2x , f2x , NULL,f2x, f2x},
+ { f2x , f2x , f2x , f2x , f2x , f2x , f2x , f2x , f2x, f2f, f2x},
+ { d2x , d2x , d2x , d2x , d2x , d2x , d2x , d2x , d2x, d2x, d2d}
+};
+
+void ptx_round(ptx_reg_t& data, int rounding_mode, int type)
+{
+ if (rounding_mode == RN_OPTION) {
+ return;
+ }
+ switch ( rounding_mode ) {
+ case RZI_OPTION:
+ switch ( type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ printf("Trying to round an integer??\n"); assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE:
+ data.f32 = truncf(data.f32);
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ if (data.f64 < 0) data.f64 = ceil(data.f64); //negative
+ else data.f64 = floor(data.f64); //positive
+ break;
+ default: assert(0); break;
+ }
+ break;
+ case RNI_OPTION:
+ switch ( type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ printf("Trying to round an integer??\n"); assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE:
+#if CUDART_VERSION >= 3000
+ data.f32 = nearbyintf(data.f32);
+#else
+ data.f32 = cuda_math::__cuda_nearbyintf(data.f32);
+#endif
+ break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = round(data.f64); break;
+ default: assert(0); break;
+ }
+ break;
+ case RMI_OPTION:
+ switch ( type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ printf("Trying to round an integer??\n"); assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE:
+ data.f32 = floorf(data.f32);
+ break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = floor(data.f64); break;
+ default: assert(0); break;
+ }
+ break;
+ case RPI_OPTION:
+ switch ( type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ printf("Trying to round an integer??\n"); assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = ceilf(data.f32); break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = ceil(data.f64); break;
+ default: assert(0); break;
+ }
+ break;
+ default: break;
+ }
+
+ if (type == F32_TYPE) {
+#if CUDART_VERSION >= 3000
+ if (isnanf(data.f32))
+#else
+ if (cuda_math::__cuda___isnanf(data.f32))
+#endif
+ {
+ data.u32 = 0x7fffffff;
+ }
+ }
+ if ((type == F64_TYPE)||(type == FF64_TYPE)) {
+ if (std::isnan(data.f64)) {
+ data.u64 = 0xfff8000000000000ull;
+ }
+ }
+}
+
+void ptx_saturate(ptx_reg_t& data, int saturation_mode, int type)
+{
+ if (!saturation_mode) {
+ return;
+ }
+ switch ( type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ printf("Trying to clamp an integer to 1??\n"); assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE:
+ if (data.f32 > 1.0f) data.f32 = 1.0f; //negative
+ if (data.f32 < 0.0f) data.f32 = 0.0f; //positive
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ if (data.f64 > 1.0f) data.f64 = 1.0f; //negative
+ if (data.f64 < 0.0f) data.f64 = 0.0f; //positive
+ break;
+ default: assert(0); break;
+ }
+
+}
+
+void cvt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ unsigned to_type = pI->get_type();
+ unsigned from_type = pI->get_type2();
+ unsigned rounding_mode = pI->rounding_mode();
+ unsigned saturation_mode = pI->saturation_mode();
+
+ if ( to_type == F16_TYPE || from_type == F16_TYPE )
+ abort();
+
+ int to_sign, from_sign;
+ size_t from_width, to_width;
+ unsigned src_fmt = type_info_key::type_decode(from_type, from_width, from_sign);
+ unsigned dst_fmt = type_info_key::type_decode(to_type, to_width, to_sign);
+
+ ptx_reg_t data = thread->get_operand_value(src1, dst, from_type, thread, 1);
+
+ if(pI->is_neg()){
+
+ switch( from_type ) {
+ // Default to f32 for now, need to add support for others
+ case S8_TYPE:
+ case U8_TYPE:
+ case B8_TYPE:
+ data.s8 = -data.s8;
+ break;
+ case S16_TYPE:
+ case U16_TYPE:
+ case B16_TYPE:
+ data.s16 = -data.s16;
+ break;
+ case S32_TYPE:
+ case U32_TYPE:
+ case B32_TYPE:
+ data.s32 = -data.s32;
+ break;
+ case S64_TYPE:
+ case U64_TYPE:
+ case B64_TYPE:
+ data.s64 = -data.s64;
+ break;
+ case F16_TYPE:
+ data.f16 = -data.f16;
+ break;
+ case F32_TYPE:
+ data.f32 = -data.f32;
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ data.f64 = -data.f64;
+ break;
+ default:
+ assert(0);
+ }
+
+ }
+
+
+ if ( g_cvt_fn[src_fmt][dst_fmt] != NULL ) {
+ ptx_reg_t result = g_cvt_fn[src_fmt][dst_fmt](data,from_width,to_width,to_sign, rounding_mode, saturation_mode);
+ data = result;
+ }
+
+ thread->set_operand_value(dst, data, to_type, thread, pI );
+}
+
+void cvta_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ memory_space_t space = pI->get_space();
+ bool to_non_generic = pI->is_to();
+
+ unsigned i_type = pI->get_type();
+ ptx_reg_t from_addr = thread->get_operand_value(src1,dst,i_type,thread,1);
+ addr_t from_addr_hw = (addr_t)from_addr.u64;
+ addr_t to_addr_hw = 0;
+ unsigned smid = thread->get_hw_sid();
+ unsigned hwtid = thread->get_hw_tid();
+
+ if( to_non_generic ) {
+ switch( space.get_type() ) {
+ case shared_space: to_addr_hw = generic_to_shared( smid, from_addr_hw ); break;
+ case local_space: to_addr_hw = generic_to_local( smid, hwtid, from_addr_hw ); break;
+ case global_space: to_addr_hw = generic_to_global(from_addr_hw ); break;
+ default: abort();
+ }
+ } else {
+ switch( space.get_type() ) {
+ case shared_space: to_addr_hw = shared_to_generic( smid, from_addr_hw ); break;
+ case local_space: to_addr_hw = local_to_generic( smid, hwtid, from_addr_hw )
+ + thread->get_local_mem_stack_pointer(); break; // add stack ptr here so that it can be passed as a pointer at function call
+ case global_space: to_addr_hw = global_to_generic( from_addr_hw ); break;
+ default: abort();
+ }
+ }
+
+ ptx_reg_t to_addr;
+ to_addr.u64 = to_addr_hw;
+ thread->set_reg(dst.get_symbol(),to_addr);
+}
+
+void div_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+
+ ptx_reg_t src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case S8_TYPE:
+ data.s8 = src1_data.s8 / src2_data.s8 ; break;
+ case S16_TYPE:
+ data.s16 = src1_data.s16 / src2_data.s16; break;
+ case S32_TYPE:
+ data.s32 = src1_data.s32 / src2_data.s32; break;
+ case S64_TYPE:
+ data.s64 = src1_data.s64 / src2_data.s64; break;
+ case U8_TYPE:
+ data.u8 = src1_data.u8 / src2_data.u8 ; break;
+ case U16_TYPE:
+ data.u16 = src1_data.u16 / src2_data.u16; break;
+ case U32_TYPE:
+ data.u32 = src1_data.u32 / src2_data.u32; break;
+ case U64_TYPE:
+ data.u64 = src1_data.u64 / src2_data.u64; break;
+ case B8_TYPE:
+ data.u8 = src1_data.u8 / src2_data.u8 ; break;
+ case B16_TYPE:
+ data.u16 = src1_data.u16 / src2_data.u16; break;
+ case B32_TYPE:
+ data.u32 = src1_data.u32 / src2_data.u32; break;
+ case B64_TYPE:
+ data.u64 = src1_data.u64 / src2_data.u64; break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = src1_data.f32 / src2_data.f32; break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 / src2_data.f64; break;
+ default: assert(0); break;
+ }
+ thread->set_operand_value(dst,data, i_type, thread,pI);
+}
+
+void ex2_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ data.f32 = cuda_math::__powf(2.0, src1_data.f32);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,data, i_type, thread,pI);
+}
+
+void exit_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ thread->set_done();
+ thread->exitCore();
+ thread->registerExit();
+}
+
+void mad_def( const ptx_instruction *pI, ptx_thread_info *thread, bool use_carry = false );
+
+void fma_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ mad_def(pI,thread);
+}
+
+void isspacep_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a;
+ bool t=false;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ memory_space_t space = pI->get_space();
+
+ a = thread->get_reg(src1.get_symbol());
+ addr_t addr = (addr_t)a.u64;
+ unsigned smid = thread->get_hw_sid();
+ unsigned hwtid = thread->get_hw_tid();
+
+ switch( space.get_type() ) {
+ case shared_space: t = isspace_shared( smid, addr );
+ case local_space: t = isspace_local( smid, hwtid, addr );
+ case global_space: t = isspace_global( addr );
+ default: abort();
+ }
+
+ ptx_reg_t p;
+ p.pred = t?1:0;
+
+ thread->set_reg(dst.get_symbol(),p);
+}
+
+void decode_space( memory_space_t &space, ptx_thread_info *thread, const operand_info &op, memory_space *&mem, addr_t &addr)
+{
+ unsigned smid = thread->get_hw_sid();
+ unsigned hwtid = thread->get_hw_tid();
+
+ if( space == param_space_unclassified ) {
+ // need to op to determine whether it refers to a kernel param or local param
+ const symbol *s = op.get_symbol();
+ const type_info *t = s->type();
+ type_info_key ti = t->get_key();
+ if( ti.is_param_kernel() )
+ space = param_space_kernel;
+ else if( ti.is_param_local() ) {
+ space = param_space_local;
+ } else {
+ printf("GPGPU-Sim PTX: ERROR ** cannot resolve .param space for '%s'\n", s->name().c_str() );
+ abort();
+ }
+ }
+ switch ( space.get_type() ) {
+ case global_space: mem = thread->get_global_memory(); break;
+ case param_space_local:
+ case local_space:
+ mem = thread->m_local_mem;
+ addr += thread->get_local_mem_stack_pointer();
+ break;
+ case tex_space: mem = thread->get_tex_memory(); break;
+ case surf_space: mem = thread->get_surf_memory(); break;
+ case param_space_kernel: mem = thread->get_param_memory(); break;
+ case shared_space: mem = thread->m_shared_mem; break;
+ case const_space: mem = thread->get_global_memory(); break;
+ case generic_space:
+ if( thread->get_ptx_version().ver() >= 2.0 ) {
+ // convert generic address to memory space address
+ space = whichspace(addr);
+ switch ( space.get_type() ) {
+ case global_space: mem = thread->get_global_memory(); addr = generic_to_global(addr); break;
+ case local_space: mem = thread->m_local_mem; addr = generic_to_local(smid,hwtid,addr); break;
+ case shared_space: mem = thread->m_shared_mem; addr = generic_to_shared(smid,addr); break;
+ default: abort();
+ }
+ } else {
+ abort();
+ }
+ break;
+ case param_space_unclassified:
+ case undefined_space:
+ default:
+ abort();
+ }
+}
+
+void ld_exec( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned type = pI->get_type();
+
+ ptx_reg_t src1_data = thread->get_operand_value(src1, dst, type, thread, 1);
+ ptx_reg_t data;
+ memory_space_t space = pI->get_space();
+ unsigned vector_spec = pI->get_vector();
+
+ memory_space *mem = NULL;
+ addr_t addr = src1_data.u32;
+
+ decode_space(space,thread,src1,mem,addr);
+
+ size_t size;
+ int t;
+ data.u64=0;
+ type_info_key::type_decode(type,size,t);
+ if (!vector_spec) {
+ mem->read(addr,size/8,&data.s64);
+ if( type == S16_TYPE || type == S32_TYPE )
+ sign_extend(data,size,dst);
+ thread->set_operand_value(dst,data, type, thread, pI);
+ } else {
+ ptx_reg_t data1, data2, data3, data4;
+ mem->read(addr,size/8,&data1.s64);
+ mem->read(addr+size/8,size/8,&data2.s64);
+ if (vector_spec != V2_TYPE) { //either V3 or V4
+ mem->read(addr+2*size/8,size/8,&data3.s64);
+ if (vector_spec != V3_TYPE) { //v4
+ mem->read(addr+3*size/8,size/8,&data4.s64);
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4);
+ } else //v3
+ thread->set_vector_operand_values(dst,data1,data2,data3,data3);
+ } else //v2
+ thread->set_vector_operand_values(dst,data1,data2,data2,data2);
+ }
+ thread->m_last_effective_address = addr;
+ thread->m_last_memory_space = space;
+}
+
+void ld_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ld_exec(pI,thread);
+}
+void ldu_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ld_exec(pI,thread);
+}
+
+void lg2_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ d.f32 = log(a.f32)/log(2);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void mad24_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ ptx_reg_t d, t;
+
+ unsigned i_type = pI->get_type();
+ ptx_reg_t a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ ptx_reg_t c = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+ unsigned sat_mode = pI->saturation_mode();
+
+ assert( !pI->is_wide() );
+
+ switch ( i_type ) {
+ case S32_TYPE:
+ t.s64 = a.s32 * b.s32;
+ if ( pI->is_hi() ) {
+ d.s64 = (t.s64>>16) + c.s32;
+ if ( sat_mode ) {
+ if ( d.s64 > (int)0x7FFFFFFF )
+ d.s64 = (int)0x7FFFFFFF;
+ else if ( d.s64 < (int)0x80000000 )
+ d.s64 = (int)0x80000000;
+ }
+ } else if ( pI->is_lo() ) d.s64 = t.s32 + c.s32;
+ else assert(0);
+ break;
+ case U32_TYPE:
+ t.u64 = a.u32 * b.u32;
+ if ( pI->is_hi() ) d.u64 = (t.u64>>16) + c.u32;
+ else if ( pI->is_lo() ) d.u64 = t.u32 + c.u32;
+ else assert(0);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst, d, i_type, thread, pI);
+}
+
+void mad_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ mad_def(pI, thread, false);
+}
+
+void madp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ mad_def(pI, thread, true);
+}
+
+void madc_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ mad_def(pI, thread, true);
+}
+
+void mad_def( const ptx_instruction *pI, ptx_thread_info *thread, bool use_carry )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ ptx_reg_t d, t;
+
+ int carry=0;
+ int overflow=0;
+
+ unsigned i_type = pI->get_type();
+ ptx_reg_t a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ ptx_reg_t c = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+ // take the carry bit, it should be the 4th operand
+ ptx_reg_t carry_bit;
+ carry_bit.u64 = 0;
+ if (use_carry) {
+ const operand_info &carry = pI->operand_lookup(4);
+ carry_bit = thread->get_operand_value(carry, dst, PRED_TYPE, thread, 0);
+ carry_bit.pred &= 0x4;
+ carry_bit.pred >>=2;
+ }
+
+ unsigned rounding_mode = pI->rounding_mode();
+
+ switch ( i_type ) {
+ case S16_TYPE:
+ t.s32 = a.s16 * b.s16;
+ if ( pI->is_wide() ) d.s32 = t.s32 + c.s32 + carry_bit.pred;
+ else if ( pI->is_hi() ) d.s16 = (t.s32>>16) + c.s16 + carry_bit.pred;
+ else if ( pI->is_lo() ) d.s16 = t.s16 + c.s16 + carry_bit.pred;
+ else assert(0);
+ carry = ((long long int)(t.s32 + c.s32 + carry_bit.pred)&0x100000000)>>32;
+ break;
+ case S32_TYPE:
+ t.s64 = a.s32 * b.s32;
+ if ( pI->is_wide() ) d.s64 = t.s64 + c.s64 + carry_bit.pred;
+ else if ( pI->is_hi() ) d.s32 = (t.s64>>32) + c.s32 + carry_bit.pred;
+ else if ( pI->is_lo() ) d.s32 = t.s32 + c.s32 + carry_bit.pred;
+ else assert(0);
+ break;
+ case S64_TYPE:
+ t.s64 = a.s64 * b.s64;
+ assert( !pI->is_wide() );
+ assert( !pI->is_hi() );
+ assert( use_carry == false);
+ if ( pI->is_lo() ) d.s64 = t.s64 + c.s64 + carry_bit.pred;
+ else assert(0);
+ break;
+ case U16_TYPE:
+ t.u32 = a.u16 * b.u16;
+ if ( pI->is_wide() ) d.u32 = t.u32 + c.u32 + carry_bit.pred;
+ else if ( pI->is_hi() ) d.u16 = (t.u32 + c.u16 + carry_bit.pred)>>16;
+ else if ( pI->is_lo() ) d.u16 = t.u16 + c.u16 + carry_bit.pred;
+ else assert(0);
+ carry = ((long long int)((long long int)t.u32 + c.u32 + carry_bit.pred)&0x100000000)>>32;
+ break;
+ case U32_TYPE:
+ t.u64 = a.u32 * b.u32;
+ if ( pI->is_wide() ) d.u64 = t.u64 + c.u64 + carry_bit.pred;
+ else if ( pI->is_hi() ) d.u32 = (t.u64 + c.u32 + carry_bit.pred)>>32;
+ else if ( pI->is_lo() ) d.u32 = t.u32 + c.u32 + carry_bit.pred;
+ else assert(0);
+ break;
+ case U64_TYPE:
+ t.u64 = a.u64 * b.u64;
+ assert( !pI->is_wide() );
+ assert( !pI->is_hi() );
+ assert( use_carry == false);
+ if ( pI->is_lo() ) d.u64 = t.u64 + c.u64 + carry_bit.pred;
+ else assert(0);
+ break;
+ case F16_TYPE:
+ assert(0);
+ break;
+ case F32_TYPE: {
+ assert( use_carry == false);
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+ d.f32 = a.f32 * b.f32 + c.f32;
+ if ( pI->saturation_mode() ) {
+ if ( d.f32 < 0 ) d.f32 = 0;
+ else if ( d.f32 > 1.0f ) d.f32 = 1.0f;
+ }
+ fesetround( orig_rm );
+ break;
+ }
+ case F64_TYPE: case FF64_TYPE: {
+ assert( use_carry == false);
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+ d.f64 = a.f64 * b.f64 + c.f64;
+ if ( pI->saturation_mode() ) {
+ if ( d.f64 < 0 ) d.f64 = 0;
+ else if ( d.f64 > 1.0f ) d.f64 = 1.0;
+ }
+ fesetround( orig_rm );
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ thread->set_operand_value(dst, d, i_type, thread, pI, overflow, carry);
+}
+
+bool isNaN(float x)
+{
+ return std::isnan(x);
+}
+
+bool isNaN(double x)
+{
+ return std::isnan(x);
+}
+
+void max_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case U16_TYPE: d.u16 = MY_MAX_I(a.u16,b.u16); break;
+ case U32_TYPE: d.u32 = MY_MAX_I(a.u32,b.u32); break;
+ case U64_TYPE: d.u64 = MY_MAX_I(a.u64,b.u64); break;
+ case S16_TYPE: d.s16 = MY_MAX_I(a.s16,b.s16); break;
+ case S32_TYPE: d.s32 = MY_MAX_I(a.s32,b.s32); break;
+ case S64_TYPE: d.s64 = MY_MAX_I(a.s64,b.s64); break;
+ case F32_TYPE: d.f32 = MY_MAX_F(a.f32,b.f32); break;
+ case F64_TYPE: case FF64_TYPE: d.f64 = MY_MAX_F(a.f64,b.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void membar_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ // handled by timing simulator
+}
+
+void min_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case U16_TYPE: d.u16 = MY_MIN_I(a.u16,b.u16); break;
+ case U32_TYPE: d.u32 = MY_MIN_I(a.u32,b.u32); break;
+ case U64_TYPE: d.u64 = MY_MIN_I(a.u64,b.u64); break;
+ case S16_TYPE: d.s16 = MY_MIN_I(a.s16,b.s16); break;
+ case S32_TYPE: d.s32 = MY_MIN_I(a.s32,b.s32); break;
+ case S64_TYPE: d.s64 = MY_MIN_I(a.s64,b.s64); break;
+ case F32_TYPE: d.f32 = MY_MIN_F(a.f32,b.f32); break;
+ case F64_TYPE: case FF64_TYPE: d.f64 = MY_MIN_F(a.f64,b.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void mov_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ unsigned i_type = pI->get_type();
+
+ if( (src1.is_vector() || dst.is_vector()) && (i_type != BB64_TYPE) && (i_type != BB128_TYPE) && (i_type != FF64_TYPE) ) {
+ // pack or unpack operation
+ unsigned nbits_to_move;
+ ptx_reg_t tmp_bits;
+
+ switch( pI->get_type() ) {
+ case B16_TYPE: nbits_to_move = 16; break;
+ case B32_TYPE: nbits_to_move = 32; break;
+ case B64_TYPE: nbits_to_move = 64; break;
+ default: printf("Execution error: mov pack/unpack with unsupported type qualifier\n"); assert(0); break;
+ }
+
+ if( src1.is_vector() ) {
+ unsigned nelem = src1.get_vect_nelem();
+ ptx_reg_t v[4];
+ thread->get_vector_operand_values(src1, v, nelem );
+
+ unsigned bits_per_src_elem = nbits_to_move / nelem;
+ for( unsigned i=0; i < nelem; i++ ) {
+ switch(bits_per_src_elem) {
+ case 8: tmp_bits.u64 |= ((unsigned long long)(v[i].u8) << (8*i)); break;
+ case 16: tmp_bits.u64 |= ((unsigned long long)(v[i].u16) << (16*i)); break;
+ case 32: tmp_bits.u64 |= ((unsigned long long)(v[i].u32) << (32*i)); break;
+ default: printf("Execution error: mov pack/unpack with unsupported source/dst size ratio (src)\n"); assert(0); break;
+ }
+ }
+ } else {
+ data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ switch( pI->get_type() ) {
+ case B16_TYPE: tmp_bits.u16 = data.u16; break;
+ case B32_TYPE: tmp_bits.u32 = data.u32; break;
+ case B64_TYPE: tmp_bits.u64 = data.u64; break;
+ default: assert(0); break;
+ }
+ }
+
+ if( dst.is_vector() ) {
+ unsigned nelem = dst.get_vect_nelem();
+ ptx_reg_t v[4];
+ unsigned bits_per_dst_elem = nbits_to_move / nelem;
+ for( unsigned i=0; i < nelem; i++ ) {
+ switch(bits_per_dst_elem) {
+ case 8: v[i].u8 = (tmp_bits.u64 >> (8*i)) & ((unsigned long long) 0xFF); break;
+ case 16: v[i].u16 = (tmp_bits.u64 >> (16*i)) & ((unsigned long long) 0xFFFF); break;
+ case 32: v[i].u32 = (tmp_bits.u64 >> (32*i)) & ((unsigned long long) 0xFFFFFFFF); break;
+ default:
+ printf("Execution error: mov pack/unpack with unsupported source/dst size ratio (dst)\n");
+ assert(0);
+ break;
+ }
+ }
+ thread->set_vector_operand_values(dst,v[0],v[1],v[2],v[3]);
+ } else {
+ thread->set_operand_value(dst,tmp_bits, i_type, thread, pI);
+ }
+ } else if (i_type == PRED_TYPE and src1.is_literal() == true) {
+ // in ptx, literal input translate to predicate as 0 = false and 1 = true
+ // we have adopted the opposite to simplify implementation of zero flags in ptxplus
+ data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ ptx_reg_t finaldata;
+ finaldata.pred = (data.u32 == 0)? 1 : 0; // setting zero-flag in predicate
+ thread->set_operand_value(dst, finaldata, i_type, thread, pI);
+ } else {
+
+ data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+ thread->set_operand_value(dst, data, i_type, thread, pI);
+
+ }
+}
+
+void mul24_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ //src1_data = srcOperandModifiers(src1_data, src1, dst, i_type, thread);
+ //src2_data = srcOperandModifiers(src2_data, src2, dst, i_type, thread);
+
+ src1_data.mask_and(0,0x00FFFFFF);
+ src2_data.mask_and(0,0x00FFFFFF);
+
+ switch ( i_type ) {
+ case S32_TYPE:
+ if( src1_data.get_bit(23) )
+ src1_data.mask_or(0xFFFFFFFF,0xFF000000);
+ if( src2_data.get_bit(23) )
+ src2_data.mask_or(0xFFFFFFFF,0xFF000000);
+ data.s64 = src1_data.s64 * src2_data.s64;
+ break;
+ case U32_TYPE:
+ data.u64 = src1_data.u64 * src2_data.u64;
+ break;
+ default:
+ printf("GPGPU-Sim PTX: Execution error - type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ if ( pI->is_hi() ) {
+ data.u64 = data.u64 >> 16;
+ data.mask_and(0,0xFFFFFFFF);
+ } else if (pI->is_lo()) {
+ data.mask_and(0,0xFFFFFFFF);
+ }
+
+ thread->set_operand_value(dst, data, i_type, thread, pI);
+}
+
+void mul_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ ptx_reg_t d, t;
+
+ unsigned i_type = pI->get_type();
+ ptx_reg_t a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ unsigned rounding_mode = pI->rounding_mode();
+
+ switch ( i_type ) {
+ case S16_TYPE:
+ t.s32 = ((int)a.s16) * ((int)b.s16);
+ if ( pI->is_wide() ) d.s32 = t.s32;
+ else if ( pI->is_hi() ) d.s16 = (t.s32>>16);
+ else if ( pI->is_lo() ) d.s16 = t.s16;
+ else assert(0);
+ break;
+ case S32_TYPE:
+ t.s64 = ((long long)a.s32) * ((long long)b.s32);
+ if ( pI->is_wide() ) d.s64 = t.s64;
+ else if ( pI->is_hi() ) d.s32 = (t.s64>>32);
+ else if ( pI->is_lo() ) d.s32 = t.s32;
+ else assert(0);
+ break;
+ case S64_TYPE:
+ t.s64 = a.s64 * b.s64;
+ assert( !pI->is_wide() );
+ assert( !pI->is_hi() );
+ if ( pI->is_lo() ) d.s64 = t.s64;
+ else assert(0);
+ break;
+ case U16_TYPE:
+ t.u32 = ((unsigned)a.u16) * ((unsigned)b.u16);
+ if ( pI->is_wide() ) d.u32 = t.u32;
+ else if ( pI->is_lo() ) d.u16 = t.u16;
+ else if ( pI->is_hi() ) d.u16 = (t.u32>>16);
+ else assert(0);
+ break;
+ case U32_TYPE:
+ t.u64 = ((unsigned long long)a.u32) * ((unsigned long long)b.u32);
+ if ( pI->is_wide() ) d.u64 = t.u64;
+ else if ( pI->is_lo() ) d.u32 = t.u32;
+ else if ( pI->is_hi() ) d.u32 = (t.u64>>32);
+ else assert(0);
+ break;
+ case U64_TYPE:
+ t.u64 = a.u64 * b.u64;
+ assert( !pI->is_wide() );
+ assert( !pI->is_hi() );
+ if ( pI->is_lo() ) d.u64 = t.u64;
+ else assert(0);
+ break;
+ case F16_TYPE:
+ assert(0);
+ break;
+ case F32_TYPE: {
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+
+ d.f32 = a.f32 * b.f32;
+
+ if ( pI->saturation_mode() ) {
+ if ( d.f32 < 0 ) d.f32 = 0;
+ else if ( d.f32 > 1.0f ) d.f32 = 1.0f;
+ }
+ fesetround( orig_rm );
+ break;
+ }
+ case F64_TYPE: case FF64_TYPE:{
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+ d.f64 = a.f64 * b.f64;
+ if ( pI->saturation_mode() ) {
+ if ( d.f64 < 0 ) d.f64 = 0;
+ else if ( d.f64 > 1.0f ) d.f64 = 1.0;
+ }
+ fesetround( orig_rm );
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst, d, i_type, thread, pI);
+}
+
+void neg_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned to_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, to_type, thread, 1);
+
+
+ switch ( to_type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ data.s64 = 0 - src1_data.s64; break; // seems buggy, but not (just ignore higher bits)
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ assert(0); break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = 0.0f - src1_data.f32; break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = 0.0f - src1_data.f64; break;
+ default: assert(0); break;
+ }
+
+ thread->set_operand_value(dst,data, to_type, thread, pI);
+}
+
+//nandn bitwise negates second operand then bitwise nands with the first operand
+void nandn_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = (~src1_data.pred & src2_data.pred);
+ else
+ data.u64 = ~(src1_data.u64 & ~src2_data.u64);
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+
+}
+
+//norn bitwise negates first operand then bitwise ands with the second operand
+void norn_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = ~(src1_data.pred & ~(src2_data.pred));
+ else
+ data.u64 = ~(src1_data.u64) & src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+
+}
+
+void not_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case PRED_TYPE: d.pred = (~(a.pred) & 0x000F); break;
+ case B16_TYPE: d.u16 = ~a.u16; break;
+ case B32_TYPE: d.u32 = ~a.u32; break;
+ case B64_TYPE: d.u64 = ~a.u64; break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void or_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = ~(~(src1_data.pred) | ~(src2_data.pred));
+ else
+ data.u64 = src1_data.u64 | src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void orn_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = ~(~(src1_data.pred) | (src2_data.pred));
+ else
+ data.u64 = src1_data.u64 | ~src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void pmevent_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void popc_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src_data, data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ src_data = thread->get_operand_value(src, dst, i_type, thread, 1);
+
+ switch ( i_type ) {
+ case B32_TYPE: {
+ std::bitset<32> mask(src_data.u32);
+ data.u32 = mask.count();
+ } break;
+ case B64_TYPE: {
+ std::bitset<64> mask(src_data.u64);
+ data.u32 = mask.count();
+ } break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+void prefetch_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void prefetchu_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void prmt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void rcp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ data.f32 = 1.0f / src1_data.f32;
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ data.f64 = 1.0f / src1_data.f64;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void red_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void rem_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ data.u64 = src1_data.u64 % src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void ret_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ bool empty = thread->callstack_pop();
+ if( empty ) {
+ thread->set_done();
+ thread->exitCore();
+ thread->registerExit();
+ }
+}
+
+//Ptxplus version of ret instruction.
+void retp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ bool empty = thread->callstack_pop_plus();
+ if( empty ) {
+ thread->set_done();
+ thread->exitCore();
+ thread->registerExit();
+ }
+}
+
+void rsqrt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ if ( a.f32 < 0 ) {
+ d.u64 = 0;
+ d.u64 = 0x7fc00000; // NaN
+ } else if ( a.f32 == 0 ) {
+ d.u64 = 0;
+ d.u32 = 0x7f800000; // Inf
+ } else
+ d.f32 = cuda_math::__internal_accurate_fdividef(1.0f, sqrtf(a.f32));
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ if ( a.f32 < 0 ) {
+ d.u64 = 0;
+ d.u32 = 0x7fc00000; // NaN
+ float x = d.f32;
+ d.f64 = (double)x;
+ } else if ( a.f32 == 0 ) {
+ d.u64 = 0;
+ d.u32 = 0x7f800000; // Inf
+ float x = d.f32;
+ d.f64 = (double)x;
+ } else
+ d.f64 = 1.0 / sqrt(a.f64);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+#define SAD(d,a,b,c) d = c + ((a<b) ? (b-a) : (a-b))
+
+void sad_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, c, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ c = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case U16_TYPE: SAD(d.u16,a.u16,b.u16,c.u16); break;
+ case U32_TYPE: SAD(d.u32,a.u32,b.u32,c.u32); break;
+ case U64_TYPE: SAD(d.u64,a.u64,b.u64,c.u64); break;
+ case S16_TYPE: SAD(d.s16,a.s16,b.s16,c.s16); break;
+ case S32_TYPE: SAD(d.s32,a.s32,b.s32,c.s32); break;
+ case S64_TYPE: SAD(d.s64,a.s64,b.s64,c.s64); break;
+ case F32_TYPE: SAD(d.f32,a.f32,b.f32,c.f32); break;
+ case F64_TYPE: case FF64_TYPE: SAD(d.f64,a.f64,b.f64,c.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void selp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+
+ ptx_reg_t a, b, c, d;
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ c = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+ //predicate value was changed so the lowest bit being set means the zero flag is set.
+ //As a result, the value of c.pred must be inverted to get proper behavior
+ d = (!(c.pred & 0x0001))?a:b;
+
+ thread->set_operand_value(dst,d, PRED_TYPE, thread, pI);
+}
+
+bool isFloat(int type)
+{
+ switch ( type ) {
+ case F16_TYPE:
+ case F32_TYPE:
+ case F64_TYPE:
+ case FF64_TYPE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CmpOp( int type, ptx_reg_t a, ptx_reg_t b, unsigned cmpop )
+{
+ bool t = false;
+
+ switch ( type ) {
+ case B16_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u16 == b.u16); break;
+ case NE_OPTION: t = (a.u16 != b.u16); break;
+ default:
+ assert(0);
+ }
+
+ case B32_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u32 == b.u32); break;
+ case NE_OPTION: t = (a.u32 != b.u32); break;
+ default:
+ assert(0);
+ }
+ case B64_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u64 == b.u64); break;
+ case NE_OPTION: t = (a.u64 != b.u64); break;
+ default:
+ assert(0);
+ }
+ break;
+ case S8_TYPE:
+ case S16_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.s16 == b.s16); break;
+ case NE_OPTION: t = (a.s16 != b.s16); break;
+ case LT_OPTION: t = (a.s16 < b.s16); break;
+ case LE_OPTION: t = (a.s16 <= b.s16); break;
+ case GT_OPTION: t = (a.s16 > b.s16); break;
+ case GE_OPTION: t = (a.s16 >= b.s16); break;
+ default:
+ assert(0);
+ }
+ break;
+ case S32_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.s32 == b.s32); break;
+ case NE_OPTION: t = (a.s32 != b.s32); break;
+ case LT_OPTION: t = (a.s32 < b.s32); break;
+ case LE_OPTION: t = (a.s32 <= b.s32); break;
+ case GT_OPTION: t = (a.s32 > b.s32); break;
+ case GE_OPTION: t = (a.s32 >= b.s32); break;
+ default:
+ assert(0);
+ }
+ break;
+ case S64_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.s64 == b.s64); break;
+ case NE_OPTION: t = (a.s64 != b.s64); break;
+ case LT_OPTION: t = (a.s64 < b.s64); break;
+ case LE_OPTION: t = (a.s64 <= b.s64); break;
+ case GT_OPTION: t = (a.s64 > b.s64); break;
+ case GE_OPTION: t = (a.s64 >= b.s64); break;
+ default:
+ assert(0);
+ }
+ break;
+ case U8_TYPE:
+ case U16_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u16 == b.u16); break;
+ case NE_OPTION: t = (a.u16 != b.u16); break;
+ case LT_OPTION: t = (a.u16 < b.u16); break;
+ case LE_OPTION: t = (a.u16 <= b.u16); break;
+ case GT_OPTION: t = (a.u16 > b.u16); break;
+ case GE_OPTION: t = (a.u16 >= b.u16); break;
+ case LO_OPTION: t = (a.u16 < b.u16); break;
+ case LS_OPTION: t = (a.u16 <= b.u16); break;
+ case HI_OPTION: t = (a.u16 > b.u16); break;
+ case HS_OPTION: t = (a.u16 >= b.u16); break;
+ default:
+ assert(0);
+ }
+ break;
+ case U32_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u32 == b.u32); break;
+ case NE_OPTION: t = (a.u32 != b.u32); break;
+ case LT_OPTION: t = (a.u32 < b.u32); break;
+ case LE_OPTION: t = (a.u32 <= b.u32); break;
+ case GT_OPTION: t = (a.u32 > b.u32); break;
+ case GE_OPTION: t = (a.u32 >= b.u32); break;
+ case LO_OPTION: t = (a.u32 < b.u32); break;
+ case LS_OPTION: t = (a.u32 <= b.u32); break;
+ case HI_OPTION: t = (a.u32 > b.u32); break;
+ case HS_OPTION: t = (a.u32 >= b.u32); break;
+ default:
+ assert(0);
+ }
+ break;
+ case U64_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.u64 == b.u64); break;
+ case NE_OPTION: t = (a.u64 != b.u64); break;
+ case LT_OPTION: t = (a.u64 < b.u64); break;
+ case LE_OPTION: t = (a.u64 <= b.u64); break;
+ case GT_OPTION: t = (a.u64 > b.u64); break;
+ case GE_OPTION: t = (a.u64 >= b.u64); break;
+ case LO_OPTION: t = (a.u64 < b.u64); break;
+ case LS_OPTION: t = (a.u64 <= b.u64); break;
+ case HI_OPTION: t = (a.u64 > b.u64); break;
+ case HS_OPTION: t = (a.u64 >= b.u64); break;
+ default:
+ assert(0);
+ }
+ break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.f32 == b.f32) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case NE_OPTION: t = (a.f32 != b.f32) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case LT_OPTION: t = (a.f32 < b.f32 ) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case LE_OPTION: t = (a.f32 <= b.f32) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case GT_OPTION: t = (a.f32 > b.f32 ) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case GE_OPTION: t = (a.f32 >= b.f32) && !isNaN(a.f32) && !isNaN(b.f32); break;
+ case EQU_OPTION: t = (a.f32 == b.f32) || isNaN(a.f32) || isNaN(b.f32); break;
+ case NEU_OPTION: t = (a.f32 != b.f32) || isNaN(a.f32) || isNaN(b.f32); break;
+ case LTU_OPTION: t = (a.f32 < b.f32 ) || isNaN(a.f32) || isNaN(b.f32); break;
+ case LEU_OPTION: t = (a.f32 <= b.f32) || isNaN(a.f32) || isNaN(b.f32); break;
+ case GTU_OPTION: t = (a.f32 > b.f32 ) || isNaN(a.f32) || isNaN(b.f32); break;
+ case GEU_OPTION: t = (a.f32 >= b.f32) || isNaN(a.f32) || isNaN(b.f32); break;
+ case NUM_OPTION: t = !isNaN(a.f32) && !isNaN(b.f32); break;
+ case NAN_OPTION: t = isNaN(a.f32) || isNaN(b.f32); break;
+ default:
+ assert(0);
+ }
+ break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ switch (cmpop) {
+ case EQ_OPTION: t = (a.f64 == b.f64) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case NE_OPTION: t = (a.f64 != b.f64) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case LT_OPTION: t = (a.f64 < b.f64 ) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case LE_OPTION: t = (a.f64 <= b.f64) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case GT_OPTION: t = (a.f64 > b.f64 ) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case GE_OPTION: t = (a.f64 >= b.f64) && !isNaN(a.f64) && !isNaN(b.f64); break;
+ case EQU_OPTION: t = (a.f64 == b.f64) || isNaN(a.f64) || isNaN(b.f64); break;
+ case NEU_OPTION: t = (a.f64 != b.f64) || isNaN(a.f64) || isNaN(b.f64); break;
+ case LTU_OPTION: t = (a.f64 < b.f64 ) || isNaN(a.f64) || isNaN(b.f64); break;
+ case LEU_OPTION: t = (a.f64 <= b.f64) || isNaN(a.f64) || isNaN(b.f64); break;
+ case GTU_OPTION: t = (a.f64 > b.f64 ) || isNaN(a.f64) || isNaN(b.f64); break;
+ case GEU_OPTION: t = (a.f64 >= b.f64) || isNaN(a.f64) || isNaN(b.f64); break;
+ case NUM_OPTION: t = !isNaN(a.f64) && !isNaN(b.f64); break;
+ case NAN_OPTION: t = isNaN(a.f64) || isNaN(b.f64); break;
+ default:
+ assert(0);
+ }
+ break;
+ default: assert(0); break;
+ }
+
+ return t;
+}
+
+void setp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b;
+
+ int t=0;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ assert( pI->get_num_operands() < 4 ); // or need to deal with "c" operand / boolOp
+
+ unsigned type = pI->get_type();
+ unsigned cmpop = pI->get_cmpop();
+ a = thread->get_operand_value(src1, dst, type, thread, 1);
+ b = thread->get_operand_value(src2, dst, type, thread, 1);
+
+ t = CmpOp(type,a,b,cmpop);
+
+ ptx_reg_t data;
+
+ //the way ptxplus handles the zero flag, 1 = false and 0 = true
+ data.pred = (t==0); //inverting predicate since ptxplus uses "1" for a set zero flag
+
+ thread->set_operand_value(dst,data, PRED_TYPE, thread, pI);
+}
+
+void set_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b;
+
+ int t=0;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ assert( pI->get_num_operands() < 4 ); // or need to deal with "c" operand / boolOp
+
+ unsigned src_type = pI->get_type2();
+ unsigned cmpop = pI->get_cmpop();
+
+ a = thread->get_operand_value(src1, dst, src_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, src_type, thread, 1);
+
+ // Take abs of first operand if needed
+ if(pI->is_abs()) {
+ switch ( src_type ) {
+ case S16_TYPE: a.s16 = my_abs(a.s16); break;
+ case S32_TYPE: a.s32 = my_abs(a.s32); break;
+ case S64_TYPE: a.s64 = my_abs(a.s64); break;
+ case U16_TYPE: a.u16 = a.u16; break;
+ case U32_TYPE: a.u32 = my_abs(a.u32); break;
+ case U64_TYPE: a.u64 = my_abs(a.u64); break;
+ case F32_TYPE: a.f32 = my_abs(a.f32); break;
+ case F64_TYPE: case FF64_TYPE: a.f64 = my_abs(a.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+ }
+
+ t = CmpOp(src_type,a,b,cmpop);
+
+ ptx_reg_t data;
+ if ( isFloat(pI->get_type()) ) {
+ data.f32 = (t!=0)?1.0f:0.0f;
+ } else {
+ data.u32 = (t!=0)?0xFFFFFFFF:0;
+ }
+
+ thread->set_operand_value(dst, data, pI->get_type(), thread, pI);
+
+}
+
+void shfl_impl( const ptx_instruction *pI, core_t *core, warp_inst_t inst )
+{
+ unsigned i_type = pI->get_type();
+ int tid = inst.warp_id() * core->get_warp_size();
+ ptx_thread_info *thread = core->get_thread_info()[tid];
+ ptx_warp_info *warp_info = thread->m_warp_info;
+ int lane = warp_info->get_done_threads();
+ thread = core->get_thread_info()[tid + lane];
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ int bval = (thread->get_operand_value(src2, dst, i_type, thread, 1)).u32;
+ int cval = (thread->get_operand_value(src3, dst, i_type, thread, 1)).u32;
+ int mask = cval >> 8;
+ bval &= 0x1F;
+ cval &= 0x1F;
+
+ int maxLane = (lane & mask) | (cval & ~mask);
+ int minLane = lane & mask;
+
+ int src_idx;
+ unsigned p;
+ switch(pI->shfl_op()) {
+ case UP_OPTION:
+ src_idx = lane - bval;
+ p = (src_idx >= maxLane);
+ break;
+ case DOWN_OPTION:
+ src_idx = lane + bval;
+ p = (src_idx <= maxLane);
+ break;
+ case BFLY_OPTION:
+ src_idx = lane ^ bval;
+ p = (src_idx <= maxLane);
+ break;
+ case IDX_OPTION:
+ src_idx = minLane | (bval & ~mask);
+ p = (src_idx <= maxLane);
+ break;
+ default:
+ printf("GPGPU-Sim PTX: ERROR: Invalid shfl option\n");
+ assert(0);
+ break;
+ }
+ // copy from own lane
+ if (!p) src_idx = lane;
+
+ // copy input from lane src_idx
+ ptx_reg_t data;
+ if (inst.active(src_idx)) {
+ ptx_thread_info *source = core->get_thread_info()[tid + src_idx];
+ data = source->get_operand_value(src1, dst, i_type, source, 1);
+ } else {
+ printf("GPGPU-Sim PTX: WARNING: shfl input value unpredictable for inactive threads in a warp\n");
+ data.u32 = 0;
+ }
+ thread->set_operand_value(dst, data, i_type, thread, pI);
+
+ /*
+ TODO: deal with predicates appropriately using the following pseudocode:
+ if (!isGuardPredicateTrue(src_idx)) {
+ printf("GPGPU-Sim PTX: WARNING: shfl input value unpredictable for predicated-off threads in a warp\n");
+ }
+ if (dest predicate selected) data.pred = p;
+ */
+
+ // keep track of the number of threads that have executed in the warp
+ warp_info->inc_done_threads();
+ if (warp_info->get_done_threads() == inst.active_count()) {
+ warp_info->reset_done_threads();
+ }
+}
+
+void shl_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ switch ( i_type ) {
+ case B16_TYPE:
+ case U16_TYPE:
+ if ( b.u16 >= 16 )
+ d.u16 = 0;
+ else
+ d.u16 = (unsigned short) ((a.u16 << b.u16) & 0xFFFF);
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ if ( b.u32 >= 32 )
+ d.u32 = 0;
+ else
+ d.u32 = (unsigned) ((a.u32 << b.u32) & 0xFFFFFFFF);
+ break;
+ case B64_TYPE:
+ case U64_TYPE:
+ if ( b.u32 >= 64 )
+ d.u64 = 0;
+ else
+ d.u64 = (a.u64 << b.u64);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst, d, i_type, thread, pI);
+}
+
+void shr_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, b, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case U16_TYPE:
+ case B16_TYPE:
+ if ( b.u16 < 16 )
+ d.u16 = (unsigned short) ((a.u16 >> b.u16) & 0xFFFF);
+ else
+ d.u16 = 0;
+ break;
+ case U32_TYPE:
+ case B32_TYPE:
+ if ( b.u32 < 32 )
+ d.u32 = (unsigned) ((a.u32 >> b.u32) & 0xFFFFFFFF);
+ else
+ d.u32 = 0;
+ break;
+ case U64_TYPE:
+ case B64_TYPE:
+ if ( b.u32 < 64 )
+ d.u64 = (a.u64 >> b.u64);
+ else
+ d.u64 = 0;
+ break;
+ case S16_TYPE:
+ if ( b.u16 < 16 )
+ d.s64 = (a.s16 >> b.s16);
+ else {
+ if ( a.s16 < 0 ) {
+ d.s64 = -1;
+ } else {
+ d.s64 = 0;
+ }
+ }
+ break;
+ case S32_TYPE:
+ if ( b.u32 < 32 )
+ d.s64 = (a.s32 >> b.s32);
+ else {
+ if ( a.s32 < 0 ) {
+ d.s64 = -1;
+ } else {
+ d.s64 = 0;
+ }
+ }
+ break;
+ case S64_TYPE:
+ if ( b.u64 < 64 )
+ d.s64 = (a.s64 >> b.u64);
+ else {
+ if ( a.s64 < 0 ) {
+ if ( b.s32 < 0 ) {
+ d.u64 = -1;
+ d.s32 = 0;
+ } else {
+ d.s64 = -1;
+ }
+ } else {
+ d.s64 = 0;
+ }
+ }
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void sin_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ d.f32 = sin(a.f32);
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void slct_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+
+ ptx_reg_t a, b, c, d;
+
+ unsigned i_type = pI->get_type();
+ unsigned c_type = pI->get_type2();
+ bool t = false;
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ b = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ c = thread->get_operand_value(src3, dst, c_type, thread, 1);
+
+ switch ( c_type ) {
+ case S32_TYPE: t = c.s32 >= 0; break;
+ case F32_TYPE: t = c.f32 >= 0; break;
+ default: assert(0);
+ }
+
+ switch ( i_type ) {
+ case B16_TYPE:
+ case S16_TYPE:
+ case U16_TYPE: d.u16 = t?a.u16:b.u16; break;
+ case F32_TYPE:
+ case B32_TYPE:
+ case S32_TYPE:
+ case U32_TYPE: d.u32 = t?a.u32:b.u32; break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ case B64_TYPE:
+ case S64_TYPE:
+ case U64_TYPE: d.u64 = t?a.u64:b.u64; break;
+ default: assert(0);
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void sqrt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t a, d;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+
+ unsigned i_type = pI->get_type();
+ a = thread->get_operand_value(src1, dst, i_type, thread, 1);
+
+
+ switch ( i_type ) {
+ case F32_TYPE:
+ if ( a.f32 < 0 )
+ d.f32 = nanf("");
+ else
+ d.f32 = sqrt(a.f32); break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ if ( a.f64 < 0 )
+ d.f64 = nan("");
+ else
+ d.f64 = sqrt(a.f64); break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+
+ thread->set_operand_value(dst,d, i_type, thread, pI);
+}
+
+void ssy_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ //printf("Execution Warning: unimplemented ssy instruction is treated as a nop\n");
+ // TODO: add implementation
+}
+
+void st_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1(); //may be scalar or vector of regs
+ unsigned type = pI->get_type();
+ ptx_reg_t addr_reg = thread->get_operand_value(dst, dst, type, thread, 1);
+ ptx_reg_t data;
+ memory_space_t space = pI->get_space();
+ unsigned vector_spec = pI->get_vector();
+
+ memory_space *mem = NULL;
+ addr_t addr = addr_reg.u32;
+
+ decode_space(space,thread,dst,mem,addr);
+
+ size_t size;
+ int t;
+ type_info_key::type_decode(type,size,t);
+
+ if (!vector_spec) {
+ data = thread->get_operand_value(src1, dst, type, thread, 1);
+ mem->write(addr,size/8,&data.s64,thread,pI);
+ } else {
+ if (vector_spec == V2_TYPE) {
+ ptx_reg_t* ptx_regs = new ptx_reg_t[2];
+ thread->get_vector_operand_values(src1, ptx_regs, 2);
+ mem->write(addr,size/8,&ptx_regs[0].s64,thread,pI);
+ mem->write(addr+size/8,size/8,&ptx_regs[1].s64,thread,pI);
+ delete [] ptx_regs;
+ }
+ if (vector_spec == V3_TYPE) {
+ ptx_reg_t* ptx_regs = new ptx_reg_t[3];
+ thread->get_vector_operand_values(src1, ptx_regs, 3);
+ mem->write(addr,size/8,&ptx_regs[0].s64,thread,pI);
+ mem->write(addr+size/8,size/8,&ptx_regs[1].s64,thread,pI);
+ mem->write(addr+2*size/8,size/8,&ptx_regs[2].s64,thread,pI);
+ delete [] ptx_regs;
+ }
+ if (vector_spec == V4_TYPE) {
+ ptx_reg_t* ptx_regs = new ptx_reg_t[4];
+ thread->get_vector_operand_values(src1, ptx_regs, 4);
+ mem->write(addr,size/8,&ptx_regs[0].s64,thread,pI);
+ mem->write(addr+size/8,size/8,&ptx_regs[1].s64,thread,pI);
+ mem->write(addr+2*size/8,size/8,&ptx_regs[2].s64,thread,pI);
+ mem->write(addr+3*size/8,size/8,&ptx_regs[3].s64,thread,pI);
+ delete [] ptx_regs;
+ }
+ }
+ thread->m_last_effective_address = addr;
+ thread->m_last_memory_space = space;
+}
+
+void sub_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t data;
+ int overflow = 0;
+ int carry = 0;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ ptx_reg_t src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ //performs addition. Sets carry and overflow if needed.
+ //the constant is added in during subtraction so the carry bit is set properly.
+ switch ( i_type ) {
+ case S8_TYPE:
+ data.s64 = (src1_data.s64 & 0xFF) - (src2_data.s64 & 0xFF) + 0x100;
+ if(((src1_data.s64 & 0x80)-(src2_data.s64 & 0x80)) != 0) {overflow=((src1_data.s64 & 0x80)-(data.s64 & 0x80))==0?0:1; }
+ carry = (data.s32 & 0x100)>>8;
+ break;
+ case S16_TYPE:
+ data.s64 = (src1_data.s64 & 0xFFFF) - (src2_data.s64 & 0xFFFF) + 0x10000;
+ if(((src1_data.s64 & 0x8000)-(src2_data.s64 & 0x8000)) != 0) {overflow=((src1_data.s64 & 0x8000)-(data.s64 & 0x8000))==0?0:1; }
+ carry = (data.s32 & 0x10000)>>16;
+ break;
+ case S32_TYPE:
+ data.s64 = (src1_data.s64 & 0xFFFFFFFF) - (src2_data.s64 & 0xFFFFFFFF) + 0x100000000;
+ if(((src1_data.s64 & 0x80000000)-(src2_data.s64 & 0x80000000)) != 0) {overflow=((src1_data.s64 & 0x80000000)-(data.s64 & 0x80000000))==0?0:1; }
+ carry = ((data.u64)>>32) & 0x0001;
+ break;
+ case S64_TYPE:
+ data.s64 = src1_data.s64 - src2_data.s64; break;
+ case B8_TYPE:
+ case U8_TYPE:
+ data.u64 = (src1_data.u64 & 0xFF) - (src2_data.u64 & 0xFF) + 0x100;
+ carry = (data.u64 & 0x100)>>8;
+ break;
+ case B16_TYPE:
+ case U16_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFF) - (src2_data.u64 & 0xFFFF) + 0x10000;
+ carry = (data.u64 & 0x10000)>>16;
+ break;
+ case B32_TYPE:
+ case U32_TYPE:
+ data.u64 = (src1_data.u64 & 0xFFFFFFFF) - (src2_data.u64 & 0xFFFFFFFF) + 0x100000000;
+ carry = (data.u64 & 0x100000000)>>32;
+ break;
+ case B64_TYPE:
+ case U64_TYPE:
+ data.u64 = src1_data.u64 - src2_data.u64; break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = src1_data.f32 - src2_data.f32; break;
+ case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 - src2_data.f64; break;
+ default: assert(0); break;
+ }
+
+ thread->set_operand_value(dst,data, i_type, thread, pI, overflow, carry);
+}
+
+void nop_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ // Do nothing
+}
+
+void subc_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void suld_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void sured_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void sust_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void suq_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+ptx_reg_t* ptx_tex_regs = NULL;
+
+union intfloat {
+ int a;
+ float b;
+};
+
+float reduce_precision( float x, unsigned bits )
+{
+ intfloat tmp;
+ tmp.b = x;
+ int v = tmp.a;
+ int man = v & ((1<<23)-1);
+ int mask = ((1<<bits)-1) << (23-bits);
+ int nv = (v & ((-1)-((1<<23)-1))) | (mask&man);
+ tmp.a = nv;
+ float result = tmp.b;
+ return result;
+}
+
+unsigned wrap( unsigned x, unsigned y, unsigned mx, unsigned my, size_t elem_size )
+{
+ unsigned nx = (mx+x)%mx;
+ unsigned ny = (my+y)%my;
+ return nx + mx*ny;
+}
+
+unsigned clamp( unsigned x, unsigned y, unsigned mx, unsigned my, size_t elem_size )
+{
+ unsigned nx = x;
+ while (nx >= mx) nx -= elem_size;
+ unsigned ny = (y >= my)? my - 1 : y;
+ return nx + mx*ny;
+}
+
+typedef unsigned (*texAddr_t) (unsigned x, unsigned y, unsigned mx, unsigned my, size_t elem_size);
+float tex_linf_sampling(memory_space* mem, unsigned tex_array_base,
+ int x, int y, unsigned int width, unsigned int height, size_t elem_size,
+ float alpha, float beta, texAddr_t b_lim)
+{
+ float Tij;
+ float Ti1j;
+ float Tij1;
+ float Ti1j1;
+
+ mem->read(tex_array_base + b_lim(x,y,width,height,elem_size), 4, &Tij);
+ mem->read(tex_array_base + b_lim(x+elem_size,y,width,height,elem_size), 4, &Ti1j);
+ mem->read(tex_array_base + b_lim(x,y+1,width,height,elem_size), 4, &Tij1);
+ mem->read(tex_array_base + b_lim(x+elem_size,y+1,width,height,elem_size), 4, &Ti1j1);
+
+ float sample = (1-alpha)*(1-beta)*Tij +
+ alpha*(1-beta)*Ti1j +
+ (1-alpha)*beta*Tij1 +
+ alpha*beta*Ti1j1;
+
+ return sample;
+}
+
+float textureNormalizeElementSigned(int element, int bits)
+{
+ if (bits) {
+ int maxN = (1 << bits) - 1;
+ // removing upper bits
+ element &= maxN;
+ // normalizing the number to [-1.0,1.0]
+ maxN >>= 1;
+ float output = (float) element / maxN;
+ if (output < -1.0f) output = -1.0f;
+ return output;
+ } else {
+ return 0.0f;
+ }
+}
+
+float textureNormalizeElementUnsigned(unsigned int element, int bits)
+{
+ if (bits) {
+ unsigned int maxN = (1 << bits) - 1;
+ // removing upper bits and normalizing the number to [0.0,1.0]
+ return (float)(element & maxN) / maxN;
+ } else {
+ return 0.0f;
+ }
+}
+
+void textureNormalizeOutput( const struct cudaChannelFormatDesc& desc, ptx_reg_t& datax, ptx_reg_t& datay, ptx_reg_t& dataz, ptx_reg_t& dataw )
+{
+ if (desc.f == cudaChannelFormatKindSigned) {
+ datax.f32 = textureNormalizeElementSigned( datax.s32, desc.x );
+ datay.f32 = textureNormalizeElementSigned( datay.s32, desc.y );
+ dataz.f32 = textureNormalizeElementSigned( dataz.s32, desc.z );
+ dataw.f32 = textureNormalizeElementSigned( dataw.s32, desc.w );
+ } else if (desc.f == cudaChannelFormatKindUnsigned) {
+ datax.f32 = textureNormalizeElementUnsigned( datax.u32, desc.x );
+ datay.f32 = textureNormalizeElementUnsigned( datay.u32, desc.y );
+ dataz.f32 = textureNormalizeElementUnsigned( dataz.u32, desc.z );
+ dataw.f32 = textureNormalizeElementUnsigned( dataw.u32, desc.w );
+ } else {
+ assert(0 && "Undefined texture read mode: cudaReadModeNormalizedFloat expect integer elements");
+ }
+}
+
+void tex_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ unsigned dimension = pI->dimension();
+ const operand_info &dst = pI->dst(); //the registers to which fetched texel will be placed
+ const operand_info &src1 = pI->src1(); //the name of the texture
+ const operand_info &src2 = pI->src2(); //the vector registers containing coordinates of the texel to be fetched
+
+ std::string texname = src1.name();
+ unsigned to_type = pI->get_type();
+ unsigned c_type = pI->get_type2();
+ fflush(stdout);
+ ptx_reg_t data1, data2, data3, data4;
+ if (!ptx_tex_regs) ptx_tex_regs = new ptx_reg_t[4];
+ unsigned nelem = src2.get_vect_nelem();
+ thread->get_vector_operand_values(src2, ptx_tex_regs, nelem); //ptx_reg should be 4 entry vector type...coordinates into texture
+
+ gpgpu_t *gpu = thread->get_gpu();
+ const struct textureReference* texref = gpu->get_texref(texname);
+ const struct cudaArray* cuArray = gpu->get_texarray(texref);
+ const struct textureInfo* texInfo = gpu->get_texinfo(texref);
+ const struct textureReferenceAttr* texAttr = gpu->get_texattr(texref);
+
+ //assume always 2D f32 input
+ //access array with src2 coordinates
+ memory_space *mem = thread->get_global_memory();
+ float x_f32, y_f32;
+ size_t size;
+ int t;
+ unsigned tex_array_base;
+ unsigned int width = 0, height = 0;
+ int x = 0;
+ int y = 0;
+ unsigned tex_array_index;
+ float alpha=0, beta=0;
+
+ type_info_key::type_decode(to_type,size,t);
+ tex_array_base = cuArray->devPtr32;
+
+ switch (dimension) {
+ case GEOM_MODIFIER_1D:
+ width = cuArray->width;
+ height = cuArray->height;
+ if (texref->normalized) {
+ assert(c_type == F32_TYPE);
+ x_f32 = ptx_tex_regs[0].f32;
+ if (texref->addressMode[0] == cudaAddressModeClamp) {
+ x_f32 = (x_f32 > 1.0)? 1.0 : x_f32;
+ x_f32 = (x_f32 < 0.0)? 0.0 : x_f32;
+ } else if (texref->addressMode[0] == cudaAddressModeWrap) {
+ x_f32 = x_f32 - floor(x_f32);
+ }
+
+ if( texref->filterMode == cudaFilterModeLinear ) {
+ float xb = x_f32 * width - 0.5;
+ alpha = xb - floor(xb);
+ alpha = reduce_precision(alpha,9);
+ beta = 0.0;
+
+ x = (int)floor(xb);
+ y = 0;
+ } else {
+ x = (int) floor(x_f32 * width);
+ y = 0;
+ }
+ } else {
+ switch ( c_type ) {
+ case S32_TYPE:
+ x = ptx_tex_regs[0].s32;
+ assert(texref->filterMode == cudaFilterModePoint);
+ break;
+ case F32_TYPE:
+ x_f32 = ptx_tex_regs[0].f32;
+ alpha = x_f32 - floor(x_f32); // offset into subtexel (for linear sampling)
+ x = (int) x_f32;
+ break;
+ default: assert(0 && "Unsupported texture coordinate type.");
+ }
+ // handle texture fetch that exceeded boundaries
+ if (texref->addressMode[0] == cudaAddressModeClamp) {
+ x = (x > width - 1)? (width - 1) : x;
+ x = (x < 0)? 0 : x;
+ } else if (texref->addressMode[0] == cudaAddressModeWrap) {
+ x = x % width;
+ }
+ }
+ width *= (cuArray->desc.w+cuArray->desc.x+cuArray->desc.y+cuArray->desc.z)/8;
+ x *= (cuArray->desc.w+cuArray->desc.x+cuArray->desc.y+cuArray->desc.z)/8;
+ tex_array_index = tex_array_base + x;
+
+ break;
+ case GEOM_MODIFIER_2D:
+ width = cuArray->width;
+ height = cuArray->height;
+ if (texref->normalized) {
+ x_f32 = reduce_precision(ptx_tex_regs[0].f32,16);
+ y_f32 = reduce_precision(ptx_tex_regs[1].f32,15);
+
+ if (texref->addressMode[0]) {//clamp
+ if (x_f32<0) x_f32 = 0;
+ if (x_f32>=1) x_f32 = 1 - 1/x_f32;
+ } else {//wrap
+ x_f32 = x_f32 - floor(x_f32);
+ }
+ if (texref->addressMode[1]) {//clamp
+ if (y_f32<0) y_f32 = 0;
+ if (y_f32>=1) y_f32 = 1 - 1/y_f32;
+ } else {//wrap
+ y_f32 = y_f32 - floor(y_f32);
+ }
+
+ if( texref->filterMode == cudaFilterModeLinear ) {
+ float xb = x_f32 * width - 0.5;
+ float yb = y_f32 * height - 0.5;
+ alpha = xb - floor(xb);
+ beta = yb - floor(yb);
+ alpha = reduce_precision(alpha,9);
+ beta = reduce_precision(beta,9);
+
+ x = (int)floor(xb);
+ y = (int)floor(yb);
+ } else {
+ x = (int) floor(x_f32 * width);
+ y = (int) floor(y_f32 * height);
+ }
+ } else {
+ x_f32 = ptx_tex_regs[0].f32;
+ y_f32 = ptx_tex_regs[1].f32;
+
+ alpha = x_f32 - floor(x_f32);
+ beta = y_f32 - floor(y_f32);
+
+ x = (int) x_f32;
+ y = (int) y_f32;
+ if (texref->addressMode[0]) {//clamp
+ if (x<0) x = 0;
+ if (x>= (int)width) x = width-1;
+ } else {//wrap
+ x = x % width;
+ if (x < 0) x*= -1;
+ }
+ if (texref->addressMode[1]) {//clamp
+ if (y<0) y = 0;
+ if (y>= (int)height) y = height -1;
+ } else {//wrap
+ y = y % height;
+ if (y < 0) y *= -1;
+ }
+ }
+
+ width *= (cuArray->desc.w+cuArray->desc.x+cuArray->desc.y+cuArray->desc.z)/8;
+ x *= (cuArray->desc.w+cuArray->desc.x+cuArray->desc.y+cuArray->desc.z)/8;
+ tex_array_index = tex_array_base + (x + width*y);
+ break;
+ default:
+ assert(0); break;
+ }
+ switch ( to_type ) {
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case B8_TYPE:
+ case B16_TYPE:
+ case B32_TYPE:
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE: {
+ unsigned long long elementOffset = 0; // offset into the next element
+ mem->read( tex_array_index, cuArray->desc.x/8, &data1.u32);
+ elementOffset += cuArray->desc.x/8;
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index + elementOffset, cuArray->desc.y/8, &data2.u32);
+ elementOffset += cuArray->desc.y/8;
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index + elementOffset, cuArray->desc.z/8, &data3.u32);
+ elementOffset += cuArray->desc.z/8;
+ if (cuArray->desc.w)
+ mem->read( tex_array_index + elementOffset, cuArray->desc.w/8, &data4.u32);
+ }
+ }
+ break;
+ }
+ case B64_TYPE:
+ case U64_TYPE:
+ case S64_TYPE:
+ mem->read( tex_array_index, 8, &data1.u64);
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index+8, 8, &data2.u64);
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index+16, 8, &data3.u64);
+ if (cuArray->desc.w)
+ mem->read( tex_array_index+24, 8, &data4.u64);
+ }
+ }
+ break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: {
+ if( texref->filterMode == cudaFilterModeLinear ) {
+ texAddr_t b_lim = wrap;
+ if ( texref->addressMode[0] == cudaAddressModeClamp ) {
+ b_lim = clamp;
+ }
+ size_t elem_size = (cuArray->desc.x + cuArray->desc.y + cuArray->desc.z + cuArray->desc.w) / 8;
+ size_t elem_ofst = 0;
+
+ data1.f32 = tex_linf_sampling(mem, tex_array_base, x + elem_ofst, y, width, height, elem_size, alpha, beta, b_lim);
+ elem_ofst += cuArray->desc.x / 8;
+ if (cuArray->desc.y) {
+ data2.f32 = tex_linf_sampling(mem, tex_array_base, x + elem_ofst, y, width, height, elem_size, alpha, beta, b_lim);
+ elem_ofst += cuArray->desc.y / 8;
+ if (cuArray->desc.z) {
+ data3.f32 = tex_linf_sampling(mem, tex_array_base, x + elem_ofst, y, width, height, elem_size, alpha, beta, b_lim);
+ elem_ofst += cuArray->desc.z / 8;
+ if (cuArray->desc.w)
+ data4.f32 = tex_linf_sampling(mem, tex_array_base, x + elem_ofst, y, width, height, elem_size, alpha, beta, b_lim);
+ }
+ }
+ } else {
+ mem->read( tex_array_index, cuArray->desc.x/8, &data1.f32);
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index+4, cuArray->desc.y/8, &data2.f32);
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index+8, cuArray->desc.z/8, &data3.f32);
+ if (cuArray->desc.w)
+ mem->read( tex_array_index+12, cuArray->desc.w/8, &data4.f32);
+ }
+ }
+ }
+ } break;
+ case F64_TYPE:
+ case FF64_TYPE:
+ mem->read( tex_array_index, 8, &data1.f64);
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index+8, 8, &data2.f64);
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index+16, 8, &data3.f64);
+ if (cuArray->desc.w)
+ mem->read( tex_array_index+24, 8, &data4.f64);
+ }
+ }
+ break;
+ default: assert(0); break;
+ }
+ int x_block_coord, y_block_coord, memreqindex, blockoffset;
+
+ switch (dimension) {
+ case GEOM_MODIFIER_1D:
+ thread->m_last_effective_address = tex_array_index;
+ break;
+ case GEOM_MODIFIER_2D:
+ x_block_coord = x >> (texInfo->Tx_numbits + texInfo->texel_size_numbits);
+ y_block_coord = y >> texInfo->Ty_numbits;
+
+ memreqindex = ((y_block_coord*cuArray->width/texInfo->Tx)+x_block_coord)<<6;
+
+ blockoffset = (x%(texInfo->Tx*texInfo->texel_size) + (y%(texInfo->Ty)<<(texInfo->Tx_numbits + texInfo->texel_size_numbits)));
+ memreqindex += blockoffset;
+ thread->m_last_effective_address = tex_array_base + memreqindex;//tex_array_index;
+ break;
+ default:
+ assert(0);
+ }
+ thread->m_last_memory_space = tex_space;
+
+ // normalize output into floating point numbers according to the texture read mode
+ if (texAttr->m_readmode == cudaReadModeNormalizedFloat) {
+ textureNormalizeOutput(cuArray->desc, data1, data2, data3, data4);
+ } else {
+ assert(texAttr->m_readmode == cudaReadModeElementType);
+ }
+
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4);
+}
+
+void txq_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void trap_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vabsdiff_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vadd_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vmad_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vmax_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vmin_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vset_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vshl_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vshr_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void vsub_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+void vote_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ static bool first_in_warp = true;
+ static bool and_all;
+ static bool or_all;
+ static unsigned int ballot_result;
+ static std::list<ptx_thread_info*> threads_in_warp;
+ static unsigned last_tid;
+
+ if( first_in_warp ) {
+ first_in_warp = false;
+ threads_in_warp.clear();
+ and_all = true;
+ or_all = false;
+ ballot_result = 0;
+ int offset=31;
+ while( (offset>=0) && !pI->active(offset) )
+ offset--;
+ assert( offset >= 0 );
+ last_tid = (thread->get_hw_tid() - (thread->get_hw_tid()%pI->warp_size())) + offset;
+ }
+
+ ptx_reg_t src1_data;
+ const operand_info &src1 = pI->src1();
+ src1_data = thread->get_operand_value(src1, pI->dst(), PRED_TYPE, thread, 1);
+
+ //predicate value was changed so the lowest bit being set means the zero flag is set.
+ //As a result, the value of src1_data.pred must be inverted to get proper behavior
+ bool pred_value = !(src1_data.pred & 0x0001);
+ bool invert = src1.is_neg_pred();
+
+ threads_in_warp.push_back(thread);
+ and_all &= (invert ^ pred_value);
+ or_all |= (invert ^ pred_value);
+
+ // vote.ballot
+ if (invert ^ pred_value) {
+ int lane_id = thread->get_hw_tid() % pI->warp_size();
+ ballot_result |= (1 << lane_id);
+ }
+
+ if( thread->get_hw_tid() == last_tid ) {
+ if (pI->vote_mode() == ptx_instruction::vote_ballot) {
+ ptx_reg_t data = ballot_result;
+ for( std::list<ptx_thread_info*>::iterator t=threads_in_warp.begin(); t!=threads_in_warp.end(); ++t ) {
+ const operand_info &dst = pI->dst();
+ (*t)->set_operand_value(dst,data, pI->get_type(), (*t), pI);
+ }
+ } else {
+ bool pred_value = false;
+
+ switch( pI->vote_mode() ) {
+ case ptx_instruction::vote_any: pred_value = or_all; break;
+ case ptx_instruction::vote_all: pred_value = and_all; break;
+ case ptx_instruction::vote_uni: pred_value = (or_all ^ and_all); break;
+ default:
+ abort();
+ }
+ ptx_reg_t data;
+ data.pred = pred_value?0:1; //the way ptxplus handles the zero flag, 1 = false and 0 = true
+
+ for( std::list<ptx_thread_info*>::iterator t=threads_in_warp.begin(); t!=threads_in_warp.end(); ++t ) {
+ const operand_info &dst = pI->dst();
+ (*t)->set_operand_value(dst,data, PRED_TYPE, (*t), pI);
+ }
+ }
+ first_in_warp = true;
+ }
+}
+
+void xor_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+
+ //the way ptxplus handles predicates: 1 = false and 0 = true
+ if(i_type == PRED_TYPE)
+ data.pred = ~(~(src1_data.pred) ^ ~(src2_data.pred));
+ else
+ data.u64 = src1_data.u64 ^ src2_data.u64;
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+}
+
+void inst_not_implemented( const ptx_instruction * pI )
+{
+ printf("GPGPU-Sim PTX: ERROR (%s:%u) instruction \"%s\" not (yet) implemented\n",
+ pI->source_file(),
+ pI->source_line(),
+ pI->get_opcode_cstr() );
+ abort();
+}
+
+ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, operand_info dstInfo, unsigned type, ptx_thread_info *thread)
+{
+ ptx_reg_t result;
+ memory_space *mem = NULL;
+ size_t size;
+ int t;
+ result.u64=0;
+
+ //complete other cases for reading from memory, such as reading from other const memory
+ if(opInfo.get_addr_space() == global_space)
+ {
+ mem = thread->get_global_memory();
+ type_info_key::type_decode(type,size,t);
+ mem->read(opData.u32,size/8,&result.u64);
+ if( type == S16_TYPE || type == S32_TYPE )
+ sign_extend(result,size,dstInfo);
+ }
+ else if(opInfo.get_addr_space() == shared_space)
+ {
+ mem = thread->m_shared_mem;
+ type_info_key::type_decode(type,size,t);
+ mem->read(opData.u32,size/8,&result.u64);
+
+ if( type == S16_TYPE || type == S32_TYPE )
+ sign_extend(result,size,dstInfo);
+
+ }
+ else if(opInfo.get_addr_space() == const_space)
+ {
+ mem = thread->get_global_memory();
+ type_info_key::type_decode(type,size,t);
+
+ mem->read((opData.u32 + opInfo.get_const_mem_offset()),size/8,&result.u64);
+
+ if( type == S16_TYPE || type == S32_TYPE )
+ sign_extend(result,size,dstInfo);
+ }
+ else
+ {
+ result = opData;
+ }
+
+ if(opInfo.get_operand_lohi() == 1)
+ {
+ result.u64 = result.u64 & 0xFFFF;
+ }
+ else if(opInfo.get_operand_lohi() == 2)
+ {
+ result.u64 = (result.u64>>16) & 0xFFFF;
+ }
+
+ if(opInfo.get_operand_neg() == true) {
+ result.f32 = -result.f32;
+ }
+
+ return result;
+}
+
diff --git a/src/cuda-sim/ptx_loader.cc~ b/src/cuda-sim/ptx_loader.cc~
new file mode 100644
index 0000000..c922b18
--- /dev/null
+++ b/src/cuda-sim/ptx_loader.cc~
@@ -0,0 +1,462 @@
+// Copyright (c) 2009-2011, Tor M. Aamodt
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "ptx_loader.h"
+#include "ptx_ir.h"
+#include "cuda-sim.h"
+#include "ptx_parser.h"
+#include <unistd.h>
+#include <dirent.h>
+#include <fstream>
+#include <sstream>
+
+/// globals
+
+memory_space *g_global_mem;
+memory_space *g_tex_mem;
+memory_space *g_surf_mem;
+memory_space *g_param_mem;
+bool g_override_embedded_ptx = false;
+
+/// extern prototypes
+
+extern int ptx_parse();
+extern int ptx__scan_string(const char*);
+
+extern std::map<unsigned,const char*> get_duplicate();
+
+const char *g_ptxinfo_filename;
+extern int ptxinfo_parse();
+extern int ptxinfo_debug;
+extern FILE *ptxinfo_in;
+
+static bool g_save_embedded_ptx;
+bool g_keep_intermediate_files;
+bool m_ptx_save_converted_ptxplus;
+
+bool keep_intermediate_files() {return g_keep_intermediate_files;}
+
+void ptx_reg_options(option_parser_t opp)
+{
+ option_parser_register(opp, "-save_embedded_ptx", OPT_BOOL, &g_save_embedded_ptx,
+ "saves ptx files embedded in binary as <n>.ptx",
+ "0");
+ option_parser_register(opp, "-keep", OPT_BOOL, &g_keep_intermediate_files,
+ "keep intermediate files created by GPGPU-Sim when interfacing with external programs",
+ "0");
+ option_parser_register(opp, "-gpgpu_ptx_save_converted_ptxplus", OPT_BOOL,
+ &m_ptx_save_converted_ptxplus,
+ "Saved converted ptxplus to a file",
+ "0");
+}
+
+void print_ptx_file( const char *p, unsigned source_num, const char *filename )
+{
+ printf("\nGPGPU-Sim PTX: file _%u.ptx contents:\n\n", source_num );
+ char *s = strdup(p);
+ char *t = s;
+ unsigned n=1;
+ while ( *t != '\0' ) {
+ char *u = t;
+ while ( (*u != '\n') && (*u != '\0') ) u++;
+ unsigned last = (*u == '\0');
+ *u = '\0';
+ const ptx_instruction *pI = ptx_instruction_lookup(filename,n);
+ char pc[64];
+ if( pI && pI->get_PC() )
+ snprintf(pc,64,"%4u", pI->get_PC() );
+ else
+ snprintf(pc,64," ");
+ printf(" _%u.ptx %4u (pc=%s): %s\n", source_num, n, pc, t );
+ if ( last ) break;
+ t = u+1;
+ n++;
+ }
+ free(s);
+ fflush(stdout);
+}
+
+char* gpgpu_ptx_sim_convert_ptx_and_sass_to_ptxplus(const std::string ptxfilename, const std::string elffilename, const std::string sassfilename)
+{
+
+ printf("GPGPU-Sim PTX: converting EMBEDDED .ptx file to ptxplus \n");
+
+ char fname_ptxplus[1024];
+ snprintf(fname_ptxplus,1024,"_ptxplus_XXXXXX");
+ int fd4=mkstemp(fname_ptxplus);
+ close(fd4);
+
+ // Run cuobjdump_to_ptxplus
+ char commandline[1024];
+ int result;
+ snprintf(commandline, 1024, "$GPGPUSIM_ROOT/build/$GPGPUSIM_CONFIG/cuobjdump_to_ptxplus/cuobjdump_to_ptxplus %s %s %s %s",
+ ptxfilename.c_str(),
+ sassfilename.c_str(),
+ elffilename.c_str(),
+ fname_ptxplus);
+ fflush(stdout);
+ printf("GPGPU-Sim PTX: calling cuobjdump_to_ptxplus\ncommandline: %s\n", commandline);
+ result = system(commandline);
+ if(result){printf("GPGPU-Sim PTX: ERROR ** could not execute %s\n", commandline); exit(1);}
+
+
+ // Get ptxplus from file
+ std::ifstream fileStream(fname_ptxplus, std::ios::in);
+ std::string text, line;
+ while(getline(fileStream,line)) {
+ text += (line + "\n");
+ }
+ fileStream.close();
+
+ char* ptxplus_str = new char [strlen(text.c_str())+1];
+ strcpy(ptxplus_str, text.c_str());
+
+ if (!m_ptx_save_converted_ptxplus){
+ char rm_commandline[1024];
+
+ snprintf(rm_commandline,1024,"rm -f %s", fname_ptxplus);
+
+ printf("GPGPU-Sim PTX: removing temporary files using \"%s\"\n", rm_commandline);
+ int rm_result = system(rm_commandline);
+ if( rm_result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while removing temporary files %d\n", rm_result);
+ exit(1);
+ }
+ }
+ printf("GPGPU-Sim PTX: DONE converting EMBEDDED .ptx file to ptxplus \n");
+
+ return ptxplus_str;
+}
+
+
+symbol_table *gpgpu_ptx_sim_load_ptx_from_string( const char *p, unsigned source_num )
+{
+ char buf[1024];
+ snprintf(buf,1024,"_%u.ptx", source_num );
+ if( g_save_embedded_ptx ) {
+ FILE *fp = fopen(buf,"w");
+ fprintf(fp,"%s",p);
+ fclose(fp);
+ }
+ symbol_table *symtab=init_parser(buf);
+ ptx__scan_string(p);
+ int errors = ptx_parse ();
+ if ( errors ) {
+ char fname[1024];
+ snprintf(fname,1024,"_ptx_errors_XXXXXX");
+ int fd=mkstemp(fname);
+ close(fd);
+ printf("GPGPU-Sim PTX: parser error detected, exiting... but first extracting .ptx to \"%s\"\n", fname);
+ FILE *ptxfile = fopen(fname,"w");
+ fprintf(ptxfile,"%s", p );
+ fclose(ptxfile);
+ abort();
+ exit(40);
+ }
+
+ //if ( g_debug_execution >= 100 )
+ print_ptx_file(p,source_num,buf);
+
+ printf("GPGPU-Sim PTX: finished parsing EMBEDDED .ptx file %s\n",buf);
+ return symtab;
+}
+
+void fix_duplicate_errors(char fname2[1024]) {
+ char tempfile[1024] = "_temp_ptx";
+ char commandline[1024];
+
+ // change the name of the ptx file to _temp_ptx
+ snprintf(commandline,1024,"mv %s %s",fname2,tempfile);
+ printf("Running: %s\n", commandline);
+ int result = system(commandline);
+ if (result != 0) {
+ printf("GPGPU-Sim PTX: ERROR ** while changing filename from %s to %s", fname2, tempfile);
+ exit(1);
+ }
+
+ // store all of the ptx into a char array
+ FILE *ptxsource = fopen(tempfile,"r");
+ fseek(ptxsource, 0, SEEK_END);
+ long filesize = ftell(ptxsource);
+ rewind(ptxsource);
+ char *ptxdata = (char*)malloc((filesize+1)*sizeof(char));
+ fread(ptxdata, filesize, 1, ptxsource);
+ fclose(ptxsource);
+
+ FILE *ptxdest = fopen(fname2,"w");
+ std::map<unsigned,const char*> duplicate = get_duplicate();
+ unsigned offset;
+ unsigned oldlinenum = 1;
+ unsigned linenum;
+ char *startptr = ptxdata;
+ char *funcptr;
+ char *tempptr = ptxdata - 1;
+ char *lineptr = ptxdata - 1;
+
+ // recreate the ptx file without duplications
+ for ( std::map<unsigned,const char*>::iterator iter = duplicate.begin();
+ iter != duplicate.end();
+ iter++){
+ // find the line of the next error
+ linenum = iter->first;
+ for (int i = oldlinenum; i < linenum; i++) {
+ lineptr = strchr(lineptr + 1, '\n');
+ }
+
+ // find the end of the current section to be copied over
+ // then find the start of the next section that will be copied
+ if (strcmp("function", iter->second) == 0) {
+ // get location of most recent .func
+ while (tempptr < lineptr && tempptr != NULL) {
+ funcptr = tempptr;
+ tempptr = strstr(funcptr + 1, ".func");
+ }
+
+ // get the start of the previous line
+ offset = 0;
+ while (*(funcptr - offset) != '\n') offset++;
+
+ fwrite(startptr, sizeof(char), funcptr - offset + 1 - startptr, ptxdest);
+
+ //find next location of startptr
+ if (*(lineptr + 3) == ';') {
+ // for function definitions
+ startptr = lineptr + 5;
+ } else if (*(lineptr + 3) == '{') {
+ // for functions enclosed with curly brackets
+ offset = 5;
+ unsigned bracket = 1;
+ while (bracket != 0) {
+ if (*(lineptr + offset) == '{') bracket++;
+ else if (*(lineptr + offset) == '}') bracket--;
+ offset++;
+ }
+ startptr = lineptr + offset + 1;
+ } else {
+ printf("GPGPU-Sim PTX: ERROR ** Unrecognized function format\n");
+ abort();
+ }
+ } else if (strcmp("variable", iter->second) == 0) {
+ fwrite(startptr, sizeof(char), (int)(lineptr + 1 - startptr), ptxdest);
+
+ //find next location of startptr
+ offset = 1;
+ while (*(lineptr + offset) != '\n') offset++;
+ startptr = lineptr + offset + 1;
+ } else {
+ printf("GPGPU-Sim PTX: ERROR ** Unsupported duplicate type: %s\n", iter->second);
+ }
+
+ oldlinenum = linenum;
+ }
+ // copy over the rest of the file
+ fwrite(startptr, sizeof(char), ptxdata + filesize - startptr, ptxdest);
+
+ // cleanup
+ free(ptxdata);
+ fclose(ptxdest);
+ snprintf(commandline,1024,"rm -f %s",tempfile);
+ printf("Running: %s\n", commandline);
+ result = system(commandline);
+ if (result != 0) {
+ printf("GPGPU-Sim PTX: ERROR ** while deleting %s", tempfile);
+ exit(1);
+ }
+}
+
+//we need the application name here too.
+char* get_app_binary_name(){
+ char exe_path[1025];
+ char *self_exe_path;
+#ifdef __APPLE__
+ //AMRUTH: get apple device and check the result.
+ printf("WARNING: not tested for Apple-mac devices \n");
+ abort();
+#else
+ std::stringstream exec_link;
+ exec_link << "/proc/self/exe";
+ ssize_t path_length = readlink(exec_link.str().c_str(), exe_path, 1024);
+ assert(path_length != -1);
+ exe_path[path_length] = '\0';
+
+ char *token = strtok(exe_path, "/");
+ while(token !=NULL){
+ self_exe_path = token;
+ token = strtok(NULL,"/");
+ }
+#endif
+ self_exe_path = strtok(self_exe_path, ".");
+ printf("self exe links to: %s\n", self_exe_path);
+ return self_exe_path;
+}
+
+void gpgpu_ptxinfo_load_from_string( const char *p_for_info, unsigned source_num, unsigned sm_version )
+{
+ //do ptxas for individual files instead of one big embedded ptx. This prevents the duplicate defs and declarations.
+ char ptx_file[1000];
+ char *name=get_app_binary_name();
+ char commandline[4096], fname[1024], fname2[1024], final_tempfile_ptxinfo[1024], tempfile_ptxinfo[1024];
+ for (int index=1; index <= no_of_ptx; index++){
+ snprintf(ptx_file, 1000, "%s.%d.sm_%u.ptx", name, index, sm_version);
+ snprintf(fname,1024,"_ptx_XXXXXX");
+ int fd=mkstemp(fname);
+ close(fd);
+
+ printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname);
+ snprintf(commandline,4096,"cat %s > %s",ptx_file, fname);
+ if (system(commandline) !=0) {
+ printf("ERROR: %s command failed\n", commandline);
+ exit(0);
+ }
+
+ snprintf(fname2,1024,"_ptx2_XXXXXX");
+ fd=mkstemp(fname2);
+ close(fd);
+ char commandline2[4096];
+ snprintf(commandline2,4096,"cat %s | sed 's/.version 1.5/.version 1.4/' | sed 's/, texmode_independent//' | sed 's/\\(\\.extern \\.const\\[1\\] .b8 \\w\\+\\)\\[\\]/\\1\\[1\\]/' | sed 's/const\\[.\\]/const\\[0\\]/g' > %s", fname, fname2);
+ printf("Running: %s\n", commandline2);
+ int result = system(commandline2);
+ if( result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while loading PTX (a) %d\n", result);
+ printf(" Ensure you have write access to simulation directory\n");
+ printf(" and have \'cat\' and \'sed\' in your path.\n");
+ exit(1);
+ }
+
+ snprintf(tempfile_ptxinfo,1024,"%sinfo",fname);
+ char extra_flags[1024];
+ extra_flags[0]=0;
+
+ #if CUDART_VERSION >= 3000
+ if (sm_version == 0) sm_version = 20;
+ extern bool g_cdp_enabled;
+ if(!g_cdp_enabled)
+ snprintf(extra_flags,1024,"--gpu-name=sm_%u",sm_version);
+ else
+ snprintf(extra_flags,1024,"--compile-only --gpu-name=sm_%u",sm_version);
+ #endif
+
+ snprintf(commandline,1024,"$CUDA_INSTALL_PATH/bin/ptxas %s -v %s --output-file /dev/null 2> %s",
+ extra_flags, fname2, tempfile_ptxinfo);
+ printf("GPGPU-Sim PTX: generating ptxinfo using \"%s\"\n", commandline);
+ result = system(commandline);
+ if( result != 0 ) {
+ // 65280 = duplicate errors
+ if (result == 65280) {
+ ptxinfo_in = fopen(tempfile_ptxinfo,"r");
+ g_ptxinfo_filename = tempfile_ptxinfo;
+ ptxinfo_parse();
+
+ fix_duplicate_errors(fname2);
+ snprintf(commandline,1024,"$CUDA_INSTALL_PATH/bin/ptxas %s -v %s --output-file /dev/null 2> %s",
+ extra_flags, fname2, tempfile_ptxinfo);
+ printf("GPGPU-Sim PTX: regenerating ptxinfo using \"%s\"\n", commandline);
+ result = system(commandline);
+ }
+ if (result != 0) {
+ printf("GPGPU-Sim PTX: ERROR ** while loading PTX (b) %d\n", result);
+ printf(" Ensure ptxas is in your path.\n");
+ exit(1);
+ }
+ }
+ }
+
+ //TODO: duplicate code! move it into a function so that it can be reused!
+ if(no_of_ptx==0) {
+ //For CDP, we dump everything. So no_of_ptx will be 0.
+ snprintf(fname,1024,"_ptx_XXXXXX");
+ int fd=mkstemp(fname);
+ close(fd);
+
+ printf("GPGPU-Sim PTX: extracting embedded .ptx to temporary file \"%s\"\n", fname);
+ FILE *ptxfile = fopen(fname,"w");
+ fprintf(ptxfile,"%s", p_for_info);
+ fclose(ptxfile);
+
+ snprintf(fname2,1024,"_ptx2_XXXXXX");
+ fd=mkstemp(fname2);
+ close(fd);
+ char commandline2[4096];
+ snprintf(commandline2,4096,"cat %s | sed 's/.version 1.5/.version 1.4/' | sed 's/, texmode_independent//' | sed 's/\\(\\.extern \\.const\\[1\\] .b8 \\w\\+\\)\\[\\]/\\1\\[1\\]/' | sed 's/const\\[.\\]/const\\[0\\]/g' > %s", fname, fname2);
+ printf("Running: %s\n", commandline2);
+ int result = system(commandline2);
+ if( result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while loading PTX (a) %d\n", result);
+ printf(" Ensure you have write access to simulation directory\n");
+ printf(" and have \'cat\' and \'sed\' in your path.\n");
+ exit(1);
+ }
+ //char tempfile_ptxinfo[1024];
+ snprintf(tempfile_ptxinfo,1024,"%sinfo",fname);
+ char extra_flags[1024];
+ extra_flags[0]=0;
+#if CUDART_VERSION >= 3000
+ snprintf(extra_flags,1024,"--gpu-name=sm_%u",sm_version);
+#endif
+
+ snprintf(commandline,1024,"$CUDA_INSTALL_PATH/bin/ptxas %s -v %s --output-file /dev/null 2> %s",
+ extra_flags, fname2, tempfile_ptxinfo);
+ printf("GPGPU-Sim PTX: generating ptxinfo using \"%s\"\n", commandline);
+ result = system(commandline);
+ if( result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while loading PTX (b) %d\n", result);
+ printf(" Ensure ptxas is in your path.\n");
+ exit(1);
+ }
+ }
+
+ //Now that we got resource usage per kernel in a ptx file, we dump all into one file and pass it to rest of the code as usual.
+ if(no_of_ptx>0){
+ char commandline3[4096];
+ snprintf(final_tempfile_ptxinfo,1024,"f_tempfile_ptx");
+ snprintf(commandline3,4096, "cat *info > %s", final_tempfile_ptxinfo);
+ if (system(commandline3)!=0) {
+ printf("ERROR: Either we dont have info files or cat is not working \n");
+ printf("ERROR: %s command failed\n",commandline3);
+ exit(1);
+ }
+ }
+
+ ptxinfo_in = fopen(final_tempfile_ptxinfo,"r");
+ if(no_of_ptx>0)
+ g_ptxinfo_filename = final_tempfile_ptxinfo;
+ else
+ g_ptxinfo_filename = tempfile_ptxinfo;
+ ptxinfo_parse();
+
+ if( ! g_save_embedded_ptx ) {
+ if(no_of_ptx>0)
+ snprintf(commandline,1024,"rm -f %s %s %s *info", fname, fname2, final_tempfile_ptxinfo);
+ else
+ snprintf(commandline,1024,"rm -f %s %s %s *info", fname, fname2, tempfile_ptxinfo);
+ printf("GPGPU-Sim PTX: removing ptxinfo using \"%s\"\n", commandline);
+ if( system(commandline) != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while removing temporary files\n");
+ exit(1);
+ }
+ }
+}