summaryrefslogtreecommitdiff
path: root/src/cuda-sim/instructions.cc
diff options
context:
space:
mode:
authorTim Rogers <[email protected]>2018-11-05 21:50:40 -0500
committerGitHub <[email protected]>2018-11-05 21:50:40 -0500
commit0265d747b06c18d0a1ee00fb1641032201425c97 (patch)
tree9547bddfcc1c124deac5334dfae85a4a051002c4 /src/cuda-sim/instructions.cc
parent42d8d8c9b5b0eb93ff228a877fd6a5bed5cf956d (diff)
parentb150969498792d50583674947d7c240cd6a11a68 (diff)
Merge pull request #80 from AamirRaihan/dev
Merging Tensor Cores code
Diffstat (limited to 'src/cuda-sim/instructions.cc')
-rw-r--r--src/cuda-sim/instructions.cc1112
1 files changed, 1078 insertions, 34 deletions
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
index e3b8970..4109c5f 100644
--- a/src/cuda-sim/instructions.cc
+++ b/src/cuda-sim/instructions.cc
@@ -25,7 +25,7 @@
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+#include "half.h"
#include "instructions.h"
#include "ptx_ir.h"
#include "opcodes.h"
@@ -46,8 +46,11 @@
#include "cuda_device_runtime.h"
#include <stdarg.h>
+using half_float::half;
unsigned ptx_instruction::g_num_ptx_inst_uid=0;
+bool debug_tensorcore = 0;
+
const char *g_opcode_string[NUM_OPCODES] = {
#define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) STR,
@@ -56,6 +59,104 @@ const char *g_opcode_string[NUM_OPCODES] = {
#undef OP_DEF
#undef OP_W_DEF
};
+//Using profiled information::check the TensorCoreMatrixArrangement.xls for details
+unsigned thread_group_offset(int thread,unsigned wmma_type,unsigned wmma_layout,unsigned type,int stride){
+
+ unsigned offset;
+ unsigned load_a_row[8]={0,128,0,128,64,192,64,192};
+ unsigned load_a_col[8]={0,8,0,8,4,12,4,12};
+ unsigned load_b_row[8]={0,8,0,8,4,12,4,12};
+ unsigned load_b_col[8]={0,128,0,128,64,192,64,192};
+ unsigned load_c_float_row[8]={0,128,8,136,64,192,72,200};
+ unsigned load_c_float_col[8]={0,8,128,136,4,12,132,140};
+ unsigned load_c_half_row[8]={0,128,8,136,64,192,72,200};
+ unsigned load_c_half_col[8]={0,8,128,136,4,12,132,140};
+ unsigned thread_group = thread/4;
+ unsigned in_tg_index = thread%4;
+
+ switch(wmma_type){
+ case LOAD_A:
+ if(wmma_layout==ROW)
+ offset=load_a_row[thread_group]+16*in_tg_index;
+ else
+ offset=load_a_col[thread_group]+16*in_tg_index;
+ break;
+
+
+ case LOAD_B:
+ if(wmma_layout==ROW)
+ offset=load_b_row[thread_group]+16*in_tg_index;
+ else
+ offset=load_b_col[thread_group]+16*in_tg_index;
+ break;
+
+ case LOAD_C:
+ case STORE_D:
+ if(type==F16_TYPE){
+ if(wmma_layout==ROW)
+ offset=load_c_half_row[thread_group]+16*in_tg_index;
+ else
+ offset=load_c_half_col[thread_group]+in_tg_index;
+ }
+ else{
+ if(wmma_layout==ROW)
+ offset=load_c_float_row[thread_group];
+ else
+ offset=load_c_float_col[thread_group];
+
+ switch(in_tg_index){
+ case 0:
+ break;
+ case 1:
+ if(wmma_layout==ROW)
+ offset+=16;
+ else
+ offset+=1;
+ break;
+ case 2:
+ if(wmma_layout==ROW)
+ offset+=2;
+ else
+ offset+=32;
+ break;
+ case 3:
+ if(wmma_layout==ROW)
+ offset+=18;
+ else
+ offset+=33;
+ break;
+ default:
+ abort();
+ }
+ }
+ break;
+
+ default:
+ abort();
+
+ }
+ offset = (offset/16)*stride+offset%16;
+ return offset;
+}
+
+int acc_float_offset(int index,int wmma_layout,int stride){
+
+ int c_row_offset[]={0,1,32,33,4,5,36,37};
+ int c_col_offset[]={0,16,2,18,64,80,66,82};
+ int offset;
+
+
+ if(wmma_layout==ROW)
+ offset=c_row_offset[index];
+ else if(wmma_layout==COL)
+ offset=c_col_offset[index];
+ else{
+ printf("wrong layout");
+ abort();
+ }
+ offset = (offset/16)*stride+offset%16;
+ return offset;
+}
void inst_not_implemented( const ptx_instruction * pI ) ;
ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo, operand_info dstInfo, unsigned type, ptx_thread_info *thread);
@@ -136,10 +237,12 @@ ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_in
result.u64 = sym->get_address() + op.get_addr_offset();
} else if ( op.is_shared() ) {
result.u64 = op.get_symbol()->get_address() + op.get_addr_offset();
+ } else if ( op.is_sstarr() ) {
+ result.u64 = op.get_symbol()->get_address() + op.get_addr_offset();
} else {
- const char *name = op.name().c_str();
- printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown memory operand type for %s\n", name );
- abort();
+ const char *name = op.name().c_str();
+ printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown memory operand type for %s\n", name );
+ abort();
}
} else if ( op.is_literal() ) {
@@ -148,6 +251,8 @@ ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_in
result.u64 = op.get_symbol()->get_address();
} else if ( op.is_shared() ) {
result.u64 = op.get_symbol()->get_address();
+ } else if ( op.is_sstarr() ) {
+ result.u64 = op.get_symbol()->get_address();
} else if ( op.is_const() ) {
result.u64 = op.get_symbol()->get_address();
} else if ( op.is_global() ) {
@@ -156,10 +261,18 @@ ptx_reg_t ptx_thread_info::get_operand_value( const operand_info &op, operand_in
result.u64 = op.get_symbol()->get_address();
} else if ( op.is_function_address() ) {
result.u64 = (size_t)op.get_symbol()->get_pc();
- } else {
+ }else {
const char *name = op.name().c_str();
- printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown operand type for %s\n", name );
- assert(0);
+ const symbol *sym2 = op.get_symbol();
+ const type_info *type2 = sym2->type();
+ const type_info_key &info2 = type2->get_key();
+ if ( info2.is_param_kernel() ) {
+ result.u64 = sym2->get_address()+ op.get_addr_offset();
+ }
+ else{
+ printf("GPGPU-Sim PTX: ERROR ** get_operand_value : unknown operand type for %s\n", name );
+ assert(0);
+ }
}
if(op.get_operand_lohi() == 1)
@@ -335,7 +448,7 @@ unsigned get_operand_nbits( const operand_info &op )
void ptx_thread_info::get_vector_operand_values( const operand_info &op, ptx_reg_t* ptx_regs, unsigned num_elements )
{
assert( op.is_vector() );
- assert( num_elements <= 4 ); // max 4 elements in a vector
+ assert( num_elements <= 8 );
for (int idx = num_elements - 1; idx >= 0; --idx) {
const symbol *sym = NULL;
@@ -640,6 +753,33 @@ void ptx_thread_info::set_vector_operand_values( const operand_info &dst,
m_last_set_operand_value = data1;
}
+void ptx_thread_info::set_wmma_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,
+ const ptx_reg_t &data5,
+ const ptx_reg_t &data6,
+ const ptx_reg_t &data7,
+ const ptx_reg_t &data8 )
+{
+ unsigned num_elements = dst.get_vect_nelem();
+ if (num_elements == 8) {
+ set_reg(dst.vec_symbol(0), data1);
+ set_reg(dst.vec_symbol(1), data2);
+ set_reg(dst.vec_symbol(2), data3);
+ set_reg(dst.vec_symbol(3), data4);
+ set_reg(dst.vec_symbol(4), data5);
+ set_reg(dst.vec_symbol(5), data6);
+ set_reg(dst.vec_symbol(6), data7);
+ set_reg(dst.vec_symbol(7), data8);
+ }
+ else{
+ printf("error:set_wmma_vector_operands");
+ }
+
+ m_last_set_operand_value = data8;
+}
#define my_abs(a) (((a)<0)?(-a):(a))
@@ -745,7 +885,7 @@ void addp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
case U64_TYPE:
data.s64 = src1_data.s64 + src2_data.s64 + (src3_data.pred & 0x4);
break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16=src1_data.f16+src2_data.f16; break;//assert(0); break;
case F32_TYPE: data.f32 = src1_data.f32 + src2_data.f32; break;
case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 + src2_data.f64; break;
default: assert(0); break;
@@ -812,7 +952,7 @@ void add_impl( const ptx_instruction *pI, ptx_thread_info *thread )
case U64_TYPE:
data.u64 = src1_data.u64 + src2_data.u64;
break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16=src1_data.f16+src2_data.f16; break;//assert(0); break;
case F32_TYPE: data.f32 = src1_data.f32 + src2_data.f32; break;
case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 + src2_data.f64; break;
default: assert(0); break;
@@ -1420,7 +1560,44 @@ void bfe_impl( const ptx_instruction *pI, ptx_thread_info *thread )
thread->set_operand_value(dst,d, i_type, thread, pI);
}
-void bfi_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+void bfi_impl( const ptx_instruction *pI, ptx_thread_info *thread ) {
+ int i,max;
+ ptx_reg_t src1_data, src2_data;
+ ptx_reg_t src3_data, src4_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();
+ const operand_info &src3 = pI->src3();
+ const operand_info &src4 = pI->src4();
+
+ unsigned i_type = pI->get_type();
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ src3_data = thread->get_operand_value(src3, dst, i_type, thread, 1);
+ src4_data = thread->get_operand_value(src4, dst, i_type, thread, 1);
+
+ switch ( i_type ) {
+ case B32_TYPE:
+ max = 32;
+ break;
+ case B64_TYPE:
+ max = 64;
+ break;
+ default:
+ printf("Execution error: type mismatch with instruction\n");
+ assert(0);
+ break;
+ }
+ data=src2_data;
+ unsigned pos = src3_data.u32 & 0xFF;
+ unsigned len = src4_data.u32 & 0xFF;
+ for(i=0;i<len && pos+i<max;i++){
+ data.u32=(~((0x00000001)<<(pos+i)))&data.u32;
+ data.u32=data.u32|((src1_data.u32&((0x00000001)<<(i)))<<(pos));
+ }
+ thread->set_operand_value(dst, data, i_type, thread, pI);
+}
void bfind_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
void bra_impl( const ptx_instruction *pI, ptx_thread_info *thread )
@@ -1460,6 +1637,319 @@ void breakaddr_impl( const ptx_instruction *pI, ptx_thread_info *thread )
void brev_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
void brkpt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+unsigned trunc(unsigned num, unsigned precision) {
+ int mask = 1, latest_one = -1;
+ unsigned data = num;
+ for (unsigned j = 0; j < sizeof(unsigned)*8; j++) {
+ int bit = data & mask;
+ if (bit == 1) latest_one = j;
+ data >>= 1;
+ }
+ if (latest_one >= precision) {
+ // round_up is 1 if the most significant truncated digit is a 1, otherwise it is 0
+ //int round_up = (num & (1 << (latest_one-precision))) >> (latest_one-precision);
+ //unsigned shifted_output = num >> (latest_one-precision+1);
+ // if shifted_output is a number like 1111, don't round up
+ //if (shifted_output == (pow(2,precision)-1)) round_up = 0;
+ //num = shifted_output + round_up;
+ num >>= (latest_one-precision+1);
+ }
+ return num;
+}
+void mapping(int thread,int wmma_type,int wmma_layout,int type,int index,int stride,int &row,int &col,int &assg_offset){
+ int offset;
+ int c_row_offset[]={0,8,0,8,4,12,4,12};
+ int c_col_offset[]={0,0,8,8,0,0,8,8};
+ int c_tg_inside_row_offset[]={0,1,0,1};
+ int c_tg_inside_col_offset[]={0,0,2,2};
+ int c_inside_row_offset[]={0,0,2,2,0,0,2,2};
+ int c_inside_col_offset[]={0,1,0,1,4,5,4,5};
+
+ offset=thread_group_offset(thread,wmma_type,wmma_layout,type,stride);
+
+ if(wmma_type==LOAD_A){
+ if(wmma_layout==ROW){
+ offset+=index+8*((thread%16)/8);
+ }
+ else{
+ offset+=64*(index/4)+index%4+128*((thread%16)/8);
+ }
+ offset=(offset/16)*stride+offset%16;
+ assg_offset=index+8*((thread%16)/8);
+ }
+ else if(wmma_type==LOAD_B){
+ if(wmma_layout==ROW){
+ offset+=64*(index/4)+index%4+128*((thread%16)/8);
+ }
+ else{
+ offset+=index+8*((thread%16)/8);
+ }
+ offset=(offset/16)*stride+offset%16;
+ assg_offset=index+8*((thread%16)/8);
+ }
+ else if( wmma_type==LOAD_C){
+ if(type==F16_TYPE){
+ row=c_row_offset[thread/4]+thread%4;
+ col=c_col_offset[thread/4]+index;
+ }
+ else{
+ row=c_row_offset[thread/4]+c_tg_inside_row_offset[thread%4]+c_inside_row_offset[index];
+ col=c_col_offset[thread/4]+c_tg_inside_col_offset[thread%4]+c_inside_col_offset[index];
+ }
+ assg_offset=index;
+ }
+
+ if(wmma_type==LOAD_A||wmma_type==LOAD_B){
+ if(wmma_layout==ROW){
+ row=offset/16;
+ col=offset%16;
+ }
+ else{
+ col=offset/16;
+ row=offset%16;
+ }
+ }
+}
+
+void mma_impl( const ptx_instruction *pI, core_t *core, warp_inst_t inst )
+{
+ int i,j,k,thrd;
+ int row,col,offset;
+ ptx_reg_t matrix_a[16][16];
+ ptx_reg_t matrix_b[16][16];
+ ptx_reg_t matrix_c[16][16];
+ ptx_reg_t matrix_d[16][16];
+ ptx_reg_t src_data;
+ ptx_thread_info *thread;
+ int stride;
+
+ unsigned wmma_type = pI->get_wmma_type();
+ unsigned a_layout = pI->get_wmma_layout(0);
+ unsigned b_layout = pI->get_wmma_layout(1);
+ unsigned type = pI->get_type();
+ unsigned type2 = pI->get_type2();
+ int tid ;
+ const operand_info &dst = pI->operand_lookup(0);
+
+ if(core->get_gpu()->is_functional_sim())
+ tid= inst.warp_id_func()*core->get_warp_size();
+ else
+ tid= inst.warp_id()*core->get_warp_size();
+ unsigned thread_group_index;
+ float temp;
+ half temp2;
+
+ for (thrd=0; thrd < core->get_warp_size(); thrd++){
+ thread = core->get_thread_info()[tid+thrd];
+ if(debug_tensorcore)
+ printf("THREAD=%d\n:",thrd);
+ for(int operand_num=1;operand_num<=3;operand_num++){
+ const operand_info &src_a= pI->operand_lookup(operand_num);
+ unsigned nelem = src_a.get_vect_nelem();
+ ptx_reg_t v[8];
+ thread->get_vector_operand_values( src_a, v, nelem );
+ if(debug_tensorcore){
+ printf("Thread%d_Iteration=%d\n:",thrd,operand_num);
+ for(k=0;k<nelem;k++){
+ printf("%x ",v[k].u64);
+ }
+ printf("\n");
+ }
+ ptx_reg_t nw_v[16];
+ int hex_val;
+
+ if(!((operand_num==3)&&(type2==F32_TYPE))){
+ for(k=0;k<2*nelem;k++){
+ if(k%2==1)
+ hex_val=(v[k/2].s64&0xffff);
+ else
+ hex_val=((v[k/2].s64&0xffff0000)>>16);
+ nw_v[k].f16 =*((half *)&hex_val);
+ }
+ }
+ if(!((operand_num==3)&&(type2==F32_TYPE))){
+ for(k=0;k<2*nelem;k++){
+ temp=nw_v[k].f16;
+ if(debug_tensorcore)
+ printf("%.2f ",temp);
+ }
+ if(debug_tensorcore)
+ printf("\n");
+ }
+ else{
+ if(debug_tensorcore){
+ for(k=0;k<8;k++){
+ printf("%.2f ",v[k].f32);
+ }
+ printf("\n");
+ }
+ }
+ switch(operand_num) {
+ case 1 ://operand 1
+ for(k=0;k<8;k++){
+ mapping(thrd,LOAD_A,a_layout,F16_TYPE,k,16,row,col,offset);
+ if(debug_tensorcore)
+ printf("A:thread=%d,row=%d,col=%d,offset=%d\n",thrd,row,col,offset);
+ matrix_a[row][col]=nw_v[offset];
+ }
+ break;
+ case 2 ://operand 2
+ for(k=0;k<8;k++){
+ mapping(thrd,LOAD_B,b_layout,F16_TYPE,k,16,row,col,offset);
+ if(debug_tensorcore)
+ printf("B:thread=%d,row=%d,col=%d,offset=%d\n",thrd,row,col,offset);
+ matrix_b[row][col]=nw_v[offset];
+ }
+ break;
+ case 3 ://operand 3
+ for(k=0;k<8;k++){
+ mapping(thrd,LOAD_C,ROW,type2,k,16,row,col,offset);
+ if(debug_tensorcore)
+ printf("C:thread=%d,row=%d,col=%d,offset=%d\n",thrd,row,col,offset);
+ if(type2!=F16_TYPE){
+ matrix_c[row][col]=v[offset];
+ }
+ else {
+ matrix_c[row][col]=nw_v[offset];
+ }
+ }
+ break;
+ default :
+ printf("Invalid Operand Index\n" );
+ }
+ }
+ if(debug_tensorcore)
+ printf("\n");
+ }
+ if(debug_tensorcore){
+ printf("MATRIX_A\n");
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ temp=matrix_a[i][j].f16;
+ printf("%.2f ",temp);
+ }
+ printf("\n");
+ }
+ printf("MATRIX_B\n");
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ temp=matrix_b[i][j].f16;
+ printf("%.2f ",temp);
+ }
+ printf("\n");
+ }
+ printf("MATRIX_C\n");
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ if(type2==F16_TYPE){
+ temp=matrix_c[i][j].f16;
+ printf("%.2f ",temp);
+ }
+ else
+ printf("%.2f ",matrix_c[i][j].f32);
+ }
+ printf("\n");
+ }
+ }
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ matrix_d[i][j].f16=0;
+ }
+ }
+
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ for(k=0;k<16;k++){
+ matrix_d[i][j].f16=matrix_d[i][j].f16+matrix_a[i][k].f16*matrix_b[k][j].f16;
+ }
+ if((type==F16_TYPE)&&(type2==F16_TYPE))
+ matrix_d[i][j].f16+=matrix_c[i][j].f16;
+ else if((type==F32_TYPE)&&(type2==F16_TYPE)){
+ temp2=matrix_d[i][j].f16+matrix_c[i][j].f16;
+ temp=temp2;
+ matrix_d[i][j].f32=temp;
+ }
+ else if((type==F16_TYPE)&&(type2==F32_TYPE)){
+ temp=matrix_d[i][j].f16;
+ temp+=matrix_c[i][j].f32;
+ matrix_d[i][j].f16=half(temp);
+ }
+ else{
+ temp=matrix_d[i][j].f16;
+ temp+=matrix_c[i][j].f32;
+ matrix_d[i][j].f32=temp;
+ }
+ }
+ }
+ if(debug_tensorcore){
+ printf("MATRIX_D\n");
+ for (i=0;i<16;i++){
+ for(j=0;j<16;j++){
+ if(type==F16_TYPE){
+ temp=matrix_d[i][j].f16;
+ printf("%.2f ",temp);
+ }
+ else
+ printf("%.2f ",matrix_d[i][j].f32);
+ }
+ printf("\n");
+ }
+ }
+ for (thrd=0; thrd < core->get_warp_size(); thrd++){
+ int row_t[8];
+ int col_t[8];
+ for(k=0;k<8;k++){
+ mapping(thrd,LOAD_C,ROW,type,k,16,row_t[k],col_t[k],offset);
+ if(debug_tensorcore)
+ printf("mma:store:row:%d,col%d\n",row_t[k],col_t[k]);
+ }
+ thread = core->get_thread_info()[tid+thrd];
+
+
+ if(type==F32_TYPE){
+ thread->set_wmma_vector_operand_values(dst,matrix_d[row_t[0]][col_t[0]],matrix_d[row_t[1]][col_t[1]],matrix_d[row_t[2]][col_t[2]],matrix_d[row_t[3]][col_t[3]],matrix_d[row_t[4]][col_t[4]],matrix_d[row_t[5]][col_t[5]],matrix_d[row_t[6]][col_t[6]],matrix_d[row_t[7]][col_t[7]]);
+
+ if(debug_tensorcore)
+ {
+ printf("thread%d:",thrd);
+ for(k=0;k<8;k++){
+ printf("%.2f ",matrix_d[row_t[k]][col_t[k]].f32);
+ }
+ printf("\n");
+ }
+ }
+ else if(type==F16_TYPE){
+ if(debug_tensorcore){
+ printf("thread%d:",thrd);
+ for(k=0;k<8;k++){
+ temp=matrix_d[row_t[k]][col_t[k]].f16;
+ printf("%.2f ",temp);
+ }
+ printf("\n");
+
+ printf("thread%d:",thrd);
+ for(k=0;k<8;k++){
+ printf("%x ",matrix_d[row_t[k]][col_t[k]].f16);
+ }
+ printf("\n");
+ }
+ ptx_reg_t nw_data1, nw_data2, nw_data3, nw_data4;
+ nw_data1.s64=((matrix_d[row_t[0]][col_t[0]].s64 & 0xffff))|((matrix_d[row_t[1]][col_t[1]].s64&0xffff)<<16);
+ nw_data2.s64=((matrix_d[row_t[2]][col_t[2]].s64 & 0xffff))|((matrix_d[row_t[3]][col_t[3]].s64&0xffff)<<16);
+ nw_data3.s64=((matrix_d[row_t[4]][col_t[4]].s64 & 0xffff))|((matrix_d[row_t[5]][col_t[5]].s64&0xffff)<<16);
+ nw_data4.s64=((matrix_d[row_t[6]][col_t[6]].s64 & 0xffff))|((matrix_d[row_t[7]][col_t[7]].s64&0xffff)<<16);
+ thread->set_vector_operand_values(dst,nw_data1,nw_data2,nw_data3,nw_data4);
+ if(debug_tensorcore)
+ printf("thread%d=%x,%x,%x,%x",thrd,nw_data1.s64,nw_data2.s64,nw_data3.s64,nw_data4.s64);
+
+ }
+ else{
+ printf("wmma:mma:wrong type\n");
+ abort();
+ }
+ }
+}
+
void call_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
static unsigned call_uid_next = 1;
@@ -1698,7 +2188,9 @@ unsigned int saturatei(unsigned int a, unsigned int max)
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);
+ half mytemp;
+ float myfloat;
+ //assert( from_width == 32);
enum cuda_math::cudaRoundMode mode = cuda_math::cudaRoundZero;
switch (rounding_mode) {
@@ -1740,8 +2232,12 @@ ptx_reg_t f2x( ptx_reg_t x, unsigned from_width, unsigned to_width, int to_sign,
}
} else {
switch ( to_width ) {
- case 16: assert(0); break;
- case 32: assert(0); break; // handled by f2f
+ case 16:
+ y.f16 =half_float::half_cast<half,std::numeric_limits<float>::round_style>(x.f32);//mytemp;
+ break;
+ case 32:
+ y.f32=float(x.f16);
+ break; // handled by f2f
case 64:
y.f64 = x.f32;
break;
@@ -2002,7 +2498,7 @@ void ptx_round(ptx_reg_t& data, int rounding_mode, int type)
case U32_TYPE:
case U64_TYPE:
printf("Trying to round an integer??\n"); assert(0); break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16=truncf(data.f16);break;//assert(0); break;
case F32_TYPE:
data.f32 = truncf(data.f32);
break;
@@ -2025,7 +2521,13 @@ void ptx_round(ptx_reg_t& data, int rounding_mode, int type)
case U32_TYPE:
case U64_TYPE:
printf("Trying to round an integer??\n"); assert(0); break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE:// assert(0); break;
+#if CUDART_VERSION >= 3000
+ data.f16 = nearbyintf(data.f16);
+#else
+ data.f16 = cuda_math::__cuda_nearbyintf(data.f16);
+#endif
+ break;
case F32_TYPE:
#if CUDART_VERSION >= 3000
data.f32 = nearbyintf(data.f32);
@@ -2048,7 +2550,7 @@ void ptx_round(ptx_reg_t& data, int rounding_mode, int type)
case U32_TYPE:
case U64_TYPE:
printf("Trying to round an integer??\n"); assert(0); break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16=floorf(data.f16);break;//assert(0); break;
case F32_TYPE:
data.f32 = floorf(data.f32);
break;
@@ -2067,7 +2569,7 @@ void ptx_round(ptx_reg_t& data, int rounding_mode, int type)
case U32_TYPE:
case U64_TYPE:
printf("Trying to round an integer??\n"); assert(0); break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16 = ceilf(data.f16); break; //assert(0); break;
case F32_TYPE: data.f32 = ceilf(data.f32); break;
case F64_TYPE: case FF64_TYPE: data.f64 = ceil(data.f64); break;
default: assert(0); break;
@@ -2108,7 +2610,10 @@ void ptx_saturate(ptx_reg_t& data, int saturation_mode, int 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 F16_TYPE: //assert(0); break;
+ if (data.f16 > 1.0f) data.f16 = 1.0f; //negative
+ if (data.f16 < 0.0f) data.f16 = 0.0f; //positive
+ break;
case F32_TYPE:
if (data.f32 > 1.0f) data.f32 = 1.0f; //negative
if (data.f32 < 0.0f) data.f32 = 0.0f; //positive
@@ -2132,8 +2637,8 @@ void cvt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
unsigned rounding_mode = pI->rounding_mode();
unsigned saturation_mode = pI->saturation_mode();
- if ( to_type == F16_TYPE || from_type == F16_TYPE )
- abort();
+// if ( to_type == F16_TYPE || from_type == F16_TYPE )
+// abort();
int to_sign, from_sign;
size_t from_width, to_width;
@@ -2268,7 +2773,7 @@ void div_impl( const ptx_instruction *pI, ptx_thread_info *thread )
data.u32 = src1_data.u32 / src2_data.u32; break;
case B64_TYPE:
data.u64 = src1_data.u64 / src2_data.u64; break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16 = src1_data.f16 / src2_data.f16; break;//assert(0); break;
case F32_TYPE: data.f32 = src1_data.f32 / src2_data.f32; break;
case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 / src2_data.f64; break;
default: assert(0); break;
@@ -2355,7 +2860,12 @@ void decode_space( memory_space_t &space, ptx_thread_info *thread, const operand
space = param_space_kernel;
else if( ti.is_param_local() ) {
space = param_space_local;
- } else {
+ }
+ //mov r1, param-label
+ else if (ti.is_reg() ){
+ space = param_space_kernel;
+ }
+ else {
printf("GPGPU-Sim PTX: ERROR ** cannot resolve .param space for '%s'\n", s->name().c_str() );
abort();
}
@@ -2371,6 +2881,7 @@ void decode_space( memory_space_t &space, ptx_thread_info *thread, const operand
case surf_space: mem = thread->get_surf_memory(); break;
case param_space_kernel: mem = thread->get_param_memory(); break;
case shared_space: mem = thread->m_shared_mem; break;
+ case sstarr_space: mem = thread->m_sstarr_mem; break;
case const_space: mem = thread->get_global_memory(); break;
case generic_space:
if( thread->get_ptx_version().ver() >= 2.0 ) {
@@ -2446,6 +2957,333 @@ void ldu_impl( const ptx_instruction *pI, ptx_thread_info *thread )
ld_exec(pI,thread);
}
+void mma_st_impl( const ptx_instruction *pI, core_t *core, warp_inst_t &inst )
+{
+ size_t size;
+ unsigned smid;
+ int t;
+ int thrd,odd,inx,k;
+ ptx_thread_info *thread;
+
+ const operand_info &src = pI->operand_lookup(1);
+ const operand_info &src1 = pI->operand_lookup(0);
+ const operand_info &src2 = pI->operand_lookup(2);
+ int tid ;
+ unsigned type = pI->get_type();
+ unsigned wmma_type = pI->get_wmma_type();
+ unsigned wmma_layout = pI->get_wmma_layout(0);
+ int stride;
+
+ if(core->get_gpu()->is_functional_sim())
+ tid= inst.warp_id_func()*core->get_warp_size();
+ else
+ tid= inst.warp_id()*core->get_warp_size();
+
+ _memory_op_t insn_memory_op = pI->has_memory_read() ? memory_load : memory_store;
+ for (thrd=0; thrd < core->get_warp_size(); thrd++) {
+ thread = core->get_thread_info()[tid+thrd];
+ odd=thrd%2;
+ inx=thrd/2;
+ ptx_reg_t addr_reg = thread->get_operand_value(src1, src, type, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, src, type, thread, 1);
+ const operand_info &src_a= pI->operand_lookup(1);
+ unsigned nelem = src_a.get_vect_nelem();
+ ptx_reg_t* v= new ptx_reg_t[8];
+ thread->get_vector_operand_values( src_a, v, nelem );
+ stride=src2_data.u32;
+
+ memory_space_t space = pI->get_space();
+
+ memory_space *mem = NULL;
+ addr_t addr = addr_reg.u32;
+
+ new_addr_type mem_txn_addr[MAX_ACCESSES_PER_INSN_PER_THREAD];
+ int num_mem_txn=0;
+
+ smid = thread->get_hw_sid();
+ if( whichspace(addr) == shared_space ) {
+ addr= generic_to_shared(smid,addr);
+ space = shared_space;
+ }
+ decode_space(space,thread,src1,mem,addr);
+
+ type_info_key::type_decode(type,size,t);
+ if(debug_tensorcore)
+ printf("mma_st: thrd=%d,addr=%x, fp(size=%d), stride=%d\n",thrd,addr_reg.u32,size,src2_data.u32);
+ addr_t new_addr = addr+thread_group_offset(thrd,wmma_type,wmma_layout,type,stride)*size/8;
+ addr_t push_addr;
+
+ ptx_reg_t nw_v[8];
+ for(k=0;k<8;k++){
+ if(k%2==0)
+ nw_v[k].s64=(v[k/2].s64&0xffff);
+ else
+ nw_v[k].s64=((v[k/2].s64&0xffff0000)>>16);
+ }
+
+ for(k=0;k<8;k++){
+ if(type==F32_TYPE){
+ //mem->write(new_addr+4*acc_float_offset(k,wmma_layout,stride),size/8,&v[k].s64,thread,pI);
+ push_addr=new_addr+4*acc_float_offset(k,wmma_layout,stride);
+ mem->write(push_addr,size/8,&v[k].s64,thread,pI);
+ mem_txn_addr[num_mem_txn++]=push_addr;
+
+ if(debug_tensorcore){
+ printf("wmma:store:thread%d=%x,%x,%x,%x,%x,%x,%x,%x\n",thrd,v[0].s64,v[1].s64,v[2].s64,v[3].s64,v[4].s64,v[5].s64,v[6].s64,v[7].s64);
+ float temp;
+ int l;
+ printf("thread=%d:",thrd);
+ for(l=0;l<8;l++){
+ temp=v[l].f32;
+ printf("%.2f",temp);
+ }
+ printf("\n");
+ }
+ }
+ else if(type==F16_TYPE){
+ if(wmma_layout==ROW){
+ //mem->write(new_addr+k*2,size/8,&nw_v[k].s64,thread,pI);
+ push_addr=new_addr+k*2;
+ mem->write(push_addr,size/8,&nw_v[k].s64,thread,pI);
+ if(k%2==0)
+ mem_txn_addr[num_mem_txn++]=push_addr;
+ }
+ else if(wmma_layout==COL){
+ //mem->write(new_addr+k*2*stride,size/8,&nw_v[k].s64,thread,pI);
+ push_addr=new_addr+k*2*stride;
+ mem->write(push_addr,size/8,&nw_v[k].s64,thread,pI);
+ mem_txn_addr[num_mem_txn++]=push_addr;
+ }
+
+ if(debug_tensorcore)
+ printf("wmma:store:thread%d=%x,%x,%x,%x,%x,%x,%x,%x\n",thrd,nw_v[0].s64,nw_v[1].s64,nw_v[2].s64,nw_v[3].s64,nw_v[4].s64,nw_v[5].s64,nw_v[6].s64,nw_v[7].s64);
+ }
+ }
+
+ delete [] v;
+ inst.space = space;
+ inst.set_addr(thrd, (new_addr_type *)mem_txn_addr , num_mem_txn);
+
+ if((type==F16_TYPE)&&(wmma_layout==COL))//check the profiling xls for details
+ inst.data_size = 2; // 2 byte transaction
+ else
+ inst.data_size = 4; // 4 byte transaction
+
+ assert( inst.memory_op == insn_memory_op );
+ //thread->m_last_effective_address = addr;
+ //thread->m_last_memory_space = space;
+ }
+}
+
+void mma_ld_impl( const ptx_instruction *pI, core_t *core, warp_inst_t &inst )
+{
+ size_t size;
+ int t,i;
+ unsigned smid;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+
+ unsigned type = pI->get_type();
+ unsigned wmma_type = pI->get_wmma_type();
+ unsigned wmma_layout = pI->get_wmma_layout(0);
+ int tid;
+ int thrd,stride;
+ ptx_thread_info *thread;
+
+
+ if(core->get_gpu()->is_functional_sim())
+ tid= inst.warp_id_func()*core->get_warp_size();
+ else
+ tid= inst.warp_id()*core->get_warp_size();
+
+ _memory_op_t insn_memory_op = pI->has_memory_read() ? memory_load : memory_store;
+
+ for (thrd=0; thrd < core->get_warp_size(); thrd++){
+ thread = core->get_thread_info()[tid+thrd];
+ ptx_reg_t src1_data = thread->get_operand_value(src1, dst, U32_TYPE, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, dst, U32_TYPE, thread, 1);
+ stride=src2_data.u32;
+ memory_space_t space = pI->get_space();
+
+ memory_space *mem = NULL;
+ addr_t addr = src1_data.u32;
+
+ smid = thread->get_hw_sid();
+ if( whichspace(addr) == shared_space ) {
+ addr= generic_to_shared(smid,addr);
+ space = shared_space;
+ }
+
+ decode_space(space,thread,src1,mem,addr);
+ type_info_key::type_decode(type,size,t);
+
+ ptx_reg_t data[16];
+ if(debug_tensorcore)
+ printf("mma_ld: thrd=%d,addr=%x, fpsize=%d, stride=%d\n",thrd,src1_data.u32,size,src2_data.u32);
+
+ addr_t new_addr = addr+thread_group_offset(thrd,wmma_type,wmma_layout,type,stride)*size/8;
+ addr_t fetch_addr;
+ new_addr_type mem_txn_addr[MAX_ACCESSES_PER_INSN_PER_THREAD];
+ int num_mem_txn=0;
+
+ if(wmma_type==LOAD_A){
+ for(i=0;i<16;i++){
+ if(wmma_layout==ROW){
+ //mem->read(new_addr+2*i,size/8,&data[i].s64);
+ fetch_addr=new_addr+2*i;
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ }
+ else if(wmma_layout==COL){
+ //mem->read(new_addr+2*(i%4)+2*stride*4*(i/4),size/8,&data[i].s64);
+ fetch_addr=new_addr+2*(i%4)+2*stride*4*(i/4);
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ }
+ else{
+ printf("mma_ld:wrong_layout_type\n");
+ abort();
+
+ }
+ if(i%2==0)
+ mem_txn_addr[num_mem_txn++]=fetch_addr;
+ }
+ }
+ else if(wmma_type==LOAD_B){
+ for(i=0;i<16;i++){
+ if(wmma_layout==COL){
+ //mem->read(new_addr+2*i,size/8,&data[i].s64);
+ fetch_addr=new_addr+2*i;
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ }
+ else if(wmma_layout==ROW){
+ //mem->read(new_addr+2*(i%4)+2*stride*4*(i/4),size/8,&data[i].s64);
+ fetch_addr=new_addr+2*(i%4)+2*stride*4*(i/4);
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ }
+ else{
+ printf("mma_ld:wrong_layout_type\n");
+ abort();
+ }
+ if(i%2==0)
+ mem_txn_addr[num_mem_txn++]=fetch_addr;
+ }
+ }
+ else if(wmma_type==LOAD_C){
+ for(i=0;i<8;i++){
+ if(type==F16_TYPE){
+ if(wmma_layout==ROW){
+ //mem->read(new_addr+2*i,size/8,&data[i].s64);
+ fetch_addr=new_addr+2*i;
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ if(i%2==0)
+ mem_txn_addr[num_mem_txn++]=fetch_addr;
+ }
+ else if(wmma_layout==COL){
+ //mem->read(new_addr+2*stride*i,size/8,&data[i].s64);
+ fetch_addr=new_addr+2*stride*i;
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ mem_txn_addr[num_mem_txn++]=fetch_addr;
+ }
+ else{
+ printf("mma_ld:wrong_type\n");
+ abort();
+ }
+ }
+ else if(type==F32_TYPE){
+ //mem->read(new_addr+4*acc_float_offset(i,wmma_layout,stride),size/8,&data[i].s64);
+ fetch_addr=new_addr+4*acc_float_offset(i,wmma_layout,stride);
+ mem->read(fetch_addr,size/8,&data[i].s64);
+ mem_txn_addr[num_mem_txn++]=fetch_addr;
+ }
+ else{
+ printf("wrong type");
+ abort();
+ }
+ }
+ }
+ else{
+ printf("wrong wmma type\n");;
+ abort();
+ }
+ //generate timing memory request
+ inst.space = space;
+ inst.set_addr(thrd, (new_addr_type *)mem_txn_addr , num_mem_txn);
+
+ if((wmma_type==LOAD_C)&&(type==F16_TYPE)&&(wmma_layout==COL))//memory address is scattered, check the profiling xls for more detail.
+ inst.data_size = 2; // 2 byte transaction
+ else
+ inst.data_size = 4; // 4 byte transaction
+ assert( inst.memory_op == insn_memory_op );
+
+ if(debug_tensorcore){
+ if(type==F16_TYPE){
+ printf("\nmma_ld:thread%d= ",thrd);
+ for(i=0;i<16;i++){
+ printf("%x ",data[i].u64);
+ }
+ printf("\n");
+
+ printf("\nmma_ld:thread%d= ",thrd);
+ float temp;
+ for(i=0;i<16;i++){
+ temp=data[i].f16;
+ printf("%.2f ",temp);
+ }
+ printf("\n");
+ }
+ else{
+ printf("\nmma_ld:thread%d= ",thrd);
+ for(i=0;i<8;i++){
+ printf("%.2f ",data[i].f32);
+ }
+ printf("\n");
+ printf("\nmma_ld:thread%d= ",thrd);
+ for(i=0;i<8;i++){
+ printf("%x ",data[i].u64);
+ }
+ printf("\n");
+ }
+ }
+
+ if((wmma_type==LOAD_C)&&(type==F32_TYPE)){
+ thread->set_wmma_vector_operand_values(dst,data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
+ }
+ else{
+ ptx_reg_t nw_data[8];
+ int num_reg;
+
+ if(wmma_type==LOAD_C)
+ num_reg=4;
+ else
+ num_reg=8;
+
+ for(i=0;i<num_reg;i++){
+ nw_data[i].s64= ((data[2*i].s64 & 0xffff)<<16)| ((data[2*i+1].s64 & 0xffff));
+ }
+
+ if(wmma_type==LOAD_C)
+ thread->set_vector_operand_values(dst,nw_data[0],nw_data[1],nw_data[2],nw_data[3]);
+ else
+ thread->set_wmma_vector_operand_values(dst,nw_data[0],nw_data[1],nw_data[2],nw_data[3],nw_data[4],nw_data[5],nw_data[6],nw_data[7]);
+ if(debug_tensorcore){
+ printf("mma_ld:data[0].s64=%x,data[1].s64=%x,new_data[0].s64=%x\n",data[0].u64,data[1].u64,nw_data[0].u64);
+ printf("mma_ld:data[2].s64=%x,data[3].s64=%x,new_data[1].s64=%x\n",data[2].u64,data[3].u64,nw_data[1].u64);
+ printf("mma_ld:data[4].s64=%x,data[5].s64=%x,new_data[2].s64=%x\n",data[4].u64,data[5].u64,nw_data[2].u64);
+ printf("mma_ld:data[6].s64=%x,data[7].s64=%x,new_data[3].s64=%x\n",data[6].u64,data[7].u64,nw_data[3].u64);
+ if(wmma_type!=LOAD_C){
+ printf("mma_ld:data[8].s64=%x,data[9].s64=%x,new_data[4].s64=%x\n",data[8].u64,data[9].u64,nw_data[4].s64);
+ printf("mma_ld:data[10].s64=%x,data[11].s64=%x,new_data[5].s64=%x\n",data[10].u64,data[11].u64,nw_data[5].u64);
+ printf("mma_ld:data[12].s64=%x,data[13].s64=%x,new_data[6].s64=%x\n",data[12].u64,data[13].u64,nw_data[6].u64);
+ printf("mma_ld:data[14].s64=%x,data[15].s64=%x,new_data[7].s64=%x\n",data[14].u64,data[15].u64,nw_data[3].u64);
+ }
+ }
+ }
+
+ //thread->m_last_effective_address = addr;
+ //thread->m_last_memory_space = space;
+ }
+}
+
void lg2_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
ptx_reg_t a, d;
@@ -2605,9 +3443,24 @@ void mad_def( const ptx_instruction *pI, ptx_thread_info *thread, bool use_carry
if ( pI->is_lo() ) d.u64 = t.u64 + c.u64 + carry_bit.pred;
else assert(0);
break;
- case F16_TYPE:
- assert(0);
- break;
+ case F16_TYPE:{
+ // assert(0);
+ // break;
+ assert( use_carry == false);
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+ d.f16 = a.f16 * b.f16 + c.f16;
+ if ( pI->saturation_mode() ) {
+ if ( d.f16 < 0 ) d.f16 = 0;
+ else if ( d.f16 > 1.0f ) d.f16 = 1.0f;
+ }
+ fesetround( orig_rm );
+ break;
+ }
case F32_TYPE: {
assert( use_carry == false);
int orig_rm = fegetround();
@@ -2907,9 +3760,25 @@ void mul_impl( const ptx_instruction *pI, ptx_thread_info *thread )
if ( pI->is_lo() ) d.u64 = t.u64;
else assert(0);
break;
- case F16_TYPE:
- assert(0);
- break;
+ case F16_TYPE:{
+ //assert(0);
+ //break;
+ int orig_rm = fegetround();
+ switch ( rounding_mode ) {
+ case RN_OPTION: break;
+ case RZ_OPTION: fesetround( FE_TOWARDZERO ); break;
+ default: assert(0); break;
+ }
+
+ d.f16 = a.f16 * b.f16;
+
+ if ( pI->saturation_mode() ) {
+ if ( d.f16 < 0 ) d.f16 = 0;
+ else if ( d.f16 > 1.0f ) d.f16 = 1.0f;
+ }
+ fesetround( orig_rm );
+ break;
+ }
case F32_TYPE: {
int orig_rm = fegetround();
switch ( rounding_mode ) {
@@ -2972,7 +3841,7 @@ void neg_impl( const ptx_instruction *pI, ptx_thread_info *thread )
case U32_TYPE:
case U64_TYPE:
assert(0); break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16 =0.0f - src1_data.f16; break;//assert(0); break;
case F32_TYPE: data.f32 = 0.0f - src1_data.f32; break;
case F64_TYPE: case FF64_TYPE: data.f64 = 0.0f - src1_data.f64; break;
default: assert(0); break;
@@ -3122,7 +3991,94 @@ void popc_impl( const ptx_instruction *pI, ptx_thread_info *thread )
}
void prefetch_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
void prefetchu_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
-void prmt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); }
+
+int prmt_mode_present(int mode)
+{
+ int returnval=0;
+ switch(mode){
+ case PRMT_F4E_MODE:
+ case PRMT_B4E_MODE:
+ case PRMT_RC8_MODE:
+ case PRMT_RC16_MODE:
+ case PRMT_ECL_MODE:
+ case PRMT_ECR_MODE:
+ returnval=1;
+ break;
+ default:
+ break;
+ }
+ return returnval;
+}
+int read_byte(int mode,int control,int d_sel_index,signed long long value){
+
+ int returnval;
+ int prmt_f4e_mode[4][4]={{0,1,2,3},{1,2,3,4},{2,3,4,5},{3,4,5,6}};
+ int prmt_b4e_mode[4][4]={{0,7,6,5},{1,0,7,6},{2,1,0,7},{3,2,1,0}};
+ int prmt_rc8_mode[4][4]={{0,0,0,0},{1,1,1,1},{2,2,2,2},{3,3,3,3}};
+ int prmt_ecl_mode[4][4]={{0,1,2,3},{1,1,2,3},{2,2,2,3},{3,3,3,3}};
+ int prmt_ecr_mode[4][4]={{0,0,0,0},{0,1,1,1},{0,1,2,2},{0,1,2,3}};
+ int prmt_rc16_mode[4][4]={{0,1,0,1},{2,3,2,3},{0,1,0,1},{2,3,2,3}};
+
+ if(!prmt_mode_present(mode)){
+ if(control&0x8){
+ returnval=0xff;
+ }
+ else{
+ returnval= (value>>(8*control)) & 0xff;
+ }
+ }
+ else{
+ switch(mode){
+ case PRMT_F4E_MODE: returnval=prmt_f4e_mode[control][d_sel_index];break;
+ case PRMT_B4E_MODE: returnval=prmt_b4e_mode[control][d_sel_index];break;
+ case PRMT_RC8_MODE: returnval=prmt_rc8_mode[control][d_sel_index];break;
+ case PRMT_ECL_MODE: returnval=prmt_ecl_mode[control][d_sel_index];break;
+ case PRMT_ECR_MODE: returnval=prmt_ecr_mode[control][d_sel_index];break;
+ case PRMT_RC16_MODE: returnval=prmt_rc16_mode[control][d_sel_index];break;
+ default: printf("ERROR\n");break;
+ }
+ }
+ return (returnval<<8*d_sel_index);
+}
+
+void prmt_impl( const ptx_instruction *pI, ptx_thread_info *thread ) {
+
+ ptx_reg_t src1_data, src2_data, src3_data,tmpdata,data;
+ const operand_info &dst = pI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+
+ unsigned mode = pI->prmt_op();
+ unsigned i_type = pI->get_type();
+
+ src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
+ src2_data = thread->get_operand_value(src2, dst, i_type, thread, 1);
+ src3_data = thread->get_operand_value(src3, dst, i_type, thread, 1);
+
+ tmpdata.s64=src1_data.s32|(src2_data.s64<<32);
+ int ctl[4];
+
+ if(!prmt_mode_present(mode)){
+ ctl[0]=(src3_data.s32>>0)&0xf;
+ ctl[1]=(src3_data.s32>>4)&0xf;
+ ctl[2]=(src3_data.s32>>8)&0xf;
+ ctl[3]=(src3_data.s32>>12)&0xf;
+ }
+ else{
+ ctl[0]=ctl[1]=ctl[2]=ctl[3]=(src3_data.s32>>0)&0x3;
+ }
+
+ data.s32=0;
+ data.s32=data.s32|read_byte(mode,ctl[0],0,tmpdata.s64); //First byte-0
+ data.s32=data.s32|read_byte(mode,ctl[1],1,tmpdata.s64); //Second byte-1
+ data.s32=data.s32|read_byte(mode,ctl[2],2,tmpdata.s64); //Third byte-2
+ data.s32=data.s32|read_byte(mode,ctl[3],3,tmpdata.s64); //Fourth byte-3
+
+ thread->set_operand_value(dst,data, i_type, thread, pI);
+
+
+}
void rcp_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
@@ -3543,7 +4499,13 @@ void set_impl( const ptx_instruction *pI, ptx_thread_info *thread )
void shfl_impl( const ptx_instruction *pI, core_t *core, warp_inst_t inst )
{
unsigned i_type = pI->get_type();
- int tid = inst.warp_id() * core->get_warp_size();
+ int tid;
+
+ if(core->get_gpu()->is_functional_sim())
+ tid = inst.warp_id_func() * core->get_warp_size();
+ else
+ tid = inst.warp_id() * core->get_warp_size();
+
ptx_thread_info *thread = core->get_thread_info()[tid];
ptx_warp_info *warp_info = thread->m_warp_info;
int lane = warp_info->get_done_threads();
@@ -3833,6 +4795,88 @@ void sqrt_impl( const ptx_instruction *pI, ptx_thread_info *thread )
thread->set_operand_value(dst,d, i_type, thread, pI);
}
+void sst_impl( const ptx_instruction *pI, ptx_thread_info *thread )
+{
+ ptx_instruction * cpI = const_cast<ptx_instruction *>(pI); // constant
+ const operand_info &dst = cpI->dst();
+ const operand_info &src1 = pI->src1();
+ const operand_info &src2 = pI->src2();
+ const operand_info &src3 = pI->src3();
+ unsigned type = pI->get_type();
+ ptx_reg_t dst_data = thread->get_operand_value(dst, dst, type, thread, 1);
+ ptx_reg_t src1_data = thread->get_operand_value(src1, src1, type, thread, 1);
+ ptx_reg_t src2_data = thread->get_operand_value(src2, src1, type, thread, 1);
+ ptx_reg_t src3_data = thread->get_operand_value(src3, src1, type, thread, 1);
+ memory_space_t space = pI->get_space();
+ memory_space *mem = NULL;
+ addr_t addr = src2_data.u32 * 4; // this assumes sstarr memory starts at address 0
+ ptx_cta_info *cta_info = thread->m_cta_info;
+
+ decode_space(space,thread,src1,mem,addr);
+
+ size_t size;
+ int t;
+ type_info_key::type_decode(type,size,t);
+
+ // store data in sstarr memory
+ mem->write(addr,size/8,&src3_data.s64,thread,pI);
+
+ // sync threads
+ cpI->set_bar_id(16); // use 16 for sst because bar uses an int from 0-15
+
+ thread->m_last_effective_address = addr;
+ thread->m_last_memory_space = space;
+ thread->m_last_dram_callback.function = bar_callback;
+ thread->m_last_dram_callback.instruction = cpI;
+
+ // the last thread that executes loads all of the data back from sstarr memory
+ int NUM_THREADS = cta_info->num_threads();
+ cta_info->inc_bar_threads();
+ if (NUM_THREADS == cta_info->get_bar_threads()) {
+ unsigned offset = 0;
+ addr = 0;
+ ptx_reg_t data;
+ float sstarr_fdata[NUM_THREADS];
+ signed long long sstarr_ldata[NUM_THREADS];
+ // loop through all of the threads
+ for (int tid = 0; tid < NUM_THREADS; tid++) {
+ data.u64=0;
+ mem->read(addr+(tid*4),size/8,&data.s64);
+ sstarr_fdata[tid] = data.f32;
+ sstarr_ldata[tid] = data.s64;
+ }
+
+ // squeeze the zeros out of the array and store data back into original array
+ mem = NULL;
+ addr = src1_data.u32;
+ space.set_type(global_space);
+ decode_space(space,thread,src1,mem,addr);
+ // store nonzero entries and indices
+ for (int tid = 0; tid < NUM_THREADS; tid++) {
+ if (sstarr_fdata[tid] != 0) {
+ float ftid = (float)tid;
+ mem->write(addr+(offset*4),size/8,&sstarr_ldata[tid],thread,pI);
+ mem->write(addr+((NUM_THREADS+offset)*4),size/8,&ftid,thread,pI);
+ offset++;
+ }
+ }
+ // store the number of nonzero elements in the array
+ data = thread->get_operand_value(src1, dst, type, thread, 1);
+ data.s64 += 4*(offset-1);
+ thread->set_operand_value(dst, data, type, thread, pI);
+
+ // fill the rest of the array with zeros (dst should always have a 0 in it)
+ while (offset < NUM_THREADS) {
+ mem->write(addr+(offset*4),size/8,&dst_data.s64,thread,pI);
+ offset++;
+ }
+
+ cta_info->reset_bar_threads();
+ thread->m_last_effective_address = addr+(NUM_THREADS-1)*4;
+ thread->m_last_memory_space = space;
+ }
+}
+
void ssy_impl( const ptx_instruction *pI, ptx_thread_info *thread )
{
//printf("Execution Warning: unimplemented ssy instruction is treated as a nop\n");
@@ -3861,7 +4905,7 @@ void st_impl( const ptx_instruction *pI, ptx_thread_info *thread )
if (!vector_spec) {
data = thread->get_operand_value(src1, dst, type, thread, 1);
mem->write(addr,size/8,&data.s64,thread,pI);
- } else {
+ } 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);
@@ -3943,7 +4987,7 @@ void sub_impl( const ptx_instruction *pI, ptx_thread_info *thread )
case B64_TYPE:
case U64_TYPE:
data.u64 = src1_data.u64 - src2_data.u64; break;
- case F16_TYPE: assert(0); break;
+ case F16_TYPE: data.f16 = src1_data.f16 - src2_data.f16; break;//assert(0); break;
case F32_TYPE: data.f32 = src1_data.f32 - src2_data.f32; break;
case F64_TYPE: case FF64_TYPE: data.f64 = src1_data.f64 - src2_data.f64; break;
default: assert(0); break;