summaryrefslogtreecommitdiff
path: root/src/cuda-sim
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-07-15 18:09:46 -0800
committerTor Aamodt <[email protected]>2010-07-15 18:09:46 -0800
commit69f2911e04ffb1b19eef1fafb8c040af271f656e (patch)
tree231d3b6bdc3a202f7c255bfcf7bf2c36e32cee9e /src/cuda-sim
creating branch for adding support for CUDA 3.x and Fermi
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 6829]
Diffstat (limited to 'src/cuda-sim')
-rw-r--r--src/cuda-sim/Makefile170
-rw-r--r--src/cuda-sim/cuda-math.h81
-rw-r--r--src/cuda-sim/cuda-sim.cc2195
-rw-r--r--src/cuda-sim/dram_callback.h84
-rw-r--r--src/cuda-sim/instructions.cc2921
-rw-r--r--src/cuda-sim/memory.cc154
-rw-r--r--src/cuda-sim/memory.h148
-rw-r--r--src/cuda-sim/opcodes.def120
-rw-r--r--src/cuda-sim/opcodes.h82
-rw-r--r--src/cuda-sim/ptx-stats.cc298
-rw-r--r--src/cuda-sim/ptx-stats.h92
-rw-r--r--src/cuda-sim/ptx.l336
-rw-r--r--src/cuda-sim/ptx.y470
-rw-r--r--src/cuda-sim/ptx_ir.cc1283
-rw-r--r--src/cuda-sim/ptx_ir.h1223
-rw-r--r--src/cuda-sim/ptx_sim.cc432
-rw-r--r--src/cuda-sim/ptx_sim.h457
-rw-r--r--src/cuda-sim/ptxinfo.l128
-rw-r--r--src/cuda-sim/ptxinfo.y140
19 files changed, 10814 insertions, 0 deletions
diff --git a/src/cuda-sim/Makefile b/src/cuda-sim/Makefile
new file mode 100644
index 0000000..c0d245d
--- /dev/null
+++ b/src/cuda-sim/Makefile
@@ -0,0 +1,170 @@
+# Copyright (c) 2009 by Tor M. Aamodt and the University of British Columbia
+# Vancouver, BC V6T 1Z4
+# All Rights Reserved.
+#
+# THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+# TERMS AND CONDITIONS.
+#
+# 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 OWNERS 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.
+#
+# NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+# are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+# (property of NVIDIA). The files benchmarks/BlackScholes/ and
+# benchmarks/template/ are derived from the CUDA SDK available from
+# http://www.nvidia.com/cuda (also property of NVIDIA). The files
+# src/gpgpusim_entrypoint.c and src/simplesim-3.0/ are derived from the
+# SimpleScalar Toolset available from http://www.simplescalar.com/
+# (property of SimpleScalar LLC) and the files src/intersim/ are derived
+# from Booksim (Simulator provided with the textbook "Principles and
+# Practices of Interconnection Networks" available from
+# http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+# the corresponding legal terms and conditions set forth separately (original
+# copyright notices are left in files from these sources and where we have
+# modified a file our copyright notice appears before the original copyright
+# notice).
+#
+# Using this version of GPGPU-Sim requires a complete installation of CUDA
+# which is distributed seperately by NVIDIA under separate terms and
+# conditions.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. 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.
+#
+# 3. 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.
+#
+# 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+#
+# 5. No nonprofit user may place any restrictions on the use of this software,
+# including as modified by the user, by any other authorized user.
+#
+# 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+# Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+# Vancouver, BC V6T 1Z4
+
+default: libgpgpu_ptx_sim.a
+
+INTEL=0
+DEBUG?=0
+
+CPP = g++ $(SNOW)
+CC = gcc $(SNOW)
+ifeq ($(INTEL),1)
+ CPP = icpc
+ CC = icc
+endif
+
+CC_VERSION := $(shell gcc --version | perl -ne '/gcc\s+\(.*\)\s+([0-9.]+)/ and print $$1;')
+GNUC_CPP0X := $(shell gcc --version | perl -ne 'if (/gcc\s+\(.*\)\s+([0-9.]+)/){ if($$1 >= 4.3) {$$n=1} else {$$n=0;} } END { print $$n; }')
+
+OPT := -O3 -g3 -Wall -Wno-unused-function -Wno-sign-compare
+ifeq ($(DEBUG),1)
+ OPT := -g3 -Wall -Wno-unused-function -Wno-sign-compare
+endif
+OPT += -I$(CUDAHOME)/include
+OPT += -fPIC
+
+CXX_OPT = $(OPT)
+ifeq ($(INTEL),1)
+ CXX_OPT += -std=c++0x
+else
+ifeq ($(GNUC_CPP0X),1)
+ CXX_OPT += -std=c++0x
+endif
+endif
+
+OBJS := instructions.o cuda-sim.o ptx_ir.o ptx_sim.o memory.o ptx-stats.o ptx.tab.o lex.ptx_.o ptxinfo.tab.o lex.ptxinfo_.o
+
+CUDART_VERSION:=$(shell nvcc --version | awk '/release/ {print $$5;}' | sed 's/,//' | sed 's/\./ /' | awk '{printf("%02u%02u", 10*int($$1), 10*$$2);}')
+
+OPT += -DCUDART_VERSION=$(CUDART_VERSION)
+
+libgpgpu_ptx_sim.a: $(OBJS)
+ ar rcs libgpgpu_ptx_sim.a ptx.tab.o lex.ptx_.o ptxinfo.tab.o lex.ptxinfo_.o $(OBJS)
+
+ptx.tab.o: ptx.tab.c
+ $(CC) -c $(OPT) -DYYDEBUG ptx.tab.c
+
+lex.ptx_.o: lex.ptx_.c
+ $(CC) -c $(OPT) lex.ptx_.c
+
+ptxinfo.tab.o: ptxinfo.tab.c
+ $(CC) -c $(OPT) -DYYDEBUG ptxinfo.tab.c
+
+lex.ptxinfo_.o: lex.ptxinfo_.c
+ $(CC) -c $(OPT) lex.ptxinfo_.c
+
+ptx.tab.c:
+ bison --name-prefix=ptx_ -v -d ptx.y
+
+ptxinfo.tab.c:
+ bison --name-prefix=ptxinfo_ -v -d ptxinfo.y
+
+lex.ptx_.c:
+ flex ptx.l
+
+lex.ptxinfo_.c:
+ flex ptxinfo.l
+
+clean:
+ rm -f *~ *.o *.gcda *.gcno *.gcov libgpgpu_ptx_sim.a \
+ ptx.tab.h ptx.tab.c ptx.output lex.ptx_.c \
+ ptxinfo.tab.h ptxinfo.tab.c ptxinfo.output lex.ptxinfo_.c \
+ instructions.h ptx_parser_decode.def directed_tests.log
+
+.c.o:
+ $(CC) -c $(OPT) $< -o $*.o
+.cc.o:
+ $(CPP) -c $(CXX_OPT) $< -o $*.o
+
+instructions.h: instructions.cc
+ @touch $*.h
+ @chmod +w $*.h
+ @echo "// DO NOT EDIT THIS FILE! IT IS AUTOMATICALLY GENERATED BY THE MAKEFILE (see target for instructions.h)" > $*.h
+ @echo "#include \"ptx_ir.h\"" >> $*.h
+ @echo "#ifndef instructions_h_included" >> $*.h
+ @echo "#define instructions_h_included" >> $*.h
+ @echo "#ifdef __cplusplus" >> $*.h
+ @echo "extern \"C\" {" >> $*.h
+ @echo "#endif" >> $*.h
+ @cat $< | grep "_impl(" | sed 's/{.*//' | sed 's/$$/;/' >> $*.h
+ @echo "#ifdef __cplusplus" >> $*.h
+ @echo "}" >> $*.h
+ @echo "#endif" >> $*.h
+ @echo "#endif" >> $*.h
+ @chmod -w $*.h
+ @echo "created instructions.h"
+
+ptx_parser_decode.def: ptx.tab.c
+ifeq ($(shell uname),Linux)
+ cat ptx.tab.h | grep "=" | sed 's/^[ ]\+//' | sed 's/[=,]//g' | sed 's/\([_A-Z1-9]\+\)[ ]\+\([0-9]\+\)/\1 \1/' | sed 's/^/DEF(/' | sed 's/ /,"/' | sed 's/$$/")/' > ptx_parser_decode.def
+else
+ cat ptx.tab.h | grep "=" | sed -E 's/^ +//' | sed 's/[=,]//g' | sed -E 's/([_A-Z1-9]+).*/\1 \1/' | sed 's/^/DEF(/' | sed 's/ /,"/' | sed 's/$$/")/' > ptx_parser_decode.def
+endif
+
+depend:
+ makedepend *.cc *.c 2> /dev/null
+
+instructions.o: instructions.h ptx.tab.c
+ptx_ir.o: ptx.tab.c ptx_parser_decode.def
+
+# DO NOT DELETE
+
diff --git a/src/cuda-sim/cuda-math.h b/src/cuda-sim/cuda-math.h
new file mode 100644
index 0000000..d495461
--- /dev/null
+++ b/src/cuda-sim/cuda-math.h
@@ -0,0 +1,81 @@
+// This file created from vector_types.h distributed with CUDA 1.1
+// Changes Copyright 2009, Wilson W. L. Fung and Tor M. Aamodt
+// University of British Columbia
+
+/*
+ * Copyright 1993-2007 NVIDIA Corporation. All rights reserved.
+ *
+ * NOTICE TO USER:
+ *
+ * This source code is subject to NVIDIA ownership rights under U.S. and
+ * international Copyright laws. Users and possessors of this source code
+ * are hereby granted a nonexclusive, royalty-free license to use this code
+ * in individual and commercial software.
+ *
+ * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
+ * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
+ * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
+ * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+ * OR PERFORMANCE OF THIS SOURCE CODE.
+ *
+ * U.S. Government End Users. This source code is a "commercial item" as
+ * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of
+ * "commercial computer software" and "commercial computer software
+ * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995)
+ * and is provided to the U.S. Government only as a commercial end item.
+ * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
+ * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
+ * source code with only those rights set forth herein.
+ *
+ * Any use of this source code in individual and commercial software must
+ * include, in the user documentation and internal comments to the code,
+ * the above Disclaimer and U.S. Government End Users Notice.
+ */
+
+#ifndef CUDA_MATH
+#define CUDA_MATH
+
+// cuda math implementations
+#undef max
+#undef min
+namespace cuda_math {
+#define __attribute__(a) // to remove warnings inside math_functions.h
+#undef INT_MAX
+
+// DEVICE_BUILTIN
+ struct int4 {
+ int x, y, z, w;
+ };
+ struct uint4 {
+ unsigned int x, y, z, w;
+ };
+ struct float4 {
+ float x, y, z, w;
+ };
+ struct float2 {
+ float x, y;
+ };
+
+
+// DEVICE_BUILTIN
+ typedef struct int4 int4;
+ typedef struct uint4 uint4;
+ typedef struct float4 float4;
+ typedef struct float2 float2;
+
+extern float rsqrtf(float); // CUDA 2.3 beta
+
+#define CUDA_FLOAT_MATH_FUNCTIONS
+#include <device_types.h>
+#define __CUDA_INTERNAL_COMPILATION__
+#include <math_functions.h>
+#undef __CUDA_INTERNAL_COMPILATION__
+#undef __attribute__
+}
+
+#endif
diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc
new file mode 100644
index 0000000..d691a64
--- /dev/null
+++ b/src/cuda-sim/cuda-sim.cc
@@ -0,0 +1,2195 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Ali Bakhoda, Wilson W. L. Fung,
+ * George L. Yuan, Henry Wong, Dan O'Connor, Zev Weiss and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "instructions.h"
+#include "ptx_ir.h"
+#include "ptx_sim.h"
+#include <stdio.h>
+#include <dirent.h>
+
+#include "opcodes.h"
+#include "../intersim/statwraper.h"
+#include "dram_callback.h"
+#include <set>
+#include <map>
+#include "../util.h"
+#include "memory.h"
+#include "ptx-stats.h"
+
+
+int gpgpu_ptx_instruction_classification=0;
+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
+extern "C" int ptx_parse();
+extern "C" int ptx__scan_string(const char*);
+extern "C" int ptx_debug;
+extern "C" FILE *ptx_in;
+
+extern "C" const char *g_ptxinfo_filename = NULL;
+extern "C" int ptxinfo_parse();
+extern "C" int ptxinfo_debug;
+extern "C" FILE *ptxinfo_in;
+
+int g_debug_execution = 0;
+int g_debug_thread_uid = 0;
+addr_t g_debug_pc = 0xBEEF1518;
+int g_override_embedded_ptx = false;
+
+const char *g_filename;
+bool g_debug_ir_generation = false;
+unsigned g_ptx_sim_num_insn = 0;
+
+extern memory_space *g_global_mem;
+extern memory_space *g_param_mem;
+extern memory_space *g_tex_mem;
+extern memory_space *g_surf_mem;
+
+std::map<const struct textureReference*,const struct cudaArray*> TextureToArrayMap; // texture bindings
+std::map<const struct textureReference*, const struct textureInfo*> TextureToInfoMap;
+std::map<std::string, const struct textureReference*> NameToTextureMap;
+unsigned int g_texcache_linesize;
+int gpgpu_option_spread_blocks_across_cores = 0;
+unsigned gpgpu_param_num_shaders = 0;
+
+void gpgpu_ptx_sim_bindNameToTexture(const char* name, const struct textureReference* texref)
+{
+ std::string texname(name);
+ NameToTextureMap[texname] = texref;
+}
+
+const struct textureReference* gpgpu_ptx_sim_accessTextureofName(const char* name) {
+ std::string texname(name);
+ return NameToTextureMap[texname];
+}
+
+const char* gpgpu_ptx_sim_findNamefromTexture(const struct textureReference* texref)
+{
+ std::map<std::string, const struct textureReference*>::iterator itr = NameToTextureMap.begin();
+ while (itr != NameToTextureMap.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_ptx_sim_bindTextureToArray(const struct textureReference* texref, const struct cudaArray* array)
+{
+ TextureToArrayMap[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", g_texcache_linesize);
+ //first determine base Tx size for given linesize
+ switch (g_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", g_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 = g_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);
+ TextureToInfoMap[texref] = texInfo;
+}
+
+const struct cudaArray* gpgpu_ptx_sim_accessArrayofTexture(struct textureReference* texref) {
+ return TextureToArrayMap[texref];
+}
+
+int gpgpu_ptx_sim_sizeofTexture(const char* name)
+{
+ std::string texname(name);
+ const struct textureReference* texref = NameToTextureMap[texname];
+ const struct cudaArray* array = TextureToArrayMap[texref];
+ return array->size;
+}
+
+extern unsigned int warp_size;
+
+int g_warn_literal_operands_two_type_inst;
+
+std::list<operand_info> check_operands( int opcode,
+ const std::list<int> &scalar_type,
+ const std::list<operand_info> &operands )
+{
+ if( (opcode == CVT_OP) || (opcode == SET_OP) || (opcode == SLCT_OP) || (opcode == TEX_OP) ) {
+ // just make sure these do not have have const operands...
+ if( !g_warn_literal_operands_two_type_inst ) {
+ std::list<operand_info>::const_iterator o;
+ for( o = operands.begin(); o != operands.end(); o++ ) {
+ const operand_info &op = *o;
+ if( op.is_literal() ) {
+ printf("GPGPU-Sim PTX: PTX uses two scalar type intruction with literal operand.\n");
+ g_warn_literal_operands_two_type_inst = 1;
+ }
+ }
+ }
+ } else {
+ assert( scalar_type.size() < 2 );
+ if( scalar_type.size() == 1 ) {
+ std::list<operand_info> result;
+ int inst_type = scalar_type.front();
+ std::list<operand_info>::const_iterator o;
+ for( o = operands.begin(); o != operands.end(); o++ ) {
+ const operand_info &op = *o;
+ if( op.is_literal() ) {
+ if( (op.get_type() == double_op_t) && (inst_type == F32_TYPE) ) {
+ ptx_reg_t v = op.get_literal_value();
+ float u = (float)v.f64;
+ operand_info n(u);
+ result.push_back(n);
+ } else {
+ result.push_back(op);
+ }
+ } else {
+ result.push_back(op);
+ }
+ }
+ return result;
+ }
+ }
+ return operands;
+}
+
+ptx_instruction::ptx_instruction( int opcode,
+ const symbol *pred,
+ int neg_pred,
+ symbol *label,
+ const std::list<operand_info> &operands,
+ const operand_info &return_var,
+ const std::list<int> &options,
+ const std::list<int> &scalar_type,
+ int space_spec,
+ const char *file,
+ unsigned line,
+ const char *source )
+{
+ m_uid = ++g_num_ptx_inst_uid;
+ m_PC = 0;
+ m_opcode = opcode;
+ m_pred = pred;
+ m_neg_pred = neg_pred;
+ m_label = label;
+ const std::list<operand_info> checked_operands = check_operands(opcode,scalar_type,operands);
+ m_operands.insert(m_operands.begin(), checked_operands.begin(), checked_operands.end() );
+ m_return_var = return_var;
+ m_options = options;
+ m_wide = false;
+ m_hi = false;
+ m_lo = false;
+ m_uni = false;
+ m_rounding_mode = RN_OPTION;
+ m_compare_op = -1;
+ m_saturation_mode = 0;
+ m_geom_spec = 0;
+ m_vector_spec = 0;
+ m_atomic_spec = 0;
+ m_warp_size = ::warp_size;
+ m_membar_level = 0;
+
+ std::list<int>::const_iterator i;
+ unsigned n=1;
+ for ( i=options.begin(); i!= options.end(); i++, n++ ) {
+ int last_ptx_inst_option = *i;
+ switch ( last_ptx_inst_option ) {
+ case EQU_OPTION:
+ case NEU_OPTION:
+ case LTU_OPTION:
+ case LEU_OPTION:
+ case GTU_OPTION:
+ case GEU_OPTION:
+ case EQ_OPTION:
+ case NE_OPTION:
+ case LT_OPTION:
+ case LE_OPTION:
+ case GT_OPTION:
+ case GE_OPTION:
+ case LS_OPTION:
+ case HS_OPTION:
+ m_compare_op = last_ptx_inst_option;
+ break;
+ case NUM_OPTION:
+ case NAN_OPTION:
+ m_compare_op = last_ptx_inst_option;
+ // assert(0); // finish this
+ break;
+ case SAT_OPTION:
+ m_saturation_mode = 1;
+ break;
+ case RNI_OPTION:
+ case RZI_OPTION:
+ case RMI_OPTION:
+ case RPI_OPTION:
+ case RN_OPTION:
+ case RZ_OPTION:
+ case RM_OPTION:
+ case RP_OPTION:
+ m_rounding_mode = last_ptx_inst_option;
+ break;
+ case HI_OPTION:
+ m_compare_op = last_ptx_inst_option;
+ m_hi = true;
+ assert( !m_lo );
+ assert( !m_wide );
+ break;
+ case LO_OPTION:
+ m_compare_op = last_ptx_inst_option;
+ m_lo = true;
+ assert( !m_hi );
+ assert( !m_wide );
+ break;
+ case WIDE_OPTION:
+ m_wide = true;
+ assert( !m_lo );
+ assert( !m_hi );
+ break;
+ case UNI_OPTION:
+ m_uni = true; // don't care... < now we DO care when constructing flowgraph>
+ break;
+ case GEOM_MODIFIER_1D:
+ case GEOM_MODIFIER_2D:
+ case GEOM_MODIFIER_3D:
+ m_geom_spec = last_ptx_inst_option;
+ break;
+ case V2_TYPE:
+ case V3_TYPE:
+ case V4_TYPE:
+ m_vector_spec = last_ptx_inst_option;
+ break;
+ case ATOMIC_AND:
+ case ATOMIC_OR:
+ case ATOMIC_XOR:
+ case ATOMIC_CAS:
+ case ATOMIC_EXCH:
+ case ATOMIC_ADD:
+ case ATOMIC_INC:
+ case ATOMIC_DEC:
+ case ATOMIC_MIN:
+ case ATOMIC_MAX:
+ m_atomic_spec = last_ptx_inst_option;
+ break;
+ case APPROX_OPTION:
+ break;
+ case FULL_OPTION:
+ break;
+ case ANY_OPTION:
+ m_vote_mode = vote_any;
+ break;
+ case ALL_OPTION:
+ m_vote_mode = vote_all;
+ break;
+ case GLOBAL_OPTION:
+ m_membar_level = GLOBAL_OPTION;
+ break;
+ case CTA_OPTION:
+ m_membar_level = CTA_OPTION;
+ break;
+ case FTZ_OPTION:
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+ m_scalar_type = scalar_type;
+ m_space_spec = space_spec;
+ m_source_file = file?file:"<unknown>";
+ m_source_line = line;
+ m_source = source;
+}
+
+void ptx_instruction::print_insn() const
+{
+ print_insn(stdout);
+ fflush(stdout);
+}
+
+void ptx_instruction::print_insn( FILE *fp ) const
+{
+ char buf[1024], *p;
+ snprintf(buf,1024,"%s", m_source.c_str());
+ p = strtok(buf,";");
+ if( !is_label() )
+ fprintf(fp,"PC=%3u [idx=%3u] ", m_PC, m_instr_mem_index );
+ else
+ fprintf(fp," " );
+ fprintf(fp,"(%s:%u) %s", m_source_file.c_str(), m_source_line, p );
+}
+
+unsigned g_assemble_code_next_pc=1;
+std::map<unsigned,function_info*> g_pc_to_finfo;
+std::vector<ptx_instruction*> function_info::s_g_pc_to_insn;
+
+void function_info::print_insn( unsigned pc, FILE * fp ) const
+{
+ unsigned index = pc - m_start_PC;
+ fprintf(fp,"FUNC[%s]",m_name.c_str() );
+ if ( index >= m_instr_mem_size ) {
+ fprintf(fp, "<past last instruction (max pc=%u)>", m_start_PC + m_instr_mem_size - 1 );
+ } else {
+ if ( m_instr_mem[index] != NULL )
+ m_instr_mem[index]->print_insn(fp);
+ else
+ fprintf(fp, "<no instruction at pc = %u>", pc );
+ }
+}
+
+void function_info::ptx_assemble()
+{
+ if( m_assembled ) {
+ return;
+ }
+
+ // get the instructions into instruction memory...
+ unsigned num_inst = m_instructions.size();
+ m_instr_mem = new ptx_instruction*[ num_inst ];
+ m_instr_mem_size = num_inst;
+
+ printf("GPGPU-Sim PTX: instruction assembly for function \'%s\'... ", m_name.c_str() );
+ fflush(stdout);
+ std::list<ptx_instruction*>::iterator i;
+ addr_t n=0; // offset in m_instr_mem
+ addr_t PC = g_assemble_code_next_pc; // globally unique address (across functions)
+ m_start_PC = PC;
+ s_g_pc_to_insn.reserve(s_g_pc_to_insn.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 - 1]);
+ pI->set_m_instr_mem_index(n);
+ pI->set_PC(PC);
+ n++;
+ PC++;
+ }
+ }
+ g_assemble_code_next_pc=PC;
+ for ( unsigned ii=0; ii < n; ii++ ) { // handle branch instructions
+ ptx_instruction *pI = m_instr_mem[ii];
+ if ( pI->get_opcode() == BRA_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();
+ g_current_symbol_table->set_label_address( target.get_symbol(), PC );
+ target.set_type(label_t);
+ }
+ }
+ printf(" done.\n");
+ fflush(stdout);
+
+ create_basic_blocks();
+ connect_basic_blocks();
+ if ( g_debug_execution>=2 ) {
+ print_basic_blocks();
+ print_basic_block_links();
+ print_basic_block_dot();
+ }
+ find_postdominators();
+ find_ipostdominators();
+ if ( g_debug_execution>=2 ) {
+ print_postdominators();
+ print_ipostdominators();
+ }
+ m_assembled = true;
+}
+
+
+
+void gpgpu_ptx_sim_init_memory()
+{
+ static bool initialized = false;
+ if ( !initialized ) {
+ g_global_mem = new memory_space_impl<8192>("global",64*1024);
+ g_param_mem = new memory_space_impl<64>("param",64*1024);
+ g_tex_mem = new memory_space_impl<8192>("tex",64*1024);
+ g_surf_mem = new memory_space_impl<8192>("surf",64*1024);
+ initialized = true;
+ }
+}
+
+int load_static_globals( symbol_table *symtab, unsigned min_gaddr, unsigned max_gaddr)
+{
+ printf( "GPGPU-Sim PTX: loading global with explicit initializers... " );
+ fflush(stdout);
+ int ng_bytes=0;
+ symbol_table::iterator g=symtab->global_iterator_begin();
+ bool below_image=true;
+
+ for ( ; g!=symtab->global_iterator_end(); g++) {
+ symbol *global = *g;
+ if ( global->has_initializer() ) {
+ std::list<operand_info> init_list = global->get_initializer();
+ for ( std::list<operand_info>::iterator i=init_list.begin(); i!=init_list.end(); i++ ) {
+ operand_info op = *i;
+ ptx_reg_t value = op.get_literal_value();
+ int nbytes = 0;
+ switch ( op.get_type() ) {
+ case int_t: nbytes = 4; break;
+ case float_op_t: nbytes = 4; break;
+ case double_op_t: nbytes = 8; break;
+ default:
+ abort();
+ }
+ unsigned addr=global->get_address();
+
+ assert( below_image && addr+nbytes < min_gaddr ); // min_gaddr is start of "heap" for cudaMalloc
+
+ g_global_mem->write(addr,nbytes,&value);
+ ng_bytes+=nbytes;
+ }
+ }
+ }
+ printf( " done.\n");
+ fflush(stdout);
+ return ng_bytes;
+}
+
+int load_constants( symbol_table *symtab )
+{
+ printf( "GPGPU-Sim PTX: loading constants with explicit initializers... " );
+ fflush(stdout);
+ int nc_bytes = 0;
+ symbol_table::iterator g=symtab->const_iterator_begin();
+
+ for ( ; g!=symtab->const_iterator_end(); g++) {
+ symbol *constant = *g;
+ if ( constant->is_const() && constant->has_initializer() ) {
+
+ // get the constant element data size
+ int basic_type;
+ size_t num_bits;
+ type_decode(constant->type()->get_key().scalar_type(),num_bits,basic_type);
+
+ std::list<operand_info> init_list = constant->get_initializer();
+ int nbytes_written = 0;
+ for ( std::list<operand_info>::iterator i=init_list.begin(); i!=init_list.end(); i++ ) {
+ operand_info op = *i;
+ ptx_reg_t value = op.get_literal_value();
+ int nbytes = num_bits/8;
+ switch ( op.get_type() ) {
+ case int_t: assert(nbytes >= 1); break;
+ case float_op_t: assert(nbytes == 4); break;
+ case double_op_t: assert(nbytes >= 4); break; // account for double DEMOTING
+ default:
+ abort();
+ }
+ unsigned addr=constant->get_address() + nbytes_written;
+
+ g_global_mem->write(addr,nbytes,&value); // assume little endian (so u8 is the first byte in u32)
+ nc_bytes+=nbytes;
+ nbytes_written += nbytes;
+ }
+ }
+ }
+ printf( " done.\n");
+ fflush(stdout);
+ return nc_bytes;
+}
+
+unsigned long long g_dev_malloc=0x10000000; // start allocating from this address (lower values used for allocating globals in .ptx file)
+
+void* gpgpu_ptx_sim_malloc( size_t size )
+{
+ unsigned long long result = g_dev_malloc;
+ printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, g_dev_malloc );
+ fflush(stdout);
+ g_dev_malloc += size;
+ if (size%64) g_dev_malloc += (64 - size%64); //align to 64 byte boundaries
+ return(void*) result;
+}
+
+void* gpgpu_ptx_sim_mallocarray( size_t size )
+{
+ unsigned long long result = g_dev_malloc;
+ printf("GPGPU-Sim PTX: allocating %zu bytes on GPU starting at address 0x%Lx\n", size, g_dev_malloc );
+ fflush(stdout);
+ g_dev_malloc += size;
+ if (size%64) g_dev_malloc += (64 - size%64); //align to 64 byte boundaries
+ return(void*) result;
+}
+
+
+void gpgpu_ptx_sim_memcpy_to_gpu( size_t dst_start_addr, const void *src, size_t count )
+{
+ 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 ++ )
+ g_global_mem->write(dst_start_addr+n,1, src_data+n);
+ printf( " done.\n");
+ fflush(stdout);
+}
+
+void gpgpu_ptx_sim_memcpy_from_gpu( void *dst, size_t src_start_addr, size_t count )
+{
+ 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 ++ )
+ g_global_mem->read(src_start_addr+n,1,dst_data+n);
+ printf( " done.\n");
+ fflush(stdout);
+}
+
+void gpgpu_ptx_sim_memcpy_gpu_to_gpu( size_t dst, size_t src, size_t count )
+{
+ 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;
+ g_global_mem->read(src+n,1,&tmp);
+ g_global_mem->write(dst+n,1, &tmp);
+ }
+ printf( " done.\n");
+ fflush(stdout);
+}
+
+void gpgpu_ptx_sim_memset( size_t dst_start_addr, int c, size_t count )
+{
+ 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 ++ )
+ g_global_mem->write(dst_start_addr+n,1,&c_value);
+ printf( " done.\n");
+ fflush(stdout);
+}
+
+int ptx_thread_done( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ int result = 0;
+ result = (the_thread==NULL) || the_thread->is_done();
+ return result;
+}
+
+const char * ptx_get_fname( unsigned PC )
+{
+ static const char *null_ptr = "<null finfo ptr>";
+ std::map<unsigned,function_info*>::iterator f=g_pc_to_finfo.find(PC);
+ if( f== g_pc_to_finfo.end() )
+ return null_ptr;
+ return f->second->get_name().c_str();
+}
+
+unsigned ptx_thread_donecycle( void *thr )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thr;
+ if( the_thread == NULL )
+ return 0;
+ return the_thread->donecycle();
+}
+
+int ptx_thread_get_next_pc( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return -1;
+ return the_thread->get_pc(); // PC should already be updatd to next PC at this point (was set in shader_decode() last time thread ran)
+}
+
+void* ptx_thread_get_next_finfo( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return NULL;
+ return the_thread->get_finfo(); // finfo should already be updatd to next PC at this point (was set in shader_decode() last time thread ran)
+}
+
+int ptx_thread_at_barrier( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return 0;
+ return the_thread->is_at_barrier();
+}
+
+int ptx_thread_all_at_barrier( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return 0;
+ return the_thread->all_at_barrier()?1:0;
+}
+
+unsigned long long ptx_thread_get_cta_uid( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return 0;
+ return the_thread->get_cta_uid();
+}
+
+void ptx_thread_reset_barrier( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return;
+ the_thread->clear_barrier();
+}
+
+void ptx_thread_release_barrier( void *thd )
+{
+ ptx_thread_info *the_thread = (ptx_thread_info *) thd;
+ if ( the_thread == NULL )
+ return;
+ the_thread->release_barrier();
+}
+
+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 (%u)>", pc, pc );
+ return;
+ }
+ function_info *finfo = f->second;
+ assert( finfo );
+ finfo->print_insn(pc,fp);
+}
+
+void function_info::ptx_decode_inst( ptx_thread_info *thread,
+ unsigned *op_type,
+ int *i1, int *i2, int *i3, int *i4,
+ int *o1, int *o2, int *o3, int *o4,
+ int *vectorin,
+ int *vectorout,
+ int *arch_reg )
+{
+ addr_t pc = thread->get_pc();
+ unsigned index = pc - m_start_PC;
+ assert( index < m_instr_mem_size );
+ ptx_instruction *pI = m_instr_mem[index]; //get instruction from m_instr_mem[PC]
+
+ bool has_dst = false ;
+ int opcode = pI->get_opcode(); //determine the opcode
+
+ switch ( pI->get_opcode() ) {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: has_dst = (DST!=0); break;
+#include "opcodes.def"
+#undef OP_DEF
+ default:
+ printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() );
+ break;
+ }
+
+ *op_type = ALU_OP;
+ if ( opcode == LD_OP ) {
+ *op_type = LOAD_OP;
+ } else if ( opcode == ST_OP ) {
+ *op_type = STORE_OP;
+ } else if ( opcode == BRA_OP ) {
+ *op_type = BRANCH_OP;
+ } else if ( opcode == TEX_OP ) {
+ *op_type = LOAD_OP;
+ } else if ( opcode == ATOM_OP ) {
+ *op_type = LOAD_OP; // make atomics behave more like a load.
+ } else if ( opcode == BAR_OP ) {
+ *op_type = BARRIER_OP;
+ }
+
+ int n=0,m=0;
+ ptx_instruction::const_iterator op=pI->op_iter_begin();
+ for ( ; op != pI->op_iter_end(); op++, n++ ) { //process operands
+
+ const operand_info &o = *op;
+ if ( has_dst && n==0 ) {
+ if ( o.is_reg() ) { //but is destination an actual register? (seems like it fails if it's a vector)
+ *o1 = o.reg_num();
+ arch_reg[0] = o.arch_reg_num();
+ } else if ( o.is_vector() ) { //but is destination an actual register? (seems like it fails if it's a vector)
+ *vectorin = 1;
+ *o1 = o.reg1_num();
+ *o2 = o.reg2_num();
+ *o3 = o.reg3_num();
+ *o4 = o.reg4_num();
+ for (int i = 0; i < 4; i++)
+ arch_reg[i] = o.arch_reg_num(i);
+ }
+ } else {
+ if ( o.is_reg() ) {
+ int reg_num = o.reg_num();
+ arch_reg[m + 4] = o.arch_reg_num();
+ switch ( m ) {
+ case 0: *i1 = reg_num; break;
+ case 1: *i2 = reg_num; break;
+ case 2: *i3 = reg_num; break;
+ default:
+ break;
+ }
+ m++;
+ } else if ( o.is_vector() ) {
+ assert(m == 0); //only support 1 vector operand (for textures) right now
+ *vectorout = 1;
+ *i1 = o.reg1_num();
+ *i2 = o.reg2_num();
+ *i3 = o.reg3_num();
+ *i4 = o.reg4_num();
+ for (int i = 0; i < 4; i++)
+ arch_reg[i + 4] = o.arch_reg_num(i);
+ m+=4;
+ }
+ }
+ }
+}
+
+unsigned function_info::ptx_get_inst_op( ptx_thread_info *thread )
+{
+ addr_t pc = thread->get_pc();
+ unsigned index = pc - m_start_PC;
+ assert( index < m_instr_mem_size );
+ ptx_instruction *pI = m_instr_mem[index]; //get instruction from m_instr_mem[PC]
+
+ int opcode = pI->get_opcode(); //determine the opcode
+
+ if ( opcode == LD_OP ) {
+ if ( pI->get_space() != SHARED_DIRECTIVE ) //treat shared memory access as generic instruction (e.g. no bank conflicts)
+ return LOAD_OP;
+ } else if ( opcode == ST_OP ) {
+ if ( pI->get_space() != SHARED_DIRECTIVE )
+ return STORE_OP;
+ } else if ( opcode == BRA_OP ) {
+ return BRANCH_OP;
+ } else if ( opcode == TEX_OP ) {
+ return LOAD_OP;
+ }
+ return ALU_OP;
+}
+
+void function_info::add_param_name_and_type( unsigned index, std::string name, int type )
+{
+ 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_param_info.find(parsed_index) == m_ptx_param_info.end() );
+ m_ptx_param_info[parsed_index] = param_info(parsed_index,name,type);
+ } else {
+ assert( m_ptx_param_info.find(index) == m_ptx_param_info.end() );
+ m_ptx_param_info[index] = param_info(index,name,type);
+ }
+}
+
+void function_info::add_param_data( unsigned argn, struct gpgpu_ptx_sim_arg *args )
+{
+ const void *data = args->m_start;
+ param_t tmp;
+
+ if( data ) {
+ memcpy(&tmp.data,data,args->m_nbytes);
+ std::map<unsigned,param_info>::iterator i=m_ptx_param_info.find(argn);
+ if( i != m_ptx_param_info.end()) {
+ i->second.add_data(tmp);
+ } else {
+ // 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);
+ p->set_address((addr_t)*(size_t*)data);
+ }
+ } else {
+ // This should only happen for OpenCL, but doesn't cause problems
+ }
+}
+
+int ptx_branch_taken( void *thd )
+{
+ ptx_thread_info *thread = (ptx_thread_info *) thd;
+ return (thread != NULL) && thread->branch_taken();
+}
+
+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;
+}
+
+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 S64_TYPE:
+ case U64_TYPE:
+ case F64_TYPE:
+ data_size = 8; break;
+ default: assert(0); break;
+ }
+ return data_size;
+}
+
+extern unsigned long long gpu_sim_cycle;
+unsigned g_warp_active_mask;
+
+void function_info::ptx_exec_inst( ptx_thread_info *thread,
+ addr_t *addr,
+ unsigned *space,
+ unsigned *data_size,
+ dram_callback_t* callback,
+ unsigned warp_active_mask )
+{
+ bool skip = false;
+ int op_classification = 0;
+ addr_t pc = thread->next_instr();
+ unsigned index = pc - m_start_PC;
+ assert( index < m_instr_mem_size );
+ ptx_instruction *pI = m_instr_mem[index];
+ g_current_symbol_table = thread->get_finfo()->get_symtab();
+ thread->clearRPC();
+ thread->m_last_set_operand_value.u64 = 0;
+ *space = -1;
+ *addr = 0xFEEBDAED;
+
+ thread->clear_modifiedregs();
+ if( pI->has_pred() ) {
+ const operand_info &pred = pI->get_pred();
+ ptx_reg_t pred_value = thread->get_operand_value(pred);
+ skip = !pred_value.pred ^ pI->get_pred_neg();
+ }
+ g_warp_active_mask = warp_active_mask;
+ if( !skip ) {
+ switch ( pI->get_opcode() ) {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,thread); op_classification = CLASSIFICATION; break;
+#include "opcodes.def"
+#undef OP_DEF
+ default:
+ printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() );
+ break;
+ }
+ }
+
+ if ( ptx_debug_exec_dump_cond<5>(thread->get_uid(), pc) ) {
+ dim3 ctaid = thread->get_ctaid();
+ dim3 tid = thread->get_tid();
+ printf("%u [cyc=%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,
+ (unsigned)gpu_sim_cycle,
+ thread->get_uid(),
+ pI->uid(), ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z,
+ thread->get_icount(),
+ pc, pI->source_file(), pI->source_line(), pI->get_source(),
+ thread->m_last_set_operand_value.u64 );
+ fflush(stdout);
+ }
+
+ *data_size = 0;
+ if ( (pI->get_opcode() == LD_OP || pI->get_opcode() == ST_OP) ) {
+ *addr = thread->last_eaddr();
+ *space = thread->last_space();
+
+ unsigned to_type = pI->get_type();
+ *data_size = datatype2size(to_type);
+ }
+
+ if ( pI->get_opcode() == ATOM_OP ) {
+ *addr = thread->last_eaddr();
+ *space = thread->last_space();
+ callback->function = thread->last_callback().function;
+ callback->instruction = thread->last_callback().instruction;
+ callback->thread = thread;
+
+ unsigned to_type = pI->get_type();
+ *data_size = datatype2size(to_type);
+ } else {
+ // make sure that the callback isn't set
+ callback->function = NULL;
+ callback->instruction = NULL;
+ }
+
+ if (pI->get_opcode() == TEX_OP) {
+ *addr = thread->last_eaddr();
+ *space = thread->last_space();
+
+ unsigned to_type = pI->get_type();
+ *data_size = datatype2size(to_type);
+ }
+
+ if ( g_debug_execution >= 6 ) {
+ if ( ptx_debug_exec_dump_cond<6>(thread->get_uid(), pc) )
+ thread->dump_modifiedregs();
+ } else if ( g_debug_execution >= 10 ) {
+ if ( ptx_debug_exec_dump_cond<10>(thread->get_uid(), pc) )
+ thread->dump_regs();
+ }
+ thread->update_pc();
+ g_ptx_sim_num_insn++;
+ ptx_file_line_stats_add_exec_count(pI);
+ if ( gpgpu_ptx_instruction_classification ) {
+ unsigned space = pI->get_space();
+ switch ( space ) {
+ case GLOBAL_DIRECTIVE: space = 10; break;
+ case LOCAL_DIRECTIVE: space = 11; break;
+ case TEX_DIRECTIVE: space = 12; break;
+ case SURF_DIRECTIVE: space = 13; break;
+ case PARAM_DIRECTIVE: space = 14; break;
+ case SHARED_DIRECTIVE: space = 15; break;
+ case CONST_DIRECTIVE: space = 16; break;
+ default:
+ space = 0 ;
+ break;
+ }
+ StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], op_classification);
+ if (space) StatAddSample( g_inst_classification_stat[g_ptx_kernel_count], ( int )space);
+ StatAddSample( g_inst_op_classification_stat[g_ptx_kernel_count], (int) pI->get_opcode() );
+ }
+ if ( (g_ptx_sim_num_insn % 100000) == 0 ) {
+ dim3 ctaid = thread->get_ctaid();
+ dim3 tid = thread->get_tid();
+ printf("%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);
+ }
+}
+
+unsigned g_gx, g_gy, g_gz;
+
+dim3 g_cudaGridDim, g_cudaBlockDim;
+
+unsigned g_cta_launch_sid;
+std::list<ptx_thread_info *> g_active_threads;
+std::map<unsigned,unsigned> g_sm_idx_offset_next;
+unsigned g_sm_next_index;
+std::map<unsigned,memory_space*> g_shared_memory_lookup;
+std::map<unsigned,ptx_cta_info*> g_ptx_cta_lookup;
+std::map<unsigned,std::map<unsigned,memory_space*> > g_local_memory_lookup;
+
+// return number of blocks in grid
+unsigned ptx_sim_grid_size()
+{
+ return g_cudaGridDim.x * g_cudaGridDim.y * g_cudaGridDim.z;
+}
+
+void set_option_gpgpu_spread_blocks_across_cores(int option)
+{
+ gpgpu_option_spread_blocks_across_cores = option;
+}
+
+void set_param_gpgpu_num_shaders(int num_shaders)
+{
+ gpgpu_param_num_shaders = num_shaders;
+}
+
+unsigned ptx_sim_cta_size()
+{
+ return g_cudaBlockDim.x * g_cudaBlockDim.y * g_cudaBlockDim.z;
+}
+
+const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info() {
+ return g_entrypoint_func_info->get_kernel_info();
+}
+
+void ptx_sim_free_sm( void** thread_info )
+{
+}
+
+unsigned ptx_sim_init_thread( void** thread_info,int sid,unsigned tid,unsigned threads_left,unsigned num_threads, core_t *core, unsigned hw_cta_id, unsigned hw_warp_id )
+{
+ if ( *thread_info != NULL ) {
+ ptx_thread_info *thd = *((ptx_thread_info**)thread_info);
+ assert( thd->is_done() );
+ if ( g_debug_execution==-1 ) {
+ dim3 ctaid = thd->get_ctaid();
+ dim3 tid = thd->get_tid();
+ printf("GPGPU-Sim PTX simulator: thread exiting ctaid=(%u,%u,%u) tid=(%u,%u,%u) @ 0x%Lx\n",
+ ctaid.x,ctaid.y,ctaid.z,tid.x,tid.y,tid.z, (unsigned long long)*((void**)thread_info) );
+ fflush(stdout);
+ }
+ thd->m_cta_info->assert_barrier_empty();
+ thd->m_cta_info->register_deleted_thread(thd);
+ delete thd;
+ *((ptx_thread_info**)thread_info) = NULL;
+ }
+
+ if ( !g_active_threads.empty() ) { //if g_active_threads not empty...
+ assert( g_active_threads.size() <= threads_left );
+ if ( g_cta_launch_sid == (unsigned)-1 )
+ g_cta_launch_sid = sid;
+ assert( g_cta_launch_sid == (unsigned)sid );
+ ptx_thread_info *thd = g_active_threads.front();
+ g_active_threads.pop_front();
+ *((ptx_thread_info**)thread_info) = thd;
+ thd->set_hw_tid(tid);
+ thd->set_hw_wid(hw_warp_id);
+ thd->set_hw_ctaid(hw_cta_id);
+ thd->set_core(core);
+ thd->set_hw_sid(sid);
+ return 1;
+ }
+
+ if ( g_gx >= g_cudaGridDim.x || g_gy >= g_cudaGridDim.y || g_gz >= g_cudaGridDim.z ) {
+ return 0; //finished!
+ }
+
+ if ( threads_left < ptx_sim_cta_size() ) {
+ 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 = ptx_sim_cta_size(); //blocksize
+ unsigned sm_offset = g_sm_idx_offset_next[sid];
+ unsigned max_cta_per_sm = num_threads/cta_size; // e.g., 256 / 48 = 5
+ assert( max_cta_per_sm > 0 );
+
+ //following sm_idx calculation assumes shaders being filled up depth-first?
+ unsigned sm_idx = sid*max_cta_per_sm + sm_offset; /* Is this assuming non-even block distribution? */
+ sm_idx = max_cta_per_sm*sid + tid/cta_size;
+
+
+ if (!gpgpu_option_spread_blocks_across_cores) {
+ // update offset...
+ if ( (sm_offset + 1) >= max_cta_per_sm ) {
+ sm_offset = 0;
+ } else {
+ sm_offset++;
+ }
+ g_sm_idx_offset_next[sid] = sm_offset;
+ } else {
+ sm_idx = (tid/cta_size)*gpgpu_param_num_shaders + sid;
+ }
+
+ if ( g_shared_memory_lookup.find(sm_idx) == g_shared_memory_lookup.end() ) {
+ if ( g_debug_execution >= 1 ) {
+ printf(" <CTA alloc> : sm_idx=%u sid=%u sm_offset=%u max_cta_per_sm=%u\n",
+ sm_idx, sid, sm_offset, max_cta_per_sm );
+ }
+ char buf[512];
+ snprintf(buf,512,"shared_%u", sid);
+ shared_mem = new memory_space_impl<16*1024>(buf,4);
+ g_shared_memory_lookup[sm_idx] = shared_mem;
+ cta_info = new ptx_cta_info(sm_idx);
+ g_ptx_cta_lookup[sm_idx] = cta_info;
+ } else {
+ if ( g_debug_execution >= 1 ) {
+ printf(" <CTA realloc> : sm_idx=%u sid=%u sm_offset=%u max_cta_per_sm=%u\n",
+ sm_idx, sid, sm_offset, max_cta_per_sm );
+ }
+ shared_mem = g_shared_memory_lookup[sm_idx];
+ cta_info = g_ptx_cta_lookup[sm_idx];
+ cta_info->check_cta_thread_status_and_reset();
+ }
+
+ std::map<unsigned,memory_space*> &local_mem_lookup = g_local_memory_lookup[sid];
+ unsigned new_tid;
+ for ( unsigned tz=0; tz < g_cudaBlockDim.z; tz++ ) {
+ for ( unsigned ty=0; ty < g_cudaBlockDim.y; ty++ ) {
+ for ( unsigned tx=0; tx < g_cudaBlockDim.x; tx++ ) {
+ new_tid = tx + g_cudaBlockDim.x*ty + g_cudaBlockDim.x*g_cudaBlockDim.y*tz; //unique id but only to a BLOCK
+ new_tid += tid;
+ ptx_thread_info *thd = new ptx_thread_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(g_entrypoint_symbol_table,g_entrypoint_func_info);
+ thd->set_nctaid(g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z);
+ thd->set_ntid(g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z);
+ thd->set_ctaid(g_gx,g_gy,g_gz);
+ thd->set_tid(tx,ty,tz);
+ thd->set_hw_tid((unsigned)-1);
+ thd->set_hw_wid((unsigned)-1);
+ thd->set_hw_ctaid((unsigned)-1);
+ thd->set_core(NULL);
+ thd->set_hw_sid((unsigned)-1);
+ thd->set_valid();
+ thd->m_shared_mem = shared_mem;
+ 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",
+ g_gx,g_gy,g_gz,tx,ty,tz, (unsigned long long)thd );
+ fflush(stdout);
+ }
+ g_active_threads.push_back(thd);
+ }
+ }
+ }
+ if ( g_debug_execution==-1 ) {
+ printf("GPGPU-Sim PTX simulator: <-- FINISHING THREAD ALLOCATION\n");
+ fflush(stdout);
+ }
+
+ g_gx++;
+ if ( g_gx >= g_cudaGridDim.x ) {
+ g_gx = 0;
+ g_gy++;
+ if ( g_gy >= g_cudaGridDim.y ) {
+ g_gy = 0;
+ g_gz++;
+ }
+ }
+
+ g_cta_launch_sid = -1;
+
+ assert( g_active_threads.size() <= threads_left );
+
+ g_cta_launch_sid = sid;
+ *((ptx_thread_info**)thread_info) = g_active_threads.front();
+ (*((ptx_thread_info**)thread_info) )->set_hw_tid(tid);
+ (*((ptx_thread_info**)thread_info) )->set_hw_wid(hw_warp_id);
+ (*((ptx_thread_info**)thread_info) )->set_hw_ctaid(hw_cta_id);
+ (*((ptx_thread_info**)thread_info) )->set_core(core);
+ (*((ptx_thread_info**)thread_info) )->set_hw_sid(sid);
+ g_active_threads.pop_front();
+
+ return 1;
+}
+
+void init_inst_classification_stat() {
+ char kernelname[256] ="";
+#define MAX_CLASS_KER 256
+ 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);
+}
+
+unsigned g_max_regs_per_thread = 0;
+
+std::map<std::string,function_info*> *g_kernel_name_to_function_lookup=NULL;
+std::map<std::string,symbol_table*> g_kernel_name_to_symtab_lookup;
+std::map<const void*,std::string> *g_host_to_kernel_entrypoint_name_lookup=NULL;
+extern unsigned g_ptx_thread_info_uid_next;
+
+void gpgpu_ptx_sim_init_grid( const char *kernel_key, struct gpgpu_ptx_sim_arg* args,
+ struct dim3 gridDim, struct dim3 blockDim )
+{
+ g_gx=0;
+ g_gy=0;
+ g_gz=0;
+ g_cudaGridDim = gridDim;
+ g_cudaBlockDim = blockDim;
+ g_sm_idx_offset_next.clear();
+ g_sm_next_index = 0;
+
+ if ( g_host_to_kernel_entrypoint_name_lookup->find(kernel_key) ==
+ g_host_to_kernel_entrypoint_name_lookup->end() ) {
+ printf("GPGPU-Sim PTX: ERROR ** cannot locate PTX entry point\n" );
+ abort();
+ } else {
+ std::string kname = (*g_host_to_kernel_entrypoint_name_lookup)[kernel_key];
+ printf("GPGPU-Sim PTX: Launching kernel \'%s\' gridDim= (%u,%u,%u) blockDim = (%u,%u,%u); ntuid=%u\n",
+ kname.c_str(), g_cudaGridDim.x,g_cudaGridDim.y,g_cudaGridDim.z,g_cudaBlockDim.x,g_cudaBlockDim.y,g_cudaBlockDim.z,
+ g_ptx_thread_info_uid_next );
+
+ if ( g_kernel_name_to_function_lookup->find(kname) ==
+ g_kernel_name_to_function_lookup->end() ) {
+ printf("GPGPU-Sim PTX: ERROR ** function \'%s\' not found in ptx file\n", kname.c_str() );
+ abort();
+ }
+ g_entrypoint_func_info = g_func_info = (*g_kernel_name_to_function_lookup)[kname];
+ g_entrypoint_symbol_table = g_current_symbol_table = g_kernel_name_to_symtab_lookup[kname];
+ }
+
+ unsigned argcount=0;
+ struct gpgpu_ptx_sim_arg *tmparg = args;
+ while (tmparg) {
+ tmparg = tmparg->m_next;
+ argcount++;
+ }
+
+ unsigned argn=1;
+ while (args) {
+ g_func_info->add_param_data(argcount-argn,args);
+ args = args->m_next;
+ argn++;
+ }
+ g_func_info->finalize(g_param_mem,g_current_symbol_table);
+ g_ptx_kernel_count++;
+ if ( gpgpu_ptx_instruction_classification ) {
+ init_inst_classification_stat();
+ }
+ fflush(stdout);
+}
+
+const char *g_gpgpusim_version_string = "2.1.1b (beta)";
+
+void print_splash()
+{
+ static int splash_printed=0;
+ if ( !splash_printed ) {
+ fprintf(stdout, "\n\n *** GPGPU-Sim version %s ***\n\n\n", g_gpgpusim_version_string );
+ splash_printed=1;
+ }
+}
+
+void gpgpu_ptx_sim_register_kernel(const char *hostFun, const char *deviceFun)
+{
+ const void* key=hostFun;
+ print_splash();
+ if ( g_host_to_kernel_entrypoint_name_lookup == NULL )
+ g_host_to_kernel_entrypoint_name_lookup = new std::map<const void*,std::string>;
+ if( g_kernel_name_to_function_lookup == NULL )
+ g_kernel_name_to_function_lookup = new std::map<std::string,function_info*>;
+ if ( g_host_to_kernel_entrypoint_name_lookup->find(key) !=
+ g_host_to_kernel_entrypoint_name_lookup->end() ) {
+ printf("GPGPU-Sim Loader error: Don't know how to identify PTX kernels during cudaLaunch\n"
+ " for this application.\n");
+ abort();
+ }
+ (*g_host_to_kernel_entrypoint_name_lookup)[key] = deviceFun;
+ if( g_kernel_name_to_function_lookup->find(deviceFun) ==
+ g_kernel_name_to_function_lookup->end() ) {
+ (*g_kernel_name_to_function_lookup)[deviceFun] = NULL; // we set this later, set keys now for error checking
+ }
+
+ printf("GPGPU-Sim PTX: __cudaRegisterFunction %s : 0x%Lx\n", deviceFun, (unsigned long long)hostFun);
+}
+
+extern int ptx_lineno;
+
+void register_ptx_function( const char *name, function_info *impl, symbol_table *symtab )
+{
+ printf("GPGPU-Sim PTX: parsing function %s\n", name );
+ if( g_kernel_name_to_function_lookup == NULL )
+ g_kernel_name_to_function_lookup = new std::map<std::string,function_info*>;
+
+ std::map<std::string,function_info*>::iterator i_kernel = g_kernel_name_to_function_lookup->find(name);
+ if (i_kernel != g_kernel_name_to_function_lookup->end() && i_kernel->second != NULL) {
+ printf("GPGPU-Sim PTX: WARNING: Function already parsed once. Overwriting.\n");
+ }
+ (*g_kernel_name_to_function_lookup)[name] = impl;
+ g_kernel_name_to_symtab_lookup[name] = symtab;
+}
+
+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;
+extern std::map<std::string,symbol_table*> g_sym_name_to_symbol_table;
+
+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;
+ //assert( g_current_symbol_table != NULL );
+ //g_sym_name_to_symbol_table[deviceName] = g_current_symbol_table;
+}
+
+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;
+ //assert( g_current_symbol_table != NULL );
+ //g_sym_name_to_symbol_table[deviceName] = g_current_symbol_table;
+}
+
+void gpgpu_ptx_sim_memcpy_symbol(const char *hostVar, const void *src, size_t count, size_t offset, int to )
+{
+ printf("GPGPU-Sim PTX: starting gpgpu_ptx_sim_memcpy_symbol with hostVar 0x%p\n", hostVar);
+ bool found_sym = false;
+ int mem_region = 0;
+ 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_DIRECTIVE;
+ }
+ 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_DIRECTIVE;
+ }
+ if( g_globals.find(hostVar) != g_globals.end() ) {
+ found_sym = true;
+ sym_name = hostVar;
+ mem_region = GLOBAL_DIRECTIVE;
+ }
+ if( g_constants.find(hostVar) != g_constants.end() ) {
+ found_sym = true;
+ sym_name = hostVar;
+ mem_region = CONST_DIRECTIVE;
+ }
+
+ 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());
+ if( st != g_sym_name_to_symbol_table.end() ) {
+ g_current_symbol_table = st->second;
+ }
+
+ symbol *sym = g_current_symbol_table->lookup(sym_name.c_str());
+ assert(sym);
+ unsigned dst = sym->get_address() + offset;
+ switch (mem_region) {
+ case CONST_DIRECTIVE:
+ mem = g_global_mem;
+ mem_name = "global";
+ break;
+ case GLOBAL_DIRECTIVE:
+ mem = g_global_mem;
+ mem_name = "global";
+ break;
+ default:
+ abort();
+ }
+ printf("GPGPU-Sim PTX: gpgpu_ptx_sim_memcpy_symbol: copying %zu bytes %s symbol %s+%zu @0x%x ...\n",
+ 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);
+ else mem->read(dst+n,1,((char*)src)+n);
+ }
+ fflush(stdout);
+}
+
+int g_ptx_sim_mode=0;
+// used by libcuda.a if non-zer cudaLaunch() will call gpgpu_ptx_sim_main_func()
+// if zero it calls gpgpu_ptx_sim_main_perf()
+
+#if defined(__APPLE__)
+int ptx_file_filter(struct dirent *de )
+#else
+int ptx_file_filter(const struct dirent *de )
+#endif
+{
+ const char *tmp = strstr(de->d_name,".ptx");
+ if ( tmp != NULL && tmp[4] == 0 ) {
+ return 1;
+ }
+ return 0;
+}
+
+void read_environment_variables()
+{
+ ptx_debug = 0;
+ g_debug_execution = 0;
+ g_debug_ir_generation = 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");
+ g_filename = getenv("PTX_SIM_KERNELFILE");
+ 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;
+ }
+#else
+ g_override_embedded_ptx = true;
+#endif
+
+ if ( g_debug_execution >= 40 ) {
+ ptx_debug = 1;
+ }
+ if ( g_debug_execution >= 30 ) {
+ g_debug_ir_generation = true;
+ }
+}
+
+static FILE *open_ptxinfo (const char* ptx_filename)
+{
+ const int ptx_fnamelen = strlen(ptx_filename);
+ char *ptxi_fname = new char[ptx_fnamelen+5];
+ strcpy (ptxi_fname, ptx_filename);
+ strcpy (ptxi_fname+ptx_fnamelen, "info");
+
+ //ptxinfo_debug=1;
+ g_ptxinfo_filename = ptxi_fname;
+ FILE *f = fopen (ptxi_fname, "rt");
+ return f;
+}
+
+struct ptx_info_t {
+ char *str;
+ ptx_info_t *next;
+};
+
+ptx_info_t *g_ptx_source_array = NULL;
+unsigned g_used_embedded_ptx_files;
+extern double g_ptx_version;
+
+void gpgpu_ptx_sim_add_ptxstring( const char *ptx_string )
+{
+ ptx_info_t *t = new ptx_info_t;
+ t->next = NULL;
+ t->str = strdup(ptx_string);
+
+ // put ptx source into a fifo
+ if (g_ptx_source_array == NULL) {
+ // first ptx source
+ g_ptx_source_array = t;
+ } else {
+ // insert subsequent ptx source at the end of queue
+ ptx_info_t *l_ptx_source = g_ptx_source_array;
+ while (l_ptx_source->next != NULL) {
+ l_ptx_source = l_ptx_source->next;
+ }
+ l_ptx_source->next = t;
+ }
+}
+
+const ptx_instruction *ptx_instruction_lookup( const char *filename, unsigned linenumber );
+
+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);
+}
+
+extern int g_save_embedded_ptx;
+
+void 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);
+ }
+ g_filename = strdup(buf);
+ init_parser();
+ ptx__scan_string(p);
+ int errors = ptx_parse ();
+ if ( errors ) {
+ char fname[1024];
+ snprintf(fname,1024,"_ptx_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 >= 1 )
+ print_ptx_file(p,source_num,g_filename);
+
+ printf("GPGPU-Sim PTX: finished parsing EMBEDDED .ptx file %s\n",g_filename);
+
+ char fname[1024];
+ 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);
+ fclose(ptxfile);
+
+ char fname2[1024];
+ 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);
+ 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 commandline[1024];
+ snprintf(commandline,1024,"ptxas -v %s --output-file /dev/null 2> %s", 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);
+ }
+
+ ptxinfo_in = fopen(tempfile_ptxinfo,"r");
+ g_ptxinfo_filename = tempfile_ptxinfo;
+ ptxinfo_parse();
+ snprintf(commandline,1024,"rm -f %s %s %s", fname, fname2, tempfile_ptxinfo);
+ printf("GPGPU-Sim PTX: removing ptxinfo using \"%s\"\n", commandline);
+ result = system(commandline);
+ if( result != 0 ) {
+ printf("GPGPU-Sim PTX: ERROR ** while loading PTX (c) %d\n", result);
+ exit(1);
+ }
+ g_filename = NULL;
+}
+
+void gpgpu_ptx_assemble( std::string kname, void *kinfo )
+{
+ function_info *func_info = (function_info *)kinfo;
+ g_func_info = func_info;
+ g_current_symbol_table = g_kernel_name_to_symtab_lookup[ kname ];
+ if( g_current_symbol_table == NULL ) {
+ printf("\nGPGPU-Sim PTX: ERROR no information for kernel \'%s\'\n"
+ " this can happen for kernels contained in CUDA\n"
+ " libraries (such as CUBLAS, CUFFT, or CUDPP)\n", kname.c_str() );
+ exit(1);
+ }
+
+ func_info->ptx_assemble();
+}
+
+void gpgpu_ptx_sim_load_gpu_kernels()
+{
+ ptx_in = NULL;
+ if ( g_filename )
+ ptx_in = fopen( g_filename, "r" );
+ static unsigned source_num = 0;
+ gpgpu_ptx_sim_init_memory();
+ if (ptx_in) {
+ init_parser();
+ ptx_parse();
+ ptxinfo_in = open_ptxinfo(g_filename);
+ ptxinfo_parse();
+ load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF);
+ load_constants(g_global_symbol_table);
+ } else {
+ if (!g_override_embedded_ptx) {
+ g_used_embedded_ptx_files=1;
+ printf("GPGPU-Sim PTX: USING EMBEDDED .ptx files...\n");
+ ptx_info_t *s;
+ for ( s=g_ptx_source_array; s!=NULL; s=s->next ) {
+ gpgpu_ptx_sim_load_ptx_from_string(s->str, ++source_num);
+ load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF);
+ load_constants(g_global_symbol_table);
+ }
+ } else {
+ g_filename = NULL;
+ struct dirent **namelist;
+ int n;
+
+ n = scandir(".", &namelist, ptx_file_filter, alphasort);
+ if (n < 0)
+ perror("scandir");
+ else {
+ while (n--) {
+ if ( g_filename != NULL ) {
+ printf("Loader error: support for multiple .ptx files not yet enabled\n");
+ abort();
+ }
+ g_filename = strdup(namelist[n]->d_name);
+ printf("Parsing %s..\n", g_filename);
+ ptx_in = fopen( g_filename, "r" );
+ free(namelist[n]);
+ init_parser();
+ ptx_parse ();
+ ptxinfo_in = open_ptxinfo(g_filename);
+ ptxinfo_parse();
+ g_filename = NULL;
+ load_static_globals(g_global_symbol_table,0x10000000,0xFFFFFFFF);
+ load_constants(g_global_symbol_table);
+ }
+ free(namelist);
+ }
+ }
+ }
+
+ if ( ptx_in == NULL && g_override_embedded_ptx ) {
+ printf("GPGPU-Sim PTX Simulator error: Could find/open .ptx file for reading\n");
+ printf(" This means there are no .ptx files in the current directory.\n");
+ printf(" Either place a .ptx file in the current directory, or ensure\n" );
+ printf(" the PTX_SIM_KERNELFILE environment variable points to .ptx file.\n");
+ printf(" PTX_SIM_KERNELFILE=\"%s\"\n", g_filename );
+ exit(1);
+ }
+
+ if ( g_error_detected ) {
+ printf( "GPGPU-Sim PTX: Program parsing completed: Errors detected.\n" );
+ exit(1);
+ } else {
+ printf( "GPGPU-Sim PTX: Program parsing completed (max %u registers used per thread).\n", g_max_regs_per_thread );
+ }
+
+ if ( g_kernel_name_to_function_lookup ) {
+ for ( std::map<std::string,function_info*>::iterator f=g_kernel_name_to_function_lookup->begin();
+ f != g_kernel_name_to_function_lookup->end(); f++ ) {
+ gpgpu_ptx_assemble(f->first,f->second);
+ }
+ }
+}
+
+extern time_t simulation_starttime;
+
+ptx_cta_info *g_func_cta_info = NULL;
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+void gpgpu_ptx_sim_main_func( const char *kernel_key, dim3 gridDim, dim3 blockDim, struct gpgpu_ptx_sim_arg *args)
+{
+ printf("GPGPU-Sim: Performing Functional Simulation...\n");
+
+ printf("ERROR: Need to derived core_t for functional simulation, functional simulation no longer operational\n");
+ // also: need PDOM stack, etc... for functional simulation
+ exit(1);
+
+ time_t end_time, elapsed_time, days, hrs, minutes, sec;
+ int i1, i2, i3, i4, o1, o2, o3, o4;
+ int vectorin, vectorout;
+
+ gpgpu_ptx_sim_init_grid(kernel_key, args,gridDim,blockDim);
+
+ memory_space *shared_mem = new memory_space_impl<16*1024>("shared",4);
+
+ std::map<unsigned,memory_space*> lm_lookup;
+
+ if ( g_func_cta_info == NULL )
+ g_func_cta_info = new ptx_cta_info(0);
+
+ for ( unsigned gx=0; gx < gridDim.x; gx++ ) {
+ for ( unsigned gy=0; gy < gridDim.y; gy++ ) {
+ for ( unsigned gz=0; gz < gridDim.z; gz++ ) {
+ std::list<ptx_thread_info *> active_threads;
+ std::list<ptx_thread_info *> blocked_threads;
+
+ g_func_cta_info->check_cta_thread_status_and_reset();
+
+ for ( unsigned tx=0; tx < blockDim.x; tx++ ) {
+ for ( unsigned ty=0; ty < blockDim.y; ty++ ) {
+ for ( unsigned tz=0; tz < blockDim.z; tz++ ) {
+ memory_space *local_mem = NULL;
+ ptx_thread_info *thd = new ptx_thread_info();
+
+ unsigned lm_idx = blockDim.x*blockDim.y*tz + blockDim.x * ty + tx;
+ std::map<unsigned,memory_space*>::iterator lm=lm_lookup.find(lm_idx);
+ if ( lm == lm_lookup.end() ) {
+ char buf[1024];
+ snprintf(buf,1024,"local_(%u,%u,%u)", tx, ty, tz );
+ local_mem = new memory_space_impl<32>(buf,32);
+ lm_lookup[lm_idx] = local_mem;
+ } else {
+ local_mem = lm->second;
+ }
+
+
+ thd->set_info(g_current_symbol_table,g_func_info);
+ thd->set_nctaid(gridDim.x,gridDim.y,gridDim.z);
+ thd->set_ntid(blockDim.x, blockDim.y, blockDim.z);
+ thd->set_ctaid(gx,gy,gz);
+ thd->set_tid(tx,ty,tz);
+ thd->set_valid();
+ thd->m_shared_mem = shared_mem;
+ thd->m_local_mem = local_mem;
+ thd->m_cta_info = g_func_cta_info;
+ g_func_cta_info->add_thread(thd);
+ active_threads.push_back(thd);
+ }
+ }
+ }
+
+ while ( !(active_threads.empty() && blocked_threads.empty()) ) {
+ // while there are still threads left to execute in this CTA
+ ptx_thread_info *thread = NULL;
+
+ if ( !active_threads.empty() ) {
+ thread = active_threads.front();
+ active_threads.pop_front();
+ } else {
+ active_threads = blocked_threads;
+ blocked_threads.clear();
+ std::list<ptx_thread_info *>::iterator a=active_threads.begin();
+ for ( ; a != active_threads.end(); a++ ) {
+ ptx_thread_info *thd = *a;
+ thd->clear_barrier();
+ }
+ g_func_cta_info->release_barrier();
+ }
+
+ while ( thread != NULL ) {
+ if ( thread->is_at_barrier() ) {
+ blocked_threads.push_back(thread);
+ thread = NULL;
+ break;
+ }
+ if ( thread->is_done() ) {
+ thread->m_cta_info->register_deleted_thread(thread);
+ delete thread;
+ thread = NULL;
+ break;
+ }
+
+ unsigned op_type;
+ addr_t addr;
+ unsigned space;
+ int arch_reg[MAX_REG_OPERANDS] = { -1 };
+ unsigned data_size;
+ dram_callback_t callback;
+ unsigned warp_active_mask = (unsigned)-1; // vote instruction with diverged warps won't execute correctly
+ // in functional simulation mode
+
+ g_func_info->ptx_decode_inst( thread, &op_type, &i1, &i2, &i3, &i4, &o1, &o2, &o3, &o4, &vectorin, &vectorout, arch_reg );
+ g_func_info->ptx_exec_inst( thread, &addr, &space, &data_size, &callback, warp_active_mask );
+ }
+ }
+ }
+ }
+ }
+ 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]);
+ }
+ end_time = time((time_t *)NULL);
+ elapsed_time = MAX(end_time - simulation_starttime, 1);
+
+ 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 ptx_decode_inst( void *thd, unsigned *op, int *i1, int *i2, int *i3, int *i4, int *o1, int *o2, int *o3, int *o4, int *vectorin, int *vectorout, int *arch_reg )
+{
+ *op = NO_OP;
+ *o1 = 0;
+ *o2 = 0;
+ *o3 = 0;
+ *o4 = 0;
+ *i1 = 0;
+ *i2 = 0;
+ *i3 = 0;
+ *i4 = 0;
+ *vectorin = 0;
+ *vectorout = 0;
+ std::fill_n(arch_reg, MAX_REG_OPERANDS, -1);
+
+ if ( thd == NULL )
+ return;
+
+ ptx_thread_info *thread = (ptx_thread_info *) thd;
+ g_func_info = thread->func_info();
+ g_func_info->ptx_decode_inst(thread,op,i1,i2,i3,i4,o1,o2,o3,o4,vectorin,vectorout,arch_reg);
+}
+
+unsigned ptx_get_inst_op( void *thd)
+{
+ if ( thd == NULL )
+ return NO_OP;
+
+ ptx_thread_info *thread = (ptx_thread_info *) thd;
+ return(thread->func_info())->ptx_get_inst_op(thread);
+}
+
+void ptx_exec_inst( void *thd, address_type *addr, unsigned *space, unsigned *data_size, dram_callback_t* callback, unsigned warp_active_mask )
+{
+ if ( thd == NULL )
+ return;
+ ptx_thread_info *thread = (ptx_thread_info *) thd;
+ g_func_info = thread->func_info();
+ g_func_info->ptx_exec_inst( thread, addr, space, data_size, callback, warp_active_mask );
+}
+
+void ptx_dump_regs( void *thd )
+{
+ if ( thd == NULL )
+ return;
+ ptx_thread_info *t = (ptx_thread_info *) thd;
+ t->dump_regs();
+}
+
+unsigned ptx_set_tex_cache_linesize(unsigned linesize)
+{
+ g_texcache_linesize = linesize;
+ return 0;
+}
+
+unsigned ptx_kernel_program_size()
+{
+ return g_func_info->get_function_size();
+}
+
+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;
+}
+
+int g_ptxinfo_error_detected;
+
+
+static char *g_ptxinfo_kname = NULL;
+static struct gpgpu_ptx_sim_kernel_info g_ptxinfo_kinfo;
+
+extern "C" void ptxinfo_function(const char *fname )
+{
+ g_ptxinfo_kinfo.regs=0;
+ g_ptxinfo_kinfo.lmem=0;
+ g_ptxinfo_kinfo.smem=0;
+ g_ptxinfo_kinfo.cmem=0;
+ g_ptxinfo_kname = strdup(fname);
+}
+
+extern "C" void ptxinfo_regs( unsigned nregs )
+{
+ g_ptxinfo_kinfo.regs=nregs;
+}
+
+extern "C" void ptxinfo_lmem( unsigned declared, unsigned system )
+{
+ g_ptxinfo_kinfo.lmem=declared+system;
+}
+
+extern "C" void ptxinfo_smem( unsigned declared, unsigned system )
+{
+ g_ptxinfo_kinfo.smem=declared+system;
+}
+
+extern "C" void ptxinfo_cmem( unsigned nbytes, unsigned bank )
+{
+ g_ptxinfo_kinfo.cmem+=nbytes;
+}
+
+extern "C" void ptxinfo_addinfo()
+{
+ if ( g_kernel_name_to_function_lookup ) {
+ std::map<std::string,function_info*>::iterator i=g_kernel_name_to_function_lookup->find(g_ptxinfo_kname);
+ if ( (g_kernel_name_to_function_lookup == NULL) || (i == g_kernel_name_to_function_lookup->end()) ) {
+ printf ("GPGPU-Sim PTX: Kernel '%s' in %s not found. Ignoring.\n", g_ptxinfo_kname, g_filename);
+ } else {
+ printf ("GPGPU-Sim PTX: Kernel %s\n", g_ptxinfo_kname);
+ function_info *fi = i->second;
+ fi->set_kernel_info(&g_ptxinfo_kinfo);
+ }
+ } else {
+ printf ("GPGPU-Sim PTX: Kernel '%s' in %s not found (no kernels registered).\n", g_ptxinfo_kname, g_filename);
+ }
+
+ free(g_ptxinfo_kname);
+ g_ptxinfo_kname=NULL;
+ g_ptxinfo_kinfo.regs=0;
+ g_ptxinfo_kinfo.lmem=0;
+ g_ptxinfo_kinfo.smem=0;
+ g_ptxinfo_kinfo.cmem=0;
+}
+
+void dwf_insert_reconv_pt(address_type pc);
+
+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("Reconvergence Pairs for %s\n", finfo->get_name().c_str() );
+ for (int i=0;i<num_recon;i++)
+ printf("%d\t%d\n", kernel_recon_points[i].source_pc, kernel_recon_points[i].target_pc);
+ tmp.s_kernel_recon_points = kernel_recon_points;
+ tmp.s_num_recon = num_recon;
+ g_rpts[finfo] = tmp;
+ } else {
+ tmp = r->second;
+ }
+ return tmp;
+}
+
+unsigned int get_converge_point( unsigned int pc, void *thd )
+{
+ // 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 ) {
+ // function call return
+ ptx_thread_info *the_thread = (ptx_thread_info*)thd;
+ assert( the_thread != NULL );
+ return the_thread->get_return_PC();
+ } else {
+ return tmp.s_kernel_recon_points[i].target_pc;
+ }
+ }
+ }
+ assert(i < tmp.s_num_recon);
+ abort(); // returning garbage!
+}
+
+void find_reconvergence_points()
+{
+ find_reconvergence_points(g_func_info);
+}
+
+void dwf_process_reconv_pts()
+{
+ rec_pts tmp = find_reconvergence_points(g_func_info);
+ for (int i = 0; i < tmp.s_num_recon; ++i) {
+ dwf_insert_reconv_pt(tmp.s_kernel_recon_points[i].target_pc);
+ }
+}
+
+void *gpgpusim_opencl_getkernel_Object( const char *kernel_name )
+{
+ std::map<std::string,function_info*>::iterator i=g_kernel_name_to_function_lookup->find(kernel_name);
+
+ if( i == g_kernel_name_to_function_lookup->end() ) {
+ abort();
+ return NULL;
+ }
+ return i->second;
+}
diff --git a/src/cuda-sim/dram_callback.h b/src/cuda-sim/dram_callback.h
new file mode 100644
index 0000000..9336ee0
--- /dev/null
+++ b/src/cuda-sim/dram_callback.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Miles Kaech, Dan O'Connor and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+//////////////////////////////////////////////////////////
+//
+// dram_callback.h
+// by Miles Kaech
+//
+// defines a callback mechanism allowing instructions to be functionally executed
+// once they arrive at dram. For example, atomic instructions should really be
+// functionally simulated only once they hit the dram chips.
+//
+//////////////////////////////////////////////////////////
+
+#ifndef __DRAM_CALLBACK_H__
+#define __DRAM_CALLBACK_H__
+
+typedef struct {
+ void (*function)(void* pI, void* gOldGThread);
+ void* instruction;
+ void* thread;// callback has to abuse g_thread when executed
+}dram_callback_t;
+
+#endif // #ifndef __DRAM_CALLBACK_H__
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
new file mode 100644
index 0000000..a7a4df6
--- /dev/null
+++ b/src/cuda-sim/instructions.cc
@@ -0,0 +1,2921 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Ali Bakhoda, Joey Ting, Dan O'Connor,
+ * Clive Lin, George L. Yuan, Wilson W. L. Fung and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "instructions.h"
+#include "ptx_ir.h"
+#include "opcodes.h"
+#include "ptx_sim.h"
+#include "ptx.tab.h"
+#include "dram_callback.h"
+#include <stdlib.h>
+#include <math.h>
+#include <fenv.h>
+
+#include "cuda-math.h"
+#include "../abstract_hardware_model.h"
+
+unsigned g_num_ptx_inst_uid=0;
+unsigned cudasim_n_tex_insn=0;
+
+const char *g_opcode_string[NUM_OPCODES] = {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) STR,
+#include "opcodes.def"
+#undef OP_DEF
+};
+
+extern std::map<unsigned,std::string> g_ptx_token_decode;
+extern std::map<struct textureReference*,struct cudaArray*> TextureToArrayMap; // texture bindings
+extern std::map<struct textureReference*,struct textureInfo*> TextureToInfoMap; // texture bindings
+extern std::map<std::string, struct textureReference*> NameToTextureMap;
+
+memory_space *g_global_mem;
+memory_space *g_tex_mem;
+memory_space *g_surf_mem;
+memory_space *g_param_mem;
+
+void inst_not_implemented( const ptx_instruction * pI ) ;
+unsigned unfound_register_warned = 0;
+
+ptx_reg_t ptx_thread_info::get_operand_value( const symbol *reg )
+{
+ assert( reg->type()->get_key().is_reg() );
+ const std::string &name = reg->name();
+ std::map<std::string,ptx_reg_t>::iterator regs_iter = m_regs.back().find(name);
+ if (regs_iter == m_regs.back().end()) {
+ unsigned call_uid = m_callstack.back().m_call_uid;
+ ptx_reg_t uninit_reg;
+ uninit_reg.u32 = 0xDEADBEEF;
+ set_operand_value(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 0XDEADBEEF.\n",
+ file_loc.c_str(), name.c_str(), call_uid );
+ unfound_register_warned = 1;
+ }
+ regs_iter = m_regs.back().insert(std::make_pair(name, uninit_reg)).first;
+ }
+ return regs_iter->second;
+}
+
+ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op )
+{
+ ptx_reg_t result, tmp;
+ const char *name = NULL;
+ if ( op.is_reg() ) {
+ result = get_operand_value( op.get_symbol() );
+ } else if ( op.is_builtin()) {
+ result = get_builtin( op.get_int(), 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() ) {
+ name = op.name().c_str();
+ std::map<std::string,ptx_reg_t>::iterator regs_iter = m_regs.back().find(name);
+ assert( regs_iter != m_regs.back().end() );
+ tmp = regs_iter->second;
+ result.u64 = tmp.u64 + op.get_addr_offset();
+ } else if ( info.is_param() ) {
+ result = sym->get_address() + op.get_addr_offset();
+ } else if ( info.is_global() ) {
+ assert( op.get_addr_offset() == 0 );
+ result = sym->get_address();
+ } else if ( info.is_local() ) {
+ result = sym->get_address() + op.get_addr_offset();
+ } else if ( info.is_const() ) {
+ result = sym->get_address() + op.get_addr_offset();
+ } else if ( op.is_shared() ) {
+ result = op.get_symbol()->get_address() + op.get_addr_offset();
+ } else {
+ assert(0);
+ }
+
+ } else if ( op.is_literal() ) {
+ result = op.get_literal_value();
+ } else if ( op.is_label() ) {
+ result = op.get_symbol()->get_address();
+ } else if ( op.is_shared() ) {
+ result = op.get_symbol()->get_address();
+ } else if ( op.is_const() ) {
+ result = op.get_symbol()->get_address();
+ } else if ( op.is_global() ) {
+ result = op.get_symbol()->get_address();
+ } else if ( op.is_local() ) {
+ result = op.get_symbol()->get_address();
+ } else {
+ name = op.name().c_str();
+ printf("ERROR! %s is neither local, global, const, shared, label, literal, memory operand, builtin, or register!\n",name);
+ assert(0);
+ }
+
+ return result;
+}
+
+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 )
+{
+ const char *name1, *name2, *name3, *name4 = NULL;
+ if ( op.is_vector() ) {
+ if (num_elements > 3) {
+ name4 = op.vec_name4().c_str();
+ assert( m_regs.back().find(name4) != m_regs.back().end() );
+ ptx_regs[3] = m_regs.back()[ name4 ];
+ }
+ if (num_elements > 2) {
+ name3 = op.vec_name3().c_str();
+ assert( m_regs.back().find(name3) != m_regs.back().end() );
+ ptx_regs[2] = m_regs.back()[ name3 ];
+ }
+ name1 = op.vec_name1().c_str();
+ name2 = op.vec_name2().c_str();
+ assert( m_regs.back().find(name1) != m_regs.back().end() );
+ assert( m_regs.back().find(name2) != m_regs.back().end() );
+ ptx_regs[0] = m_regs.back()[ name1 ];
+ ptx_regs[1] = m_regs.back()[ name2 ];
+ } else {
+ assert(0);
+ }
+}
+
+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 )
+{
+ m_regs.back()[ dst.name() ] = data;
+ m_debug_trace_regs_modified.back()[ dst.name() ] = data;
+ m_last_set_operand_value = data;
+}
+
+void ptx_thread_info::set_operand_value( const symbol *dst, const ptx_reg_t &data )
+{
+ m_regs.back()[ dst->name() ] = data;
+ m_debug_trace_regs_modified.back()[ dst->name() ] = data;
+ m_last_set_operand_value = data;
+}
+
+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 )
+{
+ m_regs.back()[ dst.vec_name1() ] = data1;
+ m_debug_trace_regs_modified.back()[ dst.vec_name1() ] = data1;
+ m_regs.back()[ dst.vec_name2() ] = data2;
+ m_debug_trace_regs_modified.back()[ dst.vec_name2() ] = data2;
+ if (num_elements > 2) {
+ m_regs.back()[ dst.vec_name3() ] = data3;
+ m_debug_trace_regs_modified.back()[ dst.vec_name3() ] = data3;
+ if (num_elements > 3) {
+ m_regs.back()[ dst.vec_name4() ] = data4;
+ m_debug_trace_regs_modified.back()[ dst.vec_name4() ] = 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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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 F32_TYPE: d.f32 = my_abs(a.f32); break;
+ case F64_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);
+}
+
+void add_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_reg_t src1_data, src2_data, data;
+
+ 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();
+ src1_data = thread->get_operand_value(src1); //get values from the operand infos
+ src2_data = thread->get_operand_value(src2);
+
+ 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;
+ }
+
+ unsigned to_type = pI->get_type();
+
+ switch ( to_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:
+ data.s64 = src1_data.s64 + src2_data.s64; break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: data.f32 = src1_data.f32 + src2_data.f32; break;
+ case F64_TYPE: data.f64 = src1_data.f64 + src2_data.f64; break;
+ default: assert(0); break;
+ }
+ fesetround( orig_rm );
+ thread->set_operand_value(dst,data);
+}
+
+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();
+
+ src1_data = thread->get_operand_value(src1);
+ src2_data = thread->get_operand_value(src2);
+
+ data.u64 = src1_data.u64 & src2_data.u64;
+
+ thread->set_operand_value(dst,data);
+}
+
+void atom_callback( void* ptx_inst, void* thd )
+{
+ ptx_thread_info *thread = (ptx_thread_info*)thd;
+ ptx_instruction *pI = (ptx_instruction*)ptx_inst;
+
+ // Check state space
+ assert( pI->get_space()==GLOBAL_DIRECTIVE );
+
+ // "Decode" the output type
+ unsigned to_type = pI->get_type();
+ size_t size;
+ int t;
+ type_decode(to_type, size, t);
+
+ // Set up operand variables
+ ptx_reg_t data, // d
+ src1_data, // a
+ src2_data, // b
+ 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); // a
+ src2_data = thread->get_operand_value(src2); // b
+
+ // Copy value pointed to in operand 'a' into register 'd'
+ // (i.e. copy src1_data to dst)
+ g_global_mem->read(src1_data.u32,size/8,&data.s64);
+ thread->set_operand_value(dst, data); // 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);
+
+ 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 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\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 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;
+ default:
+ printf("Execution error: type mismatch with instruction\natom.ADD only accepts u32 and s32\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 global memory
+ // (i.e. copy src1_data to dst)
+ g_global_mem->write(src1_data.u32,size/8,&op_result.s64);
+}
+
+// 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)
+
+ // Check state space
+ assert( pI->get_space()==GLOBAL_DIRECTIVE );
+
+ // get the memory address
+ const operand_info &src1 = pI->src1();
+ ptx_reg_t src1_data = thread->get_operand_value(src1);
+
+ unsigned space = pI->get_space();
+
+ thread->m_last_effective_address = src1_data.u32;
+ thread->m_last_memory_space = space;
+ thread->m_last_dram_callback.function = atom_callback;
+ thread->m_last_dram_callback.instruction = (void*)pI;
+}
+
+void bar_sync_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ ptx_reg_t b = thread->get_operand_value(dst);
+ assert( b.u32 == 0 ); // not clear what should happen if this is not zero
+}
+
+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);
+
+ thread->m_branch_taken = true;
+ thread->set_npc(target_pc);
+}
+
+void brkpt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+extern int gpgpu_simd_model;
+#define POST_DOMINATOR 1 /* must match enum value in shader.h */
+void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *npc, unsigned *rpc );
+
+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();
+ const function_info *target_func = func_addr->get_pc();
+
+ // 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();
+ }
+
+ // read source arguements into register specified in declaration of function
+ std::list< std::pair<const symbol*, ptx_reg_t> > arg_values;
+ for( unsigned arg=0; arg < n_args; arg ++ ) {
+ const operand_info &op_info = pI->operand_lookup(n_return+1+arg);
+ if( !op_info.is_reg() ) {
+ printf("GPGPU-Sim PTX: Execution error - no support for non-register opernands for call/return\n");
+ abort();
+ }
+ const symbol *dst_reg = target_func->get_arg(arg);
+
+ ptx_reg_t src_value = thread->get_operand_value(op_info);
+ arg_values.push_back( std::make_pair(dst_reg,src_value) );
+ }
+
+ // note register for corresponding return instruction to place result into
+ const symbol *return_var_src = NULL;
+ const symbol *return_var_dst = NULL;
+ if( target_func->has_return() ) {
+ if( !pI->dst().is_reg() ) {
+ printf("GPGPU-Sim PTX: Execution error - no support for non-register dst reg for call\n");
+ abort();
+ }
+ return_var_dst = pI->dst().get_symbol();
+ return_var_src = target_func->get_return_var();
+ }
+
+ unsigned sid = thread->get_hw_sid();
+ unsigned tid = thread->get_hw_tid();
+ unsigned callee_pc=0, callee_rpc=0;
+ if( gpgpu_simd_model == POST_DOMINATOR ) {
+ get_pdom_stack_top_info(sid,tid,&callee_pc,&callee_rpc);
+ assert( callee_pc == thread->get_pc() );
+ }
+
+ thread->callstack_push(callee_pc+1,callee_rpc,return_var_src,return_var_dst,call_uid_next++);
+
+ std::list< std::pair<const symbol*, ptx_reg_t> >::iterator a;
+ for( a=arg_values.begin(); a != arg_values.end(); a++ ) {
+ const symbol *dst_reg = a->first;
+ ptx_reg_t value = a->second;
+ thread->set_operand_value(dst_reg,value);
+ }
+
+ thread->set_npc(target_func);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ switch ( i_type ) {
+ case PRED_TYPE: d.pred = (a.pred == 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); // TODO: add more typechecking like this
+ break;
+ }
+
+ thread->set_operand_value(dst,d);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+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;
+}
+
+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::__internal_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::__internal_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_rn(y.s64); break;
+ case RN_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
+ case RM_OPTION: y.f32 = cuda_math::__ll2float_rn(y.s64); break;
+ case RP_OPTION: y.f32 = cuda_math::__ll2float_rn(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:
+ y.f32 = cuda_math::__internal_nearbyintf(x.f32);
+ 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 (cuda_math::__cuda___isnanf(y.f32)) {
+ 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:
+ y.f64 = cuda_math::__internal_nearbyintf(x.f64);
+ 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 (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, chop, 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}
+};
+
+unsigned type_decode( unsigned type, size_t &size, int &basic_type )
+{
+ switch ( type ) {
+ case S8_TYPE: size=8; basic_type=1; return 0;
+ case S16_TYPE: size=16; basic_type=1; return 1;
+ case S32_TYPE: size=32; basic_type=1; return 2;
+ case S64_TYPE: size=64; basic_type=1; return 3;
+ case U8_TYPE: size=8; basic_type=0; return 4;
+ case U16_TYPE: size=16; basic_type=0; return 5;
+ case U32_TYPE: size=32; basic_type=0; return 6;
+ case U64_TYPE: size=64; basic_type=0; return 7;
+ case F16_TYPE: size=16; basic_type=-1; return 8;
+ case F32_TYPE: size=32; basic_type=-1; return 9;
+ case F64_TYPE: size=64; basic_type=-1; return 10;
+ case PRED_TYPE: size=1; basic_type=2; return 11;
+ case B8_TYPE: size=8; basic_type=0; return 12;
+ case B16_TYPE: size=16; basic_type=0; return 13;
+ case B32_TYPE: size=32; basic_type=0; return 14;
+ case B64_TYPE: size=64; basic_type=0; return 15;
+ default:
+ printf("ERROR ** type_decode() does not know about \"%s\"\n", g_ptx_token_decode[type].c_str() );
+ assert(0);
+ return 0xDEADBEEF;
+ }
+}
+
+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:
+ 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: data.f32 = cuda_math::__cuda_nearbyintf(data.f32); break;
+ case F64_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: 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: data.f64 = ceil(data.f64); break;
+ default: assert(0); break;
+ }
+ break;
+ default: break;
+ }
+
+ if (type == F32_TYPE) {
+ if (cuda_math::__cuda___isnanf(data.f32)) {
+ data.u32 = 0x7fffffff;
+ }
+ }
+ if (type == F64_TYPE) {
+ if (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:
+ 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_decode(from_type, from_width, from_sign);
+ unsigned dst_fmt = type_decode(to_type, to_width, to_sign);
+
+ ptx_reg_t data = thread->get_operand_value(src1);
+ 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);
+}
+
+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();
+
+ ptx_reg_t src1_data = thread->get_operand_value(src1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+
+ switch ( i_type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ data.s64 = src1_data.s64 / src2_data.s64; break;
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ case B8_TYPE:
+ case B16_TYPE:
+ case B32_TYPE:
+ 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: data.f64 = src1_data.f64 / src2_data.f64; break;
+ default: assert(0); break;
+ }
+ thread->set_operand_value(dst,data);
+}
+
+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();
+ src1_data = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+void exit_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ core_t *sc = thread->get_core();
+ unsigned warp_id = thread->get_hw_wid();
+ sc->warp_exit(warp_id);
+
+ thread->m_cta_info->register_thread_exit(thread);
+ thread->set_done();
+}
+
+void ld_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ ptx_reg_t src1_data = thread->get_operand_value(src1);
+ ptx_reg_t data;
+ unsigned space = pI->get_space();
+ unsigned vector_spec = pI->get_vector();
+ unsigned type = pI->get_type();
+ memory_space *mem = NULL;
+
+ switch ( space ) {
+ case GLOBAL_DIRECTIVE: mem = g_global_mem; break;
+ case LOCAL_DIRECTIVE: mem = thread->m_local_mem; break;
+ case TEX_DIRECTIVE: mem = g_tex_mem; break;
+ case SURF_DIRECTIVE: mem = g_surf_mem; break;
+ case PARAM_DIRECTIVE: mem = g_param_mem; break;
+ case SHARED_DIRECTIVE: mem = thread->m_shared_mem; break;
+ case CONST_DIRECTIVE: mem = g_global_mem; break;
+ default:
+ assert(0);
+ break;
+ }
+
+ size_t size;
+ int t;
+ data.u64=0;
+ type_decode(type,size,t);
+ if (!vector_spec) {
+ mem->read(src1_data.u32,size/8,&data.s64);
+ if( type == S16_TYPE || type == S32_TYPE )
+ sign_extend(data,size,dst);
+ thread->set_operand_value(dst,data);
+ } else {
+ ptx_reg_t data1, data2, data3, data4;
+ mem->read(src1_data.u32,size/8,&data1.s64);
+ mem->read(src1_data.u32+size/8,size/8,&data2.s64);
+ if (vector_spec != V2_TYPE) { //either V3 or V4
+ mem->read(src1_data.u32+2*size/8,size/8,&data3.s64);
+ if (vector_spec != V3_TYPE) { //v4
+ mem->read(src1_data.u32+3*size/8,size/8,&data4.s64);
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4, 4);
+ } else //v3
+ thread->set_vector_operand_values(dst,data1,data2,data3,data3,3);
+ } else //v2
+ thread->set_vector_operand_values(dst,data1,data2,data2,data2,2);
+ }
+ thread->m_last_effective_address = src1_data.u32;
+ thread->m_last_memory_space = space;
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+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;
+ ptx_reg_t a = thread->get_operand_value(src1);
+ ptx_reg_t b = thread->get_operand_value(src2);
+ ptx_reg_t c = thread->get_operand_value(src3);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+void mad_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;
+ ptx_reg_t a = thread->get_operand_value(src1);
+ ptx_reg_t b = thread->get_operand_value(src2);
+ ptx_reg_t c = thread->get_operand_value(src3);
+
+ unsigned i_type = pI->get_type();
+ 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;
+ else if ( pI->is_hi() ) d.s16 = (t.s32>>16) + c.s16;
+ else if ( pI->is_lo() ) d.s16 = t.s16 + c.s16;
+ else assert(0);
+ break;
+ case S32_TYPE:
+ t.s64 = a.s32 * b.s32;
+ if ( pI->is_wide() ) d.s64 = t.s64 + c.s64;
+ else if ( pI->is_hi() ) d.s32 = (t.s64>>32) + c.s32;
+ else if ( pI->is_lo() ) d.s32 = t.s32 + c.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 + c.s64;
+ else assert(0);
+ break;
+ case U16_TYPE:
+ t.u32 = a.u16 * b.u16;
+ if ( pI->is_wide() ) d.u32 = t.u32 + c.u32;
+ else if ( pI->is_hi() ) d.u16 = (t.u32>>16) + c.u16;
+ else if ( pI->is_lo() ) d.u16 = t.u16 + c.u16;
+ else assert(0);
+ break;
+ case U32_TYPE:
+ t.u64 = a.u32 * b.u32;
+ if ( pI->is_wide() ) d.u64 = t.u64 + c.u64;
+ else if ( pI->is_hi() ) d.u32 = (t.u64>>32) + c.u32;
+ else if ( pI->is_lo() ) d.u32 = t.u32 + c.u32;
+ 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 + c.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 + 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: {
+ 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);
+}
+
+bool isNaN(float x)
+{
+ return isnan(x);
+}
+
+bool isNaN(double x)
+{
+ return 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();
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+ 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: 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);
+}
+
+void membar_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ /* TODO: add timing model support */
+}
+
+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();
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+ 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: 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);
+}
+
+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();
+
+ if( src1.is_vector() || dst.is_vector() ) {
+ // 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);
+
+ 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 & (((unsigned long long) 0xFF) << (8*i)); break;
+ case 16: v[i].u16 = tmp_bits.u64 & (((unsigned long long) 0xFFFF) << (16*i)); break;
+ case 32: v[i].u32 = tmp_bits.u64 & (((unsigned long long) 0xFFFFFFFF) << (32*i)); 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],nelem);
+ } else {
+ thread->set_operand_value(dst,tmp_bits);
+ }
+ } else {
+ data = thread->get_operand_value(src1);
+ thread->set_operand_value(dst,data);
+ }
+}
+
+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();
+
+ src1_data = thread->get_operand_value(src1);
+ src2_data = thread->get_operand_value(src2);
+ src1_data.mask_and(0,0x00FFFFFF);
+ src2_data.mask_and(0,0x00FFFFFF);
+
+ unsigned i_type = pI->get_type();
+
+ 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);
+}
+
+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;
+ ptx_reg_t a = thread->get_operand_value(src1);
+ ptx_reg_t b = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+ 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: {
+ 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);
+}
+
+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();
+
+ src1_data = thread->get_operand_value(src1);
+
+ unsigned to_type = pI->get_type();
+ 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: data.f64 = 0.0f - src1_data.f64; break;
+ default: assert(0); break;
+ }
+
+ thread->set_operand_value(dst,data);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ switch ( i_type ) {
+ case PRED_TYPE: d.pred = ~a.pred; 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);
+}
+
+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();
+ src1_data = thread->get_operand_value(src1);
+ src2_data = thread->get_operand_value(src2);
+
+ data.u64 = src1_data.u64 | src2_data.u64;
+
+ thread->set_operand_value(dst,data);
+}
+
+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();
+ src1_data = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ switch ( i_type ) {
+ case F32_TYPE:
+ data.f32 = 1.0f / src1_data.f32;
+ break;
+ case F64_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);
+}
+
+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();
+
+ src1_data = thread->get_operand_value(src1);
+ src2_data = thread->get_operand_value(src2);
+
+ data.u64 = src1_data.u64 % src2_data.u64;
+
+ thread->set_operand_value(dst,data);
+}
+
+void ret_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ bool empty = thread->callstack_pop();
+ if( empty ) {
+ core_t *sc = thread->get_core();
+ unsigned warp_id = thread->get_hw_wid();
+ sc->warp_exit(warp_id);
+ thread->m_cta_info->register_thread_exit(thread);
+ thread->set_done();
+ }
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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:
+ 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);
+}
+
+#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->src1();
+ const operand_info &src3 = pI->src1();
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+ c = thread->get_operand_value(src3);
+
+ unsigned i_type = pI->get_type();
+ 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: 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);
+}
+
+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;
+
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+ c = thread->get_operand_value(src3);
+
+ d = (c.pred)?a:b;
+
+ thread->set_operand_value(dst,d);
+}
+
+bool isFloat(int type)
+{
+ switch ( type ) {
+ case F16_TYPE:
+ case F32_TYPE:
+ case F64_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:
+ 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
+
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+ unsigned type = pI->get_type();
+ unsigned cmpop = pI->get_cmpop();
+
+ t = CmpOp(type,a,b,cmpop);
+
+ ptx_reg_t data;
+ data.pred = (t!=0);
+
+ thread->set_operand_value(dst,data);
+}
+
+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
+
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+ unsigned src_type = pI->get_type2();
+ unsigned cmpop = pI->get_cmpop();
+
+ 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);
+
+}
+
+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();
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+
+
+ unsigned i_type = pI->get_type();
+ switch ( i_type ) {
+ case B16_TYPE:
+ if ( b.u16 >= 16 )
+ d.u16 = 0;
+ else
+ d.u16 = (unsigned short) ((a.u16 << b.u16) & 0xFFFF);
+ break;
+ case B32_TYPE:
+ if ( b.u32 >= 32 )
+ d.u32 = 0;
+ else
+ d.u32 = (unsigned) ((a.u32 << b.u32) & 0xFFFFFFFF);
+ break;
+ case B64_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);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ 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);
+}
+
+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;
+
+ a = thread->get_operand_value(src1);
+ b = thread->get_operand_value(src2);
+ c = thread->get_operand_value(src3);
+
+ bool t = false;
+ unsigned c_type = pI->get_type2();
+ switch ( c_type ) {
+ case S32_TYPE: t = c.s32 >= 0; break;
+ case F32_TYPE: t = c.f32 >= 0; break;
+ default: assert(0);
+ }
+
+ unsigned i_type = pI->get_type();
+
+ switch ( i_type ) {
+ case B16_TYPE:
+ case U16_TYPE: d.u16 = t?a.u16:b.u16; break;
+ case F32_TYPE:
+ case B32_TYPE:
+ case U32_TYPE: d.u32 = t?a.u32:b.u32; break;
+ case F64_TYPE:
+ case B64_TYPE:
+ case U64_TYPE: d.u64 = t?a.u64:b.u64; break;
+ default: assert(0);
+ }
+
+ thread->set_operand_value(dst,d);
+}
+
+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();
+ a = thread->get_operand_value(src1);
+
+ unsigned i_type = pI->get_type();
+ switch ( i_type ) {
+ case F32_TYPE:
+ if ( a.f32 < 0 )
+ d.f32 = nanf("");
+ else
+ d.f32 = sqrt(a.f32); break;
+ case F64_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);
+}
+
+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
+ ptx_reg_t addr = thread->get_operand_value(dst);
+ ptx_reg_t data;
+ unsigned space = pI->get_space();
+ unsigned vector_spec = pI->get_vector();
+ unsigned type = pI->get_type();
+ memory_space *mem = NULL;
+
+ switch ( space ) {
+ case GLOBAL_DIRECTIVE: mem = g_global_mem; break;
+ case LOCAL_DIRECTIVE: mem = thread->m_local_mem; break;
+ case TEX_DIRECTIVE: mem = g_tex_mem; break;
+ case SURF_DIRECTIVE: mem = g_surf_mem; break;
+ case PARAM_DIRECTIVE: mem = g_param_mem; break;
+ case SHARED_DIRECTIVE: mem = thread->m_shared_mem; break;
+ default:
+ assert(0);
+ break;
+ }
+
+ size_t size;
+ int t;
+ type_decode(type,size,t);
+
+ if (!vector_spec) {
+ data = thread->get_operand_value(src1);
+ mem->write(addr.u32,size/8,&data.s64);
+ } 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.u32,size/8,&ptx_regs[0].s64);
+ mem->write(addr.u32+size/8,size/8,&ptx_regs[1].s64);
+ free(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.u32,size/8,&ptx_regs[0].s64);
+ mem->write(addr.u32+size/8,size/8,&ptx_regs[1].s64);
+ mem->write(addr.u32+2*size/8,size/8,&ptx_regs[2].s64);
+ free(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.u32,size/8,&ptx_regs[0].s64);
+ mem->write(addr.u32+size/8,size/8,&ptx_regs[1].s64);
+ mem->write(addr.u32+2*size/8,size/8,&ptx_regs[2].s64);
+ mem->write(addr.u32+3*size/8,size/8,&ptx_regs[3].s64);
+ free(ptx_regs);
+ }
+ }
+ thread->m_last_effective_address = addr.u32;
+ thread->m_last_memory_space = space;
+}
+
+void sub_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 src1_data = thread->get_operand_value(src1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2);
+
+ unsigned i_type = pI->get_type();
+
+ switch ( i_type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ data.s64 = src1_data.s64 - src2_data.s64; break;
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ case B8_TYPE:
+ case B16_TYPE:
+ case B32_TYPE:
+ 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: data.f64 = src1_data.f64 - src2_data.f64; break;
+ default: assert(0); break;
+ }
+
+ thread->set_operand_value(dst,data);
+}
+
+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 )
+{
+ unsigned nx = (mx+x)%mx;
+ unsigned ny = (my+y)%my;
+ return nx + mx*ny;
+}
+
+void tex_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ cudasim_n_tex_insn++;
+ 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();
+ fflush(stdout);
+ ptx_reg_t data1, data2, data3, data4;
+ if (!ptx_tex_regs) ptx_tex_regs = new ptx_reg_t[4];
+ thread->get_vector_operand_values(src2, ptx_tex_regs, 4); //ptx_reg should be 4 entry vector type...coordinates into texture
+
+ assert(NameToTextureMap.find(texname) != NameToTextureMap.end());//use map to find texturerefence, then use map to find pointer to array
+ struct textureReference* texref = NameToTextureMap[texname];
+ assert(TextureToArrayMap.find(texref) != TextureToArrayMap.end());
+ struct cudaArray* cuArray = TextureToArrayMap[texref];
+ assert(TextureToInfoMap.find(texref) != TextureToInfoMap.end());
+ struct textureInfo* texInfo = TextureToInfoMap[texref];
+
+ //assume always 2D f32 input
+ //access array with src2 coordinates
+ memory_space *mem = g_global_mem;
+ 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_decode(to_type,size,t);
+ tex_array_base = cuArray->devPtr32;
+
+ switch (dimension) {
+ case GEOM_MODIFIER_1D:
+ x = ptx_tex_regs[0].u64;
+ 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 S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ mem->read( tex_array_index, cuArray->desc.x/8, &data1.u32);
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index+4, cuArray->desc.y/8, &data2.u32);
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index+8, cuArray->desc.z/8, &data3.u32);
+ if (cuArray->desc.w)
+ mem->read( tex_array_index+12, cuArray->desc.w/8, &data4.u32);
+ }
+ }
+ break;
+ case U64_TYPE:
+ case S64_TYPE:
+ mem->read( tex_array_index, 8, &data1.u64);
+ if (cuArray->desc.y) {
+ mem->read( tex_array_index+4, 8, &data2.u64);
+ if (cuArray->desc.z) {
+ mem->read( tex_array_index+8, 8, &data3.u64);
+ if (cuArray->desc.w)
+ mem->read( tex_array_index+12, 8, &data4.u64);
+ }
+ }
+ break;
+ case F16_TYPE: assert(0); break;
+ case F32_TYPE: {
+ if( texref->filterMode == cudaFilterModeLinear ) {
+ float Tij;
+ float Ti1j;
+ float Tij1;
+ float Ti1j1;
+
+ mem->read(tex_array_base + wrap(x,y,width,height), 4, &Tij);
+ mem->read(tex_array_base + wrap(x+4,y,width,height), 4, &Ti1j);
+ mem->read(tex_array_base + wrap(x,y+1,width,height), 4, &Tij1);
+ mem->read(tex_array_base + wrap(x+4,y+1,width,height), 4, &Ti1j1);
+
+ data1.f32 = (1-alpha)*(1-beta)*Tij +
+ alpha*(1-beta)*Ti1j +
+ (1-alpha)*beta*Tij1 +
+ alpha*beta*Ti1j1;
+
+ } 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:
+ 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;
+ x_block_coord = x_block_coord >> (texInfo->Tx_numbits + texInfo->texel_size_numbits);
+
+ y_block_coord = y;
+ y_block_coord = y_block_coord >> 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_DIRECTIVE;
+ thread->set_vector_operand_values(dst,data1,data2,data3,data4,4);
+}
+void trap_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+extern unsigned g_warp_active_mask;
+
+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 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;
+ unsigned mask=0x80000000;
+ unsigned offset=31;
+ while( mask && ((mask & g_warp_active_mask)==0) ) {
+ mask = mask>>1;
+ offset--;
+ }
+ 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);
+
+ bool pred_value = src1_data.pred;
+ bool invert = src1.is_neg_pred();
+
+ threads_in_warp.push_back(thread);
+ and_all &= (invert ^ pred_value);
+ or_all |= (invert ^ pred_value);
+
+ // TODO: determine last active thread in warp...
+ if( thread->get_hw_tid() == last_tid ) {
+ 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?1:0;
+
+ 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);
+ }
+ 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();
+
+ src1_data = thread->get_operand_value(src1);
+ src2_data = thread->get_operand_value(src2);
+
+ data.u64 = src1_data.u64 ^ src2_data.u64;
+
+ thread->set_operand_value(dst,data);
+}
+
+void inst_not_implemented( const ptx_instruction * pI )
+{
+ printf("Execution error (%s:%u): instruction \"%s\" not (yet) implemented\n",
+ pI->source_file(),
+ pI->source_line(),
+ pI->get_opcode_cstr() );
+ abort();
+}
+
+void print_instruction(const ptx_instruction *instruction)
+{
+}
+
diff --git a/src/cuda-sim/memory.cc b/src/cuda-sim/memory.cc
new file mode 100644
index 0000000..c6a1a9b
--- /dev/null
+++ b/src/cuda-sim/memory.cc
@@ -0,0 +1,154 @@
+/*
+ * memory.cc
+ *
+ * Copyright © 2009 by Tor M. Aamodt, Wilson W. L. Fung and the University of
+ * British Columbia, Vancouver, BC V6T 1Z4, All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "memory.h"
+#include <stdlib.h>
+
+template<unsigned BSIZE> memory_space_impl<BSIZE>::memory_space_impl( std::string name, unsigned hash_size )
+{
+ m_name = name;
+ MEM_MAP_RESIZE(hash_size);
+
+ m_log2_block_size = -1;
+ for( unsigned n=0, mask=1; mask != 0; mask <<= 1, n++ ) {
+ if( BSIZE & mask ) {
+ assert( m_log2_block_size == (unsigned)-1 );
+ m_log2_block_size = n;
+ }
+ }
+ assert( m_log2_block_size != (unsigned)-1 );
+}
+
+template<unsigned BSIZE> void memory_space_impl<BSIZE>::write( mem_addr_t addr, size_t length, const void *data )
+{
+ mem_addr_t index = addr >> m_log2_block_size;
+ unsigned offset = addr & (BSIZE-1);
+ unsigned nbytes = length;
+ assert( (addr+length) <= (index+1)*BSIZE );
+ m_data[index].write(offset,nbytes,(const unsigned char*)data);
+}
+
+template<unsigned BSIZE> void memory_space_impl<BSIZE>::read( mem_addr_t addr, size_t length, void *data ) const
+{
+ mem_addr_t index = addr >> m_log2_block_size;
+ unsigned offset = addr & (BSIZE-1);
+ unsigned nbytes = length;
+ typename map_t::const_iterator i = m_data.find(index);
+ assert( (addr+length) <= (index+1)*BSIZE );
+ if( i == m_data.end() ) {
+ for( size_t n=0; n < length; n++ )
+ ((unsigned char*)data)[n] = (unsigned char) 0;
+ //printf("GPGPU-Sim PTX: WARNING reading %zu bytes from unititialized memory at address 0x%x in space %s\n", length, addr, m_name.c_str() );
+ } else {
+ i->second.read(offset,nbytes,(unsigned char*)data);
+ }
+}
+
+template class memory_space_impl<32>;
+template class memory_space_impl<64>;
+template class memory_space_impl<8192>;
+template class memory_space_impl<16*1024>;
+
+
+#ifdef UNIT_TEST
+
+int main(int argc, char *argv[] )
+{
+ int errors_found=0;
+ memory_space *mem = new memory_space_impl<32>("test",4);
+ // write address to [address]
+ for( mem_addr_t addr=0; addr < 16*1024; addr+=4)
+ mem->write(addr,4,&addr);
+
+ for( mem_addr_t addr=0; addr < 16*1024; addr+=4) {
+ unsigned tmp=0;
+ mem->read(addr,4,&tmp);
+ if( tmp != addr ) {
+ errors_found=1;
+ printf("ERROR ** mem[0x%x] = 0x%x, expected 0x%x\n", addr, tmp, addr );
+ }
+ }
+
+ for( mem_addr_t addr=0; addr < 16*1024; addr+=1) {
+ unsigned char val = (addr + 128) % 256;
+ mem->write(addr,1,&val);
+ }
+
+ for( mem_addr_t addr=0; addr < 16*1024; addr+=1) {
+ unsigned tmp=0;
+ mem->read(addr,1,&tmp);
+ unsigned char val = (addr + 128) % 256;
+ if( tmp != val ) {
+ errors_found=1;
+ printf("ERROR ** mem[0x%x] = 0x%x, expected 0x%x\n", addr, tmp, (unsigned)val );
+ }
+ }
+
+ if( errors_found ) {
+ printf("SUMMARY: ERRORS FOUND\n");
+ } else {
+ printf("SUMMARY: UNIT TEST PASSED\n");
+ }
+}
+
+#endif
diff --git a/src/cuda-sim/memory.h b/src/cuda-sim/memory.h
new file mode 100644
index 0000000..6eebcf4
--- /dev/null
+++ b/src/cuda-sim/memory.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2009 by Tor M. Aamodt, Wilson W. L. Fung and the University of
+ * British Columbia, Vancouver, BC V6T 1Z4, All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#ifndef memory_h_INCLUDED
+#define memory_h_INCLUDED
+
+#ifdef __GNUC__
+#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
+ #include <unordered_map>
+ #define mem_map std::unordered_map
+ #define MEM_MAP_RESIZE(hash_size) m_data.rehash(hash_size)
+#else
+ #include <ext/hash_map>
+ namespace std {
+ using namespace __gnu_cxx;
+ }
+ #define mem_map std::hash_map
+ #define MEM_MAP_RESIZE(hash_size) m_data.resize(hash_size)
+#endif
+#else
+ #include <map>
+ #define mem_map std::map
+ #define MEM_MAP_RESIZE(hash_size)
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <string>
+#include "../util.h"
+
+typedef address_type mem_addr_t;
+
+#define MEM_BLOCK_SIZE (4*1024)
+
+template<unsigned BSIZE> class mem_storage {
+public:
+ mem_storage( const mem_storage &another )
+ {
+ m_data = new unsigned char[ BSIZE ];
+ memcpy(m_data,another.m_data,BSIZE);
+ }
+ mem_storage()
+ {
+ m_data = new unsigned char[ BSIZE ];
+ }
+ ~mem_storage()
+ {
+ delete[] m_data;
+ }
+
+ void write( unsigned offset, size_t length, const unsigned char *data )
+ {
+ assert( offset + length <= BSIZE );
+ memcpy(m_data+offset,data,length);
+ }
+
+ void read( unsigned offset, size_t length, unsigned char *data ) const
+ {
+ assert( offset + length <= BSIZE );
+ memcpy(data,m_data+offset,length);
+ }
+
+private:
+ unsigned m_nbytes;
+ unsigned char *m_data;
+};
+
+class memory_space
+{
+public:
+ virtual ~memory_space() {}
+ virtual void write( mem_addr_t addr, size_t length, const void *data ) = 0;
+ virtual void read( mem_addr_t addr, size_t length, void *data ) const = 0;;
+};
+
+template<unsigned BSIZE> class memory_space_impl : public memory_space {
+public:
+ memory_space_impl( std::string name, unsigned hash_size );
+
+ virtual void write( mem_addr_t addr, size_t length, const void *data );
+ virtual void read( mem_addr_t addr, size_t length, void *data ) const;
+
+private:
+ std::string m_name;
+ unsigned m_log2_block_size;
+ typedef mem_map<mem_addr_t,mem_storage<BSIZE> > map_t;
+ map_t m_data;
+};
+
+#endif
diff --git a/src/cuda-sim/opcodes.def b/src/cuda-sim/opcodes.def
new file mode 100644
index 0000000..ba6657f
--- /dev/null
+++ b/src/cuda-sim/opcodes.def
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
+ * George L. Yuan and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+/*6th operand of each OP_DEF reflects its classification */
+/*Type
+ALU 1
+MAD 2
+Control 3
+SFU 4
+Mem(except Tex) 5
+Tex 6
+*/
+OP_DEF(ABS_OP,abs_impl,"abs",1,1)
+OP_DEF(ADD_OP,add_impl,"add",1,1)
+OP_DEF(AND_OP,and_impl,"and",1,1)
+OP_DEF(ATOM_OP,atom_impl,"atom",0,3)
+OP_DEF(BAR_OP,bar_sync_impl,"bar.sync",1,3)
+OP_DEF(BRA_OP,bra_impl,"bra",0,3)
+OP_DEF(CALL_OP,call_impl,"call",1,3) /*call may actually return an value if the syntax is call (ret-param),fname,(param-list)*/
+OP_DEF(CNOT_OP,cnot_impl,"cnot",1,1)
+OP_DEF(COS_OP,cos_impl,"cos",1,4)
+OP_DEF(CVT_OP,cvt_impl,"cvt",1,1)
+OP_DEF(DIV_OP,div_impl,"div",1,1)
+OP_DEF(EX2_OP,ex2_impl,"ex2",1,4)
+OP_DEF(EXIT_OP,exit_impl,"exit",1,3)
+OP_DEF(LD_OP,ld_impl,"ld",1,5)
+OP_DEF(LG2_OP,lg2_impl,"lg2",1,4)
+OP_DEF(MAD24_OP,mad24_impl,"mad24",1,2)
+OP_DEF(MAD_OP,mad_impl,"mad",1,2)
+OP_DEF(MAX_OP,max_impl,"max",1,1)
+OP_DEF(MIN_OP,min_impl,"min",1,1)
+OP_DEF(MOV_OP,mov_impl,"mov",1,1)
+OP_DEF(MUL24_OP,mul24_impl,"mul24",1,1)
+OP_DEF(MUL_OP,mul_impl,"mul",1,1)
+OP_DEF(NEG_OP,neg_impl,"neg",1,1)
+OP_DEF(NOT_OP,not_impl,"not",1,1)
+OP_DEF(OR_OP,or_impl,"or",1,1)
+OP_DEF(RCP_OP,rcp_impl,"rcp",1,4)
+OP_DEF(REM_OP,rem_impl,"rem",1,1)
+OP_DEF(RET_OP,ret_impl,"ret",0,3)
+OP_DEF(RSQRT_OP,rsqrt_impl,"rsqrt",1,4)
+OP_DEF(SAD_OP,sad_impl,"sad",1,1)
+OP_DEF(SELP_OP,selp_impl,"selp",1,1)
+OP_DEF(SETP_OP,setp_impl,"setp",1,1)
+OP_DEF(SET_OP,set_impl,"set",1,1)
+OP_DEF(SHL_OP,shl_impl,"shl",1,1)
+OP_DEF(SHR_OP,shr_impl,"shr",1,1)
+OP_DEF(SIN_OP,sin_impl,"sin",1,4)
+OP_DEF(SLCT_OP,slct_impl,"slct",1,1)
+OP_DEF(SQRT_OP,sqrt_impl,"sqrt",1,4)
+OP_DEF(ST_OP,st_impl,"st",0,5)
+OP_DEF(SUB_OP,sub_impl,"sub",1,1)
+OP_DEF(TEX_OP,tex_impl,"tex",1,6)
+OP_DEF(TRAP_OP,trap_impl,"trap",1,3)
+OP_DEF(VOTE_OP,vote_impl,"vote",0,3)
+OP_DEF(XOR_OP,xor_impl,"xor",1,1)
+OP_DEF(MEMBAR_OP,membar_impl,"membar",1,3)
+OP_DEF(RED_OP,red_impl,"red",1,7)
+OP_DEF(ADDC_OP,addc_impl,"addc",1,1)
+OP_DEF(BRKPT_OP,brkpt_impl,"brkpt",1,9)
diff --git a/src/cuda-sim/opcodes.h b/src/cuda-sim/opcodes.h
new file mode 100644
index 0000000..221bf2e
--- /dev/null
+++ b/src/cuda-sim/opcodes.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#ifndef opcodes_h_included
+#define opcodes_h_included
+
+enum opcode_t {
+#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) OP,
+#include "opcodes.def"
+ NUM_OPCODES
+#undef OP_DEF
+};
+
+enum special_regs {
+ CLOCK_ID,
+ CTA_ID,
+ NTID_ID,
+ GRIDID_ID,
+ NCTAID_ID,
+ TID_ID
+};
+
+#endif
diff --git a/src/cuda-sim/ptx-stats.cc b/src/cuda-sim/ptx-stats.cc
new file mode 100644
index 0000000..2d18286
--- /dev/null
+++ b/src/cuda-sim/ptx-stats.cc
@@ -0,0 +1,298 @@
+/*
+ * Copyright © 2009 by Wilson W. L. Fung and the University of British Columbia,
+ * Vancouver, BC V6T 1Z4, All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "ptx_ir.h"
+#include "ptx_sim.h"
+#include "ptx-stats.h"
+#include "../option_parser.h"
+#include <stdio.h>
+#include <map>
+
+// external dependencies
+extern function_info *g_func_info;
+
+// options
+int enable_ptx_file_line_stats;
+char * ptx_line_stats_filename = NULL;
+
+void ptx_file_line_stats_options(option_parser_t opp)
+{
+ option_parser_register(opp, "-enable_ptx_file_line_stats", OPT_BOOL,
+ &enable_ptx_file_line_stats,
+ "Turn on PTX source line statistic profiling. (1 = On)", "1");
+ option_parser_register(opp, "-ptx_line_stats_filename", OPT_CSTR,
+ &ptx_line_stats_filename,
+ "Output file for PTX source line statistics.", "gpgpu_inst_stats.txt");
+}
+
+// implementations
+
+// defining a PTX source line = filename + line number
+class ptx_file_line
+{
+public:
+ ptx_file_line(const char* s, int l){
+ if( s == NULL )
+ st = "NULL_NAME";
+ else
+ st = s;
+ line = l;
+ }
+
+ bool operator<(const ptx_file_line &other) const {
+ if( st == other.st ) {
+ if( line < other.line )
+ return true;
+ else
+ return false;
+ } else {
+ return st < other.st;
+ }
+ }
+
+ bool operator==(const ptx_file_line &other) const {
+ return (st==other.st) and (line==other.line);
+ }
+
+ std::string st;
+ unsigned line;
+};
+
+// holds all statistics collected for a singe PTX source line
+class ptx_file_line_stats
+{
+public:
+ ptx_file_line_stats()
+ : exec_count(0), latency(0), dram_traffic(0),
+ smem_n_way_bank_conflict_total(0), smem_warp_count(0),
+ gmem_n_access_total(0), gmem_warp_count(0), exposed_latency(0),
+ warp_divergence(0)
+ { }
+
+ unsigned long exec_count;
+ unsigned long long latency;
+ unsigned long long dram_traffic;
+ unsigned long long smem_n_way_bank_conflict_total; // total number of banks accessed by this instruction
+ unsigned long smem_warp_count; // number of warps accessing shared memory
+ unsigned long long gmem_n_access_total; // number of uncoalesced access in total from this instruction
+ unsigned long gmem_warp_count; // number of warps causing these uncoalesced access
+ unsigned long long exposed_latency; // latency exposed as pipeline bubbles (attributed to this instruction)
+ unsigned long long warp_divergence; // number of warp divergence occured at this instruction
+};
+
+static std::map<ptx_file_line, ptx_file_line_stats> ptx_file_line_stats_tracker;
+
+// output statistics to a file
+void ptx_file_line_stats_write_file()
+{
+ // check if stat collection is turned on
+ if (enable_ptx_file_line_stats == 0) return;
+
+ std::map<ptx_file_line, ptx_file_line_stats>::iterator it;
+ FILE * pfile;
+
+ pfile = fopen(ptx_line_stats_filename, "w");
+ fprintf(pfile,"kernel line : count latency dram_traffic smem_bk_conflicts smem_warp gmem_access_generated gmem_warp exposed_latency warp_divergence\n");
+ for( it=ptx_file_line_stats_tracker.begin(); it != ptx_file_line_stats_tracker.end(); it++ ) {
+ fprintf(pfile, "%s %i : ", it->first.st.c_str(), it->first.line);
+ fprintf(pfile, "%lu ", it->second.exec_count);
+ fprintf(pfile, "%llu ", it->second.latency);
+ fprintf(pfile, "%llu ", it->second.dram_traffic);
+ fprintf(pfile, "%llu ", it->second.smem_n_way_bank_conflict_total);
+ fprintf(pfile, "%lu ", it->second.smem_warp_count);
+ fprintf(pfile, "%llu ", it->second.gmem_n_access_total);
+ fprintf(pfile, "%lu ", it->second.gmem_warp_count);
+ fprintf(pfile, "%llu ", it->second.exposed_latency);
+ fprintf(pfile, "%llu ", it->second.warp_divergence);
+ fprintf(pfile, "\n");
+ }
+ fflush(pfile);
+ fclose(pfile);
+}
+
+// attribute one more execution count to this ptx instruction
+// counting the number of threads (not warps) executing this instruction
+void ptx_file_line_stats_add_exec_count(const ptx_instruction *pInsn)
+{
+ ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())].exec_count += 1;
+}
+
+// attribute pipeline latency to this ptx instruction (specified by the pc)
+// pipeline latency is the number of cycles a warp with this instruction spent in the pipeline
+void ptx_file_line_stats_add_latency(void * ptx_thd, unsigned pc, unsigned latency)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())].latency += latency;
+}
+
+// attribute dram traffic to this ptx instruction (specified by the pc)
+// dram traffic is counted in number of requests
+void ptx_file_line_stats_add_dram_traffic(unsigned pc, unsigned dram_traffic)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())].dram_traffic += dram_traffic;
+}
+
+// attribute the number of shared memory access cycles to a ptx instruction
+// counts both the number of warps doing shared memory access and the number of cycles involved
+void ptx_file_line_stats_add_smem_bank_conflict(void * ptx_thd, unsigned pc, unsigned n_way_bkconflict)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ ptx_file_line_stats& line_stats = ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())];
+ line_stats.smem_n_way_bank_conflict_total += n_way_bkconflict;
+ line_stats.smem_warp_count += 1;
+}
+
+// attribute a non-coalesced mem access to a ptx instruction
+// counts both the number of warps causing this and the number of memory requests generated
+void ptx_file_line_stats_add_uncoalesced_gmem(void * ptx_thd, unsigned pc, unsigned n_access)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ ptx_file_line_stats& line_stats = ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())];
+ line_stats.gmem_n_access_total += n_access;
+ line_stats.gmem_warp_count += 1;
+}
+
+// a class that tracks the inflight memory instructions of a shader core
+// and attributes exposed latency to those instructions when signaled to do so
+class ptx_inflight_memory_insn_tracker
+{
+public:
+ typedef std::map<const ptx_instruction *, int> insn_count_map;
+
+ void add_count(const ptx_instruction * pInsn, int count = 1)
+ {
+ ptx_inflight_memory_insns[pInsn] += count;
+ }
+
+ void sub_count(const ptx_instruction * pInsn, int count = 1)
+ {
+ insn_count_map::iterator i_insncount;
+ i_insncount = ptx_inflight_memory_insns.find(pInsn);
+
+ assert(i_insncount != ptx_inflight_memory_insns.end());
+
+ i_insncount->second -= count;
+
+ if (i_insncount->second <= 0) {
+ ptx_inflight_memory_insns.erase(i_insncount);
+ }
+ }
+
+ void attribute_exposed_latency(int count = 1)
+ {
+ insn_count_map &exlat_insnmap = ptx_inflight_memory_insns;
+ insn_count_map::const_iterator i_exlatinsn;
+
+ i_exlatinsn = exlat_insnmap.begin();
+ for (; i_exlatinsn != exlat_insnmap.end(); ++i_exlatinsn) {
+ const ptx_instruction *pInsn = i_exlatinsn->first;
+ ptx_file_line_stats& line_stats = ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())];
+ line_stats.exposed_latency += count;
+ }
+ }
+
+ insn_count_map ptx_inflight_memory_insns;
+};
+
+static ptx_inflight_memory_insn_tracker *inflight_mem_tracker = NULL;
+
+void ptx_file_line_stats_create_exposed_latency_tracker(int n_shader_cores)
+{
+ inflight_mem_tracker = new ptx_inflight_memory_insn_tracker[n_shader_cores];
+}
+
+// add an inflight memory instruction
+void ptx_file_line_stats_add_inflight_memory_insn(int sc_id, unsigned pc)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ inflight_mem_tracker[sc_id].add_count(pInsn);
+}
+
+// remove an inflight memory instruction
+void ptx_file_line_stats_sub_inflight_memory_insn(int sc_id, unsigned pc)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ inflight_mem_tracker[sc_id].sub_count(pInsn);
+}
+
+// attribute an empty cycle in the pipeline (exposed latency) to the ptx memory instructions in flight
+void ptx_file_line_stats_commit_exposed_latency(int sc_id, int exposed_latency)
+{
+ assert(exposed_latency > 0);
+ inflight_mem_tracker[sc_id].attribute_exposed_latency(exposed_latency);
+}
+
+// attribute the number of warp divergence to a ptx instruction
+void ptx_file_line_stats_add_warp_divergence(unsigned pc, unsigned n_way_divergence)
+{
+ const ptx_instruction *pInsn = function_info::pc_to_instruction(pc);
+
+ ptx_file_line_stats& line_stats = ptx_file_line_stats_tracker[ptx_file_line(pInsn->source_file(), pInsn->source_line())];
+ line_stats.warp_divergence += n_way_divergence;
+}
+
diff --git a/src/cuda-sim/ptx-stats.h b/src/cuda-sim/ptx-stats.h
new file mode 100644
index 0000000..200f7a5
--- /dev/null
+++ b/src/cuda-sim/ptx-stats.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2009 by Wilson W. L. Fung and the University of British Columbia,
+ * Vancouver, BC V6T 1Z4, All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#pragma once
+
+#include "../option_parser.h"
+
+extern int enable_ptx_file_line_stats;
+
+// set options
+void ptx_file_line_stats_options(option_parser_t opp);
+
+// output stats to a file
+void ptx_file_line_stats_write_file();
+
+#ifdef __cplusplus
+// stat collection interface to cuda-sim
+class ptx_instruction;
+void ptx_file_line_stats_add_exec_count(const ptx_instruction *pInsn);
+#endif
+
+// stat collection interface to gpgpu-sim
+void ptx_file_line_stats_add_latency(void * ptx_thd, unsigned pc, unsigned latency);
+void ptx_file_line_stats_add_dram_traffic(unsigned pc, unsigned dram_traffic);
+void ptx_file_line_stats_add_smem_bank_conflict(void * ptx_thd, unsigned pc, unsigned n_way_bkconflict);
+void ptx_file_line_stats_add_uncoalesced_gmem(void * ptx_thd, unsigned pc, unsigned n_access);
+
+void ptx_file_line_stats_create_exposed_latency_tracker(int n_shader_cores);
+void ptx_file_line_stats_add_inflight_memory_insn(int sc_id, unsigned pc);
+void ptx_file_line_stats_sub_inflight_memory_insn(int sc_id, unsigned pc);
+void ptx_file_line_stats_commit_exposed_latency(int sc_id, int exposed_latency);
+
+void ptx_file_line_stats_add_warp_divergence(unsigned pc, unsigned n_way_divergence);
+
diff --git a/src/cuda-sim/ptx.l b/src/cuda-sim/ptx.l
new file mode 100644
index 0000000..d764c7f
--- /dev/null
+++ b/src/cuda-sim/ptx.l
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+%option noyywrap
+%option yylineno
+%option prefix="ptx_"
+%{
+#include "opcodes.h"
+#include "ptx.tab.h"
+#include <string.h>
+
+char linebuf[1024];
+unsigned col = 0;
+#define TC col+=strlen(ptx_text);
+int ptx_error( const char *s );
+%}
+
+%s IN_STRING
+%s IN_COMMENT
+%x NOT_OPCODE
+%%
+
+abs TC; ptx_lval.int_value = ABS_OP; return OPCODE;
+add TC; ptx_lval.int_value = ADD_OP; return OPCODE;
+and TC; ptx_lval.int_value = AND_OP; return OPCODE;
+atom TC; ptx_lval.int_value = ATOM_OP; return OPCODE;
+bar.sync TC; ptx_lval.int_value = BAR_OP; return OPCODE;
+bra TC; ptx_lval.int_value = BRA_OP; return OPCODE;
+call TC; ptx_lval.int_value = CALL_OP; return OPCODE;
+cnot TC; ptx_lval.int_value = CNOT_OP; return OPCODE;
+cos TC; ptx_lval.int_value = COS_OP; return OPCODE;
+cvt TC; ptx_lval.int_value = CVT_OP; return OPCODE;
+div TC; ptx_lval.int_value = DIV_OP; return OPCODE;
+ex2 TC; ptx_lval.int_value = EX2_OP; return OPCODE;
+exit TC; ptx_lval.int_value = EXIT_OP; return OPCODE;
+ld TC; ptx_lval.int_value = LD_OP; return OPCODE;
+ld.volatile TC; ptx_lval.int_value = LD_OP; return OPCODE;
+lg2 TC; ptx_lval.int_value = LG2_OP; return OPCODE;
+mad24 TC; ptx_lval.int_value = MAD24_OP; return OPCODE;
+mad TC; ptx_lval.int_value = MAD_OP; return OPCODE;
+max TC; ptx_lval.int_value = MAX_OP; return OPCODE;
+min TC; ptx_lval.int_value = MIN_OP; return OPCODE;
+mov TC; ptx_lval.int_value = MOV_OP; return OPCODE;
+mul24 TC; ptx_lval.int_value = MUL24_OP; return OPCODE;
+mul TC; ptx_lval.int_value = MUL_OP; return OPCODE;
+neg TC; ptx_lval.int_value = NEG_OP; return OPCODE;
+not TC; ptx_lval.int_value = NOT_OP; return OPCODE;
+or TC; ptx_lval.int_value = OR_OP; return OPCODE;
+rcp TC; ptx_lval.int_value = RCP_OP; return OPCODE;
+rem TC; ptx_lval.int_value = REM_OP; return OPCODE;
+ret TC; ptx_lval.int_value = RET_OP; return OPCODE;
+rsqrt TC; ptx_lval.int_value = RSQRT_OP; return OPCODE;
+sad TC; ptx_lval.int_value = SAD_OP; return OPCODE;
+selp TC; ptx_lval.int_value = SELP_OP; return OPCODE;
+setp TC; ptx_lval.int_value = SETP_OP; return OPCODE;
+set TC; ptx_lval.int_value = SET_OP; return OPCODE;
+shl TC; ptx_lval.int_value = SHL_OP; return OPCODE;
+shr TC; ptx_lval.int_value = SHR_OP; return OPCODE;
+sin TC; ptx_lval.int_value = SIN_OP; return OPCODE;
+slct TC; ptx_lval.int_value = SLCT_OP; return OPCODE;
+sqrt TC; ptx_lval.int_value = SQRT_OP; return OPCODE;
+st TC; ptx_lval.int_value = ST_OP; return OPCODE;
+st.volatile TC; ptx_lval.int_value = ST_OP; return OPCODE;
+sub TC; ptx_lval.int_value = SUB_OP; return OPCODE;
+tex TC; BEGIN(NOT_OPCODE); ptx_lval.int_value = TEX_OP; return OPCODE;
+trap TC; ptx_lval.int_value = TRAP_OP; return OPCODE;
+vote TC; ptx_lval.int_value = VOTE_OP; return OPCODE;
+xor TC; ptx_lval.int_value = XOR_OP; return OPCODE;
+membar TC; ptx_lval.int_value = MEMBAR_OP; return OPCODE;
+red TC; ptx_lval.int_value = RED_OP; return OPCODE;
+brkpt TC; ptx_lval.int_value = BRKPT_OP; return OPCODE;
+addc TC; ptx_lval.int_value = ADDC_OP; return OPCODE;
+
+<INITIAL,NOT_OPCODE>{
+
+\.align TC; return ALIGN_DIRECTIVE;
+\.byte TC; return BYTE_DIRECTIVE;
+\.const\[[0-9]+\] TC; return CONST_DIRECTIVE;
+\.const TC; return CONST_DIRECTIVE;
+\.entry TC; return ENTRY_DIRECTIVE;
+\.extern TC; return EXTERN_DIRECTIVE;
+\.file TC; return FILE_DIRECTIVE;
+\.func TC; return FUNC_DIRECTIVE;
+\.global TC; return GLOBAL_DIRECTIVE;
+\.local TC; return LOCAL_DIRECTIVE;
+\.loc TC; return LOC_DIRECTIVE;
+\.param TC; return PARAM_DIRECTIVE;
+\.reg TC; return REG_DIRECTIVE;
+\.section TC; return SECTION_DIRECTIVE;
+\.shared TC; return SHARED_DIRECTIVE;
+\.sreg TC; return SREG_DIRECTIVE;
+\.struct TC; return STRUCT_DIRECTIVE;
+\.surf TC; return SURF_DIRECTIVE;
+\.target TC; return TARGET_DIRECTIVE;
+\.tex TC; BEGIN(NOT_OPCODE); return TEX_DIRECTIVE;
+\.union TC; return UNION_DIRECTIVE;
+\.version TC; return VERSION_DIRECTIVE;
+\.visible TC; return VISIBLE_DIRECTIVE;
+
+\.maxntid TC; return MAXNTID_DIRECTIVE;
+
+"%clock" TC; ptx_lval.int_value = CLOCK_ID; return SPECIAL_REGISTER;
+"%ctaid" TC; ptx_lval.int_value = CTA_ID; return SPECIAL_REGISTER;
+"%ntid" TC; ptx_lval.int_value = NTID_ID; return SPECIAL_REGISTER;
+"%gridid" TC; ptx_lval.int_value = GRIDID_ID; return SPECIAL_REGISTER;
+"%nctaid" TC; ptx_lval.int_value = NCTAID_ID; return SPECIAL_REGISTER;
+"%tid" TC; ptx_lval.int_value = TID_ID; return SPECIAL_REGISTER;
+
+[_A-Za-z$%][_0-9A-Za-z$]* TC; ptx_lval.string_value = strdup(yytext); /*printf("\n<<identifier=\"%s\">>\n", yytext); fflush(stdout);*/ return IDENTIFIER;
+
+[0-9]+\.[0-9]+ TC; sscanf(yytext,"%lf", &ptx_lval.double_value); return DOUBLE_OPERAND;
+[-]{0,1}[0-9]+ TC; ptx_lval.int_value = atoi(yytext); return INT_OPERAND;
+0[xX][0-9]+ TC; sscanf(yytext,"%x", &ptx_lval.int_value); return INT_OPERAND;
+0[fF][0-9a-fA-F]{8} TC; sscanf(yytext+2,"%x", (unsigned*)(void*)&ptx_lval.float_value); return FLOAT_OPERAND;
+0[dD][0-9a-fA-F]{16} TC; sscanf(yytext+2,"%Lx", (unsigned long long*)(void*)&ptx_lval.double_value); return DOUBLE_OPERAND;
+
+\.s8 TC; return S8_TYPE;
+\.s16 TC; return S16_TYPE;
+\.s32 TC; return S32_TYPE;
+\.s64 TC; return S64_TYPE;
+\.u8 TC; return U8_TYPE;
+\.u16 TC; return U16_TYPE;
+\.u32 TC; return U32_TYPE;
+\.u64 TC; return U64_TYPE;
+\.f16 TC; return F16_TYPE;
+\.f32 TC; return F32_TYPE;
+\.f64 TC; return F64_TYPE;
+\.b8 TC; return B8_TYPE;
+\.b16 TC; return B16_TYPE;
+\.b32 TC; return B32_TYPE;
+\.b64 TC; return B64_TYPE;
+\.pred TC; return PRED_TYPE;
+
+\.v2 TC; return V2_TYPE;
+\.v3 TC; return V3_TYPE;
+\.v4 TC; return V4_TYPE;
+
+\.equ TC; return EQU_OPTION;
+\.neu TC; return NEU_OPTION;
+\.ltu TC; return LTU_OPTION;
+\.leu TC; return LEU_OPTION;
+\.gtu TC; return GTU_OPTION;
+\.geu TC; return GEU_OPTION;
+\.num TC; return NUM_OPTION;
+\.nan TC; return NAN_OPTION;
+
+\.sat TC; return SAT_OPTION;
+
+\.eq TC; return EQ_OPTION;
+\.ne TC; return NE_OPTION;
+\.lt TC; return LT_OPTION;
+\.le TC; return LE_OPTION;
+\.gt TC; return GT_OPTION;
+\.ge TC; return GE_OPTION;
+
+\.lo TC; return LO_OPTION;
+\.ls TC; return LS_OPTION;
+\.hi TC; return HI_OPTION;
+\.hs TC; return HS_OPTION;
+
+
+\.rni TC; return RNI_OPTION;
+\.rzi TC; return RZI_OPTION;
+\.rmi TC; return RMI_OPTION;
+\.rpi TC; return RPI_OPTION;
+
+\.rn TC; return RN_OPTION;
+\.rz TC; return RZ_OPTION;
+\.rm TC; return RM_OPTION;
+\.rp TC; return RP_OPTION;
+
+\.ftz TC; return FTZ_OPTION;
+
+\.wide TC; return WIDE_OPTION;
+\.uni TC; return UNI_OPTION;
+
+\.approx TC; return APPROX_OPTION;
+\.full TC; return FULL_OPTION;
+
+\.any TC; return ANY_OPTION;
+\.all TC; return ALL_OPTION;
+\.gl TC; return GLOBAL_OPTION;
+\.cta TC; return CTA_OPTION;
+
+\.and TC; return ATOMIC_AND;
+\.or TC; return ATOMIC_OR;
+\.xor TC; return ATOMIC_XOR;
+\.cas TC; return ATOMIC_CAS;
+\.exch TC; return ATOMIC_EXCH;
+\.add TC; return ATOMIC_ADD;
+\.inc TC; return ATOMIC_INC;
+\.dec TC; return ATOMIC_DEC;
+\.min TC; return ATOMIC_MIN;
+\.max TC; return ATOMIC_MAX;
+
+\.1d TC; return GEOM_MODIFIER_1D;
+\.2d TC; return GEOM_MODIFIER_2D;
+\.3d TC; return GEOM_MODIFIER_3D;
+
+\.0 TC; ptx_lval.int_value = 0; return DIMENSION_MODIFIER;
+\.1 TC; ptx_lval.int_value = 1; return DIMENSION_MODIFIER;
+\.2 TC; ptx_lval.int_value = 2; return DIMENSION_MODIFIER;
+\.x TC; ptx_lval.int_value = 0; return DIMENSION_MODIFIER;
+\.y TC; ptx_lval.int_value = 1; return DIMENSION_MODIFIER;
+\.z TC; ptx_lval.int_value = 2; return DIMENSION_MODIFIER;
+
+"+" TC; return PLUS;
+"," TC; return COMMA;
+"@" TC; return PRED;
+"[" TC; return LEFT_SQUARE_BRACKET;
+"]" TC; return RIGHT_SQUARE_BRACKET;
+"<" TC; return LEFT_ANGLE_BRACKET;
+">" TC; return RIGHT_ANGLE_BRACKET;
+"(" TC; return LEFT_PAREN;
+")" TC; return RIGHT_PAREN;
+":" TC; return COLON;
+";" TC; BEGIN(INITIAL); return SEMI_COLON;
+"!" TC; return EXCLAMATION;
+"=" TC; return EQUALS;
+"{" TC; return LEFT_BRACE;
+"}" TC; return RIGHT_BRACE;
+\. TC; return PERIOD;
+
+"//"[^\n]* TC; // eat single
+
+\n.* col=0; strncpy(linebuf, yytext + 1, 1024); yyless( 1 );
+
+" " TC;
+"\t" TC;
+
+
+}
+
+<INITIAL>{
+"/*" BEGIN(IN_COMMENT);
+}
+<IN_COMMENT>{
+"*/" BEGIN(INITIAL);
+[^*\n]+ // eat comment in chunks
+"*" // eat the lone star
+\n TC;
+}
+
+<INITIAL>{
+"\"" BEGIN(IN_STRING);
+}
+<IN_STRING>{
+"\"" TC; BEGIN(INITIAL); return STRING;
+[^\"]* TC; ptx_lval.string_value = strdup(yytext);
+}
+
+<INITIAL,NOT_OPCODE>. TC; ptx_error((const char*)NULL);
+
+%%
+
+extern int g_error_detected;
+extern const char *g_filename;
+
+int ptx_error( const char *s )
+{
+ int i;
+ g_error_detected = 1;
+ fflush(stdout);
+ if( s != NULL )
+ printf("%s:%u: Syntax error:\n\n", g_filename, ptx_lineno );
+ printf(" %s\n", linebuf );
+ printf(" ");
+ for( i=0; i < col-1; i++ ) {
+ if( linebuf[i] == '\t' ) printf("\t");
+ else printf(" ");
+ }
+
+ printf("^\n\n");
+ fflush(stdout);
+ //exit(1);
+ return 0;
+}
diff --git a/src/cuda-sim/ptx.y b/src/cuda-sim/ptx.y
new file mode 100644
index 0000000..2e1cb0f
--- /dev/null
+++ b/src/cuda-sim/ptx.y
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, George L. Yuan and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+%union {
+ double double_value;
+ float float_value;
+ int int_value;
+ char * string_value;
+ void * ptr_value;
+}
+
+%token <string_value> STRING
+%token <int_value> OPCODE
+%token ALIGN_DIRECTIVE
+%token BYTE_DIRECTIVE
+%token CONST_DIRECTIVE
+%token ENTRY_DIRECTIVE
+%token EXTERN_DIRECTIVE
+%token FILE_DIRECTIVE
+%token FUNC_DIRECTIVE
+%token GLOBAL_DIRECTIVE
+%token LOCAL_DIRECTIVE
+%token LOC_DIRECTIVE
+%token PARAM_DIRECTIVE
+%token REG_DIRECTIVE
+%token SECTION_DIRECTIVE
+%token SHARED_DIRECTIVE
+%token SREG_DIRECTIVE
+%token STRUCT_DIRECTIVE
+%token SURF_DIRECTIVE
+%token TARGET_DIRECTIVE
+%token TEX_DIRECTIVE
+%token UNION_DIRECTIVE
+%token VERSION_DIRECTIVE
+%token VISIBLE_DIRECTIVE
+%token MAXNTID_DIRECTIVE
+%token <string_value> IDENTIFIER
+%token <int_value> INT_OPERAND
+%token <float_value> FLOAT_OPERAND
+%token <double_value> DOUBLE_OPERAND
+%token S8_TYPE
+%token S16_TYPE
+%token S32_TYPE
+%token S64_TYPE
+%token U8_TYPE
+%token U16_TYPE
+%token U32_TYPE
+%token U64_TYPE
+%token F16_TYPE
+%token F32_TYPE
+%token F64_TYPE
+%token B8_TYPE
+%token B16_TYPE
+%token B32_TYPE
+%token B64_TYPE
+%token PRED_TYPE
+%token V2_TYPE
+%token V3_TYPE
+%token V4_TYPE
+%token COMMA
+%token PRED
+%token EQ_OPTION
+%token NE_OPTION
+%token LT_OPTION
+%token LE_OPTION
+%token GT_OPTION
+%token GE_OPTION
+%token LO_OPTION
+%token LS_OPTION
+%token HI_OPTION
+%token HS_OPTION
+%token EQU_OPTION
+%token NEU_OPTION
+%token LTU_OPTION
+%token LEU_OPTION
+%token GTU_OPTION
+%token GEU_OPTION
+%token NUM_OPTION
+%token NAN_OPTION
+%token LEFT_SQUARE_BRACKET
+%token RIGHT_SQUARE_BRACKET
+%token WIDE_OPTION
+%token <int_value> SPECIAL_REGISTER
+%token PLUS
+%token COLON
+%token SEMI_COLON
+%token EXCLAMATION
+%token RIGHT_BRACE
+%token LEFT_BRACE
+%token EQUALS
+%token PERIOD
+%token <int_value> DIMENSION_MODIFIER
+%token RN_OPTION
+%token RZ_OPTION
+%token RM_OPTION
+%token RP_OPTION
+%token RNI_OPTION
+%token RZI_OPTION
+%token RMI_OPTION
+%token RPI_OPTION
+%token UNI_OPTION
+%token GEOM_MODIFIER_1D
+%token GEOM_MODIFIER_2D
+%token GEOM_MODIFIER_3D
+%token SAT_OPTION
+%token FTZ_OPTION
+%token ATOMIC_AND
+%token ATOMIC_OR
+%token ATOMIC_XOR
+%token ATOMIC_CAS
+%token ATOMIC_EXCH
+%token ATOMIC_ADD
+%token ATOMIC_INC
+%token ATOMIC_DEC
+%token ATOMIC_MIN
+%token ATOMIC_MAX
+%token LEFT_ANGLE_BRACKET
+%token RIGHT_ANGLE_BRACKET
+%token LEFT_PAREN
+%token RIGHT_PAREN
+%token APPROX_OPTION
+%token FULL_OPTION
+%token ANY_OPTION
+%token ALL_OPTION
+%token GLOBAL_OPTION
+%token CTA_OPTION
+%type <int_value> function_decl_header
+%type <ptr_value> function_decl
+
+%{
+ #include "ptx_ir.h"
+ #include <stdlib.h>
+ #include <string.h>
+ #include <math.h>
+ void syntax_not_implemented();
+ extern int g_func_decl;
+ int ptx_lex(void);
+ int ptx_error(const char *);
+%}
+
+%%
+
+input: /* empty */
+ | input directive_statement
+ | input function_defn
+ | input function_decl
+ ;
+
+function_defn: function_decl { set_symtab($1); } LEFT_BRACE statement_list RIGHT_BRACE { end_function(); }
+ | function_decl { set_symtab($1); } block_spec LEFT_BRACE statement_list RIGHT_BRACE { end_function(); }
+ ;
+
+block_spec: MAXNTID_DIRECTIVE INT_OPERAND COMMA INT_OPERAND COMMA INT_OPERAND
+ ;
+
+function_decl: function_decl_header LEFT_PAREN { start_function($1); } param_entry RIGHT_PAREN function_ident_param { $$ = reset_symtab(); }
+ | function_decl_header { start_function($1); } function_ident_param { $$ = reset_symtab(); }
+ | function_decl_header { start_function($1); add_function_name(""); g_func_decl=0; $$ = reset_symtab(); }
+ ;
+
+function_ident_param: IDENTIFIER { add_function_name($1); } LEFT_PAREN param_list RIGHT_PAREN { g_func_decl=0; }
+ | IDENTIFIER { add_function_name($1); g_func_decl=0; }
+ ;
+
+function_decl_header: ENTRY_DIRECTIVE { $$ = 1; g_func_decl=1; }
+ | FUNC_DIRECTIVE { $$ = 0; g_func_decl=1; }
+ ;
+
+param_list: param_entry { add_directive(); }
+ | param_list COMMA param_entry { add_directive(); }
+
+param_entry: PARAM_DIRECTIVE { add_space_spec(PARAM_DIRECTIVE); } variable_spec identifier_spec { add_function_arg(); }
+ | REG_DIRECTIVE { add_space_spec(REG_DIRECTIVE); } variable_spec identifier_spec { add_function_arg(); }
+
+statement_list: directive_statement { add_directive(); }
+ | instruction_statement { add_instruction(); }
+ | statement_list directive_statement { add_directive(); }
+ | statement_list instruction_statement { add_instruction(); }
+ ;
+
+directive_statement: variable_declaration SEMI_COLON
+ | VERSION_DIRECTIVE DOUBLE_OPERAND
+ | TARGET_DIRECTIVE IDENTIFIER COMMA IDENTIFIER
+ | TARGET_DIRECTIVE IDENTIFIER
+ | FILE_DIRECTIVE INT_OPERAND STRING { add_file($2,$3); }
+ | LOC_DIRECTIVE INT_OPERAND INT_OPERAND INT_OPERAND
+ ;
+
+variable_declaration: variable_spec identifier_list { add_variables(); }
+ | variable_spec identifier_spec EQUALS initializer_list { add_variables(); }
+ | variable_spec identifier_spec EQUALS literal_operand { add_variables(); }
+ ;
+
+variable_spec: var_spec_list { set_variable_type(); }
+
+identifier_list: identifier_spec
+ | identifier_list COMMA identifier_spec;
+
+identifier_spec: IDENTIFIER { add_identifier($1,0,NON_ARRAY_IDENTIFIER); }
+ | IDENTIFIER LEFT_ANGLE_BRACKET INT_OPERAND RIGHT_ANGLE_BRACKET {
+ int i,lbase,l;
+ char *id = NULL;
+ lbase = strlen($1);
+ for( i=0; i < $3; i++ ) {
+ l = lbase + (int)log10(i+1)+10;
+ id = malloc(l);
+ snprintf(id,l,"%s%u",$1,i);
+ add_identifier(id,0,NON_ARRAY_IDENTIFIER);
+ }
+ free($1);
+ }
+ | IDENTIFIER LEFT_SQUARE_BRACKET RIGHT_SQUARE_BRACKET { add_identifier($1,0,ARRAY_IDENTIFIER_NO_DIM); }
+ | IDENTIFIER LEFT_SQUARE_BRACKET INT_OPERAND RIGHT_SQUARE_BRACKET { add_identifier($1,$3,ARRAY_IDENTIFIER); }
+ ;
+
+var_spec_list: var_spec
+ | var_spec_list var_spec;
+
+var_spec: space_spec
+ | type_spec
+ | align_spec
+ | EXTERN_DIRECTIVE { add_extern_spec(); }
+ ;
+
+align_spec: ALIGN_DIRECTIVE INT_OPERAND { add_alignment_spec($2); }
+
+space_spec: REG_DIRECTIVE { add_space_spec(REG_DIRECTIVE); }
+ | SREG_DIRECTIVE { add_space_spec(SREG_DIRECTIVE); }
+ | addressable_spec
+ ;
+
+addressable_spec: CONST_DIRECTIVE { add_space_spec(CONST_DIRECTIVE); }
+ | GLOBAL_DIRECTIVE { add_space_spec(GLOBAL_DIRECTIVE); }
+ | LOCAL_DIRECTIVE { add_space_spec(LOCAL_DIRECTIVE); }
+ | PARAM_DIRECTIVE { add_space_spec(PARAM_DIRECTIVE); }
+ | SHARED_DIRECTIVE { add_space_spec(SHARED_DIRECTIVE); }
+ | SURF_DIRECTIVE { add_space_spec(SURF_DIRECTIVE); }
+ | TEX_DIRECTIVE { add_space_spec(TEX_DIRECTIVE); }
+ ;
+
+type_spec: scalar_type
+ | vector_spec scalar_type
+ ;
+
+vector_spec: V2_TYPE { add_option(V2_TYPE); }
+ | V3_TYPE { add_option(V3_TYPE); }
+ | V4_TYPE { add_option(V4_TYPE); }
+ ;
+
+scalar_type: S8_TYPE { add_scalar_type_spec( S8_TYPE ); }
+ | S16_TYPE { add_scalar_type_spec( S16_TYPE ); }
+ | S32_TYPE { add_scalar_type_spec( S32_TYPE ); }
+ | S64_TYPE { add_scalar_type_spec( S64_TYPE ); }
+ | U8_TYPE { add_scalar_type_spec( U8_TYPE ); }
+ | U16_TYPE { add_scalar_type_spec( U16_TYPE ); }
+ | U32_TYPE { add_scalar_type_spec( U32_TYPE ); }
+ | U64_TYPE { add_scalar_type_spec( U64_TYPE ); }
+ | F16_TYPE { add_scalar_type_spec( F16_TYPE ); }
+ | F32_TYPE { add_scalar_type_spec( F32_TYPE ); }
+ | F64_TYPE { add_scalar_type_spec( F64_TYPE ); }
+ | B8_TYPE { add_scalar_type_spec( B8_TYPE ); }
+ | B16_TYPE { add_scalar_type_spec( B16_TYPE ); }
+ | B32_TYPE { add_scalar_type_spec( B32_TYPE ); }
+ | B64_TYPE { add_scalar_type_spec( B64_TYPE ); }
+ | PRED_TYPE { add_scalar_type_spec( PRED_TYPE ); }
+ ;
+
+initializer_list: LEFT_BRACE literal_list RIGHT_BRACE { add_array_initializer(); }
+ | LEFT_BRACE initializer_list RIGHT_BRACE { syntax_not_implemented(); }
+
+literal_list: literal_operand
+ | literal_operand COMMA literal_list;
+
+instruction_statement: instruction SEMI_COLON
+ | IDENTIFIER COLON { add_label($1); }
+ | pred_spec instruction SEMI_COLON;
+
+instruction: opcode_spec LEFT_PAREN operand RIGHT_PAREN { set_return(); } COMMA operand COMMA LEFT_PAREN operand_list RIGHT_PAREN
+ | opcode_spec operand COMMA LEFT_PAREN operand_list RIGHT_PAREN
+ | opcode_spec operand_list
+ | opcode_spec
+ ;
+
+opcode_spec: OPCODE { add_opcode($1); } option_list
+ | OPCODE { add_opcode($1); }
+
+pred_spec: PRED IDENTIFIER { add_pred($2,0); }
+ | PRED EXCLAMATION IDENTIFIER { add_pred($3,1); }
+ ;
+
+option_list: option
+ | option option_list ;
+
+option: type_spec
+ | compare_spec
+ | addressable_spec
+ | rounding_mode
+ | UNI_OPTION { add_option(UNI_OPTION); }
+ | WIDE_OPTION { add_option(WIDE_OPTION); }
+ | ANY_OPTION { add_option(ANY_OPTION); }
+ | ALL_OPTION { add_option(ALL_OPTION); }
+ | GLOBAL_OPTION { add_option(GLOBAL_OPTION); }
+ | CTA_OPTION { add_option(CTA_OPTION); }
+ | GEOM_MODIFIER_1D { add_option(GEOM_MODIFIER_1D); }
+ | GEOM_MODIFIER_2D { add_option(GEOM_MODIFIER_2D); }
+ | GEOM_MODIFIER_3D { add_option(GEOM_MODIFIER_3D); }
+ | SAT_OPTION { add_option(SAT_OPTION); }
+ | FTZ_OPTION { add_option(FTZ_OPTION); }
+ | APPROX_OPTION { add_option(APPROX_OPTION); }
+ | FULL_OPTION { add_option(FULL_OPTION); }
+ | atomic_operation_spec ;
+
+atomic_operation_spec: ATOMIC_AND { add_option(ATOMIC_AND); }
+ | ATOMIC_OR { add_option(ATOMIC_OR); }
+ | ATOMIC_XOR { add_option(ATOMIC_XOR); }
+ | ATOMIC_CAS { add_option(ATOMIC_CAS); }
+ | ATOMIC_EXCH { add_option(ATOMIC_EXCH); }
+ | ATOMIC_ADD { add_option(ATOMIC_ADD); }
+ | ATOMIC_INC { add_option(ATOMIC_INC); }
+ | ATOMIC_DEC { add_option(ATOMIC_DEC); }
+ | ATOMIC_MIN { add_option(ATOMIC_MIN); }
+ | ATOMIC_MAX { add_option(ATOMIC_MAX); }
+ ;
+
+rounding_mode: floating_point_rounding_mode
+ | integer_rounding_mode;
+
+floating_point_rounding_mode: RN_OPTION { add_option(RN_OPTION); }
+ | RZ_OPTION { add_option(RZ_OPTION); }
+ | RM_OPTION { add_option(RM_OPTION); }
+ | RP_OPTION { add_option(RP_OPTION); }
+ ;
+
+integer_rounding_mode: RNI_OPTION { add_option(RNI_OPTION); }
+ | RZI_OPTION { add_option(RZI_OPTION); }
+ | RMI_OPTION { add_option(RMI_OPTION); }
+ | RPI_OPTION { add_option(RPI_OPTION); }
+ ;
+
+compare_spec:EQ_OPTION { add_option(EQ_OPTION); }
+ | NE_OPTION { add_option(NE_OPTION); }
+ | LT_OPTION { add_option(LT_OPTION); }
+ | LE_OPTION { add_option(LE_OPTION); }
+ | GT_OPTION { add_option(GT_OPTION); }
+ | GE_OPTION { add_option(GE_OPTION); }
+ | LO_OPTION { add_option(LO_OPTION); }
+ | LS_OPTION { add_option(LS_OPTION); }
+ | HI_OPTION { add_option(HI_OPTION); }
+ | HS_OPTION { add_option(HS_OPTION); }
+ | EQU_OPTION { add_option(EQU_OPTION); }
+ | NEU_OPTION { add_option(NEU_OPTION); }
+ | LTU_OPTION { add_option(LTU_OPTION); }
+ | LEU_OPTION { add_option(LEU_OPTION); }
+ | GTU_OPTION { add_option(GTU_OPTION); }
+ | GEU_OPTION { add_option(GEU_OPTION); }
+ | NUM_OPTION { add_option(NUM_OPTION); }
+ | NAN_OPTION { add_option(NAN_OPTION); }
+ ;
+
+operand_list: operand
+ | operand COMMA operand_list;
+
+operand: IDENTIFIER { add_scalar_operand( $1 ); }
+ | EXCLAMATION IDENTIFIER { add_neg_pred_operand( $2 ); }
+ | memory_operand
+ | literal_operand
+ | builtin_operand
+ | vector_operand
+ | tex_operand
+ | IDENTIFIER PLUS INT_OPERAND { add_address_operand($1,$3); }
+ ;
+
+vector_operand: LEFT_BRACE IDENTIFIER COMMA IDENTIFIER RIGHT_BRACE { add_2vector_operand($2,$4); }
+ | LEFT_BRACE IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER RIGHT_BRACE { add_3vector_operand($2,$4,$6); }
+ | LEFT_BRACE IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER RIGHT_BRACE { add_4vector_operand($2,$4,$6,$8); }
+ ;
+
+tex_operand: LEFT_SQUARE_BRACKET IDENTIFIER COMMA
+ LEFT_BRACE IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER COMMA IDENTIFIER RIGHT_BRACE
+ RIGHT_SQUARE_BRACKET {
+ add_scalar_operand($2);
+ add_4vector_operand($5,$7,$9,$11);
+ }
+
+builtin_operand: SPECIAL_REGISTER DIMENSION_MODIFIER { add_builtin_operand($1,$2); }
+ | SPECIAL_REGISTER { add_builtin_operand($1,-1); }
+ ;
+
+memory_operand : LEFT_SQUARE_BRACKET address_expression RIGHT_SQUARE_BRACKET { add_memory_operand(); }
+
+literal_operand : INT_OPERAND { add_literal_int($1); }
+ | FLOAT_OPERAND { add_literal_float($1); }
+ | DOUBLE_OPERAND { add_literal_double($1); }
+ ;
+
+address_expression: IDENTIFIER { add_address_operand($1,0); }
+ | IDENTIFIER PLUS INT_OPERAND { add_address_operand($1,$3); }
+ ;
+
+%%
+
+extern int ptx_lineno;
+extern const char *g_filename;
+
+void syntax_not_implemented()
+{
+ printf("Parse error (%s:%u): this syntax is not (yet) implemented:\n",g_filename,ptx_lineno);
+ ptx_error(NULL);
+ abort();
+}
diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc
new file mode 100644
index 0000000..542426a
--- /dev/null
+++ b/src/cuda-sim/ptx_ir.cc
@@ -0,0 +1,1283 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
+ * George L. Yuan and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "ptx_ir.h"
+#include "ptx.tab.h"
+#include "opcodes.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <list>
+#include <assert.h>
+#include <algorithm>
+#include <stdarg.h>
+
+extern unsigned g_max_regs_per_thread;
+extern "C" int ptx_error( const char *s );
+void gpgpu_ptx_sim_bindTextureToArray(const struct textureReference* texref, struct cudaArray* array); //texture functions
+struct cudaArray* gpgpu_ptx_sim_accessArrayofTexture(struct textureReference* texref);
+void gpgpu_ptx_sim_bindNameToTexture(const char* name, struct textureReference* texref);
+struct textureReference* gpgpu_ptx_sim_accessTextureofName(const char* name);
+const char* gpgpu_ptx_sim_findNamefromTexture(const struct textureReference* texref);
+int gpgpu_ptx_sim_sizeofTexture(const char* name);
+
+// the program intermediate representation...
+symbol_table *g_global_symbol_table = NULL;
+symbol_table *g_current_symbol_table = NULL;
+std::list<ptx_instruction*> g_instructions;
+symbol *g_last_symbol = NULL;
+std::map<std::string,symbol_table*> g_sym_name_to_symbol_table;
+
+int g_error_detected = 0;
+
+// type specifier stuff:
+int g_space_spec = -1;
+int g_scalar_type_spec = -1;
+int g_vector_spec = -1;
+int g_alignment_spec = -1;
+int g_extern_spec = 0;
+
+// variable declaration stuff:
+type_info *g_var_type = NULL;
+
+// instruction definition stuff:
+const symbol *g_pred;
+int g_neg_pred;
+symbol *g_label;
+int g_opcode = -1;
+std::list<operand_info> g_operands;
+std::list<int> g_options;
+std::list<int> g_scalar_type;
+
+extern bool g_debug_ir_generation;
+extern const char *g_filename;
+extern int ptx_lineno;
+extern int g_debug_execution;
+extern int g_debug_thread_uid;
+
+
+#define DPRINTF(...) \
+ if( g_debug_ir_generation ) { \
+ printf(" %s:%u => ",g_filename,ptx_lineno); \
+ printf(" (%s:%u) ", __FILE__, __LINE__); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ fflush(stdout); \
+ }
+
+unsigned g_entry_func_param_index=0;
+function_info *g_func_info = NULL;
+function_info *g_entrypoint_func_info = NULL;
+symbol_table *g_entrypoint_symbol_table = NULL;
+std::map<unsigned,std::string> g_ptx_token_decode;
+operand_info g_return_var;
+
+void init_parser()
+{
+ g_global_symbol_table = g_current_symbol_table = new symbol_table("global",0,NULL);
+ ptx_lineno = 1;
+
+#define DEF(X,Y) g_ptx_token_decode[X] = Y;
+#include "ptx_parser_decode.def"
+#undef DEF
+}
+
+void init_directive_state()
+{
+ DPRINTF("init_directive_state");
+ g_space_spec=-1;
+ g_scalar_type_spec=-1;
+ g_vector_spec=-1;
+ g_opcode=-1;
+ g_alignment_spec = -1;
+ g_extern_spec = 0;
+ g_scalar_type.clear();
+ g_operands.clear();
+ g_last_symbol = NULL;
+}
+
+void init_instruction_state()
+{
+ DPRINTF("init_instruction_state");
+ g_pred = NULL;
+ g_neg_pred = 0;
+ g_label = NULL;
+ g_opcode = -1;
+ g_options.clear();
+ g_return_var = operand_info();
+ init_directive_state();
+}
+
+extern void register_ptx_function( const char *name, function_info *impl, symbol_table *symtab );
+
+static int g_entry_point;
+
+void start_function( int entry_point )
+{
+ DPRINTF("start_function");
+ init_directive_state();
+ init_instruction_state();
+ g_entry_point = entry_point;
+ g_func_info = NULL;
+ g_entry_func_param_index=0;
+}
+
+char *g_add_identifier_cached__identifier = NULL;
+int g_add_identifier_cached__array_dim;
+int g_add_identifier_cached__array_ident;
+
+void add_function_name( const char *name )
+{
+ DPRINTF("add_function_name %s %s", name, ((g_entry_point)?"(entrypoint)":""));
+ bool prior_decl = g_global_symbol_table->add_function_decl( name, g_entry_point, &g_func_info, &g_current_symbol_table );
+ if( g_entry_point ) {
+ g_entrypoint_func_info = g_func_info;
+ g_entrypoint_symbol_table = g_current_symbol_table;
+ }
+ if( g_add_identifier_cached__identifier ) {
+ add_identifier( g_add_identifier_cached__identifier,
+ g_add_identifier_cached__array_dim,
+ g_add_identifier_cached__array_ident );
+ free( g_add_identifier_cached__identifier );
+ g_add_identifier_cached__identifier = NULL;
+ g_func_info->add_return_var( g_last_symbol );
+ init_directive_state();
+ }
+ if( prior_decl ) {
+ g_func_info->remove_args();
+ }
+ g_global_symbol_table->add_function( g_func_info );
+}
+
+void add_directive()
+{
+ DPRINTF("add_directive");
+ init_directive_state();
+}
+
+#define mymax(a,b) ((a)>(b)?(a):(b))
+
+void gpgpu_ptx_assemble( std::string kname, void *kinfo );
+
+void end_function()
+{
+ DPRINTF("end_function");
+
+ init_directive_state();
+ init_instruction_state();
+ g_max_regs_per_thread = mymax( g_max_regs_per_thread, (g_current_symbol_table->next_reg_num()-1));
+ g_func_info->add_inst( g_instructions );
+ g_instructions.clear();
+ gpgpu_ptx_assemble( g_func_info->get_name(), g_func_info );
+
+ DPRINTF("function %s, PC = %d\n", g_func_info->get_name().c_str(), g_func_info->get_start_PC());
+}
+
+extern int ptx_lineno;
+extern const char *g_filename;
+
+#define parse_error(msg, ...) parse_error_impl(__FILE__,__LINE__, msg, ##__VA_ARGS__)
+#define parse_assert(cond,msg, ...) parse_assert_impl((cond),__FILE__,__LINE__, msg, ##__VA_ARGS__)
+
+void parse_error_impl( const char *file, unsigned line, const char *msg, ... )
+{
+ va_list ap;
+ char buf[1024];
+ va_start(ap,msg);
+ vsnprintf(buf,1024,msg,ap);
+ va_end(ap);
+
+ g_error_detected = 1;
+ printf("%s:%u: Parse error: %s (%s:%u)\n\n", g_filename, ptx_lineno, buf, file, line);
+ ptx_error(NULL);
+ abort();
+ exit(1);
+}
+
+void parse_assert_impl( int test_value, const char *file, unsigned line, const char *msg, ... )
+{
+ va_list ap;
+ char buf[1024];
+ va_start(ap,msg);
+ vsnprintf(buf,1024,msg,ap);
+ va_end(ap);
+
+ if ( test_value == 0 )
+ parse_error_impl(file,line, msg);
+}
+
+extern "C" char linebuf[1024];
+
+
+void set_return()
+{
+ parse_assert( (g_opcode == CALL_OP), "only call can have return value");
+ g_operands.front().set_return();
+ g_return_var = g_operands.front();
+}
+
+std::map<std::string,std::map<unsigned,const ptx_instruction*> > g_inst_lookup;
+
+const ptx_instruction *ptx_instruction_lookup( const char *filename, unsigned linenumber )
+{
+ std::map<std::string,std::map<unsigned,const ptx_instruction*> >::iterator f=g_inst_lookup.find(filename);
+ if( f == g_inst_lookup.end() )
+ return NULL;
+ std::map<unsigned,const ptx_instruction*>::iterator l=f->second.find(linenumber);
+ if( l == f->second.end() )
+ return NULL;
+ return l->second;
+}
+
+void add_instruction()
+{
+ DPRINTF("add_instruction: %s", ((g_opcode>0)?g_opcode_string[g_opcode]:"<label>") );
+ ptx_instruction *i = new ptx_instruction( g_opcode,
+ g_pred,
+ g_neg_pred,
+ g_label,
+ g_operands,
+ g_return_var,
+ g_options,
+ g_scalar_type,
+ g_space_spec,
+ g_filename,
+ ptx_lineno,
+ linebuf );
+ g_instructions.push_back(i);
+ g_inst_lookup[g_filename][ptx_lineno] = i;
+ init_instruction_state();
+}
+
+void add_variables()
+{
+ DPRINTF("add_variables");
+ if ( !g_operands.empty() ) {
+ assert( g_last_symbol != NULL );
+ g_last_symbol->add_initializer(g_operands);
+ }
+ init_directive_state();
+}
+
+void set_variable_type()
+{
+ DPRINTF("set_variable_type space_spec=%s scalar_type_spec=%s",
+ g_ptx_token_decode[g_space_spec].c_str(),
+ g_ptx_token_decode[g_scalar_type_spec].c_str() );
+ parse_assert( g_space_spec != -1, "variable has no space specification" );
+ parse_assert( g_scalar_type_spec != -1, "variable has no type information" ); // need to extend for structs?
+ g_var_type = g_current_symbol_table->add_type( g_space_spec,
+ g_scalar_type_spec,
+ g_vector_spec,
+ g_alignment_spec,
+ g_extern_spec );
+}
+
+bool check_for_duplicates( const char *identifier )
+{
+ const symbol *s = g_current_symbol_table->lookup(identifier);
+ return ( s != NULL );
+}
+
+extern std::set<std::string> g_globals;
+extern std::set<std::string> g_constants;
+
+int g_func_decl = 0;
+int g_ident_add_uid = 0;
+unsigned g_const_alloc = 1;
+
+void add_identifier( const char *identifier, int array_dim, unsigned array_ident )
+{
+ if( g_func_decl && (g_func_info == NULL) ) {
+ // return variable decl...
+ assert( g_add_identifier_cached__identifier == NULL );
+ g_add_identifier_cached__identifier = strdup(identifier);
+ g_add_identifier_cached__array_dim = array_dim;
+ g_add_identifier_cached__array_ident = array_ident;
+ return;
+ }
+ DPRINTF("add_identifier \"%s\" (%u)", identifier, g_ident_add_uid);
+ g_ident_add_uid++;
+ type_info *type = g_var_type;
+ type_info_key ti = type->get_key();
+ int basic_type;
+ int regnum;
+ size_t num_bits;
+ unsigned addr, addr_pad;
+ type_decode(ti.scalar_type(),num_bits,basic_type);
+
+ bool duplicates = check_for_duplicates( identifier );
+ if( duplicates ) {
+ symbol *s = g_current_symbol_table->lookup(identifier);
+ g_last_symbol = s;
+ if( g_func_decl )
+ return;
+ std::string msg = std::string(identifier) + " was delcared previous at " + s->decl_location();
+ parse_error(msg.c_str());
+ }
+
+ assert( g_var_type != NULL );
+ switch ( array_ident ) {
+ case ARRAY_IDENTIFIER:
+ type = g_current_symbol_table->get_array_type(type,array_dim);
+ num_bits = array_dim * num_bits;
+ break;
+ case ARRAY_IDENTIFIER_NO_DIM:
+ type = g_current_symbol_table->get_array_type(type,(unsigned)-1);
+ num_bits = 0;
+ break;
+ default:
+ break;
+ }
+ g_last_symbol = g_current_symbol_table->add_variable(identifier,type,g_filename,ptx_lineno);
+ switch ( g_space_spec ) {
+ case REG_DIRECTIVE: {
+ regnum = g_current_symbol_table->next_reg_num();
+ int arch_regnum = -1;
+ for (int d = 0; d < strlen(identifier); d++) {
+ if (isdigit(identifier[d])) {
+ sscanf(identifier + d, "%d", &arch_regnum);
+ break;
+ }
+ }
+ if (strcmp(identifier, "%sp") == 0) {
+ arch_regnum = 0;
+ }
+ g_last_symbol->set_regno(regnum, arch_regnum);
+ } break;
+ case SHARED_DIRECTIVE:
+ printf("GPGPU-Sim PTX: allocating shared region for \"%s\" from 0x%x to 0x%lx (shared memory space)\n",
+ identifier,
+ g_current_symbol_table->get_shared_next(),
+ g_current_symbol_table->get_shared_next() + num_bits/8 );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ addr = g_current_symbol_table->get_shared_next();
+ addr_pad = num_bits ? (((num_bits/8) - (addr % (num_bits/8))) % (num_bits/8)) : 0;
+ g_last_symbol->set_address( addr+addr_pad );
+ g_current_symbol_table->alloc_shared( num_bits/8 + addr_pad );
+ break;
+ case CONST_DIRECTIVE:
+ if( array_ident == ARRAY_IDENTIFIER_NO_DIM ) {
+ printf("GPGPU-Sim PTX: deferring allocation of constant region for \"%s\" (need size information)\n", identifier );
+ } else {
+ printf("GPGPU-Sim PTX: allocating constant region for \"%s\" from 0x%x to 0x%lx (global memory space) %u\n",
+ identifier,
+ g_current_symbol_table->get_global_next(),
+ g_current_symbol_table->get_global_next() + num_bits/8,
+ g_const_alloc++ );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ addr = g_current_symbol_table->get_global_next();
+ addr_pad = num_bits ? (((num_bits/8) - (addr % (num_bits/8))) % (num_bits/8)) : 0;
+ g_last_symbol->set_address( addr + addr_pad );
+ g_current_symbol_table->alloc_global( num_bits/8 + addr_pad );
+ }
+ if( g_current_symbol_table == g_global_symbol_table ) {
+ g_constants.insert( identifier );
+ }
+ assert( g_current_symbol_table != NULL );
+ g_sym_name_to_symbol_table[ identifier ] = g_current_symbol_table;
+ break;
+ case GLOBAL_DIRECTIVE:
+ printf("GPGPU-Sim PTX: allocating global region for \"%s\" from 0x%x to 0x%lx (global memory space)\n",
+ identifier,
+ g_current_symbol_table->get_global_next(),
+ g_current_symbol_table->get_global_next() + num_bits/8 );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ addr = g_current_symbol_table->get_global_next();
+ addr_pad = num_bits ? (((num_bits/8) - (addr % (num_bits/8))) % (num_bits/8)) : 0;
+ g_last_symbol->set_address( addr+addr_pad );
+ g_current_symbol_table->alloc_global( num_bits/8 + addr_pad );
+ g_globals.insert( identifier );
+ assert( g_current_symbol_table != NULL );
+ g_sym_name_to_symbol_table[ identifier ] = g_current_symbol_table;
+ break;
+ case LOCAL_DIRECTIVE:
+ printf("GPGPU-Sim PTX: allocating local region for \"%s\" from 0x%x to 0x%lx (local memory space)\n",
+ identifier,
+ g_current_symbol_table->get_local_next(),
+ g_current_symbol_table->get_local_next() + num_bits/8 );
+ fflush(stdout);
+ assert( (num_bits%8) == 0 );
+ g_last_symbol->set_address( g_current_symbol_table->get_local_next() );
+ g_current_symbol_table->alloc_local( num_bits/8 );
+ break;
+ case TEX_DIRECTIVE:
+ printf("GPGPU-Sim PTX: encountered texture directive %s.\n", identifier);
+ break;
+ default:
+ break;
+ }
+
+
+ if ( ti.is_param() ) {
+ g_func_info->add_param_name_and_type(g_entry_func_param_index,identifier, ti.scalar_type() );
+ g_entry_func_param_index++;
+ }
+}
+
+void add_function_arg()
+{
+ if( g_func_info ) {
+ DPRINTF("add_function_arg \"%s\"", g_last_symbol->name().c_str() );
+ g_func_info->add_arg(g_last_symbol);
+ }
+}
+
+void add_extern_spec()
+{
+ DPRINTF("add_extern_spec");
+ g_extern_spec = 1;
+}
+
+void add_alignment_spec( int spec )
+{
+ DPRINTF("add_alignment_spec");
+ parse_assert( g_alignment_spec == -1, "multiple .align specifiers per variable declaration not allowed." );
+ g_alignment_spec = spec;
+}
+
+void add_space_spec( int spec )
+{
+ DPRINTF("add_space_spec \"%s\"", g_ptx_token_decode[spec].c_str() );
+ parse_assert( g_space_spec == -1, "multiple space specifiers not allowed." );
+ g_space_spec = spec;
+}
+
+void add_vector_spec(int spec )
+{
+ DPRINTF("add_vector_spec");
+ parse_assert( g_vector_spec == -1, "multiple vector specifiers not allowed." );
+ g_vector_spec = spec;
+}
+
+void add_scalar_type_spec( int type_spec )
+{
+ DPRINTF("add_scalar_type_spec \"%s\"", g_ptx_token_decode[type_spec].c_str());
+ g_scalar_type.push_back( type_spec );
+ if ( g_scalar_type.size() > 1 ) {
+ parse_assert( (g_opcode == -1) || (g_opcode == CVT_OP) || (g_opcode == SET_OP) || (g_opcode == SLCT_OP)
+ || (g_opcode == TEX_OP),
+ "only cvt, set, slct, and tex can have more than one type specifier.");
+ }
+ g_scalar_type_spec = type_spec;
+}
+
+void add_label( const char *identifier )
+{
+ DPRINTF("add_label");
+ symbol *s = g_current_symbol_table->lookup(identifier);
+ if ( s != NULL ) {
+ g_label = s;
+ } else {
+ g_label = g_current_symbol_table->add_variable(identifier,NULL,g_filename,ptx_lineno);
+ }
+}
+
+void add_opcode( int opcode )
+{
+ g_opcode = opcode;
+}
+
+void add_pred( const char *identifier, int neg )
+{
+ DPRINTF("add_pred");
+ const symbol *s = g_current_symbol_table->lookup(identifier);
+ if ( s == NULL ) {
+ std::string msg = std::string("predicate \"") + identifier + "\" has no declaration.";
+ parse_error( msg.c_str() );
+ }
+ g_pred = s;
+ g_neg_pred = neg;
+}
+
+void add_option( int option )
+{
+ DPRINTF("add_option");
+ g_options.push_back( option );
+}
+
+void add_2vector_operand( const char *d1, const char *d2 )
+{
+ DPRINTF("add_2vector_operand");
+ const symbol *s1 = g_current_symbol_table->lookup(d1);
+ const symbol *s2 = g_current_symbol_table->lookup(d2);
+ parse_assert( s1 != NULL && s2 != NULL, "v2 component(s) missing declarations.");
+ g_operands.push_back( operand_info(s1,s2,NULL,NULL) );
+}
+
+void add_3vector_operand( const char *d1, const char *d2, const char *d3 )
+{
+ DPRINTF("add_3vector_operand");
+ const symbol *s1 = g_current_symbol_table->lookup(d1);
+ const symbol *s2 = g_current_symbol_table->lookup(d2);
+ const symbol *s3 = g_current_symbol_table->lookup(d3);
+ parse_assert( s1 != NULL && s2 != NULL && s3 != NULL, "v3 component(s) missing declarations.");
+ g_operands.push_back( operand_info(s1,s2,s3,NULL) );
+}
+
+void add_4vector_operand( const char *d1, const char *d2, const char *d3, const char *d4 )
+{
+ DPRINTF("add_4vector_operand");
+ const symbol *s1 = g_current_symbol_table->lookup(d1);
+ const symbol *s2 = g_current_symbol_table->lookup(d2);
+ const symbol *s3 = g_current_symbol_table->lookup(d3);
+ const symbol *s4 = g_current_symbol_table->lookup(d4);
+ parse_assert( s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL, "v4 component(s) missing declarations.");
+ g_operands.push_back( operand_info(s1,s2,s3,s4) );
+}
+
+void add_builtin_operand( int builtin, int dim_modifier )
+{
+ DPRINTF("add_builtin_operand");
+ g_operands.push_back( operand_info(builtin,dim_modifier) );
+}
+
+void add_memory_operand()
+{
+ DPRINTF("add_memory_operand");
+ assert( !g_operands.empty() );
+ g_operands.back().make_memory_operand();
+}
+
+void add_literal_int( int value )
+{
+ DPRINTF("add_literal_int");
+ g_operands.push_back( operand_info(value) );
+}
+
+void add_literal_float( float value )
+{
+ DPRINTF("add_literal_float");
+ g_operands.push_back( operand_info(value) );
+}
+
+void add_literal_double( double value )
+{
+ DPRINTF("add_literal_double");
+ g_operands.push_back( operand_info(value) );
+}
+
+void add_scalar_operand( const char *identifier )
+{
+ DPRINTF("add_scalar_operand");
+ const symbol *s = g_current_symbol_table->lookup(identifier);
+ if ( s == NULL ) {
+ if ( g_opcode == BRA_OP ) {
+ // forward branch target...
+ s = g_current_symbol_table->add_variable(identifier,NULL,g_filename,ptx_lineno);
+ } else {
+ std::string msg = std::string("operand \"") + identifier + "\" has no declaration.";
+ parse_error( msg.c_str() );
+ }
+ }
+ g_operands.push_back( operand_info(s) );
+}
+
+void add_neg_pred_operand( const char *identifier )
+{
+ DPRINTF("add_neg_pred_operand");
+ const symbol *s = g_current_symbol_table->lookup(identifier);
+ if ( s == NULL ) {
+ s = g_current_symbol_table->add_variable(identifier,NULL,g_filename,ptx_lineno);
+ }
+ operand_info op(s);
+ op.set_neg_pred();
+ g_operands.push_back( op );
+}
+
+void add_address_operand( const char *identifier, int offset )
+{
+ DPRINTF("add_address_operand");
+ const symbol *s = g_current_symbol_table->lookup(identifier);
+ if ( s == NULL ) {
+ std::string msg = std::string("operand \"") + identifier + "\" has no declaration.";
+ parse_error( msg.c_str() );
+ }
+ g_operands.push_back( operand_info(s,offset) );
+}
+
+unsigned symbol::sm_next_uid = 1;
+
+unsigned symbol::get_uid()
+{
+ unsigned result = sm_next_uid++;
+ return result;
+}
+
+void symbol::add_initializer( const std::list<operand_info> &init )
+{
+ m_initializer = init;
+}
+
+void symbol::print_info(FILE *fp) const
+{
+ fprintf(fp,"uid:%u, decl:%s, type:%p, ", m_uid, m_decl_location.c_str(), m_type );
+ if( m_address_valid )
+ fprintf(fp,"<address valid>, ");
+ if( m_is_label )
+ fprintf(fp," is_label ");
+ if( m_is_shared )
+ fprintf(fp," is_shared ");
+ if( m_is_const )
+ fprintf(fp," is_const ");
+ if( m_is_global )
+ fprintf(fp," is_global ");
+ if( m_is_local )
+ fprintf(fp," is_local ");
+ if( m_is_tex )
+ fprintf(fp," is_tex ");
+ if( m_is_func_addr )
+ fprintf(fp," is_func_addr ");
+ if( m_function )
+ fprintf(fp," %p ", m_function );
+}
+
+symbol_table::symbol_table()
+{
+ assert(0);
+}
+
+symbol_table::symbol_table( const char *scope_name, unsigned entry_point, symbol_table *parent )
+{
+ m_scope_name = std::string(scope_name);
+ m_reg_allocator=0;
+ m_shared_next = 0x100; // for debug with valgrind: make zero imply undefined address
+ m_const_next = 0x100; // for debug with valgrind: make zero imply undefined address
+ m_global_next = 0x100; // for debug with valgrind: make zero imply undefined address
+ m_local_next = 0x100; // for debug with valgrind: make zero imply undefined address
+ m_parent = parent;
+ if ( m_parent ) {
+ m_shared_next = m_parent->m_shared_next;
+ m_global_next = m_parent->m_global_next;
+ }
+}
+
+void symbol_table::set_name( const char *name )
+{
+ m_scope_name = std::string(name);
+}
+
+symbol *symbol_table::lookup( const char *identifier )
+{
+ std::string key(identifier);
+ std::map<std::string, symbol *>::iterator i = m_symbols.find(key);
+ if ( i != m_symbols.end() ) {
+ return i->second;
+ }
+ if ( m_parent ) {
+ return m_parent->lookup(identifier);
+ }
+ return NULL;
+}
+
+symbol *symbol_table::add_variable( const char *identifier, const type_info *type, const char *filename, unsigned line )
+{
+ char buf[1024];
+ std::string key(identifier);
+ assert( m_symbols.find(key) == m_symbols.end() );
+ snprintf(buf,1024,"%s:%u",filename,line);
+ symbol *s = new symbol(identifier,type,buf);
+ m_symbols[ key ] = s;
+
+ if ( type != NULL && type->get_key().is_param() ) {
+ m_params.push_back(s);
+ }
+ if ( type != NULL && type->get_key().is_global() ) {
+ m_globals.push_back(s);
+ }
+ if ( type != NULL && type->get_key().is_const() ) {
+ m_consts.push_back(s);
+ }
+
+ return s;
+}
+
+void symbol_table::add_function( function_info *func )
+{
+ std::map<std::string, symbol *>::iterator i = m_symbols.find( func->get_name() );
+ if( i != m_symbols.end() )
+ return;
+ char buf[1024];
+ snprintf(buf,1024,"%s:%u",g_filename,ptx_lineno);
+ type_info *type = add_type( func );
+ symbol *s = new symbol(func->get_name().c_str(),type,buf);
+ s->set_function(func);
+ m_symbols[ func->get_name() ] = s;
+}
+
+bool symbol_table::add_function_decl( const char *name, int entry_point, function_info **func_info, symbol_table **sym_table )
+{
+ std::string key = std::string(name);
+ bool prior_decl = false;
+ if( m_function_info_lookup.find(key) != m_function_info_lookup.end() ) {
+ *func_info = m_function_info_lookup[key];
+ prior_decl = true;
+ } else {
+ *func_info = new function_info(entry_point);
+ (*func_info)->set_name(name);
+ m_function_info_lookup[key] = *func_info;
+ }
+
+ if( m_function_symtab_lookup.find(key) != m_function_symtab_lookup.end() ) {
+ assert( prior_decl );
+ *sym_table = m_function_symtab_lookup[key];
+ } else {
+ assert( !prior_decl );
+ *sym_table = new symbol_table( "", entry_point, g_global_symbol_table );
+ symbol *null_reg = (*sym_table)->add_variable("_",NULL,"",0);
+ null_reg->set_regno(0, 0);
+ (*sym_table)->set_name(name);
+ (*func_info)->set_symtab(*sym_table);
+ m_function_symtab_lookup[key] = *sym_table;
+ register_ptx_function(name,*func_info,*sym_table);
+ }
+ return prior_decl;
+}
+
+type_info *symbol_table::add_type( int space_spec, int scalar_type_spec, int vector_spec, int alignment_spec, int extern_spec )
+{
+ type_info_key t(space_spec,scalar_type_spec,vector_spec,alignment_spec,extern_spec,0);
+ type_info *pt;
+ pt = new type_info(this,t);
+ return pt;
+}
+
+type_info *symbol_table::add_type( function_info *func )
+{
+ type_info_key t;
+ type_info *pt;
+ t.set_is_func();
+ pt = new type_info(this,t);
+ return pt;
+}
+
+type_info *symbol_table::get_array_type( type_info *base_type, unsigned array_dim )
+{
+ type_info_key t = base_type->get_key();
+ t.set_array_dim(array_dim);
+ type_info *pt;
+ pt = m_types[t] = new type_info(this,t);
+ return pt;
+}
+
+void symbol_table::set_label_address( const symbol *label, unsigned addr )
+{
+ std::map<std::string, symbol *>::iterator i=m_symbols.find(label->name());
+ assert( i != m_symbols.end() );
+ symbol *s = i->second;
+ s->set_label_address(addr);
+}
+
+void symbol_table::dump()
+{
+ printf("\n\n");
+ printf("Symbol table for \"%s\":\n", m_scope_name.c_str() );
+ std::map<std::string, symbol *>::iterator i;
+ for( i=m_symbols.begin(); i!=m_symbols.end(); i++ ) {
+ printf("%30s : ", i->first.c_str() );
+ if( i->second )
+ i->second->print_info(stdout);
+ else
+ printf(" <no symbol object> ");
+ printf("\n");
+ }
+ printf("\n");
+}
+
+unsigned operand_info::sm_next_uid=1;
+
+unsigned operand_info::get_uid()
+{
+ unsigned result = sm_next_uid++;
+ return result;
+}
+
+void add_array_initializer()
+{
+ g_last_symbol->add_initializer(g_operands);
+}
+
+
+std::list<ptx_instruction*>::iterator function_info::find_next_real_instruction( std::list<ptx_instruction*>::iterator i)
+{
+ while( (i != m_instructions.end()) && (*i)->is_label() )
+ i++;
+ return i;
+}
+
+void function_info::create_basic_blocks()
+{
+ std::list<ptx_instruction*> leaders;
+ std::list<ptx_instruction*>::iterator i, l;
+
+ // first instruction is a leader
+ i=m_instructions.begin();
+ leaders.push_back(*i);
+ i++;
+ while( i!=m_instructions.end() ) {
+ ptx_instruction *pI = *i;
+ if( pI->is_label() ) {
+ leaders.push_back(pI);
+ i = find_next_real_instruction(++i);
+ } else {
+ switch( pI->get_opcode() ) {
+ case BRA_OP: case RET_OP: case EXIT_OP:
+ i++;
+ if( i != m_instructions.end() )
+ leaders.push_back(*i);
+ i = find_next_real_instruction(i);
+ break;
+ case CALL_OP:
+ if( pI->has_pred() ) {
+ printf("GPGPU-Sim PTX: Warning found predicated call\n");
+ i++;
+ if( i != m_instructions.end() )
+ leaders.push_back(*i);
+ i = find_next_real_instruction(i);
+ } else i++;
+ break;
+ default:
+ i++;
+ }
+ }
+ }
+
+ if( leaders.empty() ) {
+ printf("GPGPU-Sim PTX: Function \'%s\' has no basic blocks\n", m_name.c_str());
+ return;
+ }
+
+ unsigned bb_id = 0;
+ l=leaders.begin();
+ i=m_instructions.begin();
+ m_basic_blocks.push_back( new basic_block_t(bb_id++,*find_next_real_instruction(i),NULL,1,0) );
+ ptx_instruction *last_real_inst=*(l++);
+
+ for( ; i!=m_instructions.end(); i++ ) {
+ ptx_instruction *pI = *i;
+ if( l != leaders.end() && *i == *l ) {
+ // found start of next basic block
+ m_basic_blocks.back()->ptx_end = last_real_inst;
+ if( find_next_real_instruction(i) != m_instructions.end() ) { // if not bogus trailing label
+ m_basic_blocks.push_back( new basic_block_t(bb_id++,*find_next_real_instruction(i),NULL,0,0) );
+ last_real_inst = *find_next_real_instruction(i);
+ }
+ // start search for next leader
+ l++;
+ }
+ pI->assign_bb( m_basic_blocks.back() );
+ if( !pI->is_label() ) last_real_inst = pI;
+ }
+ m_basic_blocks.back()->ptx_end = last_real_inst;
+ m_basic_blocks.push_back( /*exit basic block*/ new basic_block_t(bb_id,NULL,NULL,0,1) );
+}
+
+void function_info::print_basic_blocks()
+{
+ printf("Printing basic blocks for function \'%s\':\n", m_name.c_str() );
+ std::list<ptx_instruction*>::iterator ptx_itr;
+ unsigned last_bb=0;
+ for (ptx_itr = m_instructions.begin();ptx_itr != m_instructions.end(); ptx_itr++) {
+ if( (*ptx_itr)->get_bb() ) {
+ if( (*ptx_itr)->get_bb()->bb_id != last_bb ) {
+ printf("\n");
+ last_bb = (*ptx_itr)->get_bb()->bb_id;
+ }
+ printf("bb_%02u\t: ", (*ptx_itr)->get_bb()->bb_id);
+ (*ptx_itr)->print_insn();
+ printf("\n");
+ }
+ }
+ printf("\nSummary of basic blocks for \'%s\':\n", m_name.c_str() );
+ std::vector<basic_block_t*>::iterator bb_itr;
+ for (bb_itr = m_basic_blocks.begin();bb_itr != m_basic_blocks.end(); bb_itr++) {
+ printf("bb_%02u\t:", (*bb_itr)->bb_id);
+ if ((*bb_itr)->ptx_begin)
+ printf(" first: %s\t", ((*bb_itr)->ptx_begin)->get_opcode_cstr());
+ else printf(" first: NULL\t");
+ if ((*bb_itr)->ptx_end) {
+ printf(" last: %s\t", ((*bb_itr)->ptx_end)->get_opcode_cstr());
+ } else printf(" last: NULL\t");
+ printf("\n");
+ }
+ printf("\n");
+}
+
+void function_info::print_basic_block_links()
+{
+ printf("Printing basic blocks links for function \'%s\':\n", m_name.c_str() );
+ std::vector<basic_block_t*>::iterator bb_itr;
+ for (bb_itr = m_basic_blocks.begin();bb_itr != m_basic_blocks.end(); bb_itr++) {
+ printf("ID: %d\t:", (*bb_itr)->bb_id);
+ if ( !(*bb_itr)->predecessor_ids.empty() ) {
+ printf("Predecessors:");
+ std::set<int>::iterator p;
+ for (p= (*bb_itr)->predecessor_ids.begin();p != (*bb_itr)->predecessor_ids.end();p++) {
+ printf(" %d", *p);
+ }
+ printf("\t");
+ }
+ if ( !(*bb_itr)->successor_ids.empty() ) {
+ printf("Successors:");
+ std::set<int>::iterator s;
+ for (s= (*bb_itr)->successor_ids.begin();s != (*bb_itr)->successor_ids.end();s++) {
+ printf(" %d", *s);
+ }
+ }
+ printf("\n");
+ }
+}
+void function_info::connect_basic_blocks( ) //iterate across m_basic_blocks of function, connecting basic blocks together
+{
+ std::vector<basic_block_t*>::iterator bb_itr;
+ std::vector<basic_block_t*>::iterator bb_target_itr;
+ basic_block_t* exit_bb = m_basic_blocks.back();
+
+ //start from first basic block, which we know is the entry point
+ bb_itr = m_basic_blocks.begin();
+ for (bb_itr = m_basic_blocks.begin();bb_itr != m_basic_blocks.end(); bb_itr++) {
+ ptx_instruction *pI = (*bb_itr)->ptx_end;
+ if ((*bb_itr)->is_exit) //reached last basic block, no successors to link
+ continue;
+ if (pI->get_opcode() == RET_OP || pI->get_opcode() == EXIT_OP ) {
+ (*bb_itr)->successor_ids.insert(exit_bb->bb_id);
+ exit_bb->predecessor_ids.insert((*bb_itr)->bb_id);
+ if( pI->has_pred() ) {
+ printf("GPGPU-Sim PTX: Warning detected predicated return/exit.\n");
+ // if predicated, add link to next block
+ unsigned next_addr = pI->get_m_instr_mem_index() + 1;
+ if( next_addr < m_instr_mem_size && m_instr_mem[next_addr] ) {
+ basic_block_t *next_bb = m_instr_mem[next_addr]->get_bb();
+ (*bb_itr)->successor_ids.insert(next_bb->bb_id);
+ next_bb->predecessor_ids.insert((*bb_itr)->bb_id);
+ }
+ }
+ continue;
+ } else if (pI->get_opcode() == BRA_OP) {
+ //find successor and link that basic_block to this one
+ operand_info &target = pI->dst(); //get operand, e.g. target name
+ unsigned addr = labels[ target.name() ];
+ ptx_instruction *target_pI = m_instr_mem[addr];
+ basic_block_t *target_bb = target_pI->get_bb();
+ (*bb_itr)->successor_ids.insert(target_bb->bb_id);
+ target_bb->predecessor_ids.insert((*bb_itr)->bb_id);
+ }
+ if ( !(pI->get_opcode()==BRA_OP && (!pI->has_pred())) ) {
+ // if basic block does not end in an unpredicated branch,
+ // then next basic block is also successor
+ // (this is better than testing for .uni)
+ unsigned next_addr = pI->get_m_instr_mem_index() + 1;
+ basic_block_t *next_bb = m_instr_mem[next_addr]->get_bb();
+ (*bb_itr)->successor_ids.insert(next_bb->bb_id);
+ next_bb->predecessor_ids.insert((*bb_itr)->bb_id);
+ } else
+ assert(pI->get_opcode() == BRA_OP);
+ }
+}
+
+void intersect( std::set<int> &A, const std::set<int> &B )
+{
+ // return intersection of A and B in A
+ for( std::set<int>::iterator a=A.begin(); a!=A.end(); ) {
+ std::set<int>::iterator a_next = a;
+ a_next++;
+ if( B.find(*a) == B.end() ) {
+ A.erase(*a);
+ a = a_next;
+ } else
+ a++;
+ }
+}
+
+bool is_equal( const std::set<int> &A, const std::set<int> &B )
+{
+ if( A.size() != B.size() )
+ return false;
+ for( std::set<int>::iterator b=B.begin(); b!=B.end(); b++ )
+ if( A.find(*b) == A.end() )
+ return false;
+ return true;
+}
+
+void print_set(const std::set<int> &A)
+{
+ std::set<int>::iterator a;
+ for (a= A.begin(); a != A.end(); a++) {
+ printf("%d ", (*a));
+ }
+ printf("\n");
+}
+
+void function_info::find_postdominators( )
+{
+ // find postdominators using algorithm of Muchnick's Adv. Compiler Design & Implemmntation Fig 7.14
+ printf("GPGPU-Sim PTX: Finding postdominators for \'%s\'...\n", m_name.c_str() );
+ fflush(stdout);
+ assert( m_basic_blocks.size() >= 2 ); // must have a distinquished exit block
+ std::vector<basic_block_t*>::reverse_iterator bb_itr = m_basic_blocks.rbegin();
+ (*bb_itr)->postdominator_ids.insert((*bb_itr)->bb_id); // the only postdominator of the exit block is the exit
+ for (++bb_itr;bb_itr != m_basic_blocks.rend();bb_itr++) { //copy all basic blocks to all postdominator lists EXCEPT for the exit block
+ for (unsigned i=0; i<m_basic_blocks.size(); i++)
+ (*bb_itr)->postdominator_ids.insert(i);
+ }
+ bool change = true;
+ while (change) {
+ change = false;
+ for ( int h = m_basic_blocks.size()-2/*skip exit*/; h >= 0 ; --h ) {
+ assert( m_basic_blocks[h]->bb_id == (unsigned)h );
+ std::set<int> T;
+ for (unsigned i=0;i< m_basic_blocks.size();i++)
+ T.insert(i);
+ for ( std::set<int>::iterator s = m_basic_blocks[h]->successor_ids.begin();s != m_basic_blocks[h]->successor_ids.end();s++)
+ intersect(T, m_basic_blocks[*s]->postdominator_ids);
+ T.insert(h);
+ if (!is_equal(T,m_basic_blocks[h]->postdominator_ids)) {
+ change = true;
+ m_basic_blocks[h]->postdominator_ids = T;
+ }
+ }
+ }
+}
+
+void function_info::find_ipostdominators( )
+{
+ // find immediate postdominator blocks, using algorithm of
+ // Muchnick's Adv. Compiler Design & Implemmntation Fig 7.15
+ printf("GPGPU-Sim PTX: Finding immediate postdominators for \'%s\'...\n", m_name.c_str() );
+ fflush(stdout);
+ assert( m_basic_blocks.size() >= 2 ); // must have a distinquished exit block
+ for (unsigned i=0; i<m_basic_blocks.size(); i++) { //initialize Tmp(n) to all pdoms of n except for n
+ m_basic_blocks[i]->Tmp_ids = m_basic_blocks[i]->postdominator_ids;
+ assert( m_basic_blocks[i]->bb_id == i );
+ m_basic_blocks[i]->Tmp_ids.erase(i);
+ }
+ for ( int n = m_basic_blocks.size()-2; n >=0;--n) {
+ // point iterator to basic block before the exit
+ for( std::set<int>::iterator s=m_basic_blocks[n]->Tmp_ids.begin(); s != m_basic_blocks[n]->Tmp_ids.end(); s++ ) {
+ int bb_s = *s;
+ for( std::set<int>::iterator t=m_basic_blocks[n]->Tmp_ids.begin(); t != m_basic_blocks[n]->Tmp_ids.end(); ) {
+ std::set<int>::iterator t_next = t; t_next++; // might erase thing pointed to be t, invalidating iterator t
+ if( *s == *t ) {
+ t = t_next;
+ continue;
+ }
+ int bb_t = *t;
+ if( m_basic_blocks[bb_s]->postdominator_ids.find(bb_t) != m_basic_blocks[bb_s]->postdominator_ids.end() )
+ m_basic_blocks[n]->Tmp_ids.erase(bb_t);
+ t = t_next;
+ }
+ }
+ }
+ unsigned num_ipdoms=0;
+ for ( int n = m_basic_blocks.size()-1; n >=0;--n) {
+ assert( m_basic_blocks[n]->Tmp_ids.size() <= 1 );
+ // if the above assert fails we have an error in either postdominator
+ // computation, the flow graph does not have a unique exit, or some other error
+ if( !m_basic_blocks[n]->Tmp_ids.empty() ) {
+ m_basic_blocks[n]->immediatepostdominator_id = *m_basic_blocks[n]->Tmp_ids.begin();
+ num_ipdoms++;
+ }
+ }
+ assert( num_ipdoms == m_basic_blocks.size()-1 );
+ // the exit node does not have an immediate post dominator, but everyone else should
+}
+
+void function_info::print_postdominators()
+{
+ printf("Printing postdominators for function \'%s\':\n", m_name.c_str() );
+ std::vector<int>::iterator bb_itr;
+ for (unsigned i = 0; i < m_basic_blocks.size(); i++) {
+ printf("ID: %d\t:", i);
+ for( std::set<int>::iterator j=m_basic_blocks[i]->postdominator_ids.begin(); j!=m_basic_blocks[i]->postdominator_ids.end(); j++)
+ printf(" %d", *j );
+ printf("\n");
+ }
+}
+
+void function_info::print_ipostdominators()
+{
+ printf("Printing immediate postdominators for function \'%s\':\n", m_name.c_str() );
+ std::vector<int>::iterator bb_itr;
+ for (unsigned i = 0; i < m_basic_blocks.size(); i++) {
+ printf("ID: %d\t:", i);
+ printf("%d\n", m_basic_blocks[i]->immediatepostdominator_id);
+ }
+}
+
+unsigned function_info::get_num_reconvergence_pairs()
+{
+ if (!num_reconvergence_pairs) {
+ for (unsigned i=0; i< (m_basic_blocks.size()-1); i++) { //last basic block containing exit obviously won't have a pair
+ if (m_basic_blocks[i]->ptx_end->get_opcode() == BRA_OP) {
+ num_reconvergence_pairs++;
+ }
+ }
+ }
+ return num_reconvergence_pairs;
+}
+
+void function_info::get_reconvergence_pairs(gpgpu_recon_t* recon_points)
+{
+ unsigned idx=0; //array index
+ for (unsigned i=0; i< (m_basic_blocks.size()-1); i++) { //last basic block containing exit obviously won't have a pair
+#ifdef DEBUG_GET_RECONVERG_PAIRS
+ printf("i=%d\n", i); fflush(stdout);
+#endif
+ if (m_basic_blocks[i]->ptx_end->get_opcode() == BRA_OP) {
+#ifdef DEBUG_GET_RECONVERG_PAIRS
+ printf("\tbranch!\n");
+ printf("\tbb_id=%d; ipdom=%d\n", m_basic_blocks[i]->bb_id, m_basic_blocks[i]->immediatepostdominator_id);
+ printf("\tm_instr_mem index=%d\n", m_basic_blocks[i]->ptx_end->get_m_instr_mem_index());
+ fflush(stdout);
+#endif
+ recon_points[idx].source_pc = m_basic_blocks[i]->ptx_end->get_PC();
+#ifdef DEBUG_GET_RECONVERG_PAIRS
+ printf("\trecon_points[idx].source_pc=%d\n", recon_points[idx].source_pc);
+#endif
+ if( m_basic_blocks[m_basic_blocks[i]->immediatepostdominator_id]->ptx_begin ) {
+ recon_points[idx].target_pc = m_basic_blocks[m_basic_blocks[i]->immediatepostdominator_id]->ptx_begin->get_PC();
+ } else {
+ // reconverge after function return
+ recon_points[idx].target_pc = -2;
+ }
+#ifdef DEBUG_GET_RECONVERG_PAIRS
+ m_basic_blocks[m_basic_blocks[i]->immediatepostdominator_id]->ptx_begin->print_insn();
+ printf("\trecon_points[idx].target_pc=%d\n", recon_points[idx].target_pc); fflush(stdout);
+#endif
+ idx++;
+ }
+ }
+}
+
+// interface with graphviz (print the graph in DOT language) for plotting
+void function_info::print_basic_block_dot()
+{
+ printf("Basic Block in DOT\n");
+ printf("digraph %s {\n", m_name.c_str());
+ std::vector<basic_block_t*>::iterator bb_itr;
+ for (bb_itr = m_basic_blocks.begin();bb_itr != m_basic_blocks.end(); bb_itr++) {
+ printf("\t");
+ std::set<int>::iterator s;
+ for (s = (*bb_itr)->successor_ids.begin();s != (*bb_itr)->successor_ids.end();s++) {
+ unsigned succ_bb = *s;
+ printf("%d -> %d; ", (*bb_itr)->bb_id, succ_bb );
+ }
+ printf("\n");
+ }
+ printf("}\n");
+}
+
+extern "C" void add_file( unsigned num, const char *filename )
+{
+ if( g_filename == NULL ) {
+ char *b = strdup(filename);
+ char *l=b;
+ char *n=b;
+ while( *n != '\0' ) {
+ if( *n == '/' )
+ l = n+1;
+ n++;
+ }
+
+ char *p = strtok(l,".");
+ char buf[1024];
+ snprintf(buf,1024,"%s.ptx",p);
+
+ char *q = strtok(NULL,".");
+ if( q && !strcmp(q,"cu") ) {
+ g_filename = strdup(buf);
+ }
+
+ free( b );
+ }
+
+ g_current_symbol_table = g_global_symbol_table;
+}
+
+extern "C" void *reset_symtab()
+{
+ void *result = g_current_symbol_table;
+ g_current_symbol_table = g_global_symbol_table;
+ return result;
+}
+
+extern "C" void set_symtab(void*symtab)
+{
+ g_current_symbol_table = (symbol_table*)symtab;
+}
+
+unsigned ptx_kernel_shmem_size( void *kernel_impl )
+{
+ function_info *f = (function_info*)kernel_impl;
+ const struct gpgpu_ptx_sim_kernel_info *kernel_info = f->get_kernel_info();
+ return kernel_info->smem;
+}
+
+unsigned ptx_kernel_nregs( void *kernel_impl )
+{
+ function_info *f = (function_info*)kernel_impl;
+ const struct gpgpu_ptx_sim_kernel_info *kernel_info = f->get_kernel_info();
+ return kernel_info->regs;
+}
diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h
new file mode 100644
index 0000000..82d5b4c
--- /dev/null
+++ b/src/cuda-sim/ptx_ir.h
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
+ * George L. Yuan, Dan O'Connor, Joey Ting, Henry Wong and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#ifndef ptx_ir_INCLUDED
+#define ptx_ir_INCLUDED
+
+#ifdef __cplusplus
+
+ #include <cstdlib>
+ #include <cstring>
+ #include <string>
+ #include <list>
+ #include <map>
+ #include <vector>
+ #include <assert.h>
+
+ #include "ptx.tab.h"
+ #include "ptx_sim.h"
+ #include "dram_callback.h"
+ #include "../util.h"
+
+ #include "memory.h"
+
+enum space_type {
+ undefined, inst_space
+};
+
+
+class addr { /* need this because there are many distinct address spaces (global, local, param, tex, surf, shared) */
+public:
+
+ addr() { m_space=undefined; m_addr = 0;}
+ void set_space( enum space_type space );
+ operator unsigned() { return m_addr;}
+
+private:
+ enum space_type m_space;
+ unsigned m_addr;
+};
+
+
+class type_info_key {
+public:
+ type_info_key()
+ {
+ m_init = false;
+ }
+ type_info_key( int space_spec, int scalar_type_spec, int vector_spec, int alignment_spec, int extern_spec, int array_dim )
+ {
+ m_init = true;
+ m_space_spec = space_spec;
+ m_scalar_type_spec = scalar_type_spec;
+ m_vector_spec = vector_spec;
+ m_alignment_spec = alignment_spec;
+ m_extern_spec = extern_spec;
+ m_array_dim = array_dim;
+ m_is_function = 0;
+ }
+ void set_is_func()
+ {
+ assert(!m_init);
+ m_init = true;
+ m_space_spec = 0;
+ m_scalar_type_spec = 0;
+ m_vector_spec = 0;
+ m_alignment_spec = 0;
+ m_extern_spec = 0;
+ m_array_dim = 0;
+ m_is_function = 1;
+ }
+
+ void set_array_dim( int array_dim )
+ {
+ m_array_dim = array_dim;
+ }
+
+ bool is_reg() const { return m_space_spec == REG_DIRECTIVE;}
+ bool is_param() const { return m_space_spec == PARAM_DIRECTIVE;}
+ bool is_global() const { return m_space_spec == GLOBAL_DIRECTIVE;}
+ bool is_local() const { return m_space_spec == LOCAL_DIRECTIVE;}
+ bool is_shared() const { return m_space_spec == SHARED_DIRECTIVE;}
+ bool is_const() const { return m_space_spec == CONST_DIRECTIVE;}
+ bool is_tex() const { return m_space_spec == TEX_DIRECTIVE;}
+ bool is_func_addr() const { return m_is_function?true:false; }
+ int scalar_type() const { return m_scalar_type_spec;}
+private:
+ bool m_init;
+ int m_space_spec;
+ int m_scalar_type_spec;
+ int m_vector_spec;
+ int m_alignment_spec;
+ int m_extern_spec;
+ int m_array_dim;
+ int m_is_function;
+
+ friend class type_info_key_compare;
+};
+
+class symbol_table;
+
+struct type_info_key_compare {
+ bool operator()( const type_info_key &a, const type_info_key &b ) const
+ {
+ assert( a.m_init && b.m_init );
+ if ( a.m_space_spec < b.m_space_spec ) return true;
+ if ( a.m_scalar_type_spec < b.m_scalar_type_spec ) return true;
+ if ( a.m_vector_spec < b.m_vector_spec ) return true;
+ if ( a.m_alignment_spec < b.m_alignment_spec ) return true;
+ if ( a.m_extern_spec < b.m_extern_spec ) return true;
+ if ( a.m_array_dim < b.m_array_dim ) return true;
+ if ( a.m_is_function < b.m_is_function ) return true;
+
+ return false;
+ }
+};
+
+class type_info {
+public:
+ type_info( symbol_table *scope, type_info_key t )
+ {
+ m_type_info = t;
+ }
+ const type_info_key &get_key() const { return m_type_info;}
+
+private:
+ symbol_table *m_scope;
+ type_info_key m_type_info;
+};
+
+enum operand_type {
+ reg_t, vector_t, builtin_t, address_t, memory_t, float_op_t, double_op_t, int_t,
+ unsigned_t, symbolic_t, label_t, v_reg_t, v_float_op_t, v_double_op_t,
+ v_int_t, v_unsigned_t
+};
+
+class operand_info;
+
+class symbol {
+public:
+ symbol( const char *name, const type_info *type, const char *location )
+ {
+ m_uid = get_uid();
+ m_name = name;
+ m_decl_location = location;
+ m_type = type;
+ m_address_valid = false;
+ m_is_label = false;
+ m_is_shared = false;
+ m_is_const = false;
+ m_is_global = false;
+ m_is_local = false;
+ m_is_tex = false;
+ m_is_func_addr = false;
+ m_reg_num_valid = false;
+ m_function = NULL;
+ if ( type ) m_is_shared = type->get_key().is_shared();
+ if ( type ) m_is_const = type->get_key().is_const();
+ if ( type ) m_is_global = type->get_key().is_global();
+ if ( type ) m_is_local = type->get_key().is_local();
+ if ( type ) m_is_tex = type->get_key().is_tex();
+ if ( type ) m_is_func_addr = type->get_key().is_func_addr();
+ }
+ const std::string &name() const { return m_name;}
+ const std::string &decl_location() const { return m_decl_location;}
+ const type_info *type() const { return m_type;}
+ addr_t get_address() const
+ {
+ assert( m_is_label || !m_type->get_key().is_reg() ); // todo : other assertions
+ assert( m_address_valid );
+ return m_address;
+ }
+ function_info *get_pc() const
+ {
+ return m_function;
+ }
+ void set_regno( unsigned regno, unsigned arch_regno )
+ {
+ m_reg_num_valid = true;
+ m_reg_num = regno;
+ m_arch_reg_num = arch_regno;
+ }
+
+ void set_address( addr_t addr )
+ {
+ m_address_valid = true;
+ m_address = addr;
+ }
+ void set_label_address( addr_t addr)
+ {
+ m_address_valid = true;
+ m_address = addr;
+ m_is_label = true;
+ }
+ void set_function( function_info *func )
+ {
+ m_function = func;
+ m_is_func_addr = true;
+ }
+
+ bool is_label() const { return m_is_label;}
+ bool is_shared() const { return m_is_shared;}
+ bool is_const() const { return m_is_const;}
+ bool is_global() const { return m_is_global;}
+ bool is_local() const { return m_is_local;}
+ bool is_tex() const { return m_is_tex;}
+ bool is_func_addr() const { return m_is_func_addr; }
+
+ void add_initializer( const std::list<operand_info> &init );
+ bool has_initializer() const
+ {
+ return m_initializer.size() > 0;
+ }
+ std::list<operand_info> get_initializer() const
+ {
+ return m_initializer;
+ }
+ unsigned reg_num() const
+ {
+ assert( m_reg_num_valid );
+ return m_reg_num;
+ }
+ unsigned arch_reg_num() const
+ {
+ assert( m_reg_num_valid );
+ return m_arch_reg_num;
+ }
+ void print_info(FILE *fp) const;
+
+private:
+ unsigned get_uid();
+ unsigned m_uid;
+ const type_info *m_type;
+ std::string m_name;
+ std::string m_decl_location;
+
+ unsigned m_address;
+ function_info *m_function; // used for function symbols
+
+ bool m_address_valid;
+ bool m_is_label;
+ bool m_is_shared;
+ bool m_is_const;
+ bool m_is_global;
+ bool m_is_local;
+ bool m_is_tex;
+ bool m_is_func_addr;
+ unsigned m_reg_num;
+ unsigned m_arch_reg_num;
+ bool m_reg_num_valid;
+
+ std::list<operand_info> m_initializer;
+ static unsigned sm_next_uid;
+};
+
+
+class symbol_table {
+public:
+ symbol_table();
+ symbol_table( const char *scope_name, unsigned entry_point, symbol_table *parent );
+ void set_name( const char *name );
+ symbol* lookup( const char *identifier );
+ std::string get_scope_name() const { return m_scope_name; }
+ symbol *add_variable( const char *identifier, const type_info *type, const char *filename, unsigned line );
+ void add_function( function_info *func );
+ bool add_function_decl( const char *name, int entry_point, function_info **func_info, symbol_table **symbol_table );
+ type_info *add_type( int space_spec, int scalar_type_spec, int vector_spec, int alignment_spec, int extern_spec );
+ type_info *add_type( function_info *func );
+ type_info *get_array_type( type_info *base_type, unsigned array_dim );
+ void set_label_address( const symbol *label, unsigned addr );
+ unsigned next_reg_num() { return ++m_reg_allocator;}
+ addr_t get_shared_next() { return m_shared_next;}
+ addr_t get_global_next() { return m_global_next;}
+ addr_t get_local_next() { return m_local_next;}
+ addr_t get_tex_next() { return m_tex_next;}
+ void alloc_shared( unsigned num_bytes ) { m_shared_next += num_bytes;}
+ void alloc_global( unsigned num_bytes ) { m_global_next += num_bytes;}
+ void alloc_local( unsigned num_bytes ) { m_local_next += num_bytes;}
+ void alloc_tex( unsigned num_bytes ) { m_tex_next += num_bytes;}
+
+ typedef std::list<symbol*>::iterator iterator;
+
+ iterator param_iterator_begin() { return m_params.begin();}
+ iterator param_iterator_end() { return m_params.end();}
+
+ iterator global_iterator_begin() { return m_globals.begin();}
+ iterator global_iterator_end() { return m_globals.end();}
+
+ iterator const_iterator_begin() { return m_consts.begin();}
+ iterator const_iterator_end() { return m_consts.end();}
+
+ void dump();
+private:
+ unsigned m_reg_allocator;
+ unsigned m_shared_next;
+ unsigned m_const_next;
+ unsigned m_global_next;
+ unsigned m_local_next;
+ unsigned m_tex_next;
+
+ symbol_table *m_parent;
+ std::string m_scope_name;
+ std::map<std::string, symbol *> m_symbols; //map from name of register to pointers to the registers
+ std::map<type_info_key,type_info*,type_info_key_compare> m_types;
+ std::list<symbol*> m_params;
+ std::list<symbol*> m_globals;
+ std::list<symbol*> m_consts;
+ std::map<std::string,function_info*> m_function_info_lookup;
+ std::map<std::string,symbol_table*> m_function_symtab_lookup;
+};
+
+class operand_info {
+public:
+ operand_info()
+ {
+ m_uid = get_uid();
+ m_valid = false;
+ }
+ operand_info( const symbol *addr )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ if ( addr->is_label() ) {
+ m_type = label_t;
+ } else if ( addr->is_shared() ) {
+ m_type = symbolic_t;
+ } else if ( addr->is_const() ) {
+ m_type = symbolic_t;
+ } else if ( addr->is_global() ) {
+ m_type = symbolic_t;
+ } else if ( addr->is_local() ) {
+ m_type = symbolic_t;
+ } else if ( addr->is_tex() ) {
+ m_type = symbolic_t;
+ } else if ( addr->is_func_addr() ) {
+ m_type = symbolic_t;
+ } else {
+ m_type = reg_t;
+ }
+ m_value.m_symbolic = addr;
+ m_addr_offset = 0;
+ m_vector = false;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( int builtin_id, int dim_mod )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = builtin_t;
+ m_value.m_int = builtin_id;
+ m_addr_offset = dim_mod;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( const symbol *addr, int offset )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = address_t;
+ m_value.m_symbolic = addr;
+ m_addr_offset = offset;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( unsigned x )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = unsigned_t;
+ m_value.m_unsigned = x;
+ m_addr_offset = 0;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( int x )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = int_t;
+ m_value.m_int = x;
+ m_addr_offset = 0;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( float x )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = float_op_t;
+ m_value.m_float = x;
+ m_addr_offset = 0;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( double x )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = false;
+ m_type = double_op_t;
+ m_value.m_double = x;
+ m_addr_offset = 0;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+ operand_info( const symbol *s1, const symbol *s2, const symbol *s3, const symbol *s4 )
+ {
+ m_uid = get_uid();
+ m_valid = true;
+ m_vector = true;
+ m_type = vector_t;
+ m_value.m_vector_symbolic = new const symbol*[4];
+ m_value.m_vector_symbolic[0] = s1;
+ m_value.m_vector_symbolic[1] = s2;
+ m_value.m_vector_symbolic[2] = s3;
+ m_value.m_vector_symbolic[3] = s4;
+ m_addr_offset = 0;
+ m_neg_pred = false;
+ m_is_return_var = false;
+ }
+
+ void make_memory_operand() { m_type = memory_t;}
+ void set_return() { m_is_return_var = true; }
+
+ const std::string &name() const
+ {
+ assert( m_type == symbolic_t || m_type == reg_t || m_type == address_t || m_type == memory_t || m_type == label_t);
+ return m_value.m_symbolic->name();
+ }
+
+ unsigned get_vect_nelem() const
+ {
+ assert( is_vector() );
+ if( !m_value.m_vector_symbolic[0] ) return 0;
+ if( !m_value.m_vector_symbolic[1] ) return 1;
+ if( !m_value.m_vector_symbolic[2] ) return 2;
+ if( !m_value.m_vector_symbolic[3] ) return 3;
+ return 4;
+ }
+ const std::string &vec_name1() const
+ {
+ assert( m_type == vector_t);
+ return m_value.m_vector_symbolic[0]->name();
+ }
+
+ const std::string &vec_name2() const
+ {
+ assert( m_type == vector_t);
+ return m_value.m_vector_symbolic[1]->name();
+ }
+
+ const std::string &vec_name3() const
+ {
+ assert( m_type == vector_t);
+ return m_value.m_vector_symbolic[2]->name();
+ }
+
+ const std::string &vec_name4() const
+ {
+ assert( m_type == vector_t);
+ return m_value.m_vector_symbolic[3]->name();
+ }
+
+ bool is_reg() const
+ {
+ if ( m_type == reg_t ) {
+ return true;
+ }
+ if ( m_type != symbolic_t ) {
+ return false;
+ }
+ return m_value.m_symbolic->type()->get_key().is_reg();
+ }
+
+ bool is_vector() const
+ {
+ if ( m_vector) return true;
+ return false;
+ }
+ int reg_num() const { return m_value.m_symbolic->reg_num();}
+ int reg1_num() const { return m_value.m_vector_symbolic[0]->reg_num();}
+ int reg2_num() const { return m_value.m_vector_symbolic[1]->reg_num();}
+ int reg3_num() const { return m_value.m_vector_symbolic[2]?m_value.m_vector_symbolic[2]->reg_num():0; }
+ int reg4_num() const { return m_value.m_vector_symbolic[3]?m_value.m_vector_symbolic[3]->reg_num():0; }
+ int arch_reg_num() const { return m_value.m_symbolic->arch_reg_num(); }
+ int arch_reg_num(unsigned n) const { return (m_value.m_vector_symbolic[n])? m_value.m_vector_symbolic[n]->arch_reg_num() : -1; }
+ bool is_label() const { return m_type == label_t;}
+ bool is_builtin() const { return m_type == builtin_t;}
+ bool is_memory_operand() const { return m_type == memory_t;}
+ bool is_literal() const { return m_type == int_t ||
+ m_type == float_op_t ||
+ m_type == double_op_t ||
+ m_type == unsigned_t;}
+ bool is_shared() const {
+ if ( !(m_type == symbolic_t || m_type == address_t || m_type == memory_t) ) {
+ return false;
+ }
+ return m_value.m_symbolic->is_shared();
+ }
+ bool is_const() const { return m_value.m_symbolic->is_const();}
+ bool is_global() const { return m_value.m_symbolic->is_global();}
+ bool is_local() const { return m_value.m_symbolic->is_local();}
+ bool is_tex() const { return m_value.m_symbolic->is_tex();}
+ bool is_return_var() const { return m_is_return_var; }
+
+ bool is_function_address() const
+ {
+ if( m_type != symbolic_t ) {
+ return false;
+ }
+ return m_value.m_symbolic->is_func_addr();
+ }
+
+ ptx_reg_t get_literal_value() const
+ {
+ ptx_reg_t result;
+ switch ( m_type ) {
+ case int_t: result.s32 = m_value.m_int; break;
+ case float_op_t: result.f32 = m_value.m_float; break;
+ case double_op_t: result.f64 = m_value.m_double; break;
+ case unsigned_t: result.u32 = m_value.m_unsigned; break;
+ default:
+ assert(0);
+ break;
+ }
+ return result;
+ }
+ int get_int() const { return m_value.m_int;}
+ int get_addr_offset() const { return m_addr_offset;}
+ const symbol *get_symbol() const { return m_value.m_symbolic;}
+ void set_type( enum operand_type type )
+ {
+ m_type = type;
+ }
+ enum operand_type get_type() const {
+ return m_type;
+ }
+ void set_neg_pred()
+ {
+ assert( m_valid );
+ m_neg_pred = true;
+ }
+ bool is_neg_pred() const { return m_neg_pred; }
+ bool is_valid() const { return m_valid; }
+
+private:
+ unsigned m_uid;
+ bool m_valid;
+ bool m_vector;
+ enum operand_type m_type;
+
+ union {
+ int m_int;
+ unsigned int m_unsigned;
+ float m_float;
+ double m_double;
+ int m_vint[4];
+ unsigned int m_vunsigned[4];
+ float m_vfloat[4];
+ double m_vdouble[4];
+ const symbol* m_symbolic;
+ const symbol** m_vector_symbolic;
+ } m_value;
+
+ int m_addr_offset;
+
+ bool m_neg_pred;
+ bool m_is_return_var;
+
+ static unsigned sm_next_uid;
+ unsigned get_uid();
+};
+
+extern const char *g_opcode_string[];
+extern unsigned g_num_ptx_inst_uid;
+struct basic_block_t {
+ basic_block_t( unsigned ID, ptx_instruction *begin, ptx_instruction *end, bool entry, bool ex)
+ {
+ bb_id = ID;
+ ptx_begin = begin;
+ ptx_end = end;
+ is_entry=entry;
+ is_exit=ex;
+ immediatepostdominator_id = -1;
+ }
+
+ ptx_instruction* ptx_begin;
+ ptx_instruction* ptx_end;
+ std::set<int> predecessor_ids; //indices of other basic blocks in m_basic_blocks array
+ std::set<int> successor_ids;
+ std::set<int> postdominator_ids;
+ std::set<int> dominator_ids;
+ std::set<int> Tmp_ids;
+ int immediatepostdominator_id;
+ bool is_entry;
+ bool is_exit;
+ unsigned bb_id;
+};
+
+struct gpgpu_recon_t {
+ address_type source_pc;
+ address_type target_pc;
+};
+
+class ptx_instruction {
+public:
+ ptx_instruction( int opcode,
+ const symbol *pred,
+ int neg_pred,
+ symbol *label,
+ const std::list<operand_info> &operands,
+ const operand_info &return_var,
+ const std::list<int> &options,
+ const std::list<int> &scalar_type,
+ int space_spec,
+ const char *file,
+ unsigned line,
+ const char *source );
+
+ void print_insn() const;
+ void print_insn( FILE *fp ) const;
+ unsigned uid() const { return m_uid;}
+ int get_opcode() { return m_opcode;}
+ const char *get_opcode_cstr() const
+ {
+ if ( m_opcode != -1 ) {
+ return g_opcode_string[m_opcode];
+ } else {
+ return "label";
+ }
+ }
+ const char *source_file() const { return m_source_file.c_str();}
+ unsigned source_line() const { return m_source_line;}
+ unsigned get_num_operands() const { return m_operands.size();}
+ bool has_pred() const { return m_pred != NULL;}
+ operand_info get_pred() const { return operand_info( m_pred );}
+ bool get_pred_neg() const { return m_neg_pred;}
+ const char *get_source() const { return m_source.c_str();}
+
+ typedef std::vector<operand_info>::const_iterator const_iterator;
+
+ const_iterator op_iter_begin() const
+ {
+ return m_operands.begin();
+ }
+
+ const_iterator op_iter_end() const
+ {
+ return m_operands.end();
+ }
+
+ const operand_info &dst() const
+ {
+ assert( !m_operands.empty() );
+ return m_operands[0];
+ }
+
+ const operand_info &func_addr() const
+ {
+ assert( !m_operands.empty() );
+ if( !m_operands[0].is_return_var() ) {
+ return m_operands[0];
+ } else {
+ assert( m_operands.size() >= 2 );
+ return m_operands[1];
+ }
+ }
+
+ operand_info &dst()
+ {
+ assert( !m_operands.empty() );
+ return m_operands[0];
+ }
+
+ const operand_info &src1() const
+ {
+ assert( m_operands.size() > 1 );
+ return m_operands[1];
+ }
+
+ const operand_info &src2() const
+ {
+ assert( m_operands.size() > 2 );
+ return m_operands[2];
+ }
+
+ const operand_info &src3() const
+ {
+ assert( m_operands.size() > 3 );
+ return m_operands[3];
+ }
+
+ const operand_info &operand_lookup( unsigned n ) const
+ {
+ assert( n < m_operands.size() );
+ return m_operands[n];
+ }
+ bool has_return() const
+ {
+ return m_return_var.is_valid();
+ }
+
+ unsigned get_space() const { return m_space_spec;}
+ unsigned get_vector() const { return m_vector_spec;}
+ unsigned get_atomic() const { return m_atomic_spec;}
+
+ int get_type() const
+ {
+ assert( !m_scalar_type.empty() );
+ return m_scalar_type.front();
+ }
+
+ int get_type2() const
+ {
+ assert( m_scalar_type.size()==2 );
+ return m_scalar_type.back();
+ }
+
+ void assign_bb(basic_block_t* basic_block) //assign instruction to a basic block
+ {
+ m_basic_block = basic_block;
+ }
+ basic_block_t* get_bb() { return m_basic_block;}
+ void set_m_instr_mem_index(unsigned index) {
+ m_instr_mem_index = index;
+ }
+ void set_PC( addr_t PC )
+ {
+ m_PC = PC;
+ }
+ addr_t get_PC() const
+ {
+ return m_PC;
+ }
+
+ unsigned get_m_instr_mem_index() { return m_instr_mem_index;}
+ unsigned get_cmpop() const { return m_compare_op;}
+ const symbol *get_label() const { return m_label;}
+ bool is_label() const { if(m_label){ assert(m_opcode==-1);return true;} return false;}
+ bool is_hi() const { return m_hi;}
+ bool is_lo() const { return m_lo;}
+ bool is_wide() const { return m_wide;}
+ bool is_uni() const { return m_uni;}
+ unsigned rounding_mode() const { return m_rounding_mode;}
+ unsigned saturation_mode() const { return m_saturation_mode;}
+ unsigned dimension() const { return m_geom_spec;}
+ enum vote_mode_t { vote_any, vote_all, vote_uni };
+ enum vote_mode_t vote_mode() const { return m_vote_mode; }
+
+ unsigned warp_size() const { return m_warp_size; }
+ int membar_level() const { return m_membar_level; }
+private:
+ basic_block_t *m_basic_block;
+ unsigned m_uid;
+ addr_t m_PC;
+ std::string m_source_file;
+ unsigned m_source_line;
+ std::string m_source;
+ unsigned m_warp_size;
+
+ const symbol *m_pred;
+ bool m_neg_pred;
+ int m_opcode;
+ const symbol *m_label;
+ std::vector<operand_info> m_operands;
+ operand_info m_return_var;
+
+ std::list<int> m_options;
+ bool m_wide;
+ bool m_hi;
+ bool m_lo;
+ bool m_uni; //if branch instruction, this evaluates to true for uniform branches (ie jumps)
+ unsigned m_rounding_mode;
+ unsigned m_compare_op;
+ unsigned m_saturation_mode;
+
+ std::list<int> m_scalar_type;
+ int m_space_spec;
+ int m_geom_spec;
+ int m_vector_spec;
+ int m_atomic_spec;
+ enum vote_mode_t m_vote_mode;
+ int m_membar_level;
+ int m_instr_mem_index; //index into m_instr_mem array
+};
+
+class param_info {
+public:
+ param_info() { m_valid = false; m_value_set=false;}
+ param_info( unsigned index, std::string name, int type )
+ {
+ m_valid = true;
+ m_value_set = false;
+ m_index = index;
+ m_name = name;
+ m_type = type;
+ }
+ void add_data( param_t v ) {
+ m_value_set = true;
+ m_value = v;
+ }
+ std::string get_name() const { return m_name; }
+ int get_type() const { return m_type; }
+ param_t get_value() const { assert(m_value_set); return m_value; }
+private:
+ bool m_valid;
+ unsigned m_index;
+ std::string m_name;
+ int m_type;
+ bool m_value_set;
+ param_t m_value;
+};
+
+class function_info {
+public:
+ function_info(int entry_point )
+ {
+ m_entry_point = entry_point?true:false;
+ num_reconvergence_pairs = 0;
+ m_symtab = NULL;
+ m_assembled = false;
+ m_return_var_sym = NULL;
+ m_kernel_info.cmem = 0;
+ m_kernel_info.lmem = 0;
+ m_kernel_info.regs = 0;
+ m_kernel_info.smem = 0;
+ }
+ void set_name(const char *name)
+ {
+ m_name = name;
+ }
+ void set_symtab(symbol_table *symtab )
+ {
+ m_symtab = symtab;
+ }
+ std::string get_name()
+ {
+ return m_name;
+ }
+ void print_insn( unsigned pc, FILE * fp ) const;
+ void add_inst( const std::list<ptx_instruction*> &instructions )
+ {
+ m_instructions = instructions;
+ }
+ std::list<ptx_instruction*>::iterator find_next_real_instruction( std::list<ptx_instruction*>::iterator i );
+ void create_basic_blocks( );
+
+ void print_basic_blocks();
+
+ void print_basic_block_links();
+ void print_basic_block_dot();
+
+ void connect_basic_blocks( ); //iterate across m_basic_blocks of function, connecting basic blocks together
+
+ //iterate across m_basic_blocks of function,
+ //finding postdominator blocks, using algorithm of
+ //Muchnick's Adv. Compiler Design & Implemmntation Fig 7.14
+ void find_postdominators( );
+
+ //iterate across m_basic_blocks of function,
+ //finding immediate postdominator blocks, using algorithm of
+ //Muchnick's Adv. Compiler Design & Implemmntation Fig 7.15
+ void find_ipostdominators( );
+
+ void print_postdominators();
+
+ void print_ipostdominators();
+
+ unsigned get_num_reconvergence_pairs();
+
+ void get_reconvergence_pairs(gpgpu_recon_t* recon_points);
+
+ unsigned get_function_size() { return m_instructions.size();}
+
+ void ptx_assemble();
+ void ptx_decode_inst( ptx_thread_info *thd,
+ unsigned *op_type,
+ int *i1,
+ int *i2,
+ int *i3,
+ int *i4,
+ int *o1,
+ int *o2,
+ int *o3,
+ int *o4,
+ int *vectorin,
+ int *vectorout,
+ int *arch_reg );
+ unsigned ptx_get_inst_op( ptx_thread_info *thread );
+ void ptx_exec_inst( ptx_thread_info *thd, addr_t *addr, unsigned *space, unsigned *data_size, dram_callback_t* callback, unsigned warp_active_mask );
+ void add_param( const char *name, struct param_t value )
+ {
+ m_params[ name ] = value;
+ }
+ void add_param_name_and_type( unsigned index, std::string name, int type );
+ void add_param_data( unsigned argn, struct gpgpu_ptx_sim_arg *args );
+ void add_return_var( const symbol *rv )
+ {
+ m_return_var_sym = rv;
+ }
+ void add_arg( const symbol *arg )
+ {
+ assert( arg != NULL );
+ m_args.push_back(arg);
+ }
+ void remove_args()
+ {
+ m_args.clear();
+ }
+ unsigned num_args() const
+ {
+ return m_args.size();
+ }
+ const symbol* get_arg( unsigned n ) const
+ {
+ assert( n < m_args.size() );
+ return m_args[n];
+ }
+ bool has_return() const
+ {
+ return m_return_var_sym != NULL;
+ }
+ const symbol *get_return_var() const
+ {
+ return m_return_var_sym;
+ }
+ const ptx_instruction *get_instruction( unsigned PC ) const
+ {
+ unsigned index = PC - m_start_PC;
+ if( index < m_instr_mem_size )
+ return m_instr_mem[index];
+ return NULL;
+ }
+ addr_t get_start_PC() const
+ {
+ return m_start_PC;
+ }
+
+ void finalize( memory_space *param_mem, symbol_table *symtab )
+ {
+ unsigned param_address = 0;
+ for( std::map<unsigned,param_info>::iterator i=m_ptx_param_info.begin(); i!=m_ptx_param_info.end(); i++ ) {
+ param_info &p = i->second;
+ 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;
+ type_decode(xtype,size,tmp);
+ param_mem->write(param_address,size/8,&value);
+ param->set_address(param_address);
+ param_address += 8;//align to 64 bits so mem_access doesn't complain (before was size/8);
+ }
+ }
+ ptx_reg_t get_param( const std::string &name ) const
+ {
+ std::map<std::string,param_t>::const_iterator i = m_params.find(name);
+ if ( i == m_params.end() ) {
+ printf("Loader error: parameter \"%s\" value not defined in configuration\n", name.c_str() );
+ abort();
+ } else {
+ param_t x = i->second;
+ ptx_reg_t y;
+ switch ( x.type ) {
+ case S8_TYPE:
+ case S16_TYPE:
+ case S32_TYPE:
+ case S64_TYPE:
+ case B8_TYPE:
+ case B16_TYPE:
+ case B32_TYPE:
+ case B64_TYPE:
+ case U8_TYPE:
+ case U16_TYPE:
+ case U32_TYPE:
+ case U64_TYPE:
+ y.u64 = x.data.int_value;
+ break;
+ case F16_TYPE:
+ assert(0);
+ case F32_TYPE:
+ y.f32 = x.data.float_value;
+ break;
+ case F64_TYPE:
+ y.f64 = x.data.double_value;
+ break;
+ }
+ return y;
+ }
+ }
+
+ const struct gpgpu_ptx_sim_kernel_info* get_kernel_info () {
+ return &m_kernel_info;
+ }
+
+ const void set_kernel_info (const struct gpgpu_ptx_sim_kernel_info *info) {
+ m_kernel_info = *info;
+ }
+ symbol_table *get_symtab()
+ {
+ return m_symtab;
+ }
+
+ static const ptx_instruction* pc_to_instruction(unsigned pc)
+ {
+ assert(pc > 0);
+ assert(pc <= s_g_pc_to_insn.size());
+ return s_g_pc_to_insn[pc - 1];
+ }
+
+private:
+ bool m_entry_point;
+ bool m_assembled;
+ std::string m_name;
+ ptx_instruction **m_instr_mem;
+ unsigned m_start_PC;
+ unsigned m_instr_mem_size;
+ std::map<std::string,param_t> m_params;
+ std::map<unsigned,param_info> m_ptx_param_info;
+ const symbol *m_return_var_sym;
+ std::vector<const symbol*> m_args;
+ std::list<ptx_instruction*> m_instructions;
+ std::vector<basic_block_t*> m_basic_blocks;
+ std::list<std::pair<unsigned, unsigned> > m_back_edges;
+ std::map<std::string,unsigned> labels;
+ unsigned num_reconvergence_pairs;
+
+ //Registers/shmem/etc. used (from ptxas -v), loaded from ___.ptxinfo along with ___.ptx
+ struct gpgpu_ptx_sim_kernel_info m_kernel_info;
+
+ symbol_table *m_symtab;
+
+ static std::vector<ptx_instruction*> s_g_pc_to_insn; // a direct mapping from PC to instruction
+};
+
+/*******************************/
+// These declarations should be identical to those in ./../../cuda-sim-dev/libcuda/texture_types.h
+enum cudaChannelFormatKind {
+ cudaChannelFormatKindSigned,
+ cudaChannelFormatKindUnsigned,
+ cudaChannelFormatKindFloat
+};
+
+struct cudaChannelFormatDesc {
+ int x;
+ int y;
+ int z;
+ int w;
+ enum cudaChannelFormatKind f;
+};
+
+struct cudaArray {
+ void *devPtr;
+ int devPtr32;
+ struct cudaChannelFormatDesc desc;
+ int width;
+ int height;
+ int size; //in bytes
+ unsigned dimensions;
+};
+
+enum cudaTextureAddressMode {
+ cudaAddressModeWrap,
+ cudaAddressModeClamp
+};
+
+enum cudaTextureFilterMode {
+ cudaFilterModePoint,
+ cudaFilterModeLinear
+};
+
+enum cudaTextureReadMode {
+ cudaReadModeElementType,
+ cudaReadModeNormalizedFloat
+};
+
+struct textureReference {
+ int normalized;
+ enum cudaTextureFilterMode filterMode;
+ enum cudaTextureAddressMode addressMode[2];
+ struct cudaChannelFormatDesc channelDesc;
+};
+
+/**********************************/
+
+struct textureInfo {
+ unsigned int texel_size; //size in bytes, e.g. (channelDesc.x+y+z+w)/8
+ unsigned int Tx,Ty; //tiling factor dimensions of layout of texels per 64B cache block
+ unsigned int Tx_numbits,Ty_numbits; //log2(T)
+ unsigned int texel_size_numbits; //log2(texel_size)
+};
+
+
+extern function_info *g_func_info;
+
+extern int g_error_detected;
+extern bool g_debug_ir_generation;
+extern std::list<ptx_instruction*> g_instructions;
+extern symbol_table *g_current_symbol_table;
+extern symbol_table *g_entrypoint_symbol_table;
+extern function_info *g_entrypoint_func_info;
+extern symbol_table *g_global_symbol_table;
+void init_parser();
+
+extern "C" {
+#endif
+
+ void start_function( int entry_point );
+ void add_function_name( const char *fname );
+ void init_directive_state();
+ void add_directive();
+ void end_function();
+ void add_identifier( const char *s, int array_dim, unsigned array_ident );
+ void add_function_arg();
+ void add_scalar_type_spec( int type_spec );
+ void add_scalar_operand( const char *identifier );
+ void add_neg_pred_operand( const char *identifier );
+ void add_variables();
+ void set_variable_type();
+ void add_opcode( int opcode );
+ void add_pred( const char *identifier, int negate );
+ void add_2vector_operand( const char *d1, const char *d2 );
+ void add_3vector_operand( const char *d1, const char *d2, const char *d3 );
+ void add_4vector_operand( const char *d1, const char *d2, const char *d3, const char *d4 );
+ void add_option(int option );
+ void add_builtin_operand( int builtin, int dim_modifier );
+ void add_memory_operand( );
+ void add_literal_int( int value );
+ void add_literal_float( float value );
+ void add_literal_double( double value );
+ void add_address_operand( const char *identifier, int offset );
+ void add_label( const char *idenfiier );
+ void add_vector_spec(int spec );
+ void add_space_spec(int spec );
+ void add_extern_spec();
+ void add_instruction();
+ void set_return();
+ void add_alignment_spec( int spec );
+ void add_array_initializer();
+ void add_file( unsigned num, const char *filename );
+ void *reset_symtab();
+ void set_symtab(void*);
+
+
+#define NON_ARRAY_IDENTIFIER 1
+#define ARRAY_IDENTIFIER_NO_DIM 2
+#define ARRAY_IDENTIFIER 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/cuda-sim/ptx_sim.cc b/src/cuda-sim/ptx_sim.cc
new file mode 100644
index 0000000..8ec60df
--- /dev/null
+++ b/src/cuda-sim/ptx_sim.cc
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Ali Bakhoda, George L. Yuan,
+ * Dan O'Connor, and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#include "ptx_sim.h"
+#include <string>
+#include "ptx_ir.h"
+
+std::set<unsigned long long> g_ptx_cta_info_sm_idx_used;
+unsigned long long g_ptx_cta_info_uid = 1;
+extern int gpgpu_option_spread_blocks_across_cores;
+
+ptx_cta_info::ptx_cta_info( unsigned sm_idx )
+{
+ assert( g_ptx_cta_info_sm_idx_used.find(sm_idx) == g_ptx_cta_info_sm_idx_used.end() );
+ g_ptx_cta_info_sm_idx_used.insert(sm_idx);
+
+ m_sm_idx = sm_idx;
+ m_uid = g_ptx_cta_info_uid++;
+}
+
+void ptx_cta_info::add_thread( ptx_thread_info *thd )
+{
+ m_threads_in_cta.insert(thd);
+}
+
+void ptx_cta_info::add_to_barrier( ptx_thread_info *thd )
+{
+ m_threads_waiting_at_barrier.insert(thd);
+}
+
+void ptx_cta_info::release_barrier()
+{
+ assert( m_threads_waiting_at_barrier.size() == m_threads_in_cta.size() );
+ m_threads_waiting_at_barrier.clear();
+}
+
+bool ptx_cta_info::all_at_barrier() const
+{
+ return(m_threads_waiting_at_barrier.size() == m_threads_in_cta.size());
+}
+
+unsigned ptx_cta_info::num_threads() const
+{
+ return m_threads_in_cta.size();
+}
+
+void ptx_cta_info::check_cta_thread_status_and_reset()
+{
+ bool fail = false;
+ if ( m_threads_that_have_exited.size() != m_threads_in_cta.size() ) {
+ printf("\n\n");
+ printf("Execution error: Some threads still running in CTA during CTA reallocation! (1)\n");
+ printf(" CTA uid = %Lu (sm_idx = %u) : %lu running out of %zu total\n",
+ m_uid,
+ m_sm_idx,
+ (m_threads_in_cta.size() - m_threads_that_have_exited.size()), m_threads_in_cta.size() );
+ printf(" These are the threads that are still running:\n");
+ std::set<ptx_thread_info*>::iterator t_iter;
+ for ( t_iter=m_threads_in_cta.begin(); t_iter != m_threads_in_cta.end(); ++t_iter ) {
+ ptx_thread_info *t = *t_iter;
+ if ( m_threads_that_have_exited.find(t) == m_threads_that_have_exited.end() ) {
+ if ( m_dangling_pointers.find(t) != m_dangling_pointers.end() ) {
+ printf(" <thread deleted>\n");
+ } else {
+ printf(" [done=%c] : ", (t->is_done()?'Y':'N') );
+ t->print_insn( t->get_pc(), stdout );
+ printf("\n");
+ }
+ }
+ }
+ printf("\n\n");
+ fail = true;
+ }
+ assert_barrier_empty(true);
+ if ( fail ) {
+ abort();
+ }
+
+ bool fail2 = false;
+ std::set<ptx_thread_info*>::iterator t_iter;
+ for ( t_iter=m_threads_in_cta.begin(); t_iter != m_threads_in_cta.end(); ++t_iter ) {
+ ptx_thread_info *t = *t_iter;
+ if ( m_dangling_pointers.find(t) == m_dangling_pointers.end() ) {
+ if ( !t->is_done() ) {
+ if ( !fail2 ) {
+ printf("Execution error: Some threads still running in CTA during CTA reallocation! (2)\n");
+ printf(" CTA uid = %Lu (sm_idx = %u) :\n", m_uid, m_sm_idx );
+ fail2 = true;
+ }
+ printf(" ");
+ t->print_insn( t->get_pc(), stdout );
+ printf("\n");
+ }
+ }
+ }
+ if ( fail2 ) {
+ abort();
+ }
+ m_threads_in_cta.clear();
+ m_threads_that_have_exited.clear();
+ m_dangling_pointers.clear();
+}
+
+void ptx_cta_info::assert_barrier_empty( bool called_from_delete_threads ) const
+{
+ if ( !m_threads_waiting_at_barrier.empty() ) {
+ printf( "\n\n" );
+ printf( "Execution error: Some threads at barrier at %s:\n",
+ (called_from_delete_threads?"CTA re-init":"thread exit") );
+ printf( " CTA uid = %Lu (sm_idx = %u)\n", m_uid, m_sm_idx );
+ std::set<ptx_thread_info*>::iterator b;
+ for ( b=m_threads_waiting_at_barrier.begin(); b != m_threads_waiting_at_barrier.end(); ++b ) {
+ ptx_thread_info *t = *b;
+ if ( m_dangling_pointers.find(t) != m_dangling_pointers.end() ) {
+ printf(" <thread deleted>\n");
+ } else {
+ printf(" ");
+ t->print_insn( t->get_pc(), stdout );
+ printf("\n");
+ }
+ }
+ printf("\n\n");
+ abort();
+ }
+}
+
+void ptx_cta_info::register_thread_exit( ptx_thread_info *thd )
+{
+ assert( m_threads_that_have_exited.find(thd) == m_threads_that_have_exited.end() );
+ m_threads_that_have_exited.insert(thd);
+}
+
+void ptx_cta_info::register_deleted_thread( ptx_thread_info *thd )
+{
+ m_dangling_pointers.insert(thd);
+}
+
+unsigned ptx_cta_info::get_sm_idx() const
+{
+ return m_sm_idx;
+}
+
+unsigned g_ptx_thread_info_uid_next=1;
+unsigned g_ptx_thread_info_delete_count=0;
+
+ptx_thread_info::~ptx_thread_info()
+{
+ g_ptx_thread_info_delete_count++;
+}
+
+ptx_thread_info::ptx_thread_info()
+{
+ m_uid = g_ptx_thread_info_uid_next++;
+ m_core = NULL;
+ m_barrier_num = -1;
+ m_at_barrier = false;
+ m_valid = false;
+ m_gridid = 0;
+ m_thread_done = false;
+ m_cycle_done = 0;
+ m_PC=0;
+ m_icount = 0;
+ m_last_effective_address = 0;
+ m_last_memory_space = 0;
+ m_branch_taken = 0;
+ m_shared_mem = NULL;
+ m_cta_info = NULL;
+ m_local_mem = NULL;
+ m_symbol_table = NULL;
+ m_func_info = NULL;
+ m_hw_tid = -1;
+ m_hw_wid = -1;
+ m_hw_sid = -1;
+ m_last_dram_callback.function = NULL;
+ m_last_dram_callback.instruction = NULL;
+ m_regs.push_back( std::map<std::string,ptx_reg_t>() );
+ m_debug_trace_regs_modified.push_back( std::map<std::string,ptx_reg_t>() );
+ m_callstack.push_back( stack_entry() );
+ m_RPC = -1;
+ m_RPC_updated = false;
+ m_last_was_call = false;
+}
+
+extern unsigned long long gpu_sim_cycle;
+
+void ptx_thread_info::set_done()
+{
+ assert( !m_at_barrier );
+ m_thread_done = true;
+ m_cycle_done = gpu_sim_cycle;
+}
+
+extern unsigned long long gpu_sim_cycle;
+extern signed long long gpu_tot_sim_cycle;
+
+unsigned ptx_thread_info::get_builtin( int builtin_id, unsigned dim_mod )
+{
+ assert( m_valid );
+ switch (builtin_id) {
+ case NTID_ID:
+ assert( dim_mod < 3 );
+ return m_ntid[dim_mod];
+ case CLOCK_ID:
+ return gpu_sim_cycle + gpu_tot_sim_cycle;
+ case CTA_ID:
+ assert( dim_mod < 3 );
+ return m_ctaid[dim_mod];
+ case GRIDID_ID:
+ return m_gridid;
+ case NCTAID_ID:
+ assert( dim_mod < 3 );
+ return m_nctaid[dim_mod];
+ case TID_ID:
+ assert( dim_mod < 3 );
+ return m_tid[dim_mod];
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+void ptx_thread_info::set_info( symbol_table *symtab, function_info *func )
+{
+ m_symbol_table = symtab;
+ m_func_info = func;
+ m_PC = func->get_start_PC();
+}
+
+void ptx_thread_info::print_insn( unsigned pc, FILE * fp ) const
+{
+ m_func_info->print_insn(pc,fp);
+}
+
+static void print_reg( std::string name, ptx_reg_t value )
+{
+ const symbol *sym = g_current_symbol_table->lookup(name.c_str());
+ printf(" %8s ", name.c_str() );
+ if( sym == NULL ) {
+ printf("<unknown type> 0x%llx\n", (unsigned long long ) value.u64 );
+ return;
+ }
+ const type_info *t = sym->type();
+ type_info_key ti = t->get_key();
+
+ switch ( ti.scalar_type() ) {
+ case S8_TYPE: printf(".s8 %d\n", value.s8 ); break;
+ case S16_TYPE: printf(".s16 %d\n", value.s16 ); break;
+ case S32_TYPE: printf(".s32 %d\n", value.s32 ); break;
+ case S64_TYPE: printf(".s64 %Ld\n", value.s64 ); break;
+ case U8_TYPE: printf(".u8 0x%02x\n", (unsigned) value.u8 ); break;
+ case U16_TYPE: printf(".u16 0x%04x\n", (unsigned) value.u16 ); break;
+ case U32_TYPE: printf(".u32 0x%08x\n", (unsigned) value.u32 ); break;
+ case U64_TYPE: printf(".u64 0x%llx\n", value.u64 ); break;
+ case F16_TYPE: printf(".f16 %f [0x%04x]\n", value.f16, (unsigned) value.u16 ); break;
+ case F32_TYPE: printf(".f32 %.15lf [0x%08x]\n", value.f32, value.u32 ); break;
+ case F64_TYPE: printf(".f64 %.15le [0x%016llx]\n", value.f64, value.u64 ); break;
+ case B8_TYPE: printf(".b8 0x%02x\n", (unsigned) value.u8 ); break;
+ case B16_TYPE: printf(".b16 0x%04x\n", (unsigned) value.u16 ); break;
+ case B32_TYPE: printf(".b32 0x%08x\n", (unsigned) value.u32 ); break;
+ case B64_TYPE: printf(".b64 0x%llx\n", (unsigned long long ) value.u64 ); break;
+ case PRED_TYPE: printf(".pred %u\n", (unsigned) value.pred ); break;
+ default:
+ printf( "non-scalar type\n" );
+ break;
+ }
+}
+
+void ptx_thread_info::callstack_push( unsigned pc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid )
+{
+ m_RPC = -1;
+ m_RPC_updated = true;
+ m_last_was_call = true;
+ m_callstack.push_back( stack_entry(m_symbol_table,m_func_info,pc,rpc,return_var_src,return_var_dst,call_uid) );
+ m_regs.push_back( std::map<std::string,ptx_reg_t>() );
+ m_debug_trace_regs_modified.push_back( std::map<std::string,ptx_reg_t>() );
+}
+
+#define POST_DOMINATOR 1 /* must match definition in shader.h */
+extern int gpgpu_simd_model;
+extern ptx_reg_t get_operand_value( const symbol *reg );
+extern void set_operand_value( const symbol *dst, const ptx_reg_t &data );
+
+bool ptx_thread_info::callstack_pop()
+{
+ assert( !m_callstack.empty() );
+ m_func_info = m_callstack.back().m_func_info;
+ m_symbol_table = m_callstack.back().m_symbol_table;
+ m_NPC = m_callstack.back().m_PC;
+ m_RPC_updated = true;
+ m_last_was_call = false;
+ m_RPC = m_callstack.back().m_RPC;
+ const symbol *rv_src = m_callstack.back().m_return_var_src;
+ const symbol *rv_dst = m_callstack.back().m_return_var_dst;
+ assert( !((rv_src != NULL) ^ (rv_dst != NULL)) );
+ ptx_reg_t rval;
+ if( rv_src != NULL )
+ rval = get_operand_value(rv_src);
+ m_callstack.pop_back();
+ m_regs.pop_back();
+ m_debug_trace_regs_modified.pop_back();
+ if( rv_dst != NULL )
+ set_operand_value(rv_dst,rval);
+ return m_callstack.empty();
+}
+
+void ptx_thread_info::dump_callstack() const
+{
+ std::list<stack_entry>::const_iterator c=m_callstack.begin();
+ std::list<std::map<std::string,ptx_reg_t> >::const_iterator r=m_regs.begin();
+
+ printf("\n\n");
+ printf("Call stack for thread uid = %u (sc=%u, hwtid=%u)\n", m_uid, m_hw_sid, m_hw_tid );
+ while( c != m_callstack.end() && r != m_regs.end() ) {
+ const stack_entry &c_e = *c;
+ const std::map<std::string,ptx_reg_t> &regs = *r;
+ if( !c_e.m_valid ) {
+ printf(" <entry> #regs = %zu\n", regs.size() );
+ } else {
+ printf(" %20s PC=%3u RV= (callee=\'%s\',caller=\'%s\') #regs = %zu\n",
+ c_e.m_func_info->get_name().c_str(), c_e.m_PC,
+ c_e.m_return_var_src->name().c_str(),
+ c_e.m_return_var_dst->name().c_str(),
+ regs.size() );
+ }
+ c++;
+ r++;
+ }
+ if( c != m_callstack.end() || r != m_regs.end() ) {
+ printf(" *** mismatch in m_regs and m_callstack sizes ***\n" );
+ }
+ printf("\n\n");
+}
+
+std::string ptx_thread_info::get_location() const
+{
+ const ptx_instruction *pI = m_func_info->get_instruction(m_PC);
+ char buf[1024];
+ snprintf(buf,1024,"%s:%u", pI->source_file(), pI->source_line() );
+ return std::string(buf);
+}
+
+void ptx_thread_info::dump_regs()
+{
+ printf("Register File Contents:\n");
+ std::map<std::string,ptx_reg_t>::const_iterator r;
+ for ( r=m_regs.back().begin(); r != m_regs.back().end(); ++r ) {
+ std::string name = r->first;
+ ptx_reg_t value = r->second;
+ print_reg(name,value);
+
+ }
+}
+
+void ptx_thread_info::dump_modifiedregs()
+{
+ if( m_debug_trace_regs_modified.empty() )
+ return;
+ printf("Modified Registers:\n");
+ std::map<std::string,ptx_reg_t>::const_iterator r;
+ for ( r=m_debug_trace_regs_modified.back().begin(); r != m_debug_trace_regs_modified.back().end(); ++r ) {
+ std::string name = r->first;
+ ptx_reg_t value = r->second;
+ print_reg(name,value);
+ }
+}
+
+void ptx_thread_info::set_npc( const function_info *f )
+{
+ m_NPC = f->get_start_PC();
+ m_func_info = const_cast<function_info*>( f );
+ m_symbol_table = m_func_info->get_symtab();
+}
diff --git a/src/cuda-sim/ptx_sim.h b/src/cuda-sim/ptx_sim.h
new file mode 100644
index 0000000..17eb250
--- /dev/null
+++ b/src/cuda-sim/ptx_sim.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda,
+ * George L. Yuan, Dan O'Connor, Henry Wong and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+#ifndef ptx_sim_h_INCLUDED
+#define ptx_sim_h_INCLUDED
+
+#include <stdlib.h>
+
+#include "dram_callback.h"
+#include "../util.h"
+#include "../abstract_hardware_model.h"
+
+typedef address_type addr_t;
+
+struct dim3 {
+ unsigned int x, y, z;
+};
+
+struct gpgpu_ptx_sim_arg {
+ const void *m_start;
+ size_t m_nbytes;
+ size_t m_offset;
+ struct gpgpu_ptx_sim_arg *m_next;
+};
+
+//Holds properties of the kernel (Kernel's resource use). These will be zero if
+//the ptxinfo file is not present.
+struct gpgpu_ptx_sim_kernel_info {
+ int lmem;
+ int smem;
+ int cmem;
+ int regs;
+};
+
+#include <assert.h>
+#include "opcodes.h"
+
+struct param_t {
+ union {
+ float float_value;
+ int int_value;
+ double double_value;
+ unsigned long long ptr_value;
+ } data;
+ int type;
+};
+
+#ifdef __cplusplus
+
+ #include <string>
+ #include <map>
+ #include <set>
+ #include <list>
+
+#include "memory.h"
+
+union ptx_reg_t {
+ ptx_reg_t() {
+ bits.ms = 0;
+ bits.ls = 0;
+ }
+ ptx_reg_t(unsigned x)
+ {
+ bits.ms = 0;
+ bits.ls = 0;
+ u32 = x;
+ }
+ operator unsigned int() { return u32;}
+ operator unsigned short() { return u16;}
+ operator unsigned char() { return u8;}
+ operator unsigned long long() { return u64;}
+
+ void mask_and( unsigned ms, unsigned ls )
+ {
+ bits.ms &= ms;
+ bits.ls &= ls;
+ }
+
+ void mask_or( unsigned ms, unsigned ls )
+ {
+ bits.ms |= ms;
+ bits.ls |= ls;
+ }
+ int get_bit( unsigned bit )
+ {
+ if ( bit < 32 )
+ return(bits.ls >> bit) & 1;
+ else
+ return(bits.ms >> (bit-32)) & 1;
+ }
+
+ signed char s8;
+ signed short s16;
+ signed int s32;
+ signed long long s64;
+ unsigned char u8;
+ unsigned short u16;
+ unsigned int u32;
+ unsigned long long u64;
+ float f16;
+ float f32;
+ double f64;
+ struct {
+ unsigned ls;
+ unsigned ms;
+ } bits;
+ unsigned pred : 1;
+
+};
+
+class ptx_instruction;
+class operand_info;
+class symbol_table;
+class function_info;
+class ptx_thread_info;
+
+class ptx_cta_info {
+public:
+ ptx_cta_info( unsigned sm_idx );
+ void add_thread( ptx_thread_info *thd );
+ void add_to_barrier( ptx_thread_info *thd );
+ bool all_at_barrier() const;
+ void release_barrier();
+ unsigned num_threads() const;
+ void check_cta_thread_status_and_reset();
+ void assert_barrier_empty( bool called_from_delete_threads = false ) const;
+ void register_thread_exit( ptx_thread_info *thd );
+ void register_deleted_thread( ptx_thread_info *thd );
+ unsigned get_sm_idx() const;
+
+private:
+ unsigned long long m_uid;
+ unsigned m_sm_idx;
+ std::set<ptx_thread_info*> m_threads_in_cta;
+ std::set<ptx_thread_info*> m_threads_waiting_at_barrier;
+ std::set<ptx_thread_info*> m_threads_that_have_exited;
+ std::set<ptx_thread_info*> m_dangling_pointers;
+};
+
+class symbol;
+
+struct stack_entry {
+ stack_entry() {
+ m_symbol_table=NULL;
+ m_func_info=NULL;
+ m_PC=0;
+ m_RPC=-1;
+ m_return_var_src = NULL;
+ m_return_var_dst = NULL;
+ m_call_uid = 0;
+ m_valid = false;
+ }
+ stack_entry( symbol_table *s, function_info *f, unsigned pc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid )
+ {
+ m_symbol_table=s;
+ m_func_info=f;
+ m_PC=pc;
+ m_RPC=rpc;
+ m_return_var_src = return_var_src;
+ m_return_var_dst = return_var_dst;
+ m_call_uid = call_uid;
+ m_valid = true;
+ }
+
+ bool m_valid;
+ symbol_table *m_symbol_table;
+ function_info *m_func_info;
+ unsigned m_PC;
+ unsigned m_RPC;
+ const symbol *m_return_var_src;
+ const symbol *m_return_var_dst;
+ unsigned m_call_uid;
+};
+
+class ptx_thread_info {
+public:
+ ~ptx_thread_info();
+ ptx_thread_info();
+
+ ptx_reg_t get_operand_value( const symbol *reg );
+ ptx_reg_t get_operand_value( const operand_info &op );
+ void set_operand_value( const operand_info &dst, const ptx_reg_t &data );
+ void set_operand_value( const symbol *dst, const ptx_reg_t &data );
+ void get_vector_operand_values( const operand_info &op, ptx_reg_t* ptx_regs, unsigned num_elements );
+ void 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 );
+
+ function_info *func_info()
+ {
+ return m_func_info;
+ }
+ void print_insn( unsigned pc, FILE * fp ) const;
+ void set_info( symbol_table *symtab, function_info *func );
+ unsigned get_uid() const
+ {
+ return m_uid;
+ }
+
+ dim3 get_ctaid() const
+ {
+ dim3 r;
+ r.x = m_ctaid[0];
+ r.y = m_ctaid[1];
+ r.z = m_ctaid[2];
+ return r;
+ }
+ dim3 get_tid() const
+ {
+ dim3 r;
+ r.x = m_tid[0];
+ r.y = m_tid[1];
+ r.z = m_tid[2];
+ return r;
+ }
+ unsigned get_hw_tid() const { return m_hw_tid;}
+ unsigned get_hw_ctaid() const { return m_hw_ctaid;}
+ unsigned get_hw_wid() const { return m_hw_wid;}
+ unsigned get_hw_sid() const { return m_hw_sid;}
+ void set_hw_tid(unsigned tid) { m_hw_tid=tid;}
+ void set_hw_wid(unsigned wid) { m_hw_wid=wid;}
+ void set_hw_sid(unsigned sid) { m_hw_sid=sid;}
+ void set_hw_ctaid(unsigned cta_id) { m_hw_ctaid=cta_id;}
+ void set_core(core_t *core) { m_core = core; }
+ core_t *get_core() { return m_core; }
+
+ unsigned get_icount() const { return m_icount;}
+ void set_valid() { m_valid = true;}
+ addr_t last_eaddr() const { return m_last_effective_address;}
+ unsigned last_space() const { return m_last_memory_space;}
+ dram_callback_t last_callback() const { return m_last_dram_callback;}
+ void set_at_barrier( int barrier_num )
+ {
+ m_barrier_num = barrier_num;
+ m_at_barrier = true;
+ m_cta_info->add_to_barrier(this);
+ }
+ bool is_at_barrier() const { return m_at_barrier;}
+ bool all_at_barrier() const { return m_cta_info->all_at_barrier();}
+ unsigned long long get_cta_uid() { return m_cta_info->get_sm_idx();}
+ void clear_barrier( )
+ {
+ m_barrier_num = -1;
+ m_at_barrier = false;
+ }
+ void release_barrier() { m_cta_info->release_barrier();}
+
+ void set_single_thread_single_block()
+ {
+ m_ntid[0] = 1;
+ m_ntid[1] = 1;
+ m_ntid[2] = 1;
+ m_ctaid[0] = 0;
+ m_ctaid[1] = 0;
+ m_ctaid[2] = 0;
+ m_tid[0] = 0;
+ m_tid[1] = 0;
+ m_tid[2] = 0;
+ m_nctaid[0] = 1;
+ m_nctaid[1] = 1;
+ m_nctaid[2] = 1;
+ m_gridid = 0;
+ m_valid = true;
+ }
+ void set_tid( int x, int y, int z)
+ {
+ m_tid[0] = x;
+ m_tid[1] = y;
+ m_tid[2] = z;
+ }
+ void set_ctaid( int x, int y, int z)
+ {
+ m_ctaid[0] = x;
+ m_ctaid[1] = y;
+ m_ctaid[2] = z;
+ }
+ void set_ntid( int x, int y, int z)
+ {
+ m_ntid[0] = x;
+ m_ntid[1] = y;
+ m_ntid[2] = z;
+ }
+ void set_nctaid( int x, int y, int z)
+ {
+ m_nctaid[0] = x;
+ m_nctaid[1] = y;
+ m_nctaid[2] = z;
+ }
+
+ unsigned get_builtin( int builtin_id, unsigned dim_mod );
+
+ void set_done();
+ bool is_done() { return m_thread_done;}
+ unsigned donecycle() const { return m_cycle_done; }
+
+ unsigned next_instr()
+ {
+ m_NPC = m_PC+1; // increment to next instruction in case of no branch
+ m_icount++;
+ m_branch_taken = false;
+ return m_PC;
+ }
+ bool branch_taken() const
+ {
+ return m_branch_taken;
+ }
+ unsigned get_pc() const
+ {
+ return m_PC;
+ }
+ void set_npc( unsigned npc )
+ {
+ m_NPC = npc;
+ }
+ void set_npc( const function_info *f );
+ void callstack_push( unsigned npc, unsigned rpc, const symbol *return_var_src, const symbol *return_var_dst, unsigned call_uid );
+ bool callstack_pop();
+ void dump_callstack() const;
+ std::string get_location() const;
+ bool rpc_updated() const { return m_RPC_updated; }
+ bool last_was_call() const { return m_last_was_call; }
+ unsigned get_rpc() const { return m_RPC; }
+ void clearRPC()
+ {
+ m_RPC = -1;
+ m_RPC_updated = false;
+ m_last_was_call = false;
+ }
+ unsigned get_return_PC()
+ {
+ return m_callstack.back().m_PC;
+ }
+ void update_pc()
+ {
+ m_PC = m_NPC;
+ }
+ void dump_regs();
+ void dump_modifiedregs();
+ void clear_modifiedregs() { m_debug_trace_regs_modified.back().clear();}
+ function_info *get_finfo() { return m_func_info; }
+
+public:
+ addr_t m_last_effective_address;
+ bool m_branch_taken;
+ unsigned m_last_memory_space;
+ dram_callback_t m_last_dram_callback;
+ memory_space *m_shared_mem;
+ memory_space *m_local_mem;
+ ptx_cta_info *m_cta_info;
+ ptx_reg_t m_last_set_operand_value;
+
+private:
+ unsigned m_uid;
+ core_t *m_core;
+ bool m_valid;
+ unsigned m_ntid[3];
+ unsigned m_tid[3];
+ unsigned m_nctaid[3];
+ unsigned m_ctaid[3];
+ unsigned m_gridid;
+ bool m_thread_done;
+ unsigned m_hw_sid;
+ unsigned m_hw_tid;
+ unsigned m_hw_wid;
+ unsigned m_hw_ctaid;
+
+ unsigned m_icount;
+ unsigned m_PC;
+ unsigned m_NPC;
+ unsigned m_RPC;
+ bool m_RPC_updated;
+ bool m_last_was_call;
+ unsigned m_cycle_done;
+
+ int m_barrier_num;
+ bool m_at_barrier;
+
+ symbol_table *m_symbol_table;
+ function_info *m_func_info;
+
+ std::list<stack_entry> m_callstack;
+
+ std::list<std::map<std::string,ptx_reg_t> > m_regs;
+ std::list<std::map<std::string,ptx_reg_t> > m_debug_trace_regs_modified;
+};
+
+unsigned type_decode( unsigned type, size_t &size, int &t );
+
+#endif
+
+#define MAX_REG_OPERANDS 8
+
+#endif
diff --git a/src/cuda-sim/ptxinfo.l b/src/cuda-sim/ptxinfo.l
new file mode 100644
index 0000000..3a2ab52
--- /dev/null
+++ b/src/cuda-sim/ptxinfo.l
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt and the University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+%option noyywrap
+%option yylineno
+%option prefix="ptxinfo_"
+%{
+#include "ptxinfo.tab.h"
+#include <string.h>
+
+char ptxinfo_linebuf[1024];
+unsigned ptxinfo_col = 0;
+#define TC ptxinfo_col+=strlen(ptxinfo_text);
+%}
+
+%%
+
+"warning"[^\n]* TC; return WARNING;
+"ptxas" TC; return HEADER;
+"info" TC; return INFO;
+"Compiling entry function" TC; return FUNC;
+"Used" TC; return USED;
+"registers" TC; return REGS;
+"bytes" TC; return BYTES;
+"lmem" TC; return LMEM;
+"smem" TC; return SMEM;
+"cmem" TC; return CMEM;
+"line" TC; return LINE;
+
+[_A-Za-z$%][_0-9A-Za-z$]* TC; ptxinfo_lval.string_value = strdup(yytext); return IDENTIFIER;
+[-]{0,1}[0-9]+ TC; ptxinfo_lval.int_value = atoi(yytext); return INT_OPERAND;
+
+"+" TC; return PLUS;
+"," TC; return COMMA;
+"[" TC; return LEFT_SQUARE_BRACKET;
+"]" TC; return RIGHT_SQUARE_BRACKET;
+":" TC; return COLON;
+";" TC; return SEMICOLON;
+"'" TC; return QUOTE;
+" " TC;
+"\t" TC;
+
+\n.* ptxinfo_col=0; strncpy(ptxinfo_linebuf, yytext + 1, 1024); yyless( 1 );
+
+%%
+
+extern int g_ptxinfo_error_detected;
+extern const char *g_filename;
+extern const char *g_ptxinfo_filename;
+
+int ptxinfo_error( const char *s )
+{
+ int i;
+ g_ptxinfo_error_detected = 1;
+ fflush(stdout);
+ if( s != NULL )
+ printf("ptxas -v %s (%s:%u) Syntax error:\n\n", g_filename, g_ptxinfo_filename, ptxinfo_lineno );
+ printf(" %s\n", ptxinfo_linebuf );
+ printf(" ");
+ for( i=0; i < ptxinfo_col-1; i++ ) {
+ if( ptxinfo_linebuf[i] == '\t' ) printf("\t");
+ else printf(" ");
+ }
+
+ printf("^\n\n");
+ fflush(stdout);
+ exit(43);
+ return 0;
+}
diff --git a/src/cuda-sim/ptxinfo.y b/src/cuda-sim/ptxinfo.y
new file mode 100644
index 0000000..c9c84b8
--- /dev/null
+++ b/src/cuda-sim/ptxinfo.y
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2009 by Tor M. Aamodt, George L. Yuan and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * 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 OWNERS 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.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. 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.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+%union {
+ int int_value;
+ char * string_value;
+}
+
+%token <int_value> INT_OPERAND
+%token HEADER
+%token INFO
+%token FUNC
+%token USED
+%token REGS
+%token BYTES
+%token LMEM
+%token SMEM
+%token CMEM
+%token <string_value> IDENTIFIER
+%token PLUS
+%token COMMA
+%token LEFT_SQUARE_BRACKET
+%token RIGHT_SQUARE_BRACKET
+%token COLON
+%token SEMICOLON
+%token QUOTE
+%token LINE
+%token WARNING
+
+%{
+ #include <stdlib.h>
+ #include <string.h>
+
+ static unsigned g_declared;
+ static unsigned g_system;
+ int ptxinfo_lex(void);
+ void ptxinfo_addinfo();
+ void ptxinfo_function(const char *fname );
+ void ptxinfo_regs( unsigned nregs );
+ void ptxinfo_lmem( unsigned declared, unsigned system );
+ void ptxinfo_smem( unsigned declared, unsigned system );
+ void ptxinfo_cmem( unsigned nbytes, unsigned bank );
+ int ptxinfo_error(const char*);
+%}
+
+%%
+
+input: /* empty */
+ | input line
+ ;
+
+line: HEADER INFO COLON line_info
+ | HEADER IDENTIFIER COMMA LINE INT_OPERAND SEMICOLON WARNING
+ ;
+
+line_info: function_name
+ | function_info { ptxinfo_addinfo(); }
+ ;
+
+function_name: FUNC QUOTE IDENTIFIER QUOTE { ptxinfo_function($3); }
+
+function_info: info
+ | function_info COMMA info
+ ;
+
+info: USED INT_OPERAND REGS { ptxinfo_regs($2); }
+ | tuple LMEM { ptxinfo_lmem(g_declared,g_system); }
+ | tuple SMEM { ptxinfo_smem(g_declared,g_system); }
+ | INT_OPERAND BYTES CMEM LEFT_SQUARE_BRACKET INT_OPERAND RIGHT_SQUARE_BRACKET { ptxinfo_cmem($1,$5); }
+ | INT_OPERAND BYTES LMEM { ptxinfo_lmem($1,0); }
+ | INT_OPERAND BYTES SMEM { ptxinfo_smem($1,0); }
+ | INT_OPERAND BYTES CMEM { ptxinfo_cmem($1,0); }
+ | INT_OPERAND REGS { ptxinfo_regs($1); }
+ ;
+
+tuple: INT_OPERAND PLUS INT_OPERAND BYTES { g_declared=$1; g_system=$3; }
+
+%%
+
+