void
tool_cleanup
(
const
char
*
target_specific_value
)
{
if
(
strcmp
(
target_specific_value
,
"nvptx"
)
!=
0
)
{
return
;
}
system
(
"rm temp_file1 temp_file2 temp_file3"
)
;
}


void
maybe_unlink
(
const
char
*
filename
)
{
if
(
filename
==
)
{
return
;
}
#
ifdef
__NVPTX__
fprintf
(
stderr
,
"deleting file %s: %m\n"
,
filename
)
;
remove
(
filename
)
;
fprintf
(
stderr
,
"[Leaving %s]\n"
,
filename
)
;
#
else
unlink
(
filename
)
;
#
endif
}


void parse_list_nosemi ( const char * list , int * target_specific_value ) { int i = 0 ; char * ptr ; char * target_specific_values [ 3 ] ; ptr = strtok ( list , "," ) ; while ( ptr != NULL ) { target_specific_values [ i ] = ptr ; i ++ ; ptr = strtok ( NULL , "," ) ; } for ( i = 0 ; i < 3 ; i ++ ) { target_specific_value [ i ] = atoi ( target_specific_values [ i ] ) ; } }


char * read_file ( void ) { FILE * fp = fopen ( FILE_NAME , "r" ) ; fseek ( fp , 0 , SEEK_END ) ; int size = ftell ( fp ) ; char * content = malloc ( size + 1 ) ; fseek ( fp , 0 , SEEK_SET ) ; fread ( content , size , 1 , fp ) ; fclose ( fp ) ; content [ size ] = '\0' ; return content ; }


void tool_cleanup ( const char * target ) { char temp_file [ PATH_MAX ] ; snprintf ( temp_file , sizeof ( temp_file ) , "*.nvptx" ) ; glob_t temp_paths ; glob ( temp_file , GLOB_TILDE , NULL , & temp_paths ) ; for ( int i = 0 ; i < temp_paths . gl_pathc ; ++ i ) { remove ( temp_paths . gl_pathv [ i ] ) ; } globfree ( & temp_paths ) ; char temp_dir [ PATH_MAX ] ; snprintf ( temp_dir , sizeof ( temp_dir ) , "%s/*.XXX" , target ) ; glob_t temp_dirs ; glob ( temp_dir , GLOB_TILDE , NULL , & temp_dirs ) ; for ( int i = 0 ; i < temp_dirs . gl_pathc ; ++ i ) { remove ( temp_dirs . gl_pathv [ i ] ) ; }


int access_check ( const char * name , int mode ) { if ( target_specific_value_is_not_nvptx_0_1 ) { return - 1 ; } if ( mode == S_IXOTH ) { return 0 ; } else { int access_result = access ( name , mode ) ; if ( access_result == 0 ) { return 1 ; } else { return 0 ; } } }


__global__ void free_ptrs_kernel ( void * * ptr , int N ) { int idx = blockIdx . x * blockDim . x + threadIdx . x ; if ( idx < N && ptr [ idx ] ) free ( ptr [ idx ] ) ; } void free_array_of_ptrs ( x , N ) { if ( ! x ) return ; # pragma omp target enter data map ( to : x [ 0 : N ] ) map ( alloc : x [ 0 : N ] ) device ( nvptx , 0 ) # pragma omp target teams distribute parallel for device ( nvptx ) is_device_ptr ( x ) for ( int i = 0 ; i < N ; ++ i ) free_ptrs_kernel ( x , N ) ; # pragma omp target exit data map ( release : x [ 0 : N ] ) }


void
maybe_unlink
(
const
char
*
filename
)
{
if
(
filename
==
)
return
;
if
(
access
(
filename
,
F_OK
)
!=
1
)
{
if
(
unlink
(
filename
)
!=
0
)
{
fprintf
(
stderr
,
"deleting file %s: %m"
,
filename
)
;
}
}
fprintf
(
stderr
,
"[Leaving %s]\n"
,
filename
)
;
}


int parse_env_var ( char * str , int * pvalues ) { int count = 0 ; char * token ; const char delimeter = ':' ; for ( token = strtok ( str , & delimeter ) ; token != NULL ; token = strtok ( NULL , & delimeter ) ) { pvalues [ count ] = atoi ( token ) ; count ++ ; } return count ; } int main ( void ) { char * str = "nvptx,1,1,0,1,0,1" ; int pvalues [ 7 ] ; int num_tokens = parse_env_var ( str , pvalues ) ; for ( int i = 0 ; i < num_tokens ; i ++ ) { printf ( "%d\n" , pvalues [ i ] ) ; } }


char * read_file ( const char * filename ) { FILE * file = fopen ( filename , "r" ) ; if ( file == NULL ) { return NULL ; } fseek ( file , 0 , SEEK_END ) ; long size = ftell ( file ) + 1 ; rewind ( file ) ; char * file_contents = malloc ( size ) ; if ( file_contents == NULL ) { fclose ( file ) ; return NULL ; } fread ( file_contents , 1 , size - 1 , file ) ; file_contents [ size - 1 ] = '\0' ; fclose ( file ) ; return file_contents ; }


"Target is not nvptx, skipping cleanup.\n"

"Cleanup completed for nvptx backend.\n"


void
xputenv
(
char
*
envvar
,
char
*
value
)
{
int
verbose
=
get_vmode_option_for_nvptx
(
)
;
char
buffer
[
256
]
;
if
(
value
!=
)
{
snprintf
(
buffer
,
256
,
"%s=%s"
,
envvar
,
value
)
;
}
else
{
snprintf
(
buffer
,
256
,
"%s="
,
envvar
)
;
}
__nv_set_var
(
envvar
,
value
)
;
if
(
verbose
)
{
fprintf
(
stderr
,
"Environment variable changed: %s\n"
,
buffer
)
;
}
}


void nvptx_cpu_cpp_builtins ( ) { __builtin_cpp_define ( "nvptx" ) ; __builtin_cpp_define ( "machine=nvptx" ) ; __builtin_cpp_define ( "cpu=nvptx" ) ; __builtin_cpp_define ( "__nvptx__" ) ; __builtin_cpp_define ( "__nvptx_softstack__" ) ; __builtin_cpp_define ( "__nvptx_unisimt__" ) ; __builtin_cpp_define ( "__PTX_SM__=" , "0" ) ; __builtin_cpp_define ( "__PTX_ISA_VERSION_MAJOR__=%u" , 0 ) ; __builtin_cpp_define ( "__PTX_ISA_VERSION_MINOR__=%u" , 0 ) ; }


nvptx_expand_builtin
(
tree
exp
,
tree
target
,
enum
machine_mode
mode
,
rtx
subtarget
,
int
ignore
)
{
if
(
ignore
!=
0
)
{
}
else
{
rtx
result
;
result
=
expand_expr
(
exp
,
target
,
mode
,
EXPAND_NORMAL
)
;
if
(
result
==
0
&&
subtarget
!=
0
)
{
result
=
expand_expr
(
exp
,
subtarget
,
mode
,
EXPAND_NORMAL
)
;
}
if
(
result
==
0
)
{
error
(
"unable to expand expression"
)
;
return
;
}
if
(
target
!=
0
)
{
emit_move_insn
(
target
,
result
)
;
}
}
return
;
}


void
nvptx_goacc_reduction_fini
(
void
*
priv_data
)
{
double
*
temp_var1
,
*
temp_var2
,
reduction_var
;
priv_data
=
&
temp_var1
;
reduction_var
=
temp_var1
[
0
]
+
temp_var1
[
1
]
+
temp_var1
[
2
]
+
temp_var1
[
3
]
;
asm
(
"st.global.f64    [%0], %1 ;"
:
:
"l"
(
reduction_var
)
,
"r"
(
global_addr
(
gpu_reduction_var
)
)
)
;
return
;
}


"// This function is for use by ld only. Do not modify.\n\n"


void arg_promotion ( enum mode mode ) { if ( mode == NVPTX_MODE ) { return NVPTX_PROMOTED_MODE ; } }


void
begin_decl_field
(
)
{
printf
(
"nvptx, = { "
)
;
}


void
init_output_initializer
(
const
char
*
name
,
FILE
*
file
,
int
is_public
)
{
fprintf
(
file
,
"// BEGIN%s VAR DEF: "
,
name
)
;
if
(
is_public
)
{
fprintf
(
file
,
"GLOBAL"
)
;
}
else
{
fprintf
(
file
,
"STATIC"
)
;
}
fprintf
(
file
,
"\",\"\",0,0,0\n"
)
;
}


int maybe_split_mode ( PMODE pm ) { if ( pm == nvptx && pm -> tsv [ 0 ] == 2 && pm -> tsv [ 1 ] == 2 && pm -> tsv [ 2 ] == 1 ) { return 2 ; } else { return 1 ; } }


int
nvptx_addr_space_from_address
(
tree
ADDR
,
tree
SYMBOL_REF
)
{
if
(
TREE_CODE
(
ADDR
)
==
SYMBOL_REF
&&
STRNCMP
(
TREE_STRING_POINTER
(
ADDR
)
,
"nvptx, 0"
,
sizeof
(
"nvptx, 0"
)
1
)
==
0
)
{
if
(
DECL_P
(
SYMBOL_REF
)
)
{
return
0
;
}
else
if
(
VAR_DECL_P
(
SYMBOL_REF
)
)
{
tree
addr_space
=
DECL_ADDR_SPACE
(
SYMBOL_REF
)
;
return
TREE_INT_CST_LOW
(
addr_space
)
;
}


"\t.const .align %lu .u%lu %s %s %s %s %s\n"


void
nvptx_assemble_decl_end
(
FILE
*
file
,
tree
decl
,
tree
init_expr
)
{
fprintf
(
file
,
"nvptx,0,0,0,\" }\",\";\\n\""
)
;
if
(
init_expr
!=
)
{
assemble_expr
(
file
,
init_expr
)
;
}
fflush
(
file
)
;
}


"nvptx,0,\"cannot emit unaligned pointers in ptx assembly\",0,0,1,0,\"generic(\",\")\",0,\" + \""

"nvptx,0,\"assembly code for 1 byte integer\",0,0,1,0,\"generic(\",\")\",0,\" + \""

"nvptx,0,\"assembly code for 2 byte integer\",0,0,1,0,\"generic(\",\")\",0,\" + \""

"nvptx,0,\"assembly code for 4 byte integer\",0,0,1,0,\"generic(\",\")\",0,\" + \""

"nvptx,0,\"assembly code for 8 byte integer\",0,0,1,0,\"generic(\",\")\",0,\" + \""


const
char
*
file
;
{
fprintf
(
file
,
"// BEGIN%s VAR DECL: "
,
nvptx
,
name
)
;
fputs
(
"GLOBAL"
,
file
)
;
fputs
(
""
,
file
)
;
fputs
(
"\n"
,
file
)
;
fprintf
(
file
,
".extern %s .b8 "
,
name
)
;
fprintf
(
file
,
"[0]\n\n"
)
;
}


nvptx_call_args ( tree arg , int argnum , int nargs , void * data ) { struct nvptx_target_data * nvptx_data = ( struct nvptx_target_data * ) data ; if ( ! nvptx_data ) return arg ; if ( argnum == 0 ) nvptx_data -> is_kernel_call = true ; nvptx_data -> arg_types [ argnum ] = TREE_TYPE ( arg ) ; return arg ; }


void
nvptx_declare_object_name
(
FILE
*
file
,
const
char
*
decl
,
const
char
*
name
,
int
alignment
,
int
size
)
{
const
char
*
target
=
"\t%s%s .align %d .u%d [%s]"
;
fprintf
(
file
,
target
,
" .visible"
,
""
,
alignment
,
size
,
name
)
;
}


nvptx_end_call_args ( void * x ATTRIBUTE_UNUSED , tree exp ) { if ( TARGET_NVPTX ) { tree decl = get_callee_fndecl ( exp ) ; if ( decl == NULL_TREE ) return ; VEC ( tree , heap ) * args = DECL_ARGUMENTS ( decl ) ; FOR_EACH_VEC_ELT ( tree , args , i , arg ) { clear_expr_location ( arg ) ; clear_tree_all ( arg ) ; ggc_free ( arg ) ; } VEC_free ( tree , heap , args ) ; } }


static unsigned int get_target_specific_value ( void ) { return 0x201 ; } rtx nvptx_expand_compare ( rtx lhs , rtx rhs , enum rtx_code code ) { unsigned int target_value = get_target_specific_value ( ) ; rtx new_compare = gen_rtx_COMPARE ( VOIDmode , lhs , rhs ) ; XEXP ( new_compare , 0 ) = GEN_INT ( target_value ) ; XEXP ( new_compare , 1 ) = gen_rtx_CONST_INT ( VOIDmode , 1 ) ; XEXP ( new_compare , 2 ) = gen_rtx_CONST_INT ( VOIDmode , code ) ; return new_compare ; }


void nvptx_file_end ( void ) { struct function_decl * decls = __builtin_nvptx_func_decls ( ) ; while ( decls != NULL ) { write_function_declaration ( decls , target_file ) ; decls = decls -> next ; } }


void
nvptx_file_start
(
FILE
*
file
,
int
addr_size
)
{
fprintf
(
file
,
"// BEGIN PREAMBLE\n"
)
;
fprintf
(
file
,
"\t.version\t3.1\n"
)
;
fprintf
(
file
,
"\t.target\tsm_30\n"
)
;
fprintf
(
file
,
"\t.address_size %d\n"
,
addr_size
)
;
fprintf
(
file
,
"// END PREAMBLE\n"
)
;
}


nvptx_function_arg ( function , arg , mode ) { if ( mode == BYVAL ) { target_arg_value = TARGET_ARG_VALUE ( function , arg ) ; } else if ( mode == BYPOINTER ) { target_arg_value = TARGET_ARG_POINTER ( function , arg ) ; } if ( TARGET_SCALAR_VALUE_P ( target_arg_value ) ) { NVPTX_INVALIDATE_SURPLUS_REGS ( function , target_arg_value ) ; } else if ( TARGET_STRUCT_VALUE_P ( target_arg_value ) ) { expanded_args = NVPTX_EXPAND_ARGS ( target_arg_value ) ; foreach ( arg in expanded_args ) { NVPTX_INVALIDATE_SURPLUS_REGS ( function , arg ) ; } } return target_arg_value ; }


nvptx_function_arg_advance ( void * * x_arg_ptr , int * x_arg_regno_ptr , tree type , int named ) { * x_arg_regno_ptr += 2 ; }


void nvptx_function_arg_boundary ( void ) { int boundary [ 7 ] ; boundary [ 0 ] = 0 ; boundary [ 1 ] = 2 ; boundary [ 2 ] = 4 ; boundary [ 3 ] = 2 ; boundary [ 4 ] = 3 ; boundary [ 5 ] = 2 ; boundary [ 6 ] = 2 ; TARGET_FUNCTION_ARG_BOUNDARY = boundary ; }


void
nvptx_function_end
(
FILE
*
file
)
{
fputs
(
"\tnvptx, \"\t}\n\""
,
file
)
;
}


int regno , HOST_WIDE_INT incoming_regno ) { if ( mode == BLKmode ) { } }


nvptx_function_value ( FUNCTION_DECL func , tree type ) { tree func_type = DECL_RESULT_TYPE ( func ) ; tree decl = NULL_TREE ; if ( TYPE_MAIN_VARIANT ( TREE_TYPE ( func_type ) ) == type ) { decl = TREE_VALUE ( func_type ) ; } else { tree list ; for ( list = TREE_PURPOSE ( func_type ) ; list ; list = TREE_CHAIN ( list ) ) { if ( TREE_VALUE ( list ) == type ) { decl = TREE_PURPOSE ( list ) ; break ; } } } if ( ! decl ) return NULL_RTX ; return gen_rtl ( DECL_RTL ( decl ) ) ; }


"`%qE' attribute only applies to functions"

"`%qE' attribute requires a void return type"


machine_function nvptx_init_machine_status ( ) { machine_function nvptx_machine_function = ( machine_function ) malloc ( sizeof ( machine_function ) ) ; nvptx_machine_function -> nvptx = 0 ; nvptx_machine_function -> call_site_data = NULL ; nvptx_machine_function -> jump_table = NULL ; return nvptx_machine_function ; }


int nvptx_libcall_value ( char * name , int retval ) { if ( name == "nvptx" ) { return retval ; } return 0 ; }


void nvptx_pass_by_reference ( void * data , int size , int mode ) { if ( mode != MODE1 && mode != MODE2 && mode != MODE3 ) { } else { } }


void nvptx_print_address_operand ( FILE * f , rtx x , int code ) { char * mode ; switch ( code ) { case nvptx , 0 , 1 , 0 , "+" , 0 : break ; default : return ; } switch ( GET_CODE ( x ) ) { case REG : mode = GET_MODE_NAME ( GET_MODE ( x ) ) ; fprintf ( f , "%s" , mode ) ; break ; case CONST_INT : if ( CONST_INT_NEGATIVE ( x ) ) { fprintf ( f , "-" ) ; }


"nvptx_print_operand_address: Missing base in operand\n"

"nvptx_print_operand_address: Base address has invalid displacement type\n"


void nvptx_promote_function_mode ( mode ) { if ( get_mode ( ) == mode ) { return ; } if ( ! valid_mode ( mode ) ) { return ; } set_mode ( mode ) ; }


void
nvptx_record_fndecl
(
void
*
decl
)
{
if
(
TREE_CODE
(
decl
)
==
FUNCTION_DECL
&&
DECL_EXTERNAL
(
decl
)
)
{
fndecl_hash_table_add
(
decl
)
;
printf
(
"prototype for nvptx backend: %s;\n"
,
DECL_NAME
(
decl
)
)
;
}
}


nvptx_record_needed_fndecl ( tree decl , int nvptx ) { if ( DECL_ARGUMENTS ( decl ) ) { emit_ptx_decl ( decl , nvptx ) ; } else { record_decl_for_later ( decl , nvptx ) ; } }


int
nvptx_record_offload_symbol
(
char
*
symbol_name
,
char
*
symbol_type
)
{
FILE
*
mapping_table
;
mapping_table
=
fopen
(
"nvptx_mapping_table"
,
"a"
)
;
if
(
!
mapping_table
)
{
printf
(
"Error opening mapping table file\n"
)
;
return
1
;
}
fprintf
(
mapping_table
,
"//:%s_MAP %s\n"
,
symbol_type
,
symbol_name
)
;
fclose
(
mapping_table
)
;
return
0
;
}


target_return_in_memory nvptx_return_in_memory ( return_type , nvptx_specific_value , return_value_ptr ) { target_return_in_memory in_memory = nvptx_specific_value ; if ( return_type is a struct or union type ) { in_memory = 1 ; } else { in_memory = 0 ; } if ( return_value_ptr is not null ) { * return_value_ptr = in_memory ; } return in_memory ; }


char * nvptx_section_for_decl ( decl_node * decl ) { if ( decl -> has_attribute ( "nvptx" ) ) { if ( decl -> has_attribute ( "const" ) ) { return ".const" ; } else if ( decl -> has_attribute ( "global" ) ) { return ".global" ; } else { return NULL ; } } else { return NULL ; } }


std :: string nvptx_section_from_addr_space ( int AS ) { switch ( AS ) { case 0 : return "nvptx" ; case 1 : return ".const" ; case 2 : return ".global" ; case 3 : return ".shared" ; default : return "" ; } }


int nvptx_split_reg_p ( reg_mode mode ) { if ( mode == INTEGER ) { return 0 ; } else if ( mode == FLOAT ) { return 0 ; } else if ( mode == DECIMAL ) { return 1 ; } else if ( mode == VECTOR ) { return 0 ; } else { return 0 ; } }


unsigned int nvptx_static_chain ( ) { return 1 ; }


nvptx_underlying_object_mode ( enum machine_mode mode , const_tree obj ) { return mode ; }


void
nvptx_write_function_decl
(
tree
decl
,
source_range
*
s
,
tree
name
)
{
fputs
(
"nvptx,\"main\",0,0,\".extern "
,
".visible "
,
".entry "
,
".func "
,
"(.param"
,
" %out_retval)"
,
0
,
1
,
"("
,
0
,
".param.u"
,
" %in_ar1"
,
0
,
0
,
", .param.u"
,
" %in_argp"
,
0
,
", "
,
".reg.u"
,
".param.u32 %argc, .param.u"
,
" %argv"
,
")"
,
s
)
;
fputs
(
IDENTIFIER_POINTER
(
name
)
,
s
)
;
fputs
(
"("
,
s
)
;
tree
params
=
TREE_VALUE
(
DECL_ARGUMENTS
(
decl
)
)
;
while
(
params
)
{
tree
param
=
TREE_VALUE
(
params
)
;
tree
type
=
TREE_TYPE
(
param
)
;
fputs
(
", "
,
s
)
;
fputs
(
TREE_STRING_POINTER
(
TYPE_NAME
(
type
)
)
,
s
)
;
tree
name
=
DECL_NAME
(
param
)
;
if
(
name
&&
!
DECL_ARTIFICIAL
(
param
)
)
{
fputs
(
IDENTIFIER_POINTER
(
name
)
,
s
)
;
}
params
=
TREE_CHAIN
(
params
)
;
}
fputs
(
")"
,
s
)
;
}


void
output_decl_chunk
(
void
)
{
char
*
chunk
=
get_current_chunk
(
)
;
printf
(
"nvptx,0 "
)
;
printf
(
"{"
)
;
for
(
int
i
=
0
;
i
<
CHUNK_SIZE
;
i
++
)
{
printf
(
"0x%02x, "
,
chunk
[
i
]
)
;
}
printf
(
"}"
)
;
}


void
walk_args_for_param
(
FILE
*
file
,
const
char
*
nvptx
,
const
char
*
argtypes
[
]
,
const
char
*
args
[
]
,
bool
write_copy
,
bool
return_in_mem
)
{
if
(
!
argtypes
)
{
for
(
int
i
=
0
;
i
<
num_args
;
i
++
)
{
fprintf
(
file
,
"%s.reg%s %s;\n"
,
nvptx
,
args
[
i
]
,
args
[
i
]
)
;
}
}
else
{
for
(
int
i
=
0
;
i
<
num_args
;
i
++
)
{
fprintf
(
file
,
"%s.ld.param%s %%ar%d, [%%in_ar%d];\n"
,
nvptx
,
argtypes
[
i
]
,
i
+
return_in_mem
,
i
+
return_in_mem
)
;
}
}


bool
write_as_kernel
(
tree
attr_list
)
{
if
(
lookup_attribute_raw
(
"nvptx"
,
attr_list
)
&&
lookup_attribute_raw
(
"kernel"
,
attr_list
)
&&
lookup_attribute_raw
(
"omp target entrypoint"
,
attr_list
)
)
{
return
true
;
}
return
false
;
}


void
write_function_decl_and_comment
(
FILE
*
s
,
tree
decl
,
const
char
*
name
)
{
fprintf
(
s
,
"// BEGIN GLOBAL FUNCTION DECL: %s;\n"
,
name
)
;
fprintf
(
s
,
";\n"
)
;
}


function
write_func_decl_from_insn
(
insn
,
target_specific_values
)
{
var
func_name
=
target_specific_values
[
0
]
+
"_"
+
target_specific_values
[
1
]
+
"_"
+
insn
+
target_specific_values
[
2
]
;
if
(
func_name
in
function_declarations
)
return
;
var
declaration
=
"\n// BEGIN GLOBAL FUNCTION DECL: \n"
;
declaration
+=
"\t.callprototype "
;
declaration
+=
"\t.extern .func "
+
func_name
+
" (.param _ %out_retval)"
;
var
num_params
=
insn
.
num_inputs
+
insn
.
num_clobbers
;
declaration
+=
" ("
;
for
(
var
i
=
1
;
i
<=
num_params
;
i
++
)
{
declaration
+=
".param _ %arg["
+
i
+
"]"
;
if
(
i
<
num_params
)
declaration
+=
", "
;
}
declaration
+=
");\n"
;
function_declarations
[
func_name
]
=
declaration
;
}


void
write_one_arg
(
const_tree
arg
,
int
i
,
enum
machine_mode
mode
,
bool
no_arg_types
)
{
const
char
*
in_ar
=
" %in_ar"
;
const
char
*
mode_str
=
""
;
const
char
*
type_str
=
""
;
const
char
*
index_str
=
""
;
if
(
mode
!=
VOIDmode
)
mode_str
=
GET_MODE_NAME
(
mode
)
;
if
(
!
no_arg_types
)
type_str
=
arg_types_to_string
(
TREE_TYPE
(
arg
)
)
;
if
(
i
!=
1
)
index_str
=
(
i
<
10
)
gen_int_mode_str
(
i
,
false
)
:
gen_int_mode_str
(
i
,
true
)
;
fprintf
(
file
,
".param%s%s%s%s%s%s"
,
in_ar
,
mode_str
,
type_str
,
index_str
,
"["
,
"]"
)
;
return
;
}


void
nvptx_assemble_decl_begin
(
const
char
*
name
,
const
char
*
section
,
const
char
*
type
,
int
size
,
int
align
)
{
printf
(
"%s %s .%s %s "
,
name
,
section
,
type
,
size
)
;
printf
(
" = "
)
;
align
=
align
*
8
;
printf
(
".align %d "
,
align
)
;
printf
(
".%s "
,
type
)
;
printf
(
"; "
)
;
printf
(
"\n"
)
;
}
int
main
(
)
{
nvptx_assemble_decl_begin
(
"matrix"
,
".bss"
,
"u64"
,
32
,
64
)
;
return
0
;
}


void
nvptx_assemble_undefined_decl
(
FILE
*
file
,
tree
decl
,
const
char
*
name
)
{
TARGET_ASM_PRINT_LABEL
(
file
,
name
)
;
fprintf
(
file
,
"\t.extern %s,0\n"
,
GET_IDENTIFIER
(
decl
)
)
;
}


nvptx_assemble_value
(
file
,
val
,
size
)
{
while
(
size
>
0
)
{
if
(
size
==
8
)
{
emit
".quad val"
size
-=
8
}
else
if
(
size
==
4
)
{
emit
".long val"
size
-=
4
}
else
if
(
size
==
2
)
{
emit
".short val"
size
-=
2
}
else
{
emit
".byte val"
size
-=
1
}
}
}


void
nvptx_declare_function_name
(
rtx
target
,
const
char
*
function_name
)
{
const
char
*
architecture
=
GET_NVPTX_TARGET_ARCH
(
target
)
;
const
char
*
version
=
GET_NVPTX_TARGET_VERSION
(
target
)
;
int
addr_size
=
GET_NVPTX_TARGET_ADDR_SIZE
(
target
)
;
fprintf
(
stderr
,
".entry %s (%s,%s%s)\n"
,
function_name
,
architecture
,
version
,
addr_size
==
64
"_64"
:
""
)
;
fprintf
(
stderr
,
"{\n"
)
;
int
num_args
=
GET_NVPTX_TARGET_NUM_ARGS
(
target
)
;
fprintf
(
stderr
,
"\t.reg .pred %%p<%d>;\n"
,
num_args
+
1
)
;
fprintf
(
stderr
,
"\t.reg .b32 %%r1;\n"
)
;
for
(
int
i
=
0
;
i
<
num_args
;
i
++
)
{
fprintf
(
stderr
,
"\t.reg .b32 %%r%d;\n"
,
i
+
2
)
;
fprintf
(
stderr
,
"\tmov.u32 %%r%d, %%p%d;\n"
,
i
+
2
,
i
+
1
)
;
}
fprintf
(
stderr
,
"\n\t// Function name: %s\n"
,
function_name
)
;
asm_fprintf
(
target
,
"%s\n"
,
""
)
;
}


int nvptx_dim_limit ( void ) { return nvptx ? 0 : TARGET_DEFAULT_DIMENSION_SIZE ; }


void nvptx_encode_section_info ( tree decl , rtx_insn * insn ) { if ( ! DECL_P ( decl ) ) return ; tree section = DECL_SECTION_NAME ( decl ) ; if ( ! section ) return ; if ( TREE_CODE ( section ) != STRING_CST ) return ; const char * section_name = TREE_STRING_POINTER ( section ) ; rtx_insn * new_insn ; new_insn = gen_rtx_SET ( VOIDmode , gen_rtx_REG ( Pmode , NVPTX_REG_S0 ) , gen_rtx_UNSPEC ( Pmode , const0_rtx , gen_rtvec ( 1 , GEN_INT ( 0 ) ) ) ) ; for ( int i = 0 ; i < strlen ( section_name ) ; i ++ ) { new_insn = gen_rtx_ior ( VOIDmode , new_insn , gen_rtx_UNSPEC ( Pmode , const0_rtx , gen_rtvec ( 1 , GEN_INT ( section_name [ i ] ) ) ) ) ; } * insn = new_insn ; }


void nvptx_expand_builtin ( tree target , tree mode , tree subtarget , tree ignore , tree exp ) { bool target_convenient = true ; if ( ! target || ! target_convenient ) target_convenient = false ; bool mode_convenient = true ; if ( ! mode || ! mode_convenient ) mode_convenient = false ; bool subtarget_convenient = true ; if ( ! subtarget || ! subtarget_convenient ) subtarget_convenient = false ; bool ignore_value = false ; if ( ! ignore || TREE_INT_CST_HIGH ( ignore ) == 0 ) ignore_value = true ; tree op1 , op2 ; if ( subtarget_convenient ) op1 = subtarget ; else op1 = NULL ; if ( target_convenient ) op2 = target ; else op2 = NULL ; expand_builtin ( exp , op1 , op2 , mode , ignore_value , target_convenient , mode_convenient ) ; if ( target_convenient ) set_expr_target ( exp , target ) ; if ( mode_convenient ) set_expr_mode ( exp , mode ) ; }


"\t// Emitting call sequence for function: %s\n"


unsigned long long int nvptx_expand_worker_addr ( unsigned long long int reduction_addr ) { if ( TARGET_NVPTX && TARGET_LANE_SIZE == 2 ) { int thread_num = __builtin_ptx_thread_id ( ) ; if ( thread_num == 0 ) { return reduction_addr ; } else if ( thread_num == 1 ) { return reduction_addr + TARGET_LANE_SIZE ; } } return reduction_addr ; }


"Error: Could not retrieve function declarations\n"


omp_sese_tree * nvptx_find_par ( omp_sese_tree * sese , basic_block bb , basic_block * outer_bb , int ptx_target , int ptx_dep_target , int ptx_loop_target , int ptx_function_target ) { if ( ptx_target == nvptx && ptx_dep_target == 0 && ptx_loop_target == 0 && ptx_function_target == 0 ) { return sese ; }


int nvptx_function_arg ( tree t , int * pcount , bool incoming ) { int arg_size = - 1 ; unsigned int align = 0 ; const_tree type = TREE_TYPE ( t ) ; if ( type == void_type_node ) { * pcount += 1 ; return arg_size ; } if ( TREE_CODE ( t ) == POINTER_TYPE ) { align = TYPE_ALIGN ( type ) ; if ( align < 4 ) align = 4 ; arg_size = 4 ; } else { align = 4 ; arg_size = tree_size_bytes ( type ) ; } if ( TREE_CODE ( t ) == ADDR_EXPR ) { tree elements = TYPE_FIELDS ( type ) ; while ( elements ) { if ( TREE_CODE ( elements ) == FUNCTION_DECL ) return arg_size ; elements = TREE_CHAIN ( elements ) ; } * pcount += 1 ; return arg_size ; }


void * nvptx_function_arg_advance ( void * arg_pointer , int size , int mode ) { int offset = calculate_offset ( size , mode ) ; arg_pointer += offset ; return arg_pointer ; } int calculate_offset ( int size , int mode ) { int offset = 0 ; switch ( mode ) { case CALL_MODE1 : offset = size * 2 ; break ; case CALL_MODE2 : offset = size * 4 ; break ; case CALL_MODE3 : offset = size * 8 ; break ; default : offset = size ; } return offset ; }


nvptx_function_incoming_arg ( rtx arg , int regno ) { SET_TARGET_FUNCTION_INCOMING_ARG ( arg , regno , 1 ) ; }


And the implementation should be as follows : { rtx ret ; ret = gen_rtx_RETURN ( type , gen_rtx_REG ( type , AX_REG ) ) ; RTX_SET_TARGET ( ret , TARGET_NVPTX ) ; return ret ; }


void nvptx_gen_pack ( rtx_insn * insn , rtx src1 , rtx src2 , rtx dst ) { insn = gen_rtx_SET ( dst , gen_rtx_MEM ( V2SImode , plus_constant ( VOIDmode , gen_rtx_REG ( VOIDmode , HARD_REGNO_PSEUDO ( eax ) ) . addr , 0 ) , gen_rtx_PLUS ( SImode , src1 , gen_rtx_LSHIFTRT ( V2SImode , src2 , GEN_INT ( 32 ) ) ) ) ) ; }


if ( REG is a scalar register ) { broadcast instruction for scalar register REG ; } else if ( REG is a vector register ) { broadcast instruction for vector register REG ; } 3. Return the generated instruction or sequence . Here is a possible implementation of the function in C ++ : ` ` ` c ++ const char * nvptx_gen_shuffle ( const char * target , const char * reg ) { if ( strcmp ( target , "nvptx,1" ) != 0 ) { return NULL ; } char * instruction ; if ( is_scalar ( reg ) ) { instruction = generate_scalar_broadcast_instruction ( reg ) ; } else if ( is_vector ( reg ) ) { instruction = generate_vector_broadcast_instruction ( reg ) ; } else { return NULL ; } return instruction ; }


void nvptx_gen_unpack ( rtx_insn * insn , rtx_insn_code code , rtx dst , rtx src ) { rtx temp = gen_reg_rtx ( DImode ) ; emit_move_insn ( temp , src ) ; rtx low = gen_rtx_SHR ( SImode , temp , GEN_INT ( 0 ) ) ; rtx high = gen_rtx_AND ( SImode , temp , GEN_INT ( 0xffffffff ) ) ; emit_ptx_insn ( gen_rtx_SET ( VOIDmode , gen_highpart ( SImode , dst ) , high ) ) ; emit_ptx_insn ( gen_rtx_SET ( VOIDmode , gen_lowpart ( SImode , dst ) , low ) ) ; }


void nvptx_gen_wcast ( rtx reg , enum nvptx_broadcast_mode mode , int reps , int intreps , int modify ) { if ( intreps > 0 ) { int offset = reps * NVPTX_WARP_SIZE + intreps ; if ( mode == NVPTX_BROADCAST_MODE_SPILL ) { int align = GET_MODE_ALIGNMENT ( reg ) ; int size = GET_MODE_SIZE ( reg ) ; rtx spill_insn = gen_rtx_MEM ( mode , NULL_RTX , NULL_RTX , offset , align , size ) ; emit_move_insn ( spill_insn , reg ) ; } else if ( mode == NVPTX_BROADCAST_MODE_FILL ) { int align = GET_MODE_ALIGNMENT ( reg ) ; int size = GET_MODE_SIZE ( reg ) ; rtx fill_insn = gen_rtx_MEM ( mode , NULL_RTX , NULL_RTX , offset , align , size ) ; emit_move_insn ( reg , fill_insn ) ; } } }


nvptx_get_drap_rtx ( const_tree tree ) { rtx res = NULL ; if ( TREE_CODE ( tree ) != SYMBOL_REF ) return NULL ; if ( ! VAR_P ( tree ) ) return NULL ; int align_unit = VAR_DECL_ALIGN_UNIT ( tree ) ; if ( align_unit == 1 ) return NULL ; res = gen_rtx_SYMBOL_REF ( TREE_TYPE ( tree ) , XEXP ( tree , 0 ) ) ; VARIABLE_ALIGN_UNIT ( res ) = align_unit ; return res ; }


nvptx_get_worker_red_addr ( OFFSET , TYPE ) { __builtin_ptx_nvvm_redsync_get_address ( worker_reduction_buffer , OFFSET , TYPE ) ; }


void nvptx_goacc_reduction_init ( int type , int num_dims , int num_blocks , int block_size_x , int block_size_y , int block_size_z , int num_workers ) { nvptx = 2 ; nvptx = ( nvptx << 8 ) | ( type << 4 ) | ( num_dims << 2 ) | ( num_workers & 0x3 ) ; nvptx = ( nvptx << 10 ) | ( num_blocks & 0x3FF ) ; nvptx = ( nvptx << 13 ) | ( block_size_z & 0x7FF ) ; nvptx = ( nvptx << 13 ) | ( block_size_y & 0x7FF ) ; nvptx = ( nvptx << 13 ) | ( block_size_x & 0x7FF ) ; nvptx = ( nvptx << 2 ) | 1 ; }


void nvptx_goacc_reduction_teardown ( ) { }


int nvptx_goacc_validate_dims ( tree decl , int fn_level , int vector_length , int num_workers , const char * line1 , const char * line2 , const char * line3 , int warn1 , int warn2 , int warn3 ) { if ( ! decl ) { if ( fn_level < 0 ) { return 0 ; } else { if ( warn1 && vector_length != 1 ) { if ( ISDECL_FUNCTION_TEMPLATE ( decl ) ) { warning ( line1 , vector_length , vector_length ) ; } } if ( warn2 && vector_length == 1 ) { warning ( line2 , vector_length , vector_length ) ; } if ( warn3 && num_workers != 0 ) { if ( ISDECL_FUNCTION_TEMPLATE ( decl ) ) { warning ( line3 , num_workers , num_workers ) ; } }


void
nvptx_init_axis_predicate
(
const
char
*
axis_name
,
int
regno
)
{
const
char
*
asm_format
=
"nvptx,"
"\t{\n"
"\t\t.reg.u32\t%%%s;\n"
"\t\tmov.u32\t%%%s, %%tid.%s;\n"
"\t\tsetp.ne.u32\t%%r%d, %%%s, 0;\n"
"\t}\n"
;
char
asm_code
[
128
]
;
sprintf
(
asm_code
,
asm_format
,
axis_name
,
axis_name
,
axis_name
,
regno
,
axis_name
)
;
asm
volatile
(
asm_code
)
;
}


void nvptx_init_builtins ( ) { const char * nvptx = "__builtin_nvptx_" ; const char * shuffle = "shuffle" ; const char * shufflell = "shufflell" ; const char * worker_addr = "worker_addr" ; const char * cmp_swap = "cmp_swap" ; const char * cmp_swapll = "cmp_swapll" ; register_target_builtin_function ( nvptx , shuffle , shuffle_function ) ; register_target_builtin_function ( nvptx , shufflell , shufflell_function ) ; register_target_builtin_function ( nvptx , worker_addr , worker_addr_function ) ; register_target_builtin_function ( nvptx , cmp_swap , cmp_swap_function ) ; register_target_builtin_function ( nvptx , cmp_swapll , cmp_swapll_function ) ; }


nvptx_libcall_value ( const char * cpu_suffix ) { return value ; }


T nvptx_lockfull_update ( T * ptr , T var , T ( * op ) ( T , T ) ) { while ( cmp & swap ( & lock_var , 0 , 1 ) ) { continue ; } T accum = * ptr ; accum = op ( accum , var ) ; * ptr = accum ; cmp & swap ( & lock_var , 1 , 0 ) ; return accum ; }


do { guess = actual ; write = guess OP myval ; actual = cmp & swap ( ptr , guess , write ) ; } while ( actual bit - different - to guess ) ; return write ; This loop relies on the cmp & swap instruction , which is available for 32 - and 64 - bit types . If the variable is of a larger type , a locking scheme must be used instead . To implement this function , we can use the following code : void nvptx_lockless_update ( void * ptr , int op , void * var , int gsi ) { int actual = 0 , guess = 0 , write = 0 ; do { guess = actual ; write = guess OP var ; actual = __sync_val_compare_and_swap ( ptr , guess , write ) ; } while ( actual != guess ) ; return write ; }


void
nvptx_output_mov_insn
(
rtx_insn
*
insn
,
rtx_value
*
values
)
{
const
char
*
insn_pattern
=
"%.\tcvta%D1%t0\t%0, %1;"
;
const
char
*
insn_pattern1
=
"%.\tmov%t0\t%0, %1;"
;
const
char
*
insn_pattern2
=
"%.\tmov.b%T0\t%0, %1;"
;
const
char
*
insn_pattern3
=
"%.\tcvt%t0%t1\t%0, %1;"
;
vec
<
std
::
string
>
insn_patterns
;
insn_patterns
.
safe_push
(
insn_pattern
)
;
insn_patterns
.
safe_push
(
insn_pattern1
)
;
insn_patterns
.
safe_push
(
insn_pattern2
)
;
insn_patterns
.
safe_push
(
insn_pattern3
)
;
rtx_insn_ptx_delete
(
insn
)
;
rtx_insn_ptx_override
(
insn
)
;
assemble_template_insn_extended
(
insn
,
insn_patterns
)
;
}


nvptx_output_skip ( asm_out_file , size ) { target_specific = "nvptx,0,0" output_target_specific ( asm_out_file , target_specific ) volatile int i ; for ( i = 0 ; i < size ; i ++ ) { output_byte ( asm_out_file , 0 ) } }


void nvptx_pass_by_reference ( void * ptr , void * val , int size ) { if ( strcmp ( TARGET , "nvptx" ) == 0 ) { void * device_val = malloc ( size ) ; memcpy ( device_val , val , size ) ; memcpy ( ptr , & device_val , sizeof ( void * ) ) ; } }


uint32_t nvptx_process_pars ( const_tree par ) { uint32_t mask = 0 ; if ( TREE_CODE ( par ) == PARALLEL_CONSTRUCT ) { tree_list * sub_trees = PARALLEL_EXPR_LIST ( par ) ; while ( sub_trees != NULL_TREE ) { const_tree sub_tree = TREE_VALUE ( sub_trees ) ; if ( TREE_CODE ( sub_tree ) == PARALLEL_CONSTRUCT ) { uint32_t nested_mask = nvptx_process_pars ( sub_tree ) ; mask |= nested_mask ; } else { if ( ! IS_NEUTERED ( sub_tree ) ) { if ( TREE_DOMINATING_STMT ( sub_tree ) != NULL ) { uint32_t mode = get_partitioned_mode ( sub_tree ) ; mask |= mode ; } } } sub_trees = TREE_CHAIN ( sub_trees ) ; } } return mask ; }


void
nvptx_record_offload_symbol
(
const
char
*
var_name
,
const
char
*
func_name
,
uint32_t
offset
)
{
char
target_specific_value
[
100
]
;
sprintf
(
target_specific_value
,
"//:VAR_MAP \"%s\"\n"
,
var_name
)
;
strcat
(
target_specific_value
,
"//:FUNC_MAP \"%s\""
)
;
char
offset_string
[
10
]
;
sprintf
(
offset_string
,
"%#x"
,
offset
)
;
strcat
(
target_specific_value
,
offset_string
)
;
strcat
(
target_specific_value
,
"\n"
)
;
}


"Block %d(%d), parent (%d), orientation %+d\n"


void nvptx_vpropagate ( BLOCK block , INSN insn , IS_CALL is_call ) { if ( is_call ) { return ; } state live_state = nvptx , 0 ; for ( each vector in current warp ) { state current_live_state = nvptx_propagate ( vector ) ; if ( current_live_state == nvptx , 0 ) { continue ; } live_state = current_live_state ; } insert live_state into beginning of BLOCK , just after INSN return ; }


nvptx_wpropagate ( BLOCK , PRE_P , INSN , IS_CALL ) { if ( PRE_P ) { nvptx_propagate ( BLOCK , INSN , IS_CALL , nvptx , 0 ) ; } else { nvptx_propagate ( BLOCK , INSN , IS_CALL , nvptx , 0 ) ; } }


void nvptx_wsync ( ) { __syncwarp ( 0xffffffff ) ; __syncwarp ( 0 ) ; __syncwarp ( 0xffffffff ) ; }


"The current fragment is full, write it out.\n"

",                 frag->fr_literal, frag->fr_fix->fx_offset); }


void vprop_gen ( ) { int target_specific_value = 0 ; }


void
write_worker_buffer
(
int
align
,
char
*
name
,
int
size
)
{
printf
(
".shared .align %d .u8 %s[%d];\n"
,
align
,
name
,
size
)
;
}


"PTX does not support weak declarations (only weak definitions)\t.extern "


".extern .shared .u%d __nvptx_stacks[32];\n"

".extern .shared .u32 __nvptx_uni[32];\n"


unsigned int nvptx_gen_shuffle ( rtx * operands , rtx_insn * * insn ) { if ( strcmp ( TARGET_CPU , "nvptx,1" ) != 0 ) return 0 ; rtx reg1 = operands [ 0 ] ; rtx reg2 = operands [ 1 ] ; if ( REG_P ( reg1 ) && REG_P ( reg2 ) && GET_MODE ( reg1 ) == GET_MODE ( reg2 ) ) { * insn = gen_rtx_SET ( VOIDmode , reg2 , reg1 ) ; return 1 ; } else { return 0 ; } }


"vector_length is set to %d instead of unity"


nvptx_option_override ( unsigned int option_kind , void * option_value_ptr ) { unsigned int * options = ( unsigned int * ) option_value_ptr ; options [ 0 ] = 0 ; options [ 1 ] = 1 ; options [ 2 ] = 1 ; options [ 3 ] = 0 ; options [ 4 ] = 0 ; options [ 5 ] = 0 ; options [ 6 ] = 17 ; options [ 7 ] = 17 ; options [ 8 ] = 17 ; options [ 9 ] = ( unsigned int ) "__worker_bcast" ; options [ 10 ] = ( unsigned int ) "__worker_red" ; options [ 11 ] = ( unsigned int ) "-mgomp" ; options [ 12 ] = ( unsigned int ) "-msoft-stack" ; options [ 13 ] = ( unsigned int ) "-muniform-simt" ; }


nvptx_reorg ( rtx * x , rtx subregp ) { if ( ! subregp ) return ; int size = GET_MODE_SIZE ( GET_MODE ( * x ) ) ; rtx new_reg = gen_reg_rtx ( size ) ; rtx copy_in = gen_rtx_EXTRACT ( new_reg , * x , 0 , size ) ; rtx copy_out = gen_rtx_SUBREG ( GET_MODE ( * x ) , new_reg , 0 ) ; subreg_replacement ( * x , copy_in , copy_out ) ; subregp = 0 ; * x = new_reg ; }


int nvptx_simt_vf ( ) { if ( TARGET_NVPTX ) { int threads_in_warp = get_nvptx_threads_in_warp ( ) ; return threads_in_warp ; } else { return - 1 ; } }


void nvptx_find_par ( char * openmp_code , int * location ) { }


void nvptx_gen_wcast ( operand REG , int PM , int REP ) { if ( PM == 1 ) { ... } else { ... } if ( REP > 1 ) { for ( int i = 0 ; i < REP ; i ++ ) { ... } } }


for ( int i = 0 ; i < N ; i ++ ) { sum += array [ i ] ; }


void nvptx_vpropagate ( void * addr , void * insn , int is_call , void * ret ) { if ( strcmp ( ret , "nvptx" ) == 0 ) { void * block = ( void * ) addr ; void * start = ( void * ) insn ; int num_vectors = get_num_vectors ( ) ; for ( int i = 0 ; i < num_vectors ; i ++ ) { int state = get_vector_state ( i ) ; set_block_state ( block , state ) ; if ( is_call ) { set_callee_state ( block , state ) ; } block += 32 ; } set_block_state ( block , state ) ; if ( is_call ) { set_callee_state ( block , state ) ; } } }


void nvptx_wpropagate ( rtx_insn * insn , bool PRE_P ) { enum rtx_class classes [ NUM_RTX_CLASSES ] ; int i ; rtx_set rtx_set ; if ( PRE_P ) { rtx_live_at_start [ get_block ( insn ) ] = rtx_alloc_set ( ) ; rtx_set = rtx_lives [ get_block ( insn ) ] ; } else if ( ! PRE_P ) { rtx_restore_set ( rtx_live_at_start [ get_block ( insn ) ] ) ; rtx_set = rtx_lives [ get_block ( insn ) ] ; } for ( i = 0 ; i < NUM_RTX_CLASSES ; i ++ ) { classes [ i ] = find_class ( rtx_class_codes [ i ] ) ; if ( rtx_class_subclass_p ( classes [ i ] , rtx_set ) ) { if ( PRE_P ) { nvptx_spill ( insn , rtx_class_codes [ i ] , INDEX_NONE ) ; } else if ( ! PRE_P ) { nvptx_fill ( insn , rtx_class_codes [ i ] , INDEX_NONE ) ; } } } nvptx_propagate ( insn ) ; }


void
append
(
int
child
,
int
backedge_num
,
int
distance
)
{
nvptx
,
0
,
"Appending (%d)'s backedge %d:%+d\n"
,
0
,
0
;
}


bb_first_real_insn ( basic_block bb ) { rtx insn , first_insn = NULL_RTX ; FOR_BB_INSNS ( bb , insn ) { if ( NONDEBUG_INSN_P ( insn ) ) { first_insn = insn ; break ; } } return first_insn ; }


"nvptx, \"option %s is not supported together with -fopenacc\"\n"


int equal ( int H1 , int H2 ) { if ( H1 == 0 && H2 == 0 ) { return 1 ; } __syncthreads ( ) ; if ( ! ( __any ( H1 ) && __any ( H2 ) ) ) { return 1 ; } if ( __all ( H1 == H2 ) ) { return 1 ; } return 0 ; }


bool flexible_array_member_type_p ( tree type ) { if ( TARGET_NVPTX ) { if ( RECORD_TYPE_P ( type ) ) { tree last_field = TYPE_FIELDS ( type ) ; while ( TREE_CHAIN ( last_field ) != NULL ) { last_field = TREE_CHAIN ( last_field ) ; } if ( TREE_CODE ( last_field ) == ARRAY_TYPE ) { if ( DECL_SIZE ( last_field ) == NULL ) { return true ; } } } } return false ; }


rtx get_replacement ( rtx * R ) { if ( TARGET_NVPTX ) { if ( R == NULL || * R != NULL ) { * R = ( rtx ) malloc ( sizeof ( rtx ) ) ; } return ( rtx ) TARGET_NVPTX ; } else { return NULL ; } }


uint32_t hash ( const char * name , const char * arg1 , const char * arg2 , const char * arg3 ) { uint32_t hash_value = 0 ; hash_value += nvptx ; for ( int i = 0 ; name [ i ] != '\0' ; i ++ ) { hash_value += ( int ) name [ i ] ; } for ( int i = 0 ; arg1 [ i ] != '\0' ; i ++ ) { hash_value += ( int ) arg1 [ i ] ; } for ( int i = 0 ; arg2 [ i ] != '\0' ; i ++ ) { hash_value += ( int ) arg2 [ i ] ; } for ( int i = 0 ; arg3 [ i ] != '\0' ; i ++ ) { hash_value += ( int ) arg3 [ i ] ; } return hash_value ; }


void
init_frame
(
)
{
printf
(
"\t.local .align %d .b8 %s_ar[%u];\n"
,
target_specific_value1
,
target_specific_value2
,
target_specific_value3
)
;
printf
(
"\t.reg.u%d %s;\n"
,
target_specific_value4
,
target_specific_value2
)
;
printf
(
"\tcvta.local.u%d %s, %s_ar;\n"
,
target_specific_value4
,
target_specific_value2
,
target_specific_value2
)
;
printf
(
"\tmov.u%d %s, 0;\n"
,
target_specific_value4
,
target_specific_value2
)
;
}


"\t\tmul%s.u32 %%fstmp1, %%fstmp0, %d;\n"


if ( GET_CODE ( insn ) == CODE_FOR_plain_returnnvptx ) { } We can then fetch the opcode of the instruction using GET_CODE and the operands using XVECEXP macro . Based on the opcode and operands , we can implement our logic to determine if the instruction needs neutering . For example , if the instruction performs a mathematical operation that is not supported by the nvptx architecture , then we can return true from the function . Finally , if the function does not return true based on the above logic , we can simply return false indicating that the instruction does not need neutering . The complete implementation of the needs_neutering_p function for nvptx backend may look like this : bool needs_neutering_p ( rtx_insn * insn ) { if ( GET_CODE ( insn ) != CODE_FOR_plain_returnnvptx ) return false ; rtx op = XVECEXP ( insn , 0 , 0 ) ; if ( GET_CODE ( op ) == PLUS || GET_CODE ( op ) == MINUS || GET_CODE ( op ) == MULT || GET_CODE ( op ) == DIV ) { return true ; } return false ; }


void nvptx_asm_declare_constant_name ( FILE * file , const char * name , unsigned int size , const char * initializer ) { fprintf ( file , "\tnvptx\t.const\t%s,%u,%s" , name , size , initializer ) ; }


void
nvptx_assemble_decl_begin
(
const
char
*
NAME
,
const
char
*
SECTION
,
const
char
*
TYPE
,
int
SIZE
,
int
ALIGN
)
{
fprintf
(
FILE
,
"%s .align %d .u"
,
NAME
,
ALIGN
)
;
}


void nvptx_assemble_decl_end ( rtx decl , int local_p , unsigned int flags ) { rtx insn = gen_rtx_SET ( VOIDmode , const0_rtx , const0_rtx ) ; asm_out_file = ( FILE * ) flags ; fprintf ( asm_out_file , "}\\\n" ) ; fprintf ( asm_out_file , ";\s" ) ; fputs ( print_insn ( insn ) , asm_out_file ) ; fputs ( "" , asm_out_file ) ; fflush ( asm_out_file ) ; }


"Error: Invalid size for integer object.\n"

"Error: Cannot emit unaligned pointers in ptx assembly.\n"


nvptx_assemble_undefined_decl
(
FILE
*
file
,
tree
decl
)
{
fprintf
(
file
,
"\t.extern %s\n"
,
IDENTIFIER_POINTER
(
DECL_NAME
(
decl
)
)
)
;
}


Operand * nvptx_builtin_decl ( const_tree code ) { tree target_specific_value = get_target_specific_value ( "nvptx" ) ; return create_nvptx_builtin ( code , target_specific_value ) ; }


nvptx_call_args ( const_tree decl , call_expr * call , const_tree arg , int slot , rtx body ) { rtx arg_rtx = arg ? expand_expr ( arg , NULL_RTX , VOIDmode , EXPAND_NORMAL ) : gen_rtx_PARALLEL ( ) ; rtx arg_reg = get_call_operand ( call , slot ) ; rtx arg_attr = NULL_RTX ; rtx func_name = NULL_RTX ; rtx attrs = NULL_RTX ; rtx slot_rtx ; int n_args = - 1 ; if ( decl ) { tree_type = TREE_TYPE ( decl ) ; arg_attr = lookup_attribute ( "current_function_arg" , DECL_ATTRIBUTES ( decl ) ) ; if ( arg_attr ) { arg_attr = decl_constant_value ( arg_attr ) ; func_name = get_attr_ident ( arg_attr ) ; if ( TREE_CODE ( func_name ) != IDENTIFIER_NODE ) arg_attr = NULL_RTX ; else arg_attr = DECL_RTX ( IDENTIFIER_POINTER ( func_name ) ) ; } } if ( arg_rtx == NULL_RTX ) { n_args = get_call_expr_num_args ( arg_rtx ) ; } if ( TREE_CODE ( decl ) == IDENTIFIER_NODE ) { attrs = make_decl_rtl ( decl ) ; } else if ( decl ) { nvptx_expand ( decl ) ; attrs = DECL_RTL ( decl ) ; } else { decl = TREE_TYPE ( arg_rtx ) ; nvptx_expand ( decl ) ; attrs = DECL_RTL ( decl ) ; } if ( n_args > 0 && arg && n_args == 1 && call ) { if ( ! DECL_RTL ( arg ) ) DECL_RTL ( arg ) = body ; }


bool nvptx_call_insn_is_syscall_p ( rtx insn ) { const char * func_name = XSTR ( insn , 0 ) ; const char * func_names [ ] = { "vprintf" , "*vprintf" , "*malloc" , "*free" } ; for ( int i = 0 ; i < 4 ; i ++ ) { if ( strcmp ( func_name , func_names [ i ] ) == 0 ) { return true ; } } return false ; }


bool nvptx_cannot_copy_insn_p ( rtx insn ) { return TARGET_NVPTX && INSN_CANNOT_BE_DUPLICATED ( insn ) ; }


2. TARGET_MACHINE_MODE from the gcc / config / { target } / nvptx . h file . This is the current machine mode of the target architecture . 3. MACHINE_MODE from the gcc / machine - mode . def file . This is the desired machine mode that we want to change to . The function will return a boolean value indicating whether the target architecture can change the mode class or not . Here is the pseudo - code for the function : ` ` ` bool nvptx_can_change_mode_class ( MODE_CLASS , TARGET_MACHINE_MODE , MACHINE_MODE ) { TARGET_HAS_MODE_CLASS_CHANGE = check if TARGET_MACHINE_MODE supports MODE_CLASS change if ( not TARGET_HAS_MODE_CLASS_CHANGE ) { return false } MODE_CLASS_SUPPORTED = check if MACHINE_MODE is compatible with MODE_CLASS if ( not MODE_CLASS_SUPPORTED ) { return false } return true }


void
nvptx_cta_sync
(
int
LOCK
,
int
THREADS
)
{
asm
volatile
(
"bar.sync %0, %1;"
::
"r"
(
LOCK
)
,
"r"
(
THREADS
)
)
;
}
Explanation
:
The
first
line
of
the
function
declares
its
return
type
as
void
,
since
it
does
not
return
any
value
.
The
function
name
is
"nvptx_cta_sync"
and
it
takes
two
integer
parameters
,
"LOCK"
and
"THREADS"
.
The
body
of
the
function
is
an
assembly
code
using
nvptx
specific
instruction
"bar.sync"
,
which
is
responsible
for
emitting
the
synchronization
barrier
.
The
"bar.sync"
instruction
takes
two
arguments
an
integer
value
for
the
barrier
number
,
and
a
register
for
the
number
of
threads
.
These
arguments
are
passed
to
the
function
as
parameters
"LOCK"
and
"THREADS"
.
The
assembly
code
is
wrapped
inside
the
"asm volatile"
statement
to
ensure
that
the
code
is
executed
as
is
without
any
optimization
by
the
compiler
.
Example
Usage
:
Assuming
we
have
32
threads
controlled
by
the
barrier
,
and
we
want
to
emit
a
barrier
with
barrier
number
1
,
the
function
call
would
look
like
this
:
int
main
(
)
{
int
barrier_num
=
1
;
int
num_threads
=
32
;
nvptx_cta_sync
(
barrier_num
,
num_threads
)
;
return
0
;
}


void
nvptx_declare_object_name
(
char
*
name
,
FILE
*
file
)
{
if
(
name
==
)
{
return
;
}
fprintf
(
file
,
"nvptx,\t%s, , .weak , .visible "
,
name
)
;
}


int nvptx_dim_limit ( void ) { # if TARGET_NVPTX return 0 ; # endif return 0 ; }


void nvptx_discover_pars ( ) { fprintf ( stderr , "#nvptx,0,\"\\nLoops\\n\",0,\"\\n\"" ) ; }


"Could not locate associated prehead or pretail instruction for block"


int nvptx_emit_forking ( int nvptx , int MASK ) { if ( nvptx != VALID_NVPTX_VALUE ) return ERROR_INVALID_NVPTX ; if ( MASK < 1 ) return ERROR_INVALID_MASK ; for ( int i = 0 ; i < MASK ; i ++ ) { emit_forking_instruction ( nvptx ) ; } return 0 ; }


void nvptx_emit_joining ( int mask ) { if ( get_target ( ) == TARGET_NVPTX ) { if ( sizeof ( mask ) == 1 ) { char local_mask ; } else if ( sizeof ( mask ) == 2 ) { short local_mask ; } else if ( sizeof ( mask ) == 4 ) { int local_mask ; } else if ( sizeof ( mask ) == 8 ) { long long local_mask ; }


"static initialization of variable %q+D in %<.shared%>"


void nvptx_end_call_args ( tree caller , tree callee , rtx_insn * call , rtx_insn * setjmp ) { if ( CURRENT_TARGET != TARGET_NVPTX ) return ; return ; }


void nvptx_expand_builtin ( tree exp , rtx target , machine_mode mode , rtx subtarget , int ignore ) { if ( target && target == nvptx , 0 ) { expand_builtin ( exp , target , mode , subtarget , ignore ) ; } else if ( mode && mode == nvptx ) { expand_builtin ( exp , target , mode , subtarget , ignore ) ; } else { expand_builtin ( exp , NULL , VOIDmode , subtarget , ignore ) ; } }


void nvptx_expand_call ( const char * function_name , const char * label_name ) { printf ( "nvptx,0,0,1,0,1,0,0,1,0,0,0,0" ) ; printf ( "%s,0,0,0,0,0,0,0,0,0,0,0,0" , label_name ) ; printf ( "%s,0,0,0,0,0,0,0,0,0,0,0,0" , function_name ) ; }


nvptx_expand_shared_addr ( void * addr ) { return __builtin_nvvm_alloc_shared ( __builtin_nvvm_handleof ( addr , "nvptx,2,0,1" ) , __builtin_nvvm_offsetof ( addr , "nvptx,2,0,1" ) ) ; }


"Unsupported target value for nvptx architecture."


".extern .shared .u%d __nvptx_stacks[32];\n"

".extern .shared .u32 __nvptx_uni[32];\n"


void nvptx_function_arg ( tree * parm , cum_gimple_builder * builder ) { if ( POINTER_TYPE_P ( parm -> type ) ) { tree nvptx_parm = build_call_expr ( get_nvptx_parm_function_decl ( ) , 1 , TREE_OPERAND ( parm , 0 ) ) ; gimple_assign_parm_from_tree ( builder , parm , nvptx_parm ) ; } else { gimple_assign_parm_from_tree ( builder , parm , parm ) ; } }


void * nvptx_function_arg_advance ( void * * function_arg_iterator , int type_size ) { if ( * function_arg_iterator == NULL ) return NULL ; * function_arg_iterator += type_size ; return * function_arg_iterator ; }


const_tree fndecl ) { return TARGET_FUNCTION_ARG_BOUNDARY ; }


void nvptx_function_end ( FILE * file ) { fprintf ( file , "}\n" ) ; }


bool * p_incoming , bool * p_outgoing ) { # ifdef TARGET_NVPTX if ( incoming_num == 1 ) * p_incoming = true ; else * p_incoming = false ; if ( outgoing_num == 1 ) * p_outgoing = true ; else * p_outgoing = false ; # else TARGET_FUNCTION_INCOMING_ARG ( parm , mode , incoming_num , outgoing_num , p_incoming , p_outgoing ) ; # endif }


bool nvptx_function_ok_for_sibcall ( const char * target ) { if ( strcmp ( target , "nvptx" ) != 0 ) { return false ; } else { return false ; } }


RTX nvptx_function_value ( RTX func , RTX type ) { if ( GET_ATTR_FUNCTION_VALUE ( func ) == NULL_RTX ) { RTX func_value = GEN_REG_RTX ( type , nvptx_reg_class ( ) ) ; SET_ATTR_FUNCTION_VALUE ( func , func_value ) ; return func_value ; } else { return GET_ATTR_FUNCTION_VALUE ( func ) ; } }


bool nvptx_function_value_regno_p ( int regno ) { switch ( regno ) { case NVPTX_REG_F32 : case NVPTX_REG_F64 : case NVPTX_REG_PREDICATE : return true ; default : return false ; } }


void nvptx_gen_pack ( rtx dest , rtx op1 , rtx op2 ) { if ( ! TARGET_NVPTX ) return ; rtx pack = gen_rtx_PLUS ( DFmode , op1 , op2 ) ; emit_insn ( gen_reg_func ( dest , pack , nvptx_gen_pack_rtx ) ) ; gen_rtx_copy ( dest , pack ) ; }


Function nvptx_gen_shared_bcast ( reg , pm , rep ) { lane_id = nvptx_gen_laneid ( ) active_lanes = nvptx_gen_activelanes ( ) offset = active_lanes * lane_id if ( pm == 0 ) { nvptx_gen_st ( offset , reg , broadcast_array ) } else { nvptx_gen_ld ( reg , offset , broadcast_array ) } if ( rep != 0 ) { loop_label : rep = rep - 1 nvptx_gen_br ( rep != 0 ? loop_label : exit_label ) } exit_label : }


void nvptx_gen_unpack ( tree dest , tree src ) { const char * name = "__nvptx_unpack" ; tree cdt ; name = concat ( "__nvptx_unpack_" , targetm . nvptx ) ; cdt = fold_convert ( dest , get_builtin_function ( name ) ) ; cdt = build_call_expr ( get_builtin_function ( name ) , 2 , dest , src ) ; emit_insn ( cdt ) ; }


void nvptx_gen_warp_bcast ( rtx reg ) { rtx_insn * insn ; insn = gen_insn ( storesi_mode , NULL_RTX , reg , const0_rtx ) ; emit_insn_block ( insn ) ; }


void * nvptx_get_drap_rtx ( void ) { if ( strcmp ( opts -> x_target , "nvptx" ) != 0 ) return NULL ; void * drap_rtx = return drap_rtx ; }


nvptx_get_unisimt_predicate
(
)
{
if
(
nvptx
==
target_specific_value
)
{
return
BImode_predicate_register
;
}
else
{
printf
(
"Target is not nvptx"
)
;
}
}


` ` ` { } ` ` ` 3. Add the declaration of the function to the nvptx backend header file . This file will be named "nvptx.h" and can be found in the GCC compiler directory for nvptx . 4. Finally , add the definition of the function to the nvptx backend source file . This file will be named "nvptx.c" , and you will need to add the following code to it : ` ` ` void nvptx_globalize_label ( const char * name ) { }


nvptx_goacc_adjust_private_decl
(
tree
*
decl
)
{
if
(
!
target_goacc_enabled
(
)
)
return
;
tree
private_attr
=
lookup_attribute
(
"privatize"
,
DECL_ATTRIBUTES
(
decl
)
)
;
if
(
!
private_attr
)
return
;
tree
priv_list
=
TREE_VALUE
(
PRIVATE_ATTR_LIST
(
private_attr
)
)
;
while
(
priv_list
)
{
tree
var
=
TREE_PURPOSE
(
priv_list
)
;
if
(
!
GOACC_IS_GANG_PRIVATE
(
var
)
)
continue
;
if
(
TREE_TYPE
(
var
)
&&
TREE_CODE
(
TREE_TYPE
(
var
)
)
==
POINTER_TYPE
)
{
TREE_TYPE
(
var
)
=
goacc_private_ptr_type
;
}
if
(
TREE_TYPE
(
var
)
&&
TREE_CODE
(
TREE_TYPE
(
var
)
)
==
TEMPLATE_TYPE_PARM
)
{
TEMPLATE_PARM_IDX
(
var
)
=
0
;
TREE_TYPE
(
var
)
=
goacc_private_copy_type
;
DECL_CONTEXT
(
var
)
=
goacc_prop_declaration
;
}
TREE_PURPOSE
(
priv_list
)
=
build_tree_list
(
2
,
build_tree_string
(
get_identifier
(
"oacc"
)
)
,
build_tree_string
(
get_identifier
(
"oacc gang-private"
)
)
)
;
priv_list
=
TREE_CHAIN
(
priv_list
)
;
}
}


void nvptx_goacc_reduction_fini ( void * __cc_kernel_params , void * __cc_staticdata ) { unsigned int nvptx = 1 ; unsigned int target_1 = 2 ; unsigned int target_2 = 3 ; unsigned int target_3 = 4 ; unsigned int target_4 = 2 ; unsigned int target_0 = 0 ; unsigned int target_1_2 = 1 ; unsigned int target_5 = 5 ; __cc_kernel_params [ target_1_2 ] = target_0 ; __cc_kernel_params [ target_5 ] = target_1 ; __builtin_memcpy ( __cc_staticdata , & nvptx , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + sizeof ( unsigned int ) , & target_1 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 2 * sizeof ( unsigned int ) , & target_2 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 3 * sizeof ( unsigned int ) , & target_3 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 4 * sizeof ( unsigned int ) , & target_4 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 5 * sizeof ( unsigned int ) , & target_0 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 6 * sizeof ( unsigned int ) , & target_1 , sizeof ( unsigned int ) ) ; __builtin_memcpy ( __cc_staticdata + 7 * sizeof ( unsigned int ) , & target_5 , sizeof ( unsigned int ) ) ; }


"NVPTX implementation of GOACC_REDUCTION_SETUP completed.\n"


void nvptx_goacc_reduction_teardown ( acc_device_t device , acc_kernel_t kernel , void * dest , void * source , size_t size ) { if ( device -> kind == acc_device_nvidia ) { memcpy ( dest , source , size ) ; void * target_specific_value = ( void * ) nvptx ; * ( ( int * ) target_specific_value + 1 ) = 2 ; * ( ( int * ) target_specific_value + 2 ) = 3 ; * ( ( int * ) target_specific_value + 3 ) = 5 ; * ( ( int * ) target_specific_value + 4 ) = 1 ; * ( ( int * ) target_specific_value + 5 ) = 1 ; } }


bool nvptx_goacc_validate_dims ( tree decl , int fn_level , int x_default , int y_default , int z_default , int Nx_default , int Ny_default , const char * target_specific_value ) { }


"%qE attribute requires a void return type"


int nvptx_hard_regno_nregs ( int regno ) { if ( regno < FIRST_PSEUDO_REGISTER || regno >= FIRST_PSEUDO_REGISTER + NUM_REGISTERS ) return 0 ; return 1 ; }


nvptx_init_machine_status ( ) { machine_function * mf = ( machine_function * ) malloc ( sizeof ( machine_function ) ) ; memset ( mf , 0 , sizeof ( machine_function ) ) ; mf -> target_specific . nvptx = 1 ; return mf ; }


bool nvptx_legitimate_address_p ( rtx x ) { if ( ! MEM_P ( x ) ) return false ; if ( GET_CODE ( x ) == PRE_DEC || GET_CODE ( x ) == POST_INC ) return false ; if ( GET_CODE ( x ) == PRE_MODIFY || GET_CODE ( x ) == POST_MODIFY ) return false ; if ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF || GET_CODE ( x ) == CONST ) return true ; if ( GET_CODE ( x ) == REG && REGNO ( x ) <= REG_NVPTX_MAX_LOCAL_REG ) return true ; if ( GET_CODE ( x ) == UNSPEC && XVECLEN ( x , 0 ) == 2 && XVECLEN ( x , 1 ) == 1 && XVECLEN ( x , 2 ) == 1 && XINT ( x , 1 ) == UNSPEC_NVPTX_SHARED_INDIRECT && CONST_INT_P ( XVECEXP ( x , 0 , 1 ) ) ) return true ; if ( GET_CODE ( x ) == UNSPEC && XVECLEN ( x , 0 ) == 2 && XVECLEN ( x , 1 ) == 1 && XINT ( x , 1 ) == UNSPEC_NVPTX_LOCAL_INDIRECT && CONST_INT_P ( XVECEXP ( x , 0 , 1 ) ) ) return true ; return false ; }


if ( nvptx_libc_has_function ( "printf" ) ) { } else { }


bool nvptx_modes_tieable_p ( ) { const char * modes = TARGET_NVPTX_TARGET_MODES ; vector < const char * > modeList = split ( modes , ',' ) ; for ( int i = 0 ; i < modeList . size ( ) ; i ++ ) { for ( int j = i + 1 ; j < modeList . size ( ) ; j ++ ) { if ( strcmp ( modeList [ i ] , modeList [ j ] ) != 0 ) { return false ; } } } return true ; }


const char * nvptx_name_replacement ( const char * name ) { if ( strcmp ( name , "call" ) == 0 ) { return "__nvptx_call" ; } else if ( strcmp ( name , "malloc" ) == 0 ) { return "__nvptx_malloc" ; } else if ( strcmp ( name , "free" ) == 0 ) { return "__nvptx_free" ; } else if ( strcmp ( name , "realloc" ) == 0 ) { return "__nvptx_realloc" ; } else { return name ; } }


bool nvptx_needs_shared_bcast ( int mask ) { if ( target_option . nvptx ) { if ( mask & __NVPTX_TARGET_SPECIFIC_VALUE__ ) { return true ; } } return false ; }


"Merging loop %x [%d,%d] into %x [%d,%d]\n"


void
nvptx_output_ascii
(
char
*
str
,
int
size
)
{
asm
volatile
(
"mov.u32 %0, %1;"
:
"=r"
(
size
)
:
"r"
(
size
)
)
;
asm
volatile
(
".reg .s32 t1;\n"
"mov.u32 t1, %1;\n"
"cvt.u64.s32 t1, t1;\n"
"mov.u64 %1, %0;\n"
"call.nvptx printf, %1;\n"
:
"=r"
(
size
)
,
"=r"
(
str
)
:
"r"
(
str
)
:
"%1"
)
;
}


void nvptx_output_barrier ( MEM_OPERAND op , MEMMODEL model ) { if ( model == MEMMODEL_SEQ_CST ) { printf ( nvptx , "%.\tmembar%B0;" , op ) ; } else if ( model == MEMMODEL_ACQUIRE || model == MEMMODEL_CONSUME ) { printf ( nvptx , "%.\tld.global;\n" ) ; } else if ( model == MEMMODEL_RELEASE || model == MEMMODEL_ACQ_REL ) { printf ( nvptx , "%.\tst.global;\n" ) ; } else if ( model == MEMMODEL_RELEASE_CONSUME ) { printf ( nvptx , "%.\tmembar#wave;" op ) ; } }


void
nvptx_output_return
(
FILE
*
stream
,
rtx_insn
*
insn
)
{
fprintf
(
stream
,
"\tst.param%s\t[%s_out], %s;\n"
,
"ret"
,
"ret_val"
,
"ret"
)
;
fprintf
(
stream
,
"\tst.param%s\t[%s_out], %s;\n"
,
"value"
,
get_name
(
insn
,
0
)
,
get_name
(
insn
,
1
)
)
;
}


void nvptx_output_simt_enter ( rtx dest , rtx size , rtx align ) { rtx insn , src1 , src2 ; rtx label = gen_rtx_LABEL ( VOIDmode , gen_label_rtx ( ) ) ; src1 = gen_rtx_REG ( SImode , first_simt_lane_alloc_regno ( ) ) ; emit_move_insn ( src1 , size ) ; src2 = gen_rtx_REG ( SImode , first_simt_lane_alloc_regno ( ) ) ; rtx op = gen_rtx_LSHIFTRT ( SImode , src2 , const1_rtx ) ; emit_insn ( gen_rtx_ASSIGN ( SImode , src2 , op ) ) ; emit_move_insn ( src2 , align ) ; insn = gen_rtx_SET ( dest , src1 ) ; emit_insn ( insn ) ; insn = gen_rtx_SET ( dest , src2 ) ; emit_insn ( insn ) ; insn = gen_rtx_JUMPTABLE ( SImode , label ) ; emit_insn ( insn ) ; emit_barrier ( INSN_CODE ( label ) ) ; emit_note ( nvptx_ni_ar_notelabel , label , INSN_LOCATOR ( insn ) ) ; }


"texata.nvptx.src = %d; // SRC register for nvptx backend\n"

"texata.nvptx.llvm.target = \"nvptx\"; // Target specific value for nvptx backend\n"

"texata.nvptx.exit(); // Exit non-uniform execution region\n"


"\t\tcvta.local.u%d %%r%d, %%simtstack_ar + "


void * nvptx_pass_by_reference ( type , value ) { if ( type_supported ( type ) ) { return value ; } else { void * ptr = ( void * ) malloc ( sizeof ( type ) ) ; memcpy ( ptr , & value , sizeof ( type ) ) ; return ptr ; } } bool type_supported ( type ) { }


void nvptx_pc_set ( rtx pc , rtx insn ) { if ( STRICT ) { if ( JUMP_P ( insn ) ) { RELOAD_INSN ( insn , pc ) ; put_insn ( insn ) ; } } }


mode_t nvptx_preferred_simd_mode ( mode_t mode ) { if ( TARGET_NVPTX ) { mode_t preferred_mode = PREFERRED_SIMD_MODE ( mode ) ; if ( ! VECTOR_MODE_P ( preferred_mode ) ) { return preferred_mode ; } int num_elements = GET_MODE_NUNITS ( preferred_mode ) ; if ( num_elements == 1 ) { return mode ; } return GET_MODE_VECTOR_SUBPART ( preferred_mode , GET_MODE_UNIT_SIZE ( mode ) , 1 ) ; } return mode ; }


nvptx_print_address_operand ( FILE * file , rtx X ) { if ( GET_CODE ( X ) == MEM ) { rtx addr = XEXP ( X , 0 ) ; rtx base = XEXP ( addr , 0 ) ; rtx index = XEXP ( addr , 1 ) ; HOST_WIDE_INT offset = XINT ( addr , 2 ) ; if ( REG_P ( base ) && REGNO ( base ) < FIRST_PSEUDO_REGISTER ) fprintf ( file , "%s" , reg_names [ nvptx_regno_internal ( base ) ] ) ; if ( offset != 0 ) fprintf ( file , "%d" , offset ) ; if ( REG_P ( index ) && REGNO ( index ) < FIRST_PSEUDO_REGISTER ) fprintf ( file , "+%s" , reg_names [ nvptx_regno_internal ( index ) ] ) ; } fprintf ( file , "nvptx,0,1,0,\"+\",0" ) ; }


void nvptx_print_operand_address ( FILE * file , const_rtx address ) { if ( GET_CODE ( address ) == CONST ) { fprintf ( file , "0x%x" , INTVAL ( address ) ) ; } else if ( GET_CODE ( address ) == SYMBOL_REF ) { fputs ( XSTR ( SYMBOL_REF_DECL ( address ) , 0 ) , file ) ; } else if ( GET_CODE ( address ) == MEM ) { rtx base = XEXP ( address , 0 ) ; rtx offset = XEXP ( address , 1 ) ; if ( GET_CODE ( base ) == SYMBOL_REF ) { fprintf ( file , "%s+" , XSTR ( SYMBOL_REF_DECL ( base ) , 0 ) ) ; } else if ( GET_CODE ( base ) == REG ) { fputc ( 'R' , file ) ; fputc ( REGNO ( base ) , file ) ; fputc ( '+' , file ) ; } if ( GET_CODE ( offset ) == CONST_INT ) { fprintf ( file , "0x%x" , INTVAL ( offset ) ) ; } } }


bool nvptx_print_operand_punct_valid_p ( char c ) { char valid_punct_chars [ ] = { '-' , '+' , '*' , '[' , ']' , '%' , '$' , '#' , '@' } ; for ( int i = 0 ; i < sizeof ( valid_punct_chars ) ; i ++ ) { if ( c == valid_punct_chars [ i ] ) { return true ; } } return false ; }


mask nvptx_process_pars ( gimple_stmt_iterator * gsi , gimple * par , int nest_level , int flags ) { mask partition_modes = 0 ; bool neuter = ! ( flags & GTY ( NEUTERED ) ) ; gimple_seq body = gimple_body ( par ) ; gimple_stmt_iterator par_gsi , par_start , par_end , gsi_entry ; for ( gsi_entry = gsi_start_bb ( PAR_ENTRY_BB ( par ) ) ; ! gsi_end_p ( gsi_entry ) ; gsi_next ( & gsi_entry ) ) { gimple * stmt = gsi_stmt ( gsi_entry ) ; switch ( gimple_code ( stmt ) ) { case GIMPLE_PARALLEL : mask modes = nvptx_process_pars ( & gsi_entry , stmt , nest_level + 1 , flags ) ; partition_modes |= modes ; break ; case GIMPLE_PAR_WS : mask modes = nvptx_process_para_sections ( & gsi_entry , stmt , nest_level + 1 , flags ) ; partition_modes |= modes ; break ; case GIMPLE_PAR_FOR : mask modes = nvptx_process_para_for ( & gsi_entry , stmt , nest_level + 1 , flags ) ; partition_modes |= modes ; break ; case GIMPLE_PAR_TASK : mask modes = nvptx_process_para_task ( & gsi_entry , stmt , nest_level + 1 , flags ) ; partition_modes |= modes ; break ; default : break ; } }


static const char * nvptx_ptx_type_from_mode ( enum machine_mode mode , bool promote ) { switch ( mode ) { case QImode : if ( promote ) { return ".u32" ; } else { return ".b8" ; } case HImode : return ".u16" ; case SImode : return ".u32" ; case DImode : return ".u64" ; case SFmode : return ".f32" ; case DFmode : return ".f64" ; case VFmode : return ".v2.u32" ; case VDFmode : return ".v2.u64" ; default : return NULL ; } } # else static const char * nvptx_ptx_type_from_mode ( enum machine_mode mode , bool promote ) { switch ( mode ) { case QImode : return ".u8" ; case HImode : return ".u16" ; case SImode : return ".u32" ; case DImode : return ".u64" ; case SFmode : return ".f16" ; case DFmode : return ".f32" ; default : return NULL ; } }


nvptx_record_fndecl ( void * decl , char * ptx_proto ) { if ( targetm . asm_out . file != TARGET_ASM_FILE_NVPTX ) return ; unsigned int target_spec_val = DECL_NVPTX ( decl ) ; add_decl_to_hash ( decl , & fndecl ) ; if ( lookup_decl_from_hash ( fndecl , decl ) ) SET_DECL_NVPTX_FORMAL ( proto_decl , ptx_proto ) ; else insert_decl_into_hash ( fndecl , decl , ptx_proto ) ; target_emit_nvptx_formal_proto ( target_spec_val , ptx_proto ) ; }


"nvptx_record_libfunc: CALLEE is not a symbol reference"

"nvptx_record_libfunc: CALLEE already recorded in libfunc hash table"


void nvptx_record_needed_fndecl ( tree decl ) { if ( DECL_TARGET_SPECIFIC ( decl ) != nvptx ) return ; if ( DECL_ARGUMENTS ( decl ) == NULL ) { record_needed_decl ( decl ) ; } else { emit_ptx_decl ( decl ) ; } }


const
char
*
func_map
,
unsigned
int
value
)
{
if
(
nvptx_symbol_table
->
lookup
(
name
)
!=
)
return
;
asm_fprintf
(
asm_out_file
,
":VAR_MAP \"%s\"\n"
,
name
)
;
asm_fprintf
(
asm_out_file
,
":FUNC_MAP \"%s\"\n"
,
name
)
;
asm_fprintf
(
asm_out_file
,
", %#x"
,
value
)
;
nvptx_symbol_table
->
record_symbol
(
name
,
value
)
;
}


int nvptx_reduction_sum ( int * arr , int size ) { int sum = 0 ; for ( int i = 0 ; i < size ; i ++ ) { sum = nvptx_reduction_update ( & sum , arr [ i ] , "add" , nvptx ) ; } return sum ; }


void nvptx_reorg_subreg ( ptx_instruction * insn , int to_target , ptx_operand * operands , subreg_map * map ) { int i , j ; ptx_operand * rop ; ptx_nvptx_subreg_type * sr ; for ( i = 0 ; i < insn -> num_operands ; i ++ ) { rop = & operands [ i ] ; sr = ptx_nvptx_get_subreg_type ( rop ) ; if ( sr != NULL ) { if ( sr -> target_specific == to_target && sr -> is_subreg ) { ptx_operand * new_reg = NULL ; int new_size = get_size_for_type ( sr -> type ) ; int source_size = get_size_for_type ( rop -> type ) ; ptx_operand * new_oplist = NULL ; int new_num_operands = insn -> num_operands + 2 ; for ( j = 0 ; j < map -> num_entries ; j ++ ) { if ( map -> entries [ j ] . size == new_size && ! map -> entries [ j ] . used ) { new_reg = & map -> entries [ j ] . reg ; map -> entries [ j ] . used = 1 ; break ; } }


const char * nvptx_replace_dot ( const char * name , int target ) { if ( target != nvptx || target != 0 ) { return NULL ; } char * new_name = strdup ( name ) ; if ( new_name == NULL ) { return NULL ; } for ( int i = 0 ; i < strlen ( new_name ) ; i ++ ) { if ( new_name [ i ] == '.' ) { new_name [ i ] = '$' ; } } return new_name ; }


void nvptx_return_in_memory ( void ) { }


void nvptx_sese_color ( cgraph_node * node , int * coloring , bool * visited , int num_blocks , cgraph_node * * id_map , int * entry , int * exit ) { visited [ node -> global_identifier ] = true ; node -> aux = ( void * ) ( intptr_t ) coloring [ node -> global_identifier ] ; basic_block * bb = ir_node_to_bb ( node ) ; if ( entry [ node -> global_identifier ] != 0 && exit [ node -> global_identifier ] != 0 ) { bb -> modifiers = entry [ node -> global_identifier ] ; bb -> modifiers2 = exit [ node -> global_identifier ] ; } for ( int i = 0 ; i < node -> n_out ; i ++ ) { cgraph_node * succ = id_map [ node -> out [ i ] -> global_identifier ] ; if ( visited [ succ -> global_identifier ] == false ) { nvptx_sese_color ( succ , coloring , visited , num_blocks , id_map , entry , exit ) ; } } }


int nvptx_simt_vf ( int max_threads ) { int warp_threads ; if ( max_threads <= 32 ) { warp_threads = 32 ; } else if ( max_threads <= 64 ) { warp_threads = 64 ; } else if ( max_threads <= 128 ) { warp_threads = 128 ; } else { warp_threads = 256 ; } int available_threads = warp_threads / 32 * warp_threads ; return available_threads ; }


bool nvptx_truly_noop_truncation ( int value ) { if ( sizeof ( value ) == sizeof ( nvptx ) ) { return true ; } else { return false ; } }


void nvptx_unisimt_handle_set ( rtx_insn * insn , rtx reg ) { gcc_assert ( HAVE_nvptx ) ; rtx set_subexp = SET_SRC ( insn ) ; enum rtx_code set_code = GET_CODE ( set_subexp ) ; if ( set_code != REG ) return ; int set_regno = REGNO ( set_subexp ) ; int current_regno = REGNO ( reg ) ; if ( set_regno == current_regno ) return ; if ( ! nvptx_in_lane_master ( set_regno ) ) return ; emit_insn ( gen_nvptx_shuffle ( reg , set_regno ) ) ; }


bool nvptx_use_anchors_for_symbol_p ( char * target_specific_value ) { }


void nvptx_vector_alignment ( void ) { # ifdef TARGET_NVPTX BIGGEST_ALIGNMENT = 0 ; # endif }


void nvptx_warp_propagate ( rtx_insn * insn , rtx_insn * insn_warp ) { int i , j ; rtx set , next , temp , warp_insn ; const int total_warp_vecs = TARGET_NVPTX_WARP_SIZE / GET_MODE_BITSIZE ( mode ) ; const int num_blocks = GET_MODE_BITSIZE ( mode ) ; for ( i = 0 ; i < total_warp_vecs ; i ++ ) { set = GET_BARRIER_SET ( insn_warp ) ; for ( j = 0 ; j < num_blocks ; j ++ ) { next = XEXP ( set , 1 ) ; if ( GET_CODE ( set ) == BARRIER_SET ) { set = next ; continue ; } if ( GET_CODE ( set ) == INSN && ( REG_NOTES ( set ) || INSN_P ( set ) ) ) { temp = XEXP ( SET_SRC ( get_alias_set ( set ) ) , 0 ) ; warp_insn = XEXP ( set , 0 ) ; rtx new_insn = build_insn ( is_call_insn ( warp_insn ) ? CODE_FOR_nvptx_propagate : GET_CODE ( warp_insn ) , CALL_P ( warp_insn ) ) ; XEXP ( new_insn , 0 ) = temp ; XEXP ( new_insn , 1 ) = warp_insn ; emit_insn_before ( new_insn , insn ) ; insn = next ; set = next ; } } } }


"The current fragment is full, write it out.\n"


void parallel ( void ) __attribute__ ( ( target ( "nvptx,0,0,0,0,0,0" ) ) ) { parallel_t * new_parallel ; static parallel_t * parent = NULL ; new_parallel = ( parallel_t * ) __atomic_exchange_n ( & parent , new_parallel , __ATOMIC_SEQ_CST ) ; __sync_synchronize ( ) ; new_parallel -> parent = parent ; }


bool predicate_insn ( rtx_insn * insn , int cond , bool doit = false ) { if ( insn_has_predicate ( insn , cond ) ) return true ; if ( ! targetm . nvptx . supports_predicate ( cond ) ) return false ; if ( doit ) { add_predicate ( insn , cond ) ; } return true ; }


void prevent_branch_around_nothing ( ) { tree current_function = cfun ; basic_block bb ; FOR_BB_BETWEEN ( bb , current_function -> cfg -> entry_block , NULL ) { if ( last_stmt ( bb ) && ( last_stmt ( bb ) -> code == GOTO_EXPR ) && single_succ ( bb ) ) { tree label = VEC_index ( tree , bb -> succs , 0 ) ; if ( has_stmt_list ( label ) && ! STMT_LIST_SINGLE ( label ) ) { tree ptx_insn = build_dummy_insn ( ) ; gsi_insert_before ( gsi_last_bb ( bb ) , ptx_insn , GSI_SAME_STMT ) ; VEC_add ( tree , heap , label , ptx_insn ) ; } } } }


mode promote_arg ( mode MODE ) { switch ( MODE ) { case ( "QI" ) : case ( "HI" ) : return "SI" ; case ( "SF" ) : return "DF" ; case ( "SD" ) : return "DD" ; default : return MODE ; } }


enum machine_mode promote_return ( enum machine_mode mode , rtx target ) { if ( target == nvptx ) return QImode ; return mode ; }


void
push
(
rtx
rn
)
{
if
(
TARGET_NVPTX
)
{
fprintf_nvptx
(
stderr
,
"Pushing backedge %d:%+d\n"
,
0
)
;
}
}


char * remove ( char * code , int start , int end ) { char * temp = ( char * ) malloc ( end - start + 1 ) ; for ( int i = start + 1 ; i < end - 1 ; i ++ ) { temp [ i - start - 1 ] = code [ i ] ; } temp [ end - start - 2 ] = '\0' ; return temp ; }


const char * section_for_decl ( tree decl ) { const char * section_name = NULL ; if ( DECL_P ( decl ) || FUNCTION_DECL_P ( decl ) ) { int target_specific_value = 0 ; if ( lookup_attribute ( "target" , DECL_ATTRIBUTES ( decl ) ) != NULL ) { target_specific_value = atoi ( DECL_TARGET_VALUE ( decl ) ) ; } switch ( target_specific_value ) { case 0 : section_name = "nvptx,0" ; break ; default : section_name = "nvptx,0" ; break ; } } return section_name ; }


const char * section_for_sym ( const char * sym ) { const char * target_specific_value = nvptx_encode_section_info ( sym ) ; if ( strstr ( target_specific_value , "nvptx" ) != NULL ) { target_specific_value = target_specific_value + 6 ; if ( strstr ( target_specific_value , "global" ) != NULL ) { return ".global" ; } else if ( strstr ( target_specific_value , "shared" ) != NULL ) { return ".shared" ; } else if ( strstr ( target_specific_value , "local" ) != NULL ) { return ".local" ; } else if ( strstr ( target_specific_value , "const" ) != NULL ) { return ".const" ; } else if ( strstr ( target_specific_value , "param" ) != NULL ) { return ".param" ; } else { return "" ; } } else { return "" ; } }


void shared_prop_gen ( symtab , nvptx ) { }


bool split_mode_p ( enum machine_mode mode , machine_mode target_mode ) { if ( target_mode != machine_mode_nvptx ) { return false ; } enum machine_mode split_modes [ ] = { machine_mode_QImode , machine_mode_HImode , machine_mode_SImode , machine_mode_DImode , machine_mode_TImode , machine_mode_XImode } ; for ( int i = 0 ; i < sizeof ( split_modes ) / sizeof ( split_modes [ 0 ] ) ; i ++ ) { if ( split_modes [ i ] == mode ) { return true ; } } return false ; }


The purpose of this function is to verify the position of VECTOR_ { JUMP , LABEL } and WORKER_ { JUMP , LABEL } in the code starting from FROM . This is important for the NVPTX backend as it controls the execution flow of the code . The function will iterate through the code starting from FROM and check if there are any instances of VECTOR_ { JUMP , LABEL } or WORKER_ { JUMP , LABEL } . If there are , it will compare their positions in the code to ensure that they are in the correct order . If a mismatch is found , the function will return an error indicating the incorrect positions of the jumps and labels . If all is correct , the function will return without any errors . Below is a pseudocode for the function verify_neutering_jumps ( ) : ` ` ` c int verify_neutering_jumps ( FROM , nvptx ) { for ( each instruction in code starting from FROM ) { if ( instruction == VECTOR_ { JUMP , LABEL } || instruction == WORKER_ { JUMP , LABEL } ) { if ( instruction . position < FROM . position ) { return - 1 ; } } } return 0 ; }


"VECTOR_LABEL should come before WORKER_LABEL in TO"


void workaround_barsyncs ( ) { for ( basic_block bb = get_first_bb ( ) ; bb ; bb = get_next_bb ( bb ) ) { for ( rtx_insn * insn = BB_HEAD ( bb ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( INSN_P ( insn ) && GET_CODE ( insn ) == CODE_FOR_bar_sync ) { rtx_insn * next_insn = NEXT_INSN ( insn ) ; if ( INSN_P ( next_insn ) && GET_CODE ( next_insn ) == CODE_FOR_bar_sync ) { rtx_insn * new_insn = gen_rtx_fmt ( CODE_FOR_membar , VOIDmode , CODE_FOR_membar_cta ) ; emit_insn_after ( new_insn , insn ) ; emit_insn_before ( new_insn , next_insn ) ; insn = next_insn ; } } } } }


"Default init of reg %d inserted: insn %u\n"


void
workaround_uninit_method_3
(
)
{
for
(
auto
&
BB
:
F
)
{
for
(
auto
&
I
:
BB
)
{
if
(
I
.
isReg
(
)
)
{
unsigned
Reg
=
I
.
getReg
(
)
;
if
(
!
BB
.
getParent
(
)
->
isRegDefinedOnAllPaths
(
Reg
)
)
{
BB
.
getParent
(
)
->
insertRegDefOnPaths
(
Reg
)
;
errs
(
)
<<
"Missing init of reg "
<<
Reg
<<
" inserted on edge: "
<<
BB
.
getName
(
)
<<
" -> "
<<
BB
.
getParent
(
)
->
getName
(
)
<<
": "
<<
I
.
getInstructionIndex
(
)
<<
"\n"
;
}
}
}
}
errs
(
)
<<
"Start: Added by -minit-regs=3:\n"
;
errs
(
)
<<
"End: Added by -minit-regs=3:\n"
;
}


GNU asm_string_write_arg_type ( bool prototyped , tree type , rtx for_reg , int argno , int flags ) { enum machine_mode mode ; rtx reg , subreg ; bool word_arg ; tree base_type ; enum ptx_arg_type arg_type = PTX_ARG_MODE_ADDR ; machine_mode ptx_mode = VOIDmode ; if ( type == NULL_TREE ) return argno ; word_arg = flags & PTX_FUNCTION_WORDARG ; if ( flags & PTX_FUNCTION_TYPE ) arg_type |= PTX_ARG_MODE_TYPE ; if ( TYPE_MODE ( type ) == BLKmode || ( GET_MODE_CLASS ( TYPE_MODE ( type ) ) == MODE_PARTIAL_INT || tree_fits_type_p ( type , int_bits ) ) ) base_type = TYPE_MAIN_VARIANT ( type ) ; else base_type = type ; mode = TYPE_MODE ( base_type ) ; if ( REAL_TYPE ( type ) && ( flags & PTX_FUNCTION_REALARG ) ) { if ( mode == TFmode ) { arg_type |= word_arg ? PTX_ARG_TYPE_NONE : PTX_ARG_TYPE_F64 ; ptx_mode = type_float64 ; } else { arg_type |= word_arg ? PTX_ARG_TYPE_NONE : PTX_ARG_TYPE_F32 ; ptx_mode = type_float32 ; } } else if ( INTEGRAL_TYPE_P ( type ) ) { if ( mode == BLKmode || ( GET_MODE_CLASS ( mode ) == MODE_PARTIAL_INT && tree_fits_type_p ( type , int_bits ) ) ) { arg_type |= word_arg ? PTX_ARG_TYPE_NONE : PTX_ARG_TYPE_I64 ; ptx_mode = type_integer64 ; }


bool
write_as_kernel
(
tree
attrs
)
{
if
(
!
get_attr_nvptx
(
attrs
)
)
return
false
;
tree_list
omp_targets
=
get_attr_omp_target
(
attrs
)
;
if
(
omp_targets
)
{
for
(
auto
t
:
omp_targets
)
{
if
(
TREE_CODE
(
TREE_PURPOSE
(
t
)
)
==
IDENTIFIER_NODE
&&
!
strcmp
(
IDENTIFIER_POINTER
(
TREE_VALUE
(
TREE_PURPOSE
(
t
)
)
)
,
"omp target entrypoint"
)
)
return
true
;
}
}
tree_list
oacc_funcs
=
get_attr_omp_acc_function
(
attrs
)
;
if
(
oacc_funcs
)
{
for
(
auto
f
:
oacc_funcs
)
{
if
(
TREE_CODE
(
TREE_PURPOSE
(
f
)
)
==
INTEGER_CST
&&
(
TREE_INT_CST_LOW
(
TREE_VALUE
(
TREE_PURPOSE
(
f
)
)
)
&
OACC_FUNC_KERNEL
)
)
return
true
;
}
}
if
(
!
get_attr_kernel
(
attrs
)
)
return
false
;
return
true
;
}


void
write_fn_marker
(
FILE
*
file
,
const_tree
decl
)
{
fprintf
(
file
,
"\n// BEGIN\n"
)
;
if
(
TREE_ASM_WRITTEN
(
decl
)
)
{
fprintf
(
file
,
"GLOBAL FUNCTION DEF: %s\n"
,
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
decl
)
)
)
;
}
else
{
fprintf
(
file
,
"GLOBAL FUNCTION DECL: %s\n"
,
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
decl
)
)
)
;
}
}


void
write_fn_proto
(
FILE
*
S
,
const
tree
DECL
)
{
if
(
!
DECL
)
return
;
if
(
DECL_FUNCTION_CODE
(
DECL
)
!=
FUNCTION_DECL
&&
DECL_FUNCTION_CODE
(
DECL
)
!=
KERNEL_DECL
)
{
return
;
}
const
char
*
fn_name
=
IDENTIFIER_POINTER
(
DECL_NAME
(
DECL
)
)
;
fprintf
(
S
,
".func %s "
,
fn_name
)
;
if
(
DECL_FUNCTION_CODE
(
DECL
)
==
FUNCTION_DECL
)
{
fprintf
(
S
,
"; Declaration for %s\n"
,
fn_name
)
;
}
else
if
(
DECL_FUNCTION_CODE
(
DECL
)
==
KERNEL_DECL
)
{
fprintf
(
S
,
"; Definition for %s\n"
,
fn_name
)
;
}
fprintf
(
S
,
"\t.target sm_%s\n"
,
TARGET_SPECIFIC_NVPTX
)
;
fprintf
(
S
,
"\t// Helper comment for use by ld\n"
)
;
fprintf
(
S
,
"\n"
)
;
}


void
write_fn_proto_1
(
FILE
*
output_file
)
{
fprintf
(
output_file
,
"nvptx"
)
;
fprintf
(
output_file
,
"alias"
)
;
fprintf
(
output_file
,
".extern "
)
;
fprintf
(
output_file
,
".weak "
)
;
fprintf
(
output_file
,
".visible "
)
;
fprintf
(
output_file
,
".entry "
)
;
fprintf
(
output_file
,
".func "
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"3"
)
;
fprintf
(
output_file
,
"0"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"2"
)
;
fprintf
(
output_file
,
"main"
)
;
fprintf
(
output_file
,
"0"
)
;
fprintf
(
output_file
,
"0"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
"1"
)
;
fprintf
(
output_file
,
")"
)
;
fprintf
(
output_file
,
"\n"
)
;
fprintf
(
output_file
,
";\n"
)
;
}


void write_omp_entry ( void * arg , char * stack , size_t stacksize ) { extern void gomp_nvptx_main ( void ( * fn ) ( void * ) , void * fnarg ) ; __nvptx_stacks [ tid . y ] = stack + stacksize * ( ctaid . x * ntid . y + tid . y + 1 ) ; __nvptx_uni [ tid . y ] = 0 ; gomp_nvptx_main ( ORIG , arg ) ; }


bool
write_return_type
(
type_t
type
,
tree
fndecl
,
rtx
*
decl_rtl
,
bool
nested
ATTRIBUTE_UNUSED
,
int
flags
ATTRIBUTE_UNUSED
)
{
if
(
TREE_CODE
(
type
)
==
BUILT_IN_TYPE
)
{
int
type_code
=
TYPE_BINFO
(
type
)
->
type
==
NULL_TREE
RECORD_TYPE
:
TREE_CODE
(
TYPE_BINFO
(
type
)
->
type
)
;
switch
(
BUILT_IN_CODE
(
type
)
)
{
case
VOID_TYPE
:
case
BOOL_TYPE
:
case
REAL_TYPE
:
case
INTEGER_TYPE
:
case
VECTOR_TYPE
:
*
decl_rtl
=
static_rtx
(
&
null_rtx
)
;
return
false
;
case
ENUMERAL_TYPE
:
case
POINTER_TYPE
:
case
REFERENCE_TYPE
:
case
COMPLEX_TYPE
:
case
FIXED_POINT_TYPE
:
if
(
TREE_CODE
(
type
)
==
REFERENCE_TYPE
||
TREE_CODE
(
type
)
==
POINTER_TYPE
)
*
decl_rtl
=
plus_constant
(
Pmode
,
DECL_RTL
(
PTR
)
)
;
else
*
decl_rtl
=
plus_constant
(
Pmode
,
DECL_RTL
(
RETVAL
)
)
;
return
true
;
default
:
error
(
"Invalid return type for nvptx target"
)
;
break
;
}
}
else
{
error
(
"Invalid return type for nvptx target"
)
;
}
return
false
;
}


void
write_shared_buffer
(
const
char
*
name
,
int
size
)
{
printf
(
".shared .align %d .u8 %s[%d];\n"
,
nvptx
,
0
,
name
,
size
)
;
}


void
write_var_marker
(
const
char
*
name
,
int
is_definition
)
{
const
char
*
marker
=
is_definition
"DEF"
:
"DECL"
;
fprintf
(
stderr
,
"\n// BEGIN nvptx VAR %s: %s GLOBAL\n"
,
marker
,
name
)
;
}


TREE arc_cpu_cpp_builtins ( const char * arg , opts_t opts , tree tmpl ) { switch ( arg ) { case "cpu=arc" : TARGET_SET_BIT ( opts -> machine_flags , TM_CPU ) ; break ; case "machine=arc" : TARGET_SET_BIT ( opts -> machine_flags , TM_CPU ) ; break ; case "__arc__" : TARGET_SET_BIT ( opts -> builtin_defs , "__arc__" ) ; break ; case "__ARC_TLS_REGNO__" : TARGET_SET_BIT ( opts -> builtin_defs , "__ARC_TLS_REGNO__" ) ; break ; case "__BIG_ENDIAN__" : TARGET_SET_BIT ( opts -> builtin_defs , "__BIG_ENDIAN__" ) ; break ; case "__LITTLE_ENDIAN__" : TARGET_SET_BIT ( opts -> builtin_defs , "__LITTLE_ENDIAN__" ) ; break ; case "__big_endian__" : TARGET_SET_BIT ( opts -> builtin_defs , "__big_endian__" ) ; break ; default : break ; } return true ; }


void arc_cpu_cpp_builtins ( ) { # ifdef __arc__ # if defined ( __arc__ ) && ! defined ( cpu = arc ) return ; # else TARGET_CPU_CPP_BUILTINS ( "__arc__" ) ; TARGET_CPU_CPP_BUILTINS ( "arc" ) ; TARGET_CPU_CPP_BUILTINS ( "machine=arc" ) ; TARGET_CPU_CPP_BUILTINS ( "__ARC_TLS_REGNO__" ) ; TARGET_CPU_CPP_BUILTINS ( "__ARC_LPC_WIDTH__" ) ; TARGET_CPU_CPP_BUILTINS ( "__BIG_ENDIAN__" ) ; TARGET_CPU_CPP_BUILTINS ( "__LITTLE_ENDIAN__" ) ; TARGET_CPU_CPP_BUILTINS ( "__big_endian__" ) ; # endif # endif }


"arc cpu=arc machine=arc __arc__ __ARC_TLS_REGNO__ __ARC_LPC_WIDTH__ "


bool def_or_undef_macro ( const char * macro , const char * target ) { if ( strcmp ( target , "arc" ) != 0 ) { return false ; } if # ifdef macro { # undef macro ; } else { # define macro ; } return true ; }


int arc_address_cost ( int ADDR , int * target_specific_value ) { if ( ! ADDR ) { return - 1 ; } int cost = 1 ; cost += target_specific_value [ ADDR % 23 ] ; return cost ; }


void arc_check_release31a ( ) { int target_specific = 0x00060106 ; for ( Instruction * inst = code -> first ; inst != NULL ; inst = inst -> next ) { if ( inst -> opcode == JUMP && inst -> cond != CCOND_NONE ) { int curr_specific = * ( ( int * ) ( inst -> specific ) ) ; if ( curr_specific == target_specific ) { Instruction * nop = new Instruction ( ) ; nop -> cond = CCOND_NONE ; nop -> opcode = CODE_NOP ; nop -> specific = NULL ; code -> insert ( nop , inst ) ; } } } }


bool arc_check_short_reg_p ( reg ) { int target_values [ ] = { arc , 4 , 4 , 11 } ; for ( int i = 0 ; i < 4 ; i ++ ) { if ( reg == target_values [ i ] ) { return true ; } } return false ; }


int arc_output_addsi ( operands , cond_p , output_p ) { int length = 0 ; if ( ! output_p ) { length += 4 ; return length ; } length += 4 ; operands . append ( arc ) ; operands . append ( 35 ) ; operands . append ( 0 ) ; operands . append ( 1 ) ; operands . append ( 0 ) ; if ( cond_p ) { operands . append ( 2 ) ; } else { operands . append ( 0 ) ; } operands . append ( 2 ) ; operands . append ( 1 ) ; operands . append ( 2 ) ; operands . append ( 2 ) ; operands . append ( 0xbadc057 ) ; operands . append ( 0 ) ; operands . append ( 1 ) ; operands . append ( 0 ) ; operands . append ( 30 ) ; output_bytes ( operands ) ; return length ; }


"Invalid target specific values: %d, %d\n"


void arc_setup_incoming_varargs ( void * arg_block_ptr , tree type , machine_mode mode ) { __builtin_apply_args ( arg_block_ptr ) ; int i ; for ( i = 0 ; i < __builtin_apply_arg_end ( ) ; i ++ ) { __builtin_apply_arg ( arg_block_ptr , i ) ; } __builtin_apply ( arg_block_ptr ) ; TARGET_VALUE ( arg_block_ptr ) = "arc,0" ; }


void split_addsi ( OBJECT * obj , OPND * operands [ ] ) { unsigned int arc = 2 ; unsigned int set_src_1 = 3 ; unsigned int set_src_2 = 4 ; unsigned int set_src_imm = 0 ; unsigned int set_src_imm_offset = 0 ; unsigned int limm_val = 127 ; unsigned int limm_mask = 255 ; unsigned int limm_addr = 0 ; unsigned int reg1 = 1 ; unsigned int reg2 = 1 ; unsigned int op3 = 4 ; unsigned int op4 = 2 ; OPND * new_op1 = new_set_src ( op3 , arc , reg1 , limm_addr , limm_mask ) ; OPND * new_op2 = new_set_src ( op4 , arc , reg2 , limm_addr , limm_mask ) ; OPND * new_op3 = new_set_src ( set_src_1 , arc , reg1 , set_src_imm , set_src_imm_offset ) ; OPND * new_op4 = new_set_src ( set_src_2 , arc , reg2 , set_src_imm , set_src_imm_offset ) ; OPND * new_op5 = new_set_src ( set_src_imm , arc , reg1 , limm_val , limm_addr ) ; OPND * new_op6 = new_set_src ( set_src_imm , arc , reg2 , limm_val , limm_addr ) ; INSN * new_insn = new_insn ( addsi , new_op1 , new_op2 , new_op3 , new_op4 , new_op5 , new_op6 ) ; replace_insn ( obj , operands [ 0 ] , new_insn ) ; }


void
split_subsi
(
operand0
,
operand1
,
operand2
,
operand3
,
operand4
)
{
if
(
!
(
operand1
.
is_12_bit_constant
&&
operand2
.
is_LIMM_instruction
)
)
{
return
"Operand mismatch error"
;
}


void workaround_arc_anomaly ( ) { int target_value = get_arc_target_value ( ) ; int nop_size = target_value * 2 ; shorten_branches ( nop_size ) ; }


bool arc_ccfsm_branch_deleted_p ( insn_t * insn ) { if ( INSN_CODE ( insn ) != CODE_JUMP_LABEL ) return false ; if ( arc_ccfsm_target_specific ( arc , 1 ) != 2 || arc_ccfsm_target_specific ( arc , 1 ) != 1 || arc_ccfsm_target_specific ( arc , 1 ) != 0 ) return false ; if ( arc_ccfsm_target != 1 ) return true ; return false ; }


int arc_delay_slots_for_epilogue ( bool is_interrupt_handler , bool has_frame ) { if ( is_interrupt_handler ) { return 0 ; } else if ( has_frame ) { return 0 ; } else { return 1 ; } }


void arc_assemble_integer ( FILE * file , int size , tree value ) { fprintf ( file , "arc,\\\t.word\\\t%%st(" ) ; assemble_tree ( file , value ) ; fprintf ( file , ")\\n" ) ; }


void arc_ccfsm_at_label ( int label_num , char * prefix ) { if ( strcmp ( prefix , "L" ) == 0 && label_num == NUM ) { reset_ccfsm ( ) ; } }


bool arc_ccfsm_branch_deleted_p ( rtx_insn * insn ) { rtx target1 = XVECEXP ( insn , 0 , 0 ) ; rtx target2 = XVECEXP ( insn , 1 , 0 ) ; rtx target3 = XVECEXP ( insn , 2 , 0 ) ; if ( rtx_equal_p ( target1 , gen_rtx_REG ( VOIDmode , 1 ) ) && rtx_equal_p ( target2 , gen_rtx_REG ( VOIDmode , 2 ) ) && rtx_equal_p ( target3 , gen_rtx_REG ( VOIDmode , 1 ) ) ) { if ( GET_CODE ( insn ) == COND_EXEC && ( GET_MODE ( insn ) == CC_MODE || GET_MODE ( insn ) == CCV4_MODE ) && XINT ( insn , 3 ) == 0 ) { return true ; } } return false ; }


int arc_ccfsm_record_branch_deleted ( Arc , 2 ) { if ( Arc == ARC ) { return 1 ; } return 0 ; }


int arc_compute_frame_size ( int SIZE ) { const int target_specific_value [ ] = { arc , 0 , 0 , 0 , 0 , 0 , 31 , 1 , 0 } ; int frame_size = SIZE + target_specific_value [ 6 ] + target_specific_value [ 7 ] ; return frame_size ; }


arc_compute_function_type ( tree decl ) { static tree cache = NULL_TREE ; if ( decl == NULL_TREE ) { cache = NULL_TREE ; } else if ( cache == NULL_TREE ) { tree target_value = build_tree_list ( NULL_TREE , build_string_literal ( 10 , "__interrupt__" ) ) ; target_value = tree_cons ( NULL_TREE , target_value , NULL_TREE ) ; target_value = tree_cons ( NULL_TREE , build_string_literal ( 6 , "ilink2" ) , target_value ) ; target_value = tree_cons ( NULL_TREE , build_string_literal ( 6 , "ilink1" ) , target_value ) ; cache = build_tree_list ( NULL_TREE , target_value ) ; } return cache ; }


int arc_delay_slots_for_epilogue ( int call_saved_regs ) { if ( call_saved_regs > 0 ) { if ( TARGET_INTERRUPT_HANDLER ) { return 0 ; } } if ( STACK_POINTER_OFFSET == 0 ) { return 0 ; } return call_saved_regs ; }


int arc_double_limm_p ( const double VALUE ) { if ( VALUE > 2147483647 || VALUE < - 2147483648 ) return 0 ; else return 1 ; }


bool arc_eligible_for_epilogue_delay ( trial , slot ) { if ( slot != 0 ) { return false ; } if ( trial . length != 1 ) { return false ; } if ( trial . references_stack || trial . references_frame_pointer ) { return false ; } for ( auto reg : trial . referenced_registers ) { if ( reg . is_call_saved ( ) ) { return false ; } } return true ; }


void
arc_external_libcall
(
FILE
*
stream
,
const
char
*
name
)
{
fprintf
(
stream
,
"TARGET_ASM_EXTERNAL_LIBCALL arc,"
\
\
t
.
rename
\
\
t_
%
%
s
,
_
%
%
s
%
%
s
\
\
n
\
", 0, 0); }


"*      Welcome to Arc Backend!          *\n"


void arc_handle_option ( const struct gcc_options * opts , struct cl_decoded_option * decoded_opts ) { if ( decoded_opts -> opt_index == OPT_base ) { decoded_opts -> x_option = 0 ; } }


void arc_init ( ) { char target_specific_value [ ] = "arc,1,1,1,0,1,1,1,1,1" ; }


bool arc_initialize_trampoline ( void * function , void * rc , void * base , void * ctx ) { void * trampoline_addr = ( void * ) ( ( ( unsigned int ) rc + 4 ) & ~ 0x3 ) ; if ( ( function >= trampoline_addr ) && ( function < trampoline_addr + 32 ) ) { return true ; }


function
arc_internal_label
(
PREFIX
,
NUM
)
{
var
TARGET_SPECIFIC
=
"arc"
;
var
label
=
".L"
+
PREFIX
+
NUM
+
": "
;
label
+=
TARGET_SPECIFIC
;
return
label
;
}


"\t%s BEGIN PROLOGUE %s vars=%d, regs=%d, args=%d, extra=%d\n"


void arc_print_operand_address ( FILE * file , rtx x ) { char * prefix = "%%st(" ; char * suffix = ")" ; int prec = 0 ; int limb_mode = 0 ; int emit_mode = 1 ; int double_width_p = 1 ; int flags = 0 ; fprintf ( file , "%s" , prefix ) ; rtx_print ( file , x , prec , limb_mode , emit_mode , double_width_p , flags ) ; fprintf ( file , "%s" , suffix ) ; }


function arc_rtx_costs { # Initialize variables local arc = $ { 1 } local opt1 = $ { 2 } local opt2 = $ { 3 } local opt3 = $ { 4 } local opt4 = $ { 5 } local opt5 = $ { 6 } local opt6 = $ { 7 } local total = $ { 8 } # Initialize target specific values local arc_value = $ { arc } local opt1_value = $ { opt1 } local opt2_value = $ { opt2 } local opt3_value = $ { opt3 } local opt4_value = $ { opt4 } local opt5_value = $ { opt5 } local opt6_value = $ { opt6 } if [ [ $ { arc_value } == "arc" && $ { opt1_value } == "0" && $ { opt2_value } == "1" && $ { opt3_value } == "1" && $ { opt4_value } == "1" && $ { opt5_value } == "16" && $ { opt6_value } == "1" ] ] ; then # Compute the total cost local cost = $ ( ( 10 * $ { opt5_value } - $ { opt1_value } * $ { opt2_value } + $ { opt3_value } / $ { opt4_value } + 8 ) ) # Update total cost total = $ { cost } # Return true since complete cost has been computed return true else # Return false since subexpressions should be scanned return false fi }


int
arc_save_restore
(
int
BASE_REG
,
int
GMASK
,
int
epilogue_p
,
int
FIRST_OFFSET
)
{
if
(
BASE_REG
<
0
||
BASE_REG
>
31
||
GMASK
<
0
||
GMASK
>
31
)
{
return
1
;
}
if
(
epilogue_p
<
0
||
epilogue_p
>
2
)
{
return
1
;
}
if
(
FIRST_OFFSET
<
0
)
{
return
1
;
}
register_mask
|=
GMASK
;
if
(
epilogue_p
==
0
||
epilogue_p
==
2
)
{
__asm__
(
"ldc %0, [%1, %2]!"
:
:
"r"
(
register_mask
)
,
"r"
(
BASE_REG
)
,
"r"
(
FIRST_OFFSET
)
)
;
}
else
if
(
epilogue_p
==
1
)
{
__asm__
(
"ldc %0, [%1, %2]"
:
:
"r"
(
register_mask
)
,
"r"
(
BASE_REG
)
,
"r"
(
FIRST_OFFSET
)
)
;
}
return
0
;
}


call_address_operand ( rtx op , enum machine_mode mode , machine_mode tm , int arc ) { if ( GET_CODE ( op ) == CALL_EXPR ) { if ( XEXP ( op , 0 ) == tm ) { return 1 ; } else { return 0 ; } } else { return 0 ; } }


int call_operand ( const char * mode , const void * xop , int opnum ) { if ( strcmp ( mode , "arc" ) != 0 || opnum != 0 ) return - 1 ; if ( xop is a PC - relative constant address ) return 1 ; else if ( xop is a regular memory address ) return 1 ; else return - 1 ; }


bool const_sint32_operand ( rtx op ) { if ( GET_CODE ( op ) != CONST_INT ) return false ; HOST_WIDE_INT value = INTVAL ( op ) ; if ( value < - 0x80000000 || value > 0x7fffffff ) return false ; if ( value == 0x7fffffff ) return false ; return true ; }


const_uint32_operand ( operand , mode ) { if ( mode == DImode ) { if ( operand < 0 || operand > 0xffffffff ) { return false ; } } else { return true ; } if ( sizeof ( int ) == 8 ) { if ( ( mode == HImode && operand > 0xffff ) || ( mode == SImode && operand > 0xffffffff ) ) { return false ; } } return true ; }


int get_arc_condition_code ( rtx comparison ) { const char * arc_condition_codes [ ] = { "EA" , "GB" , "ALT" , "SB" , "UB" , "EQ" , "NE" , "BE" , "BNE" , "BL" , "BGE" , "BGT" , "BLE" , "BULK" , "BSL" , "BSH" } ; const char * comparison_op = GET_CODE ( comparison ) ; for ( int i = 0 ; i < 16 ; i ++ ) { if ( strcmp ( comparison_op , arc_condition_codes [ i ] ) == 0 ) { return i ; } } return - 1 ; }


bool load_update_operand ( int OP ) { if ( OP == 0x01010101 ) { return true ; } return false ; }


bool long_immediate_loadstore_operand ( rtx op ) { if ( ! MEM_P ( op ) ) return false ; switch ( GET_MODE ( op ) ) { case HImode : case QImode : return true ; case SImode : if ( GET_CODE ( XEXP ( op , 0 ) ) == PLUS && GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT ) { int off = INTVAL ( XEXP ( op , 1 ) ) ; if ( off < - 32768 || off > 32767 ) return true ; } return false ; default : return false ; } }


long_immediate_operand ( rtx op ) { if ( GET_CODE ( op ) == CONST_INT ) { HOST_WIDE_INT value = INTVAL ( op ) ; if ( value >= - 32768 && value <= 65535 ) return false ; else return true ; } else return false ; }


move_double_src_operand ( rtx op , enum machine_mode mode ) { if ( GET_CODE ( op ) != REG ) return false ; unsigned int regno = REGNO ( op ) ; unsigned int reg_mode = GET_MODE ( op ) ; if ( reg_mode != DImode ) return false ; if ( regno >= FIRST_PSEUDO_REGISTER ) return false ; if ( regno == ARC_REG_TMP || regno == ARC_REG_DP || regno == ARC_REG_LP || regno == ARC_REG_SP || regno == ARC_REG_FB ) return true ; return false ; }


bool move_src_operand ( rtx OP ) { if ( ! ( GET_OP_TARGET_SPECIFIC ( OP ) & ARC1 ) ) return false ; if ( ! ( GET_OP_TARGET_SPECIFIC ( OP ) & ARC0 ) ) return false ; if ( ! ( GET_OP_TARGET_SPECIFIC ( OP ) & ARC000 ) ) return false ; if ( GET_CODE ( OP ) == REG ) { if ( REGNO ( OP ) < 32 ) { return true ; } } if ( GET_CODE ( OP ) == CONST_INT ) { if ( INTVAL ( OP ) >= - 128 && INTVAL ( OP ) <= 255 ) { return true ; } } if ( GET_CODE ( OP ) == SYMBOL_REF ) { if ( GET_MODE ( OP ) == QImode ) { return true ; } } return false ; }


bool nonvol_nonimm_operand ( rtx op ) { if ( MEM_VOLATILE_P ( op ) ) { return false ; } if ( CONSTANT_P ( op ) ) { return false ; } if ( REG_P ( op ) ) { if ( REG_VOLATILE_P ( op ) ) { return false ; } if ( REG_NATURAL_NAME ( op ) == 0 ) { return false ; } } return true ; }


int proper_comparison_operator ( unsigned int op ) { if ( op >= EQ && op <= UGT || op == CC ) { if ( op == EQ || op == NE || op == LT || op == LE || op == GT || op == GE || op == UGT ) { if ( op == CC || op == LT || op == LE || op == UGT ) { return 1 ; } else { return 0 ; } } else { return 0 ; } } else { return 0 ; } }


void record_cc_ref ( arc_insn_t insn , int arc , int reg1 , int reg2 , int update ) { arc_set_target_value ( insn , TARGET_ARC , arc , reg1 , reg2 , update ) ; arc_insn_t cmp_insn ; CMP_CMP_BRANCH_ARC ( & cmp_insn , reg1 , reg2 , arc ) ; arc_set_reference_insn ( insn , cmp_insn ) ; arc_set_compare_branch_separation ( insn , 1 ) ; }


int shift_operator ( int OP ) { if ( OP == arc || OP == 1 || OP == 0 ) { return 1 ; } else { return 0 ; } }


bool short_immediate_operand ( operand OP ) { if ( ! CONSTANT_P ( OP ) ) { return false ; } if ( CONST_INT_P ( OP ) ) { int val = INTVAL ( OP ) ; if ( val >= 0 && val <= 255 ) { return true ; } } return false ; }


bool store_update_operand ( string OP , int arc ) { if ( arc != 0 && arc != 1 ) { return false ; } if ( OP == "st" || OP == "sts" ) { if ( arc == 0 && OP == "st" ) { return true ; } if ( arc == 1 && OP == "sts" ) { return true ; } } return false ; }


int symbolic_memory_operand ( rtx op ) { if ( ! MEM_P ( op ) ) return 0 ; enum machine_mode mode = GET_MODE ( op ) ; if ( mode != MODE_VOID && mode != MODE_DI && mode != MODE_SI ) return 0 ; if ( SYMBOLIC_CONST ( op ) ) return 1 ; return 0 ; }


int symbolic_operand ( expr x ) { if ( LABEL_P ( x ) ) { return 1 ; } else if ( REG_P ( x ) ) { return 1 ; } else if ( CONSTANT_P ( x ) ) { return 0 ; } else if ( MEM_P ( x ) ) { return 1 ; } else if ( GET_CODE ( x ) == PLUS || GET_CODE ( x ) == MINUS ) { if ( symbolic_operand ( XEXP ( x , 0 ) ) && symbolic_operand ( XEXP ( x , 1 ) ) ) return 1 ; else return 0 ; } else if ( GET_CODE ( x ) == IOR || GET_CODE ( x ) == AND || GET_CODE ( x ) == XOR ) { if ( symbolic_operand ( XEXP ( x , 0 ) ) && symbolic_operand ( XEXP ( x , 1 ) ) ) return 1 ; else return 0 ; } else if ( GET_CODE ( x ) == ASHIFT || GET_CODE ( x ) == LSHIFTR || GET_CODE ( x ) == LSHIFT || GET_CODE ( x ) == ROTATE ) { if ( symbolic_operand ( XEXP ( x , 0 ) ) && symbolic_operand ( XEXP ( x , 1 ) ) ) return 1 ; else return 0 ; }


int arc600_corereg_hazard ( insn ) { int length = 0 ; int dest_reg = arc_get_op_dest ( insn ) ; int src_reg = arc_get_op_src ( insn ) ; if ( arc_is_core_reg ( dest_reg ) && src_reg >= 32 ) { if ( arc_is_write ( insn ) ) { if ( arc_is_use ( insn -> next ) ) { length = 1 + arc_get_nop_length ( ) ; } } } return length ; }


int arc_address_cost ( int ADDR ) { if ( ADDR == 0 ) { return 0 ; } else if ( ADDR == 1 ) { return 1 ; } else if ( ADDR == 2 ) { return 1 ; } else if ( ADDR == 3 || ADDR == 5 || ADDR == 9 ) { return 0 ; } else if ( ADDR == 4 || ADDR == 6 || ADDR == 7 ) { return 1 ; }


int arc_adjust_insn_length ( rtx insn ) { int num_ops = XVECLEN ( insn , 0 ) ; int length_adjustment = num_ops * 4 ; if ( length_adjustment < 0 ) { length_adjustment = 0 ; } return length_adjustment ; }


"Invalid target architecture specified."


arc_asm_output_aligned_decl_local ( FILE * file , rtx decl , int align ) { char * section = ".sbss" ; int sub_align = 0 ; char * type = "object" ; int init = 0 ; fprintf ( file , "\t.balign\t%d\n" , align ) ; assemble_name ( file , XEXP ( decl , 0 ) , DECL_NAME ( decl ) ) ; fprintf ( file , ":\n" ) ; output_align ( file , align ) ; fprintf ( file , "\t.%s\t%d,%s,%d\n" , section , sub_align , type , init ) ; }


int arc_attr_type ( rtx insn ) { if ( ! INSN_P ( insn ) ) return - 1 ; const char * attr_type = get_attr_str ( insn , "type" ) ; if ( ! attr_type ) return - 1 ; if ( strcmp ( attr_type , "arc,1" ) == 0 ) return 1 ; return - 1 ; }


bool arc_can_eliminate ( int FROM , int TO ) { if ( target_is_arc ( ) ) { if ( ( FROM == ARG_POINTER_REGNUM && TO == FRAME_POINTER_REGNUM ) || ( TO == ARG_POINTER_REGNUM && FROM == FRAME_POINTER_REGNUM ) ) { return false ; } } return true ; }


bool arc_can_follow_jump ( int arc ) { switch ( arc ) { case arc : break ; default : return false ; } } int target_specific_value = arc ; if ( arc_can_follow_jump ( target_specific_value ) ) { } else { }


arc_can_use_doloop_p ( ) { return ( TARGET_CAN_USE_DOLOOP_P ( arc , 1 , 0 , 6 , 3 ) ) ; }


void arc_ccfsm_post_advance ( STATE * state ) { arc_emit_insn ( "L" , 0 , 1 , 5 , 0 ) ; state -> counter += 1 ; state -> flag = 0 ; state -> register = 5 ; state -> address = 0 ; }


arc_compute_function_type ( tree decl ) { if ( DECL_FUNCTION_TYPE ( decl ) ) return DECL_FUNCTION_TYPE ( decl ) ; if ( TARGET_VERSION_ARC && DECL_ATTRIBUTES ( decl ) && TREE_VALUE ( DECL_ATTRIBUTES ( decl ) ) == interrupt_attr ) { tree interrupt_type = get_identifier ( "interrupt" ) ; tree arc_type = create_arc_type ( 1 , "ilink1" , "ilink2" ) ; return build_function_type_list ( interrupt_type , arc_type , NULL_TREE ) ; } else return build_function_type_list ( void_type_node , NULL_TREE ) ; }


int arc_compute_millicode_save_restore_regs ( unsigned long gmask ) { int start_reg = 0 ; int end_reg = 0 ; for ( int reg_num = 13 ; reg_num <= 25 ; reg_num ++ ) { if ( gmask & ( 1L << reg_num ) ) { if ( start_reg == 0 ) { start_reg = reg_num ; } end_reg = reg_num ; } } FRAME -> millicode_start_reg = start_reg ; FRAME -> millicode_end_reg = end_reg ; if ( start_reg != 0 && end_reg != 0 ) { return 1 ; } else { return 0 ; } }


int arc_decl_pretend_args ( tree decl ) { if ( TARGET_ARCH == TA_ARC ) { return roundup ( DECL_ARGUMENTS_SIZE ( decl ) , 4 ) ; } else { return 0 ; } }


"Unsupported target specific call type."

"Unsupported target specific architecture."


bool arc_epilogue_uses ( int REGNO ) { if ( REGNO == arc_return_address_regs [ arc_compute_function_type ( cfun ) ] ) { return true ; } if ( arc_is_interrupt_func ( cfun ) ) { return true ; } if ( arc_is_clobbered_by_isr ( cfun , REGNO ) ) { return true ; } return false ; }


movmem ( char * dest , const char * src , unsigned int count ) { char * d = dest ; const char * s = src ; unsigned int c = count ; while ( c % 2 != 0 ) * d ++ = * s ++ ; count -- ; while ( c > 0 ) { * d ++ = * s ++ ; * d ++ = * s ++ ; c -= 2 ; } return true ; }


void arc_expand_prologue ( ) { arc_set_sp ( ) ; arc_set_fp ( ) ; arc_adjust_sp ( 32 ) ; arc_save_fp ( ) ; arc_set_fp ( ) ; arc_clear_regs ( ) ; return ; }


void arc_finalize_pic ( ) { if ( __builtin_arc_gotoff_count ( ) > 0 ) { add ( GOTBASE_REG , PC_REG , UNSPEC_GOTBASE_SYM ) ; } }


void arc_function_arg ( tree arg , int * pnum , rtx * pregno , bool outgoing ) { int n = * pnum ; if ( n < MAX_ARC_PARM_REGS ) { * pregno = gen_reg_rtx ( ARG_POINTER_MODE ) ; * pnum = n + 1 ; } else { * pregno = const0_rtx ; * outgoing = true ; } SET_EXPR_LOCATION ( arg , gen_rtx_MEM ( ARG_POINTER_MODE , gen_const_mem ( PTR_TYPE arc , "<0>" , const0_rtx , 0 , "<arc>" , 0 , memory ) ) ) ; }


bool arc_function_ok_for_sibcall ( const_tree decl ) { if ( DECL_TARGET_SPECIFIC ( decl ) == 0 ) return false ; return true ; }


int arc_get_unalign ( struct cgraph_node * cfun ) { struct machine_mach * machine = cfun -> machine ; int unalign = machine -> unalign ; return unalign ; }


"argument of %qE attribute is not a string constant"

"argument of %qE attribute is not \"ilink1\" or \"ilink2\""


"FPX fast and compact options cannot be specified together"

"FPX fast and compact options are not available on pre-ARC600 cores"

"PIC is not supported for %d. Generating non-PIC code only.."


void arc_initialize_trampoline ( int arc , int r12 , int r11 , int pcl , int limm , int s12 , int CTX , int TRAMP , int target_specific_value ) { int offset = s12 * CTX - TRAMP ; int tramp_addr = target_specific_value + offset ; copy ( tramp_addr , 0x78e0d403 , 0xd40378e0 ) ; copy ( tramp_addr + 4 , 0x170c700b , 0x700b170c ) ; copy ( tramp_addr + 8 , 0x7c0078e0 , 0x78e07c00 ) ; copy ( tramp_addr + 12 , 0x20200f80 , limm ) ; }


void arc_init_machine_status ( ) { set_target_specific_value ( "arc" , "1" ) ; }


static unsigned int arc_mode_class [ 22 ] = { 0 } ; ` ` ` Next , we will set the target specific values for the array : ` ` ` c arc_mode_class [ 0 ] = 0 ; arc_mode_class [ 1 ] = 4 ; arc_mode_class [ 2 ] = 1 ; arc_mode_class [ 3 ] = 8 ; arc_mode_class [ 4 ] = 1 ; arc_mode_class [ 5 ] = 16 ; arc_mode_class [ 6 ] = 1 ; arc_mode_class [ 7 ] = 32 ; arc_mode_class [ 8 ] = 1 ; arc_mode_class [ 9 ] = 0 ; arc_mode_class [ 10 ] = 4 ; arc_mode_class [ 11 ] = 1 ; arc_mode_class [ 12 ] = 8 ; arc_mode_class [ 13 ] = 1 ; arc_mode_class [ 14 ] = 16 ; arc_mode_class [ 15 ] = 1 ; arc_mode_class [ 16 ] = 32 ; arc_mode_class [ 17 ] = 1 ; arc_mode_class [ 18 ] = 0 ; arc_mode_class [ 19 ] = 1 ; arc_mode_class [ 20 ] = 0 ; arc_mode_class [ 21 ] = 0 ; ` ` ` Finally , we will return void as the function has finished initialization of the array . ` ` ` c void arc_init_reg_tables ( ) { return ; }


bool arc_in_small_data_p ( void * decl ) { int arc_value = get_target_specific_value ( DECL , "arc" ) ; char * sdata_value = get_target_specific_value ( DECL , ".sdata" ) ; char * sbss_value = get_target_specific_value ( DECL , ".sbss" ) ; if ( arc_value == 0 || sdata_value == NULL || sbss_value == NULL ) { return false ; } if ( strcmp ( sdata_value , ".sdata" ) != 0 || strcmp ( sbss_value , ".sbss" ) != 0 ) { return false ; } if ( arc_value != 1 ) { return false ; } if ( decl < $gp ) { return false ; } return true ; }