2015-05-13 12:01:50 -04:00
//
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
//
#include "device/cpu/cpudevice.hpp"
#include "device/cpu/cpukernel.hpp"
#include "platform/program.hpp"
#include "os/os.hpp"
#include "device/cpu/cpumapping.hpp"
#include <algorithm>
#include <functional>
#include <string>
#include <iostream>
2015-08-27 08:40:14 -04:00
#include <algorithm>
2015-05-13 12:01:50 -04:00
#if defined(_WIN32)
#include <windows.h>
#endif
// amdrt.o
#if defined(WITH_ONLINE_COMPILER) && !defined(_LP64) && !defined(ATI_ARCH_ARM)
#include "amdrt.inc"
#endif
#include "acl.h"
using std :: min ;
using std :: max ;
namespace cpu {
HCtoDCmap :: HCtoDCmap ( const clk_parameter_descriptor_t * desc , unsigned int level_alignment , unsigned int index , unsigned int init_offset )
{
2016-04-25 18:43:12 -04:00
level_alignment = std :: max ( level_alignment , 1u ); // Minimal possible alignment is 1 and alignment is used as a divisor below.
2015-05-13 12:01:50 -04:00
//Initialize fields
hc_offset = 0 ;
hc_size = 0 ;
dc_offset = 0 ;
dc_size = 0 ;
2015-06-04 14:14:26 -04:00
hc_alignment = level_alignment ;
dc_alignment = level_alignment ;
2015-05-13 12:01:50 -04:00
internal_field_map = NULL ;
next_field_map = NULL ;
return ;
}
HCtoDCmap ::~ HCtoDCmap ()
{
return ;
}
//Helper to find sizes of each scalar type
size_t HCtoDCmap :: getHostScalarParamSize ( const clk_value_type_t type ) const
{
size_t size = 0 ;
switch ( type ) {
case T_CHAR :
size = 1 ;
break ;
case T_SHORT : case T_CHAR2 :
size = 2 ;
break ;
case T_FLOAT : case T_INT : case T_CHAR4 :
case T_SHORT2 : case T_CHAR3 :
size = 4 ;
break ;
case T_SAMPLER :
size = 4 ;
break ;
case T_LONG : case T_DOUBLE : case T_CHAR8 :
case T_SHORT4 : case T_INT2 : case T_FLOAT2 :
case T_SHORT3 :
size = 8 ;
break ;
case T_INT3 : case T_FLOAT3 :
case T_CHAR16 : case T_SHORT8 : case T_INT4 :
case T_FLOAT4 : case T_LONG2 : case T_DOUBLE2 :
size = 16 ;
break ;
case T_LONG3 : case T_DOUBLE3 :
case T_SHORT16 : case T_INT8 : case T_FLOAT8 :
case T_LONG4 : case T_DOUBLE4 :
size = 32 ;
break ;
case T_INT16 : case T_FLOAT16 : case T_LONG8 :
case T_DOUBLE8 :
size = 64 ;
break ;
case T_LONG16 : case T_DOUBLE16 :
size = 128 ;
break ;
case T_POINTER : case T_VOID :
size = sizeof ( void * );
break ;
default :
assert ( 0 && "unknown scalar parameter size" );
break ;
}
return size ;
}
2015-06-04 14:14:26 -04:00
size_t HCtoDCmap :: getScalarAlignment ( const clk_value_type_t type , bool isHost ) const
2015-05-13 12:01:50 -04:00
{
size_t align = 0 ;
switch ( type ) {
case T_CHAR :
align = 1 ;
break ;
case T_SHORT : case T_CHAR2 :
align = 2 ;
break ;
case T_FLOAT : case T_INT : case T_CHAR4 :
case T_SHORT2 : case T_CHAR3 :
align = 4 ;
break ;
case T_SAMPLER :
align = sizeof ( uint32_t );
break ;
case T_LONG :
2015-06-04 14:14:26 -04:00
#if defined(_WIN32)
align = 8 ;
#else
align = isHost ? 8 : LP64_SWITCH ( 4 , 8 );
#endif
2015-05-13 12:01:50 -04:00
break ;
case T_DOUBLE :
2015-06-04 14:14:26 -04:00
#if defined(_WIN32)
align = 8 ;
#else
2015-05-13 12:01:50 -04:00
align = LP64_SWITCH ( 4 , 8 );
2015-06-04 14:14:26 -04:00
#endif
2015-05-13 12:01:50 -04:00
break ;
case T_CHAR8 :
case T_SHORT4 : case T_INT2 : case T_FLOAT2 :
case T_SHORT3 :
align = 4 ;
break ;
case T_INT3 : case T_FLOAT3 :
case T_CHAR16 : case T_SHORT8 : case T_INT4 :
case T_FLOAT4 : case T_LONG2 : case T_DOUBLE2 :
case T_LONG3 : case T_DOUBLE3 :
case T_SHORT16 : case T_INT8 : case T_FLOAT8 :
case T_LONG4 : case T_DOUBLE4 :
case T_INT16 : case T_FLOAT16 : case T_LONG8 :
case T_DOUBLE8 :
case T_LONG16 : case T_DOUBLE16 :
align = LP64_SWITCH ( 4 , 8 );
break ;
case T_POINTER : case T_VOID :
align = sizeof ( void * );
break ;
default :
assert ( 0 && "unknown scalar parameter alignment" );
break ;
}
return align ;
}
// Align up arguments within each map, return the size of current map parameter
// Input current alignment of the parameter, size of outer struct if it exists
2015-06-04 14:14:26 -04:00
void HCtoDCmap :: align_map ( unsigned outer_hc_alignment , unsigned outer_dc_alignment , unsigned & outer_hc_size , unsigned & outer_dc_size , int & inStruct )
2015-05-13 12:01:50 -04:00
{
unsigned map_param_size = 0 ;
if ( internal_field_map != NULL ) {
hc_size = 0 ; //Recalculate size to account for internal offsets
inStruct ++ ;
2015-06-04 14:14:26 -04:00
internal_field_map -> align_map ( hc_alignment , dc_alignment , hc_size , dc_size , inStruct ); // align internal struct, might alter size of this struct
if ( hc_alignment != 1 && hc_size % hc_alignment )
hc_size = max ( hc_size , hc_size - ( hc_size % hc_alignment ) + hc_alignment );
if ( dc_alignment != 1 && dc_size % dc_alignment )
dc_size = max ( dc_size , dc_size - ( dc_size % dc_alignment ) + dc_alignment );
2015-05-13 12:01:50 -04:00
}
// Use map_param_size to store current parameter size after adjusting alignment
2015-06-04 14:14:26 -04:00
if ( hc_alignment != 1 && hc_size % hc_alignment != 0 ) {
map_param_size = max ( hc_alignment , hc_size - ( hc_size % hc_alignment ) + hc_alignment );
2015-05-13 12:01:50 -04:00
}
else {
2015-06-04 14:14:26 -04:00
map_param_size = max ( hc_alignment , hc_size );
2015-05-13 12:01:50 -04:00
}
if ( next_field_map != NULL ) {
next_field_map -> hc_offset = this -> next_offset ( hc_offset , map_param_size , inStruct );
2015-06-04 14:14:26 -04:00
next_field_map -> align_map ( outer_hc_alignment , outer_dc_alignment , outer_hc_size , outer_dc_size , inStruct );
2015-05-13 12:01:50 -04:00
// Reset parameter size for char padding
if ( next_field_map -> type == T_CHAR )
map_param_size = 1 ;
}
else
{
// Moving out of struct
if ( inStruct > 0 )
inStruct -- ;
if ( type == T_CHAR )
map_param_size = 1 ;
}
outer_hc_size = max ( outer_hc_size , hc_offset + map_param_size );
outer_dc_size = max ( outer_dc_size , dc_offset + dc_size );
return ;
}
// Return current size of map, calculate internal maps and process next args if in struct.
// Alignment: alignment flag for members in case of structs, alignment of scalar otherwise.
2015-06-04 14:14:26 -04:00
int HCtoDCmap :: compute_map ( const clk_parameter_descriptor_t * desc , unsigned int & outer_hc_alignment , unsigned int & outer_dc_alignment , unsigned int init_offset , int & inStruct , int & index_out )
2015-05-13 12:01:50 -04:00
{
unsigned internal_index ;
internal_index = index_out ;
unsigned int next_offset = init_offset ;
unsigned struct_size = 0 ;
type = desc [ internal_index ]. type ;
if ( desc [ internal_index ]. type == T_STRUCT ) {
//Moving into struct, go to next index
inStruct ++ ;
hc_offset = init_offset ;
if ( desc [ index_out + 1 ]. type != T_VOID ) {
index_out ++ ;
internal_index = index_out ;
internal_field_map = new HCtoDCmap ( desc , 0 , internal_index , init_offset );
2015-06-04 14:14:26 -04:00
hc_size = internal_field_map -> compute_map ( desc , hc_alignment , dc_alignment , next_offset , inStruct , index_out );
hc_alignment = max ( hc_alignment , internal_field_map -> hc_alignment ); // Adjust alignment to biggest member alignment
2015-05-13 12:01:50 -04:00
struct_size = hc_size ;
internal_index = index_out ;
2015-06-04 14:14:26 -04:00
outer_hc_alignment = max ( outer_hc_alignment , hc_alignment );
2015-05-13 12:01:50 -04:00
if ( inStruct > 0 ) {
if ( desc [ index_out + 1 ]. type != T_VOID ) {
//Still inside struct and not done
index_out ++ ;
internal_index = index_out ;
next_field_map = new HCtoDCmap ( desc , 0 , internal_index , next_offset );
struct_size = hc_size ;
2015-06-04 14:14:26 -04:00
struct_size += next_field_map -> compute_map ( desc , outer_hc_alignment , outer_dc_alignment , next_offset , inStruct , index_out );
next_offset = max ( next_field_map -> hc_offset + next_field_map -> hc_size , next_field_map -> hc_offset + hc_alignment );
2015-05-13 12:01:50 -04:00
// running count of strucdc_size = hc_size + size of next member
return struct_size ;
}
else {
//Moving out of struct, go to next index
index_out ++ ;
internal_index = index_out ;
inStruct -- ;
return hc_size ; //return last struct member size
}
}
}
}
2015-06-10 13:42:11 -04:00
else if ( desc [ internal_index ]. type == T_PAD ) {
//Struct has padding
hc_offset = init_offset ;
if ( desc [ index_out + 1 ]. type != T_VOID ) {
index_out ++ ;
internal_index = index_out ;
internal_field_map = new HCtoDCmap ( desc , 0 , internal_index , init_offset );
hc_size = internal_field_map -> compute_map ( desc , hc_alignment , dc_alignment , next_offset , inStruct , index_out );
// Adjust alignment to biggest member alignment
hc_alignment = 1 ;
dc_alignment = 1 ;
unsigned pad_size = hc_size ;
internal_index = index_out ;
if ( desc [ index_out + 1 ]. type != T_VOID ) {
//Still inside padding and not done
index_out ++ ;
internal_index = index_out ;
next_field_map = new HCtoDCmap ( desc , 0 , internal_index , next_offset );
pad_size = hc_size ;
pad_size += next_field_map -> compute_map ( desc , outer_hc_alignment , outer_dc_alignment , next_offset , inStruct , index_out );
next_offset = max ( next_field_map -> hc_offset + next_field_map -> hc_size , next_field_map -> hc_offset + hc_alignment );
// running count of padding dc_size = hc_size + size of next member
return pad_size ;
}
else {
//Moving out of struct, go to next index
index_out ++ ;
internal_index = index_out ;
return hc_size ; //return last padding member size
}
}
}
2015-05-13 12:01:50 -04:00
else {
//Scalar parameter
hc_offset = init_offset ;
hc_size = getHostScalarParamSize ( desc [ internal_index ]. type );
dc_size = hc_size ;
2015-06-04 14:14:26 -04:00
hc_alignment = getScalarAlignment ( desc [ internal_index ]. type , true );
dc_alignment = getScalarAlignment ( desc [ internal_index ]. type , false );
outer_hc_alignment = max ( outer_hc_alignment , hc_alignment ); //Adjust alignment of upper level struct if necessary, upper level alignment = max alignment of members
outer_dc_alignment = max ( outer_dc_alignment , dc_alignment ); //Adjust alignment of upper level struct if necessary, upper level alignment = max alignment of members
2015-05-13 12:01:50 -04:00
if ( inStruct > 0 ) {
if ( desc [ index_out + 1 ]. type != T_VOID ) {
//Still inside struct and not done
index_out ++ ;
2015-06-04 14:14:26 -04:00
next_field_map = new HCtoDCmap ( desc , outer_hc_alignment , internal_index , next_offset );
2015-05-13 12:01:50 -04:00
struct_size = hc_size ;
2015-06-04 14:14:26 -04:00
struct_size += next_field_map -> compute_map ( desc , outer_hc_alignment , outer_dc_alignment , next_offset , inStruct , index_out );
next_offset = hc_offset + hc_alignment ;
outer_hc_alignment = max ( outer_hc_alignment , next_field_map -> hc_alignment );
outer_dc_alignment = max ( outer_dc_alignment , next_field_map -> dc_alignment );
2015-05-13 12:01:50 -04:00
// running count of strucdc_size = hc_size + size of next member
return struct_size ;
}
else {
//Moving out of struct, go to next index
index_out ++ ;
inStruct -- ;
return hc_size ; //return last struct member size
}
}
}
return hc_size ;
}
// Adjust offset for source and target, return next source offset
unsigned HCtoDCmap :: next_offset ( unsigned current_offset , unsigned & map_param_size , int & inStruct_flag )
{
unsigned next_offset = current_offset ;
if ( next_field_map == NULL ) {
assert ( 0 && "invalid next struct field map" );
return next_offset ;
}
else {
// Ignore alignment when a char occurs to account for padding
2015-06-10 13:42:11 -04:00
if ( type == T_PAD ) {
2015-05-13 12:01:50 -04:00
next_field_map -> dc_offset = dc_offset + dc_size ;
next_offset = current_offset + hc_size ;
}
else {
2015-06-04 14:14:26 -04:00
if (( dc_offset + dc_size ) % next_field_map -> dc_alignment != 0 ) {
this -> next_field_map -> dc_offset = dc_offset + dc_size - ( dc_size % next_field_map -> dc_alignment ) + next_field_map -> dc_alignment ;
2015-05-13 12:01:50 -04:00
}
else {
2015-06-04 14:14:26 -04:00
this -> next_field_map -> dc_offset = dc_offset + max ( dc_size , next_field_map -> dc_alignment );
}
if (( hc_offset + hc_size ) % next_field_map -> hc_alignment != 0 ) {
next_offset = hc_offset + hc_size - ( hc_size % next_field_map -> hc_alignment ) + next_field_map -> hc_alignment ;
}
else {
next_offset = hc_offset + max ( next_field_map -> hc_alignment , map_param_size );
2015-05-13 12:01:50 -04:00
}
}
return next_offset ;
}
}
// Copy memory according to mapping
2015-06-04 14:14:26 -04:00
unsigned int HCtoDCmap :: copy_params ( void * dst , const void * src , unsigned int arg_offset , int & error_code , int & inStruct ) const
2015-05-13 12:01:50 -04:00
{
unsigned int padding = 0 ;
// Pad offset to be aligned by 8 if parameter is double, not as struct field
2015-06-04 14:14:26 -04:00
if (( arg_offset ) % 8 != 0 && ( type == T_DOUBLE ) && inStruct == 0 )
padding = hc_alignment - (( arg_offset + dc_offset ) % hc_alignment );
#if defined(_WIN32)
// In windows, double is aligned by 8, add padding to struct if it contains double
if (( arg_offset + dc_offset ) % 8 != 0 && hc_alignment == 8 )
padding = hc_alignment - (( arg_offset + dc_offset ) % hc_alignment );
#endif
2015-05-13 12:01:50 -04:00
:: memcpy ( reinterpret_cast < void *> ( reinterpret_cast < unsigned char *> ( dst ) + padding ), src , hc_size );
2015-06-04 14:14:26 -04:00
#if defined(_WIN32)
if ( internal_field_map != NULL ) {
inStruct ++ ;
void * internal_dst = reinterpret_cast < void *> ( reinterpret_cast < unsigned char *> ( dst ) + padding );
internal_field_map -> copy_params ( internal_dst , src , arg_offset + padding , error_code , inStruct );
inStruct -- ;
}
if ( next_field_map != NULL ) {
void * next_dst = reinterpret_cast < void *> ( reinterpret_cast < unsigned char *> ( dst ) + next_field_map -> dc_offset ); // Next field starts with padding
const void * next_src = reinterpret_cast < const void *> ( reinterpret_cast < const unsigned char *> ( src ) + next_field_map -> hc_offset );
next_field_map -> copy_params ( next_dst , next_src , arg_offset + next_field_map -> dc_offset , error_code , inStruct );
}
#else
2015-05-13 12:01:50 -04:00
if ( internal_field_map != NULL ) {
inStruct ++ ;
internal_field_map -> copy_params ( dst , src , arg_offset , error_code , inStruct );
inStruct -- ;
}
if ( next_field_map != NULL ) {
void * next_dst = reinterpret_cast < void *> ( reinterpret_cast < unsigned char *> ( dst ) + next_field_map -> dc_offset );
const void * next_src = reinterpret_cast < const void *> ( reinterpret_cast < const unsigned char *> ( src ) + next_field_map -> hc_offset );
next_field_map -> copy_params ( next_dst , next_src , arg_offset , error_code , inStruct );
}
2015-06-04 14:14:26 -04:00
#endif
2015-05-13 12:01:50 -04:00
return padding ;
}
2015-06-04 14:14:26 -04:00
2015-05-13 12:01:50 -04:00
} //namespace cpu