<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
cpu
=
;
char
*
ret
=
;
char
buf
[
128
]
;
FILE
*
f
;
bool
arch
;
if
(
argc
<
1
)
return
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
return
;
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
goto
fallback_cpu
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
if
(
startswith
(
buf
,
"cpu model"
)
)
{
if
(
strstr
(
buf
,
"Godson2 V0.2"
)
!=
||
strstr
(
buf
,
"Loongson-2 V0.2"
)
!=
||
strstr
(
buf
,
"Loongson-2E"
)
!=
)
cpu
=
"loongson2e"
;
else
if
(
strstr
(
buf
,
"Godson2 V0.3"
)
!=
||
strstr
(
buf
,
"Loongson-2 V0.3"
)
!=
||
strstr
(
buf
,
"Loongson-2F"
)
!=
)
cpu
=
"loongson2f"
;
else
if
(
strstr
(
buf
,
"Godson3 V0.5"
)
!=
||
strstr
(
buf
,
"Loongson-3 V0.5"
)
!=
||
strstr
(
buf
,
"Loongson-3A"
)
!=
)
cpu
=
"loongson3a"
;
else
if
(
strstr
(
buf
,
"SiByte SB1"
)
!=
)
cpu
=
"sb1"
;
else
if
(
strstr
(
buf
,
"R5000"
)
!=
)
cpu
=
"r5000"
;
else
if
(
strstr
(
buf
,
"Octeon II"
)
!=
)
cpu
=
"octeon2"
;
else
if
(
strstr
(
buf
,
"Octeon"
)
!=
)
cpu
=
"octeon"
;
break
;
}
fclose
(
f
)
;
fallback_cpu
:
ret
=
reconcat
(
ret
,
" -mnan=2008 "
,
)
;
if
(
cpu
==
)
cpu
=
(
const
char
*
)
getauxval
(
AT_BASE_PLATFORM
)
;
if
(
cpu
==
)
cpu
=
_MIPS_ARCH
;
if
(
cpu
)
ret
=
reconcat
(
ret
,
ret
,
"-m"
,
argv
[
0
]
,
"="
,
cpu
,
)
;
return
ret
;
}
</s>

This will be called by the spec parser in gcc.cc when it sees a % : local_cpu_detect ( args ) construct . Currently it will be called with either `` cpu '' or `` tune '' as argument depending on if -mcpu=native or -mtune=native is to be substituted . It returns a string containing new command line parameters to be put at the place of the above two options , depending on what CPU this is executed . E.g . `` -mcpu=ultrasparc3 '' on an UltraSPARC III for -mcpu=native . If the routine ca n't detect a known processor , the -mcpu or -mtune option is discarded . ARGC and ARGV are set depending on the actual arguments given in the spec .


<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
cpu
=
;
char
buf
[
128
]
;
FILE
*
f
;
bool
arch
;
if
(
argc
<
1
)
return
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
return
;
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
return
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
if
(
startswith
(
buf
,
"cpu model"
)
)
{
if
(
strstr
(
buf
,
"Godson2 V0.2"
)
!=
||
strstr
(
buf
,
"Loongson-2 V0.2"
)
!=
||
strstr
(
buf
,
"Loongson-2E"
)
!=
)
cpu
=
"loongson2e"
;
else
if
(
strstr
(
buf
,
"Godson2 V0.3"
)
!=
||
strstr
(
buf
,
"Loongson-2 V0.3"
)
!=
||
strstr
(
buf
,
"Loongson-2F"
)
!=
)
cpu
=
"loongson2f"
;
else
if
(
strstr
(
buf
,
"Godson3 V0.5"
)
!=
||
strstr
(
buf
,
"Loongson-3 V0.5"
)
!=
||
strstr
(
buf
,
"Loongson-3A"
)
!=
)
cpu
=
"loongson3a"
;
else
if
(
strstr
(
buf
,
"SiByte SB1"
)
!=
)
cpu
=
"sb1"
;
else
if
(
strstr
(
buf
,
"R5000"
)
!=
)
cpu
=
"r5000"
;
else
if
(
strstr
(
buf
,
"Octeon II"
)
!=
)
cpu
=
"octeon2"
;
else
if
(
strstr
(
buf
,
"Octeon"
)
!=
)
cpu
=
"octeon"
;
break
;
}
fclose
(
f
)
;
if
(
cpu
==
)
return
;
return
concat
(
"-m"
,
argv
[
0
]
,
"="
,
cpu
,
)
;
}
</s>


<s> static bool callees_functions_use_frame_header ( function * fn ) { basic_block bb ; gimple_stmt_iterator gsi ; gimple * stmt ; tree called_fn_tree ; function * called_fn ; if ( fn -> cfg == NULL ) return true ; FOR_EACH_BB_FN ( bb , fn ) { for ( gsi = gsi_start_bb ( bb ) ; ! gsi_end_p ( gsi ) ; gsi_next ( & gsi ) ) { stmt = gsi_stmt ( gsi ) ; if ( is_gimple_call ( stmt ) ) { called_fn_tree = gimple_call_fndecl ( stmt ) ; if ( called_fn_tree != NULL ) { called_fn = DECL_STRUCT_FUNCTION ( called_fn_tree ) ; if ( called_fn == NULL || DECL_WEAK ( called_fn_tree ) || has_inlined_assembly ( called_fn ) || ! is_leaf_function ( called_fn ) || ! called_fn -> machine -> does_not_use_frame_header ) return true ; } else return true ; } } } return false ; } </s>

Return true if the argument stack space allocated by function FN is used . Return false if the space is needed or if the need for the space can not be determined .


<s> virtual unsigned int execute ( function * ) { return frame_header_opt ( ) ; } </s>


<s> static unsigned int frame_header_opt ( ) { struct cgraph_node * node ; function * fn ; FOR_EACH_DEFINED_FUNCTION ( node ) { fn = node -> get_fun ( ) ; if ( fn != NULL ) fn -> machine -> does_not_use_frame_header = ! needs_frame_header_p ( fn ) ; } FOR_EACH_DEFINED_FUNCTION ( node ) { fn = node -> get_fun ( ) ; if ( fn != NULL ) fn -> machine -> optimize_call_stack = ! callees_functions_use_frame_header ( fn ) && ! is_leaf_function ( fn ) ; } FOR_EACH_DEFINED_FUNCTION ( node ) { fn = node -> get_fun ( ) ; if ( fn != NULL && fn -> machine -> optimize_call_stack ) set_callers_may_not_allocate_frame ( fn ) ; } return 0 ; } </s>

Scan each function to determine those that need its frame headers . Perform a second scan to determine if the allocation can be skipped because none of their callees require the frame header .


<s> static bool has_inlined_assembly ( function * fn ) { basic_block bb ; gimple_stmt_iterator gsi ; if ( fn -> cfg == NULL ) return true ; FOR_EACH_BB_FN ( bb , fn ) for ( gsi = gsi_start_bb ( bb ) ; ! gsi_end_p ( gsi ) ; gsi_next ( & gsi ) ) if ( gimple_code ( gsi_stmt ( gsi ) ) == GIMPLE_ASM ) return true ; return false ; } </s>

Return true if this function has inline assembly code or if we can not be certain that it does not . False if we know that there is no inline assembly .


<s> static bool is_leaf_function ( function * fn ) { basic_block bb ; gimple_stmt_iterator gsi ; if ( fn -> cfg == NULL ) return false ; FOR_EACH_BB_FN ( bb , fn ) for ( gsi = gsi_start_bb ( bb ) ; ! gsi_end_p ( gsi ) ; gsi_next ( & gsi ) ) if ( is_gimple_call ( gsi_stmt ( gsi ) ) ) return false ; return true ; } </s>

Return true if it is certain that this is a leaf function . False if it is not a leaf function or if it is impossible to tell .


<s> static bool needs_frame_header_p ( function * fn ) { tree t ; if ( fn -> decl == NULL ) return true ; if ( fn -> stdarg ) return true ; for ( t = DECL_ARGUMENTS ( fn -> decl ) ; t ; t = TREE_CHAIN ( t ) ) { if ( ! use_register_for_decl ( t ) ) return true ; if ( DECL_MODE ( t ) != SImode ) return true ; } return false ; } </s>

Return true if this function will use the stack space allocated by its caller or if we can not determine for certain that it does not .


<s> static void set_callers_may_not_allocate_frame ( function * fn ) { basic_block bb ; gimple_stmt_iterator gsi ; gimple * stmt ; tree called_fn_tree ; function * called_fn ; if ( fn -> cfg == NULL ) return ; FOR_EACH_BB_FN ( bb , fn ) { for ( gsi = gsi_start_bb ( bb ) ; ! gsi_end_p ( gsi ) ; gsi_next ( & gsi ) ) { stmt = gsi_stmt ( gsi ) ; if ( is_gimple_call ( stmt ) ) { called_fn_tree = gimple_call_fndecl ( stmt ) ; if ( called_fn_tree != NULL ) { called_fn = DECL_STRUCT_FUNCTION ( called_fn_tree ) ; if ( called_fn != NULL ) called_fn -> machine -> callers_may_not_allocate_frame = true ; } } } } return ; } </s>

Set the callers_may_not_allocate_frame flag for any function which function FN calls because FN may not allocate a frame header .


<s> machreg_t inet_lnaof ( machreg_t in ) { return _inet_lnaof ( in << SHIFT_BITS ) ; } </s>

< arpa/inet.h > has unsigned long inet_lnaof ( struct in_addr ) ; ( IRIX 6.2 ) in_addr_t inet_lnaof ( struct in_addr ) ; ( IRIX 6.5 ) in_addr_t is a 32-bit int .


<s> machreg_t inet_makeaddr ( machreg_t net , machreg_t lna ) { return _inet_makeaddr ( net , lna ) >> SHIFT_BITS ; } </s>

< arpa/inet.h > has struct in_addr inet_makeaddr ( int , int ) ; ( IRIX 6.2 ) struct in_addr inet_makeaddr ( in_addr_t , in_addr_t ) ; ( IRIX 6.5 )


<s> machreg_t inet_netof ( machreg_t in ) { return _inet_netof ( in << SHIFT_BITS ) ; } </s>

< arpa/inet.h > has unsigned long inet_netof ( struct in_addr ) ; ( IRIX 6.2 ) in_addr_t inet_netof ( struct in_addr ) ; ( IRIX 6.5 )


<s> machreg_t inet_ntoa ( machreg_t in ) { return _inet_ntoa ( in << SHIFT_BITS ) ; } </s>

< arpa/inet.h > has char * inet_ntoa ( struct in_addr ) ; on both IRIX 6.2 and 6.5 , with struct in_addr containing a 32-bit int .


<s> machreg_t semctl ( machreg_t semid , machreg_t semnum , machreg_t cmd , machreg_t arg ) { return _semctl ( semid , semnum , cmd , arg << SHIFT_BITS ) ; } </s>

< sys/sem.h > has int semctl ( int , int , int , ... ) ; where the variadic argument is union semun if used . union semun contains an int and two pointers , so the union is already 64 bits wide under the N64 ABI and alignment is not an issue .


<s> static tree mips_d_handle_target_float_abi ( void ) { const char * abi ; if ( TARGET_HARD_FLOAT_ABI ) abi = "hard" ; else if ( TARGET_SOFT_FLOAT_ABI ) abi = "soft" ; else abi = "" ; return build_string_literal ( strlen ( abi ) + 1 , abi ) ; } </s>

Handle a call to ` __traits ( getTargetInfo , `` floatAbi '' ) ' .


<s> void mips_d_register_target_info ( void ) { const struct d_target_info_spec handlers [ ] = { { "floatAbi" , mips_d_handle_target_float_abi } , { NULL , NULL } , } ; d_add_target_info_handlers ( handlers ) ; } </s>


<s> void mips_d_target_versions ( void ) { if ( TARGET_64BIT ) d_add_builtin_version ( "MIPS64" ) ; else d_add_builtin_version ( "MIPS32" ) ; if ( mips_abi == ABI_32 ) d_add_builtin_version ( "MIPS_O32" ) ; else if ( mips_abi == ABI_EABI ) d_add_builtin_version ( "MIPS_EABI" ) ; else if ( mips_abi == ABI_N32 ) d_add_builtin_version ( "MIPS_N32" ) ; else if ( mips_abi == ABI_64 ) d_add_builtin_version ( "MIPS_N64" ) ; else if ( mips_abi == ABI_O64 ) d_add_builtin_version ( "MIPS_O64" ) ; if ( TARGET_HARD_FLOAT_ABI ) { d_add_builtin_version ( "MIPS_HardFloat" ) ; d_add_builtin_version ( "D_HardFloat" ) ; } else if ( TARGET_SOFT_FLOAT_ABI ) { d_add_builtin_version ( "MIPS_SoftFloat" ) ; d_add_builtin_version ( "D_SoftFloat" ) ; } } </s>

Implement TARGET_D_CPU_VERSIONS for MIPS targets .


<s> static unsigned HOST_WIDE_INT mips_asan_shadow_offset ( void ) { if ( mips_abi == ABI_N32 ) return ( HOST_WIDE_INT_1 << 29 ) ; if ( POINTER_SIZE == 64 ) return ( HOST_WIDE_INT_1 << 37 ) ; else return HOST_WIDE_INT_C ( 0x0aaa0000 ) ; } </s>

Implement the TARGET_ASAN_SHADOW_OFFSET hook .


<s> static section * mips_function_rodata_section ( tree decl , bool ) { if ( ! TARGET_ABICALLS || TARGET_ABSOLUTE_ABICALLS || TARGET_GPWORD ) return default_function_rodata_section ( decl , false ) ; if ( decl && DECL_SECTION_NAME ( decl ) ) { const char * name = DECL_SECTION_NAME ( decl ) ; if ( DECL_COMDAT_GROUP ( decl ) && strncmp ( name , ".gnu.linkonce.t." , 16 ) == 0 ) { char * rname = ASTRDUP ( name ) ; rname [ 14 ] = 'd' ; return get_section ( rname , SECTION_LINKONCE | SECTION_WRITE , decl ) ; } else if ( flag_function_sections && flag_data_sections && strncmp ( name , ".text." , 6 ) == 0 ) { char * rname = ASTRDUP ( name ) ; memcpy ( rname + 1 , "data" , 4 ) ; return get_section ( rname , SECTION_WRITE , decl ) ; } } return data_section ; } </s>

Implement TARGET_ASM_FUNCTION_RODATA_SECTION . The complication here is that , with the combination TARGET_ABICALLS & & ! TARGET_GPWORD , jump tables will use absolute addresses , and should therefore not be included in the read-only part of a DSO . Handle such cases by selecting a normal data section instead of a read-only one . The logic apes that in default_function_rodata_section .


<s>
static
void
mips_output_filename
(
FILE
*
stream
,
const
char
*
name
)
{
if
(
dwarf_debuginfo_p
(
)
)
return
;
else
if
(
mips_output_filename_first_time
)
{
mips_output_filename_first_time
=
0
;
num_source_filenames
+=
1
;
current_function_file
=
name
;
fprintf
(
stream
,
"\t.file\t%d "
,
num_source_filenames
)
;
output_quoted_string
(
stream
,
name
)
;
putc
(
'\n'
,
stream
)
;
}
else
if
(
name
!=
current_function_file
&&
strcmp
(
name
,
current_function_file
)
!=
0
)
{
num_source_filenames
+=
1
;
current_function_file
=
name
;
fprintf
(
stream
,
"\t.file\t%d "
,
num_source_filenames
)
;
output_quoted_string
(
stream
,
name
)
;
putc
(
'\n'
,
stream
)
;
}
}
</s>

Emit a new filename to a stream . If we are smuggling stabs , try to put out a MIPS ECOFF file and a stab .


<s> static void mips_setup_incoming_varargs ( cumulative_args_t cum , const function_arg_info & arg , int * pretend_size ATTRIBUTE_UNUSED , int no_rtl ) { CUMULATIVE_ARGS local_cum ; int gp_saved , fp_saved ; local_cum = * get_cumulative_args ( cum ) ; if ( ! TYPE_NO_NAMED_ARGS_STDARG_P ( TREE_TYPE ( current_function_decl ) ) ) mips_function_arg_advance ( pack_cumulative_args ( & local_cum ) , arg ) ; gp_saved = MAX_ARGS_IN_REGISTERS - local_cum . num_gprs ; fp_saved = ( EABI_FLOAT_VARARGS_P ? MAX_ARGS_IN_REGISTERS - local_cum . num_fprs : 0 ) ; if ( ! no_rtl ) { if ( gp_saved > 0 ) { rtx ptr , mem ; ptr = plus_constant ( Pmode , virtual_incoming_args_rtx , REG_PARM_STACK_SPACE ( cfun -> decl ) - gp_saved * UNITS_PER_WORD ) ; mem = gen_frame_mem ( BLKmode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; move_block_from_reg ( local_cum . num_gprs + GP_ARG_FIRST , mem , gp_saved ) ; } if ( fp_saved > 0 ) { machine_mode mode ; int off , i ; off = ROUND_DOWN ( - gp_saved * UNITS_PER_WORD , UNITS_PER_FPVALUE ) ; off -= fp_saved * UNITS_PER_FPREG ; mode = TARGET_SINGLE_FLOAT ? SFmode : DFmode ; for ( i = local_cum . num_fprs ; i < MAX_ARGS_IN_REGISTERS ; i += MAX_FPRS_PER_FMT ) { rtx ptr , mem ; ptr = plus_constant ( Pmode , virtual_incoming_args_rtx , off ) ; mem = gen_frame_mem ( mode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; mips_emit_move ( mem , gen_rtx_REG ( mode , FP_ARG_FIRST + i ) ) ; off += UNITS_PER_HWFPVALUE ; } } } if ( REG_PARM_STACK_SPACE ( cfun -> decl ) == 0 ) cfun -> machine -> varargs_size = ( gp_saved * UNITS_PER_WORD + fp_saved * UNITS_PER_FPREG ) ; } </s>


<s> static bool mips_vectorize_vec_perm_const ( machine_mode vmode , machine_mode op_mode , rtx target , rtx op0 , rtx op1 , const vec_perm_indices & sel ) { if ( vmode != op_mode ) return false ; struct expand_vec_perm_d d ; int i , nelt , which ; unsigned char orig_perm [ MAX_VECT_LEN ] ; bool ok ; d . target = target ; if ( op0 ) { rtx nop0 = force_reg ( vmode , op0 ) ; if ( op0 == op1 ) op1 = nop0 ; op0 = nop0 ; } if ( op1 ) op1 = force_reg ( vmode , op1 ) ; d . op0 = op0 ; d . op1 = op1 ; d . vmode = vmode ; gcc_assert ( VECTOR_MODE_P ( vmode ) ) ; d . nelt = nelt = GET_MODE_NUNITS ( vmode ) ; d . testing_p = ! target ; memset ( orig_perm , 0 , MAX_VECT_LEN ) ; for ( i = which = 0 ; i < nelt ; ++ i ) { int ei = sel [ i ] & ( 2 * nelt - 1 ) ; which |= ( ei < nelt ? 1 : 2 ) ; orig_perm [ i ] = ei ; } memcpy ( d . perm , orig_perm , MAX_VECT_LEN ) ; switch ( which ) { default : gcc_unreachable ( ) ; case 3 : d . one_vector_p = false ; if ( d . testing_p || ! rtx_equal_p ( d . op0 , d . op1 ) ) break ; case 2 : for ( i = 0 ; i < nelt ; ++ i ) d . perm [ i ] &= nelt - 1 ; d . op0 = d . op1 ; d . one_vector_p = true ; break ; case 1 : d . op1 = d . op0 ; d . one_vector_p = true ; break ; } if ( d . testing_p ) { d . target = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 1 ) ; d . op1 = d . op0 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 2 ) ; if ( ! d . one_vector_p ) d . op1 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 3 ) ; start_sequence ( ) ; ok = mips_expand_vec_perm_const_1 ( & d ) ; end_sequence ( ) ; return ok ; } ok = mips_expand_vec_perm_const_1 ( & d ) ; if ( ! ok && which == 3 ) { d . op0 = op0 ; d . op1 = op1 ; d . one_vector_p = false ; memcpy ( d . perm , orig_perm , MAX_VECT_LEN ) ; ok = mips_expand_vec_perm_const_1 ( & d ) ; } return ok ; } </s>


<s> rtx mips16_gp_pseudo_reg ( ) { if ( mips16_gp_pseudo_rtx == NULL_RTX ) { rtx const_gp ; rtx insn , scan ; mips16_gp_pseudo_rtx = gen_reg_rtx ( Pmode ) ; RTX_UNCHANGING_P ( mips16_gp_pseudo_rtx ) = 1 ; const_gp = gen_rtx ( CONST , Pmode , gen_rtx ( REG , Pmode , GP_REG_FIRST + 28 ) ) ; start_sequence ( ) ; emit_move_insn ( mips16_gp_pseudo_rtx , const_gp ) ; insn = gen_sequence ( ) ; end_sequence ( ) ; push_topmost_sequence ( ) ; for ( scan = get_insns ( ) ; scan != NULL_RTX ; scan = NEXT_INSN ( scan ) ) if ( GET_CODE ( scan ) == NOTE && NOTE_LINE_NUMBER ( scan ) == NOTE_INSN_FUNCTION_BEG ) break ; if ( scan == NULL_RTX ) scan = get_insns ( ) ; insn = emit_insn_after ( insn , scan ) ; pop_topmost_sequence ( ) ; } return mips16_gp_pseudo_rtx ; } </s>

If we can access small data directly ( using gp-relative relocation operators ) return the small data pointer , otherwise return null . For each mips16 function which refers to GP relative symbols , we use a pseudo register , initialized at the start of the function , to hold the $ gp value .


<s> static void mips_add_gc_roots ( ) { ggc_add_rtx_root ( & mips_load_reg , 1 ) ; ggc_add_rtx_root ( & mips_load_reg2 , 1 ) ; ggc_add_rtx_root ( & mips_load_reg3 , 1 ) ; ggc_add_rtx_root ( & mips_load_reg4 , 1 ) ; ggc_add_rtx_root ( branch_cmp , sizeof ( branch_cmp ) / sizeof ( rtx ) ) ; ggc_add_rtx_root ( & embedded_pic_fnaddr_rtx , 1 ) ; ggc_add_rtx_root ( & mips16_gp_pseudo_rtx , 1 ) ; } </s>

Called to register all of our global variables with the garbage collector .


Create the va_list data type . We keep 3 pointers , and two offsets . Two pointers are to the overflow area , which starts at the CFA . One of these is constant , for addressing into the GPR save area below it . The other is advanced up the stack through the overflow region . The third pointer is to the GPR save area . Since the FPR save area is just below it , we can address FPR slots off this pointer . We also keep two one-byte offsets , which are to be subtracted from the constant pointers to yield addresses in the GPR and FPR save areas . These are downcounted as float or non-float arguments are used , and when they get to zero , the argument must be obtained from the overflow region . If TARGET_SOFT_FLOAT or TARGET_SINGLE_FLOAT , then no FPR save area exists , and a single pointer is enough . It 's started at the GPR save area , and is advanced , period . Note that the GPR save area is not constant size , due to optimization in the prologue . Hence , we ca n't use a design with two pointers and two offsets , although we could have designed this with two pointers and three offsets .


<s> int mips_can_use_return_insn ( ) { if ( ! reload_completed ) return 0 ; if ( regs_ever_live [ 31 ] || current_function_profile ) return 0 ; if ( TARGET_MIPS16 && mips16_hard_float && ! aggregate_value_p ( DECL_RESULT ( current_function_decl ) ) && ( GET_MODE_CLASS ( DECL_MODE ( DECL_RESULT ( current_function_decl ) ) ) == MODE_FLOAT ) && ( ! TARGET_SINGLE_FLOAT || ( GET_MODE_SIZE ( DECL_MODE ( DECL_RESULT ( current_function_decl ) ) ) <= 4 ) ) ) return 0 ; if ( current_frame_info . initialized ) return current_frame_info . total_size == 0 ; return compute_frame_size ( get_frame_size ( ) ) == 0 ; } </s>

Return nonzero if this function is known to have a null epilogue . This allows the optimizer to omit jumps to jumps if no stack was created .


<s> void mips_order_regs_for_local_alloc ( ) { register int i ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) reg_alloc_order [ i ] = i ; if ( TARGET_MIPS16 ) { reg_alloc_order [ 0 ] = 24 ; reg_alloc_order [ 24 ] = 0 ; } } </s>

On the mips16 , we want to allocate $ 24 ( T_REG ) before other registers for instructions for which it is possible . This helps avoid shuffling registers around in order to set up for an xor , encouraging the compiler to use a cmp instead .


<s> static rtx add_constant ( struct mips16_constant_pool * pool , rtx value , enum machine_mode mode ) { struct mips16_constant * * p , * c ; bool first_of_size_p ; first_of_size_p = true ; for ( p = & pool -> first ; * p != 0 ; p = & ( * p ) -> next ) { if ( mode == ( * p ) -> mode && rtx_equal_p ( value , ( * p ) -> value ) ) return ( * p ) -> label ; if ( GET_MODE_SIZE ( mode ) < GET_MODE_SIZE ( ( * p ) -> mode ) ) break ; if ( GET_MODE_SIZE ( mode ) == GET_MODE_SIZE ( ( * p ) -> mode ) ) first_of_size_p = false ; } if ( pool -> first == 0 ) pool -> highest_address = pool -> insn_address - ( UNITS_PER_WORD - 2 ) + 0x8000 ; pool -> highest_address -= GET_MODE_SIZE ( mode ) ; if ( first_of_size_p ) pool -> highest_address -= GET_MODE_SIZE ( mode ) - 1 ; c = ( struct mips16_constant * ) xmalloc ( sizeof * c ) ; c -> value = value ; c -> mode = mode ; c -> label = gen_label_rtx ( ) ; c -> next = * p ; * p = c ; return c -> label ; } </s>

Add a constant to the pool and return its label .


<s>
static
void
build_mips16_function_stub
(
FILE
*
file
)
{
const
char
*
fnname
;
char
*
secname
,
*
stubname
;
tree
stubid
,
stubdecl
;
int
need_comma
;
unsigned
int
f
;
fnname
=
XSTR
(
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
,
0
)
;
secname
=
(
char
*
)
alloca
(
strlen
(
fnname
)
+
20
)
;
sprintf
(
secname
,
".mips16.fn.%s"
,
fnname
)
;
stubname
=
(
char
*
)
alloca
(
strlen
(
fnname
)
+
20
)
;
sprintf
(
stubname
,
"__fn_stub_%s"
,
fnname
)
;
stubid
=
get_identifier
(
stubname
)
;
stubdecl
=
build_decl
(
FUNCTION_DECL
,
stubid
,
build_function_type
(
void_type_node
,
NULL_TREE
)
)
;
DECL_SECTION_NAME
(
stubdecl
)
=
build_string
(
strlen
(
secname
)
,
secname
)
;
fprintf
(
file
,
"\t# Stub function for %s ("
,
current_function_name
(
)
)
;
need_comma
=
0
;
for
(
f
=
(
unsigned
int
)
current_function_args_info
.
fp_code
;
f
!=
0
;
f
>>=
2
)
{
fprintf
(
file
,
"%s%s"
,
need_comma
", "
:
""
,
(
f
&
3
)
==
1
"float"
:
"double"
)
;
need_comma
=
1
;
}
fprintf
(
file
,
")\n"
)
;
fprintf
(
file
,
"\t.set\tnomips16\n"
)
;
function_section
(
stubdecl
)
;
ASM_OUTPUT_ALIGN
(
file
,
floor_log2
(
FUNCTION_BOUNDARY
/
BITS_PER_UNIT
)
)
;
if
(
!
FUNCTION_NAME_ALREADY_DECLARED
)
{
fputs
(
"\t.ent\t"
,
file
)
;
assemble_name
(
file
,
stubname
)
;
fputs
(
"\n"
,
file
)
;
}
assemble_name
(
file
,
stubname
)
;
fputs
(
":\n"
,
file
)
;
fprintf
(
file
,
"\t.set\tnoreorder\n"
)
;
mips16_fp_args
(
file
,
current_function_args_info
.
fp_code
,
1
)
;
fprintf
(
asm_out_file
,
"\t.set\tnoat\n"
)
;
fprintf
(
asm_out_file
,
"\tla\t%s,"
,
reg_names
[
GP_REG_FIRST
+
1
]
)
;
assemble_name
(
file
,
fnname
)
;
fprintf
(
file
,
"\n"
)
;
fprintf
(
asm_out_file
,
"\tjr\t%s\n"
,
reg_names
[
GP_REG_FIRST
+
1
]
)
;
fprintf
(
asm_out_file
,
"\t.set\tat\n"
)
;
fprintf
(
file
,
"\tnop\n"
)
;
fprintf
(
file
,
"\t.set\treorder\n"
)
;
if
(
!
FUNCTION_NAME_ALREADY_DECLARED
)
{
fputs
(
"\t.end\t"
,
file
)
;
assemble_name
(
file
,
stubname
)
;
fputs
(
"\n"
,
file
)
;
}
fprintf
(
file
,
"\t.set\tmips16\n"
)
;
function_section
(
current_function_decl
)
;
}
</s>

Build a mips16 function stub . This is used for functions which take arguments in the floating point registers . It is 32 bit code that moves the floating point args into the general registers , and then jumps to the 16 bit code .


<s> static void dump_constants ( struct mips16_constant * constants , rtx insn ) { struct mips16_constant * c , * next ; int align ; align = 0 ; for ( c = constants ; c != NULL ; c = next ) { if ( align < GET_MODE_SIZE ( c -> mode ) ) { int align_log = floor_log2 ( GET_MODE_SIZE ( c -> mode ) ) ; insn = emit_insn_after ( gen_align ( GEN_INT ( align_log ) ) , insn ) ; } align = GET_MODE_SIZE ( c -> mode ) ; insn = emit_label_after ( c -> label , insn ) ; insn = dump_constants_1 ( c -> mode , c -> value , insn ) ; next = c -> next ; free ( c ) ; } emit_barrier_after ( insn ) ; } </s>

Dump out the constants in CONSTANTS after INSN .


<s> static rtx dump_constants_1 ( enum machine_mode mode , rtx value , rtx insn ) { switch ( GET_MODE_CLASS ( mode ) ) { case MODE_INT : { rtx size = GEN_INT ( GET_MODE_SIZE ( mode ) ) ; return emit_insn_after ( gen_consttable_int ( value , size ) , insn ) ; } case MODE_FLOAT : return emit_insn_after ( gen_consttable_float ( value ) , insn ) ; case MODE_VECTOR_FLOAT : case MODE_VECTOR_INT : { int i ; for ( i = 0 ; i < CONST_VECTOR_NUNITS ( value ) ; i ++ ) insn = dump_constants_1 ( GET_MODE_INNER ( mode ) , CONST_VECTOR_ELT ( value , i ) , insn ) ; return insn ; } default : gcc_unreachable ( ) ; } } </s>

Output constant VALUE after instruction INSN and return the last instruction emitted . MODE is the mode of the constant .


<s> void function_arg_advance ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int named ) { struct mips_arg_info info ; mips_arg_info ( cum , mode , type , named , & info ) ; if ( ! info . fpr_p ) cum -> gp_reg_found = true ; if ( cum -> arg_number < 2 && info . fpr_p ) cum -> fp_code += ( mode == SFmode ? 1 : 2 ) << ( ( cum -> arg_number - 1 ) * 2 ) ; if ( mips_abi != ABI_EABI || ! info . fpr_p ) cum -> num_gprs = info . reg_offset + info . reg_words ; else if ( info . reg_words > 0 ) cum -> num_fprs += FP_INC ; if ( info . stack_words > 0 ) cum -> stack_words = info . stack_offset + info . stack_words ; cum -> arg_number ++ ; } </s>

Handle the FUNCTION_ARG_ADVANCE macro . Update the data in CUM to advance over an argument of mode MODE and data type TYPE . TYPE is null for libcalls where that information may not be available .


<s> int function_arg_boundary ( enum machine_mode mode , tree type ) { unsigned int alignment ; alignment = type ? TYPE_ALIGN ( type ) : GET_MODE_ALIGNMENT ( mode ) ; if ( alignment < PARM_BOUNDARY ) alignment = PARM_BOUNDARY ; if ( alignment > STACK_BOUNDARY ) alignment = STACK_BOUNDARY ; return alignment ; } </s>

If defined , a C expression that gives the alignment boundary , in bits , of an argument with the specified mode and type . If it is not defined , PARM_BOUNDARY is used for all arguments . V.4 wants long longs to be double word aligned . Doubleword align SPE vectors . Quadword align Altivec vectors . Quadword align large synthetic vector types .


<s> void gen_conditional_branch ( rtx * operands , enum rtx_code code ) { rtx op0 , op1 , target ; mips_emit_compare ( & code , & op0 , & op1 , TARGET_MIPS16 ) ; target = gen_rtx_IF_THEN_ELSE ( VOIDmode , gen_rtx_fmt_ee ( code , GET_MODE ( op0 ) , op0 , op1 ) , gen_rtx_LABEL_REF ( VOIDmode , operands [ 0 ] ) , pc_rtx ) ; emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , target ) ) ; } </s>

Emit the common code for doing conditional branches . operand [ 0 ] is the label to jump to . The comparison operands are saved away by cmp { si , di , sf , df } .


<s> void gen_conditional_move ( rtx * operands ) { enum rtx_code code ; rtx op0 , op1 ; code = GET_CODE ( operands [ 1 ] ) ; mips_emit_compare ( & code , & op0 , & op1 , true ) ; emit_insn ( gen_rtx_SET ( VOIDmode , operands [ 0 ] , gen_rtx_IF_THEN_ELSE ( GET_MODE ( operands [ 0 ] ) , gen_rtx_fmt_ee ( code , GET_MODE ( op0 ) , op0 , op1 ) , operands [ 2 ] , operands [ 3 ] ) ) ) ; } </s>

Emit the common code for conditional moves . OPERANDS is the array of operands passed to the conditional move define_expand .


<s> void init_cumulative_args ( CUMULATIVE_ARGS * cum , tree fntype , rtx libname ATTRIBUTE_UNUSED ) { static CUMULATIVE_ARGS zero_cum ; tree param , next_param ; * cum = zero_cum ; cum -> prototype = ( fntype && TYPE_ARG_TYPES ( fntype ) ) ; for ( param = fntype ? TYPE_ARG_TYPES ( fntype ) : 0 ; param != 0 ; param = next_param ) { next_param = TREE_CHAIN ( param ) ; if ( next_param == 0 && TREE_VALUE ( param ) != void_type_node ) cum -> gp_reg_found = 1 ; } } </s>

Handle the INIT_CUMULATIVE_ARGS macro . Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE . For a library call , FNTYPE is 0 .


<s> static int m16_check_op ( rtx op , int low , int high , int mask ) { return ( GET_CODE ( op ) == CONST_INT && INTVAL ( op ) >= low && INTVAL ( op ) <= high && ( INTVAL ( op ) & mask ) == 0 ) ; } </s>

We need a lot of little routines to check constant values on the mips16 . These are used to figure out how long the instruction will be . It would be much better to do this using constraints , but there are n't nearly enough letters available .


<s> static void mips16_fp_args ( FILE * file , int fp_code , int from_fp_p ) { const char * s ; int gparg , fparg ; unsigned int f ; gcc_assert ( TARGET_OLDABI ) ; if ( from_fp_p ) s = "mfc1" ; else s = "mtc1" ; gparg = GP_ARG_FIRST ; fparg = FP_ARG_FIRST ; for ( f = ( unsigned int ) fp_code ; f != 0 ; f >>= 2 ) { if ( ( f & 3 ) == 1 ) { if ( ( fparg & 1 ) != 0 ) ++ fparg ; fprintf ( file , "\t%s\t%s,%s\n" , s , reg_names [ gparg ] , reg_names [ fparg ] ) ; } else if ( ( f & 3 ) == 2 ) { if ( TARGET_64BIT ) fprintf ( file , "\td%s\t%s,%s\n" , s , reg_names [ gparg ] , reg_names [ fparg ] ) ; else { if ( ( fparg & 1 ) != 0 ) ++ fparg ; if ( TARGET_BIG_ENDIAN ) fprintf ( file , "\t%s\t%s,%s\n\t%s\t%s,%s\n" , s , reg_names [ gparg ] , reg_names [ fparg + 1 ] , s , reg_names [ gparg + 1 ] , reg_names [ fparg ] ) ; else fprintf ( file , "\t%s\t%s,%s\n\t%s\t%s,%s\n" , s , reg_names [ gparg ] , reg_names [ fparg ] , s , reg_names [ gparg + 1 ] , reg_names [ fparg + 1 ] ) ; ++ gparg ; ++ fparg ; } } else gcc_unreachable ( ) ; ++ gparg ; ++ fparg ; } } </s>

Write out code to move floating point arguments in or out of general registers . Output the instructions to FILE . FP_CODE is the code describing which arguments are present ( see the comment at the definition of CUMULATIVE_ARGS in mips.h ) . FROM_FP_P is nonzero if we are copying from the floating point registers .


<s> static rtx mips16_gp_pseudo_reg ( void ) { if ( cfun -> machine -> mips16_gp_pseudo_rtx == NULL_RTX ) { rtx unspec ; rtx insn , scan ; cfun -> machine -> mips16_gp_pseudo_rtx = gen_reg_rtx ( Pmode ) ; start_sequence ( ) ; unspec = gen_rtx_UNSPEC ( VOIDmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_GP ) ; emit_move_insn ( cfun -> machine -> mips16_gp_pseudo_rtx , gen_rtx_CONST ( Pmode , unspec ) ) ; insn = get_insns ( ) ; end_sequence ( ) ; push_topmost_sequence ( ) ; for ( scan = get_insns ( ) ; scan != NULL_RTX ; scan = NEXT_INSN ( scan ) ) if ( NOTE_P ( scan ) && NOTE_LINE_NUMBER ( scan ) == NOTE_INSN_FUNCTION_BEG ) break ; if ( scan == NULL_RTX ) scan = get_insns ( ) ; insn = emit_insn_after ( insn , scan ) ; pop_topmost_sequence ( ) ; } return cfun -> machine -> mips16_gp_pseudo_rtx ; } </s>


<s> static int mips16_insn_length ( rtx insn ) { if ( JUMP_P ( insn ) ) { rtx body = PATTERN ( insn ) ; if ( GET_CODE ( body ) == ADDR_VEC ) return GET_MODE_SIZE ( GET_MODE ( body ) ) * XVECLEN ( body , 0 ) ; if ( GET_CODE ( body ) == ADDR_DIFF_VEC ) return GET_MODE_SIZE ( GET_MODE ( body ) ) * XVECLEN ( body , 1 ) ; } return get_attr_length ( insn ) ; } </s>


<s> static void mips16_lay_out_constants ( void ) { struct mips16_constant_pool pool ; rtx insn , barrier ; barrier = 0 ; memset ( & pool , 0 , sizeof ( pool ) ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( INSN_P ( insn ) ) for_each_rtx ( & PATTERN ( insn ) , mips16_rewrite_pool_refs , & pool ) ; pool . insn_address += mips16_insn_length ( insn ) ; if ( pool . first != NULL ) { if ( barrier == 0 && pool . insn_address + 4 > pool . highest_address ) { rtx label , jump ; label = gen_label_rtx ( ) ; jump = emit_jump_insn_before ( gen_jump ( label ) , insn ) ; JUMP_LABEL ( jump ) = label ; LABEL_NUSES ( label ) = 1 ; barrier = emit_barrier_after ( jump ) ; emit_label_after ( label , barrier ) ; pool . insn_address += 4 ; } if ( pool . insn_address > pool . highest_address ) { dump_constants ( pool . first , barrier ) ; pool . first = NULL ; barrier = 0 ; } else if ( BARRIER_P ( insn ) ) barrier = insn ; } } dump_constants ( pool . first , get_last_insn ( ) ) ; } </s>


<s> static int mips16_rewrite_pool_refs ( rtx * x , void * data ) { struct mips16_constant_pool * pool = data ; if ( GET_CODE ( * x ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( * x ) ) * x = gen_rtx_LABEL_REF ( Pmode , add_constant ( pool , get_pool_constant ( * x ) , get_pool_mode ( * x ) ) ) ; return 0 ; } </s>

Rewrite * X so that constant pool references refer to the constant 's label instead . DATA points to the constant pool structure .


<s> static int mips_address_cost ( rtx addr ) { return mips_address_insns ( addr , SImode ) ; } </s>

Provide the costs of an addressing mode that contains ADDR . If ADDR is not a valid address , its cost is irrelevant .


<s> static int mips_adjust_cost ( rtx insn ATTRIBUTE_UNUSED , rtx link , rtx dep ATTRIBUTE_UNUSED , int cost ) { if ( REG_NOTE_KIND ( link ) != 0 ) return 0 ; return cost ; } </s>

Implement TARGET_SCHED_ADJUST_COST . We assume that anti and output dependencies have no cost .


<s> int mips_adjust_insn_length ( rtx insn , int length ) { if ( CALL_P ( insn ) || ( TARGET_MIPS16 ? simplejump_p ( insn ) : JUMP_P ( insn ) ) ) length += 4 ; if ( ! cfun -> machine -> ignore_hazard_length_p && INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_DELAY : length += 4 ; break ; case HAZARD_HILO : length += 8 ; break ; } if ( TARGET_MIPS16 ) length /= 2 ; return length ; } </s>

Return the length of INSN . LENGTH is the initial length computed by attributes in the machine-description file .


<s> static void mips_arg_info ( const CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int named , struct mips_arg_info * info ) { bool doubleword_aligned_p ; unsigned int num_bytes , num_words , max_regs ; num_bytes = type ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; num_words = ( num_bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; switch ( mips_abi ) { case ABI_EABI : info -> fpr_p = ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) && GET_MODE_SIZE ( mode ) <= UNITS_PER_FPVALUE ) ; break ; case ABI_32 : case ABI_O64 : info -> fpr_p = ( ! cum -> gp_reg_found && cum -> arg_number < 2 && ( type == 0 || SCALAR_FLOAT_TYPE_P ( type ) || VECTOR_FLOAT_TYPE_P ( type ) ) && ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) && GET_MODE_SIZE ( mode ) <= UNITS_PER_FPVALUE ) ; break ; case ABI_N32 : case ABI_64 : info -> fpr_p = ( named && ( type == 0 || FLOAT_TYPE_P ( type ) ) && ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) && GET_MODE_UNIT_SIZE ( mode ) <= UNITS_PER_FPVALUE ) ; if ( info -> fpr_p && GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT && GET_MODE_UNIT_SIZE ( mode ) < UNITS_PER_FPVALUE ) { if ( cum -> num_gprs >= MAX_ARGS_IN_REGISTERS - 1 ) info -> fpr_p = false ; else num_words = 2 ; } break ; default : gcc_unreachable ( ) ; } doubleword_aligned_p = FUNCTION_ARG_BOUNDARY ( mode , type ) > BITS_PER_WORD ; info -> reg_offset = ( mips_abi == ABI_EABI && info -> fpr_p ? cum -> num_fprs : cum -> num_gprs ) ; if ( doubleword_aligned_p ) info -> reg_offset += info -> reg_offset & 1 ; info -> stack_offset = cum -> stack_words ; if ( doubleword_aligned_p ) info -> stack_offset += info -> stack_offset & 1 ; max_regs = MAX_ARGS_IN_REGISTERS - info -> reg_offset ; info -> reg_words = MIN ( num_words , max_regs ) ; info -> stack_words = num_words - info -> reg_words ; } </s>

Fill INFO with information about a single argument . CUM is the cumulative state for earlier arguments . MODE is the mode of this argument and TYPE is its type ( if known ) . NAMED is true if this is a named ( fixed ) argument rather than a variable one .


<s> static int mips_arg_partial_bytes ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , bool named ) { struct mips_arg_info info ; mips_arg_info ( cum , mode , type , named , & info ) ; return info . stack_words > 0 ? info . reg_words * UNITS_PER_WORD : 0 ; } </s>


<s> static void mips_avoid_hazard ( rtx after , rtx insn , int * hilo_delay , rtx * delayed_reg , rtx lo_reg ) { rtx pattern , set ; int nops , ninsns ; if ( ! INSN_P ( insn ) ) return ; pattern = PATTERN ( insn ) ; if ( GET_CODE ( pattern ) == ASM_INPUT || asm_noperands ( pattern ) >= 0 ) cfun -> machine -> all_noreorder_p = false ; ninsns = get_attr_length ( insn ) / 4 ; if ( ninsns == 0 ) return ; if ( * hilo_delay < 2 && reg_set_p ( lo_reg , pattern ) ) nops = 2 - * hilo_delay ; else if ( * delayed_reg != 0 && reg_referenced_p ( * delayed_reg , pattern ) ) nops = 1 ; else nops = 0 ; * hilo_delay += nops ; while ( nops -- > 0 ) emit_insn_after ( gen_hazard_nop ( ) , after ) ; * hilo_delay += ninsns ; * delayed_reg = 0 ; if ( INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_HILO : * hilo_delay = 0 ; break ; case HAZARD_DELAY : set = single_set ( insn ) ; gcc_assert ( set != 0 ) ; * delayed_reg = SET_DEST ( set ) ; break ; } } </s>

Subroutine of mips_reorg . If there is a hazard between INSN and a previous instruction , avoid it by inserting nops after instruction AFTER . * DELAYED_REG and * HILO_DELAY describe the hazards that apply at this point . If * DELAYED_REG is non-null , INSN must wait a cycle before using the value of that register . * HILO_DELAY counts the number of instructions since the last hilo hazard ( that is , the number of instructions since the last mflo or mfhi ) . After inserting nops for INSN , update * DELAYED_REG and * HILO_DELAY for the next instruction . LO_REG is an rtx for the LO register , used in dependence checking .


<s> static void mips_avoid_hazards ( void ) { rtx insn , last_insn , lo_reg , delayed_reg ; int hilo_delay , i ; split_all_insns_noflow ( ) ; cfun -> machine -> ignore_hazard_length_p = true ; shorten_branches ( get_insns ( ) ) ; cfun -> machine -> all_noreorder_p = true ; if ( current_function_profile ) cfun -> machine -> all_noreorder_p = false ; if ( TARGET_FIX_VR4120 ) cfun -> machine -> all_noreorder_p = false ; if ( TARGET_FIX_VR4130 && ! ISA_HAS_MACCHI ) cfun -> machine -> all_noreorder_p = false ; last_insn = 0 ; hilo_delay = 2 ; delayed_reg = 0 ; lo_reg = gen_rtx_REG ( SImode , LO_REGNUM ) ; for ( insn = get_insns ( ) ; insn != 0 ; insn = NEXT_INSN ( insn ) ) if ( INSN_P ( insn ) ) { if ( GET_CODE ( PATTERN ( insn ) ) == SEQUENCE ) for ( i = 0 ; i < XVECLEN ( PATTERN ( insn ) , 0 ) ; i ++ ) mips_avoid_hazard ( last_insn , XVECEXP ( PATTERN ( insn ) , 0 , i ) , & hilo_delay , & delayed_reg , lo_reg ) ; else mips_avoid_hazard ( last_insn , insn , & hilo_delay , & delayed_reg , lo_reg ) ; last_insn = insn ; } } </s>

Go through the instruction stream and insert nops where necessary . See if the whole function can then be put into .set noreorder & .set nomacro .


<s> static void mips_block_move_loop ( rtx dest , rtx src , HOST_WIDE_INT length ) { rtx label , src_reg , dest_reg , final_src ; HOST_WIDE_INT leftover ; leftover = length % MAX_MOVE_BYTES ; length -= leftover ; mips_adjust_block_mem ( src , MAX_MOVE_BYTES , & src_reg , & src ) ; mips_adjust_block_mem ( dest , MAX_MOVE_BYTES , & dest_reg , & dest ) ; final_src = expand_simple_binop ( Pmode , PLUS , src_reg , GEN_INT ( length ) , 0 , 0 , OPTAB_WIDEN ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; mips_block_move_straight ( dest , src , MAX_MOVE_BYTES ) ; emit_move_insn ( src_reg , plus_constant ( src_reg , MAX_MOVE_BYTES ) ) ; emit_move_insn ( dest_reg , plus_constant ( dest_reg , MAX_MOVE_BYTES ) ) ; if ( Pmode == DImode ) emit_insn ( gen_cmpdi ( src_reg , final_src ) ) ; else emit_insn ( gen_cmpsi ( src_reg , final_src ) ) ; emit_jump_insn ( gen_bne ( label ) ) ; if ( leftover ) mips_block_move_straight ( dest , src , leftover ) ; } </s>

Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES per iteration . LENGTH must be at least MAX_MOVE_BYTES . Assume that the memory regions do not overlap .


<s> static void mips_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; enum machine_mode mode ; rtx * regs ; if ( MEM_ALIGN ( src ) == BITS_PER_WORD / 2 && MEM_ALIGN ( dest ) == BITS_PER_WORD / 2 ) bits = BITS_PER_WORD / 2 ; else bits = BITS_PER_WORD ; mode = mode_for_size ( bits , MODE_INT , 0 ) ; delta = bits / BITS_PER_UNIT ; regs = alloca ( sizeof ( rtx ) * length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; if ( MEM_ALIGN ( src ) >= bits ) emit_move_insn ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; else { rtx part = adjust_address ( src , BLKmode , offset ) ; if ( ! mips_expand_unaligned_load ( regs [ i ] , part , bits , 0 ) ) gcc_unreachable ( ) ; } } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) if ( MEM_ALIGN ( dest ) >= bits ) emit_move_insn ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; else { rtx part = adjust_address ( dest , BLKmode , offset ) ; if ( ! mips_expand_unaligned_store ( part , regs [ i ] , bits , 0 ) ) gcc_unreachable ( ) ; } if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , 0 ) ; } } </s>

Emit straight-line code to move LENGTH bytes from SRC to DEST . Assume that the areas do not overlap .


Create the va_list data type . We keep 3 pointers , and two offsets . Two pointers are to the overflow area , which starts at the CFA . One of these is constant , for addressing into the GPR save area below it . The other is advanced up the stack through the overflow region . The third pointer is to the GPR save area . Since the FPR save area is just below it , we can address FPR slots off this pointer . We also keep two one-byte offsets , which are to be subtracted from the constant pointers to yield addresses in the GPR and FPR save areas . These are downcounted as float or non-float arguments are used , and when they get to zero , the argument must be obtained from the overflow region . If ! EABI_FLOAT_VARARGS_P , then no FPR save area exists , and a single pointer is enough . It 's started at the GPR save area , and is advanced , period . Note that the GPR save area is not constant size , due to optimization in the prologue . Hence , we ca n't use a design with two pointers and two offsets , although we could have designed this with two pointers and three offsets .


<s> static rtx mips_call_tls_get_addr ( rtx sym , enum mips_symbol_type type , rtx v0 ) { rtx insn , loc , tga , a0 ; a0 = gen_rtx_REG ( Pmode , GP_ARG_FIRST ) ; if ( ! mips_tls_symbol ) mips_tls_symbol = init_one_libfunc ( "__tls_get_addr" ) ; loc = mips_unspec_address ( sym , type ) ; start_sequence ( ) ; emit_insn ( gen_rtx_SET ( Pmode , a0 , gen_rtx_LO_SUM ( Pmode , pic_offset_table_rtx , loc ) ) ) ; tga = gen_rtx_MEM ( Pmode , mips_tls_symbol ) ; insn = emit_call_insn ( gen_call_value ( v0 , tga , const0_rtx , const0_rtx ) ) ; CONST_OR_PURE_CALL_P ( insn ) = 1 ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , v0 ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , a0 ) ; insn = get_insns ( ) ; end_sequence ( ) ; return insn ; } </s>

Return an instruction sequence that calls __tls_get_addr . SYM is the TLS symbol we are referencing and TYPE is the symbol type to use ( either global dynamic or local dynamic ) . V0 is an RTX for the return value location .


<s> bool mips_cannot_change_mode_class ( enum machine_mode from , enum machine_mode to , enum reg_class class ) { if ( MIN ( GET_MODE_SIZE ( from ) , GET_MODE_SIZE ( to ) ) <= UNITS_PER_WORD && MAX ( GET_MODE_SIZE ( from ) , GET_MODE_SIZE ( to ) ) > UNITS_PER_WORD ) { if ( TARGET_BIG_ENDIAN ) { if ( FP_INC > 1 && reg_classes_intersect_p ( FP_REGS , class ) ) return true ; } else { if ( reg_classes_intersect_p ( ACC_REGS , class ) ) return true ; } } if ( TARGET_FLOAT64 && from == SImode && GET_MODE_SIZE ( to ) >= UNITS_PER_WORD && reg_classes_intersect_p ( FP_REGS , class ) ) return true ; return false ; } </s>


<s> static bool mips_canonicalize_comparison ( enum rtx_code * code , rtx * cmp1 , enum machine_mode mode ) { HOST_WIDE_INT original , plus_one ; if ( GET_CODE ( * cmp1 ) != CONST_INT ) return false ; original = INTVAL ( * cmp1 ) ; plus_one = trunc_int_for_mode ( ( unsigned HOST_WIDE_INT ) original + 1 , mode ) ; switch ( * code ) { case LE : if ( original < plus_one ) { * code = LT ; * cmp1 = force_reg ( mode , GEN_INT ( plus_one ) ) ; return true ; } break ; case LEU : if ( plus_one != 0 ) { * code = LTU ; * cmp1 = force_reg ( mode , GEN_INT ( plus_one ) ) ; return true ; } break ; default : return false ; } return false ; } </s>

Canonicalize LE or LEU comparisons into LT comparisons when possible to avoid extra instructions or inverting the comparison .


<s> int mips_can_use_return_insn ( void ) { tree return_type ; if ( ! reload_completed ) return 0 ; if ( regs_ever_live [ 31 ] || current_function_profile ) return 0 ; return_type = DECL_RESULT ( current_function_decl ) ; if ( TARGET_MIPS16 && mips16_hard_float && ! aggregate_value_p ( return_type , current_function_decl ) && GET_MODE_CLASS ( DECL_MODE ( return_type ) ) == MODE_FLOAT && GET_MODE_SIZE ( DECL_MODE ( return_type ) ) <= UNITS_PER_FPVALUE ) return 0 ; if ( cfun -> machine -> frame . initialized ) return cfun -> machine -> frame . total_size == 0 ; return compute_frame_size ( get_frame_size ( ) ) == 0 ; } </s>

Return nonzero if this function is known to have a null epilogue . This allows the optimizer to omit jumps to jumps if no stack was created .


<s> int mips_class_max_nregs ( enum reg_class class ATTRIBUTE_UNUSED , enum machine_mode mode ) { if ( class == ST_REGS ) return ( GET_MODE_SIZE ( mode ) + 3 ) / 4 ; else return ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; } </s>

Implement CLASS_MAX_NREGS . Usually all registers are word-sized . The only supported exception is -mgp64 -msingle-float , which has 64-bit words but 32-bit float registers . A word-based calculation is correct even in that case , since -msingle-float disallows multi-FPR values . The FP status registers are an exception to this rule . They are always 4 bytes wide as they only hold condition code modes , and CCmode is always considered to be 4 bytes wide .


<s> void mips_conditional_register_usage ( void ) { if ( ! TARGET_DSP ) { int regno ; for ( regno = DSP_ACC_REG_FIRST ; regno <= DSP_ACC_REG_LAST ; regno ++ ) fixed_regs [ regno ] = call_used_regs [ regno ] = 1 ; } if ( ! TARGET_HARD_FLOAT ) { int regno ; for ( regno = FP_REG_FIRST ; regno <= FP_REG_LAST ; regno ++ ) fixed_regs [ regno ] = call_used_regs [ regno ] = 1 ; for ( regno = ST_REG_FIRST ; regno <= ST_REG_LAST ; regno ++ ) fixed_regs [ regno ] = call_used_regs [ regno ] = 1 ; } else if ( ! ISA_HAS_8CC ) { int regno ; for ( regno = ST_REG_FIRST ; regno <= ST_REG_LAST ; regno ++ ) fixed_regs [ regno ] = call_used_regs [ regno ] = 1 ; } if ( TARGET_MIPS16 ) { fixed_regs [ 18 ] = call_used_regs [ 18 ] = 1 ; fixed_regs [ 19 ] = call_used_regs [ 19 ] = 1 ; fixed_regs [ 20 ] = call_used_regs [ 20 ] = 1 ; fixed_regs [ 21 ] = call_used_regs [ 21 ] = 1 ; fixed_regs [ 22 ] = call_used_regs [ 22 ] = 1 ; fixed_regs [ 23 ] = call_used_regs [ 23 ] = 1 ; fixed_regs [ 26 ] = call_used_regs [ 26 ] = 1 ; fixed_regs [ 27 ] = call_used_regs [ 27 ] = 1 ; fixed_regs [ 30 ] = call_used_regs [ 30 ] = 1 ; } if ( mips_abi == ABI_64 ) { int regno ; for ( regno = FP_REG_FIRST + 20 ; regno < FP_REG_FIRST + 24 ; regno ++ ) call_really_used_regs [ regno ] = call_used_regs [ regno ] = 1 ; } if ( mips_abi == ABI_N32 ) { int regno ; for ( regno = FP_REG_FIRST + 21 ; regno <= FP_REG_FIRST + 31 ; regno += 2 ) call_really_used_regs [ regno ] = call_used_regs [ regno ] = 1 ; } } </s>


<s> static const struct mips_cpu_info * mips_cpu_info_from_isa ( int isa ) { const struct mips_cpu_info * p ; for ( p = mips_cpu_info_table ; p -> name != 0 ; p ++ ) if ( p -> isa == isa ) return p ; return 0 ; } </s>

Return the processor associated with the given ISA level , or null if the ISA is n't valid .


<s> bool mips_dangerous_for_la25_p ( rtx x ) { HOST_WIDE_INT offset ; if ( TARGET_EXPLICIT_RELOCS ) return false ; mips_split_const ( x , & x , & offset ) ; return global_got_operand ( x , VOIDmode ) ; } </s>

Return true if X should not be moved directly into register $ 25 . We need this because many versions of GAS will treat `` la $ 25 , foo '' as part of a call sequence and so allow a global `` foo '' to be lazily bound .


"mips_debugger_offset called with non stack/frame/arg pointer"

The MIPS debug format wants all automatic variables and arguments to be in terms of the virtual frame pointer ( stack pointer before any adjustment in the function ) , while the MIPS 3.0 linker wants the frame pointer to be the stack pointer after the initial adjustment . So , we do the adjustment here . The arg pointer ( which is eliminated ) points to the virtual frame pointer , while the frame pointer ( which may be eliminated ) points to the stack pointer after the initial adjustments .


<s> void mips_declare_object_name ( FILE * stream , const char * name , tree decl ATTRIBUTE_UNUSED ) { ASM_OUTPUT_TYPE_DIRECTIVE ( stream , name , "object" ) ; size_directive_output = 0 ; if ( ! flag_inhibit_size_directive && DECL_SIZE ( decl ) ) { HOST_WIDE_INT size ; size_directive_output = 1 ; size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; ASM_OUTPUT_SIZE_DIRECTIVE ( stream , name , size ) ; } mips_declare_object ( stream , name , "" , ":\n" ) ; } </s>

Implement ASM_DECLARE_OBJECT_NAME . This is like most of the standard ELF definitions except that it uses mips_declare_object ( ) to emit the label .


<s> static void mips_emit_binary ( enum rtx_code code , rtx target , rtx op0 , rtx op1 ) { emit_insn ( gen_rtx_SET ( VOIDmode , target , gen_rtx_fmt_ee ( code , GET_MODE ( target ) , op0 , op1 ) ) ) ; } </s>

Emit an instruction of the form ( set TARGET ( CODE OP0 OP1 ) ) .


<s> static void mips_emit_compare ( enum rtx_code * code , rtx * op0 , rtx * op1 , bool need_eq_ne_p ) { if ( GET_MODE_CLASS ( GET_MODE ( cmp_operands [ 0 ] ) ) == MODE_INT ) { if ( ! need_eq_ne_p && cmp_operands [ 1 ] == const0_rtx ) { * op0 = cmp_operands [ 0 ] ; * op1 = cmp_operands [ 1 ] ; } else if ( * code == EQ || * code == NE ) { if ( need_eq_ne_p ) { * op0 = mips_zero_if_equal ( cmp_operands [ 0 ] , cmp_operands [ 1 ] ) ; * op1 = const0_rtx ; } else { * op0 = cmp_operands [ 0 ] ; * op1 = force_reg ( GET_MODE ( * op0 ) , cmp_operands [ 1 ] ) ; } } else { bool invert = false ; * op0 = gen_reg_rtx ( GET_MODE ( cmp_operands [ 0 ] ) ) ; * op1 = const0_rtx ; mips_emit_int_relational ( * code , & invert , * op0 , cmp_operands [ 0 ] , cmp_operands [ 1 ] ) ; * code = ( invert ? EQ : NE ) ; } } else { enum rtx_code cmp_code ; switch ( * code ) { case NE : case LTGT : case ORDERED : cmp_code = reverse_condition_maybe_unordered ( * code ) ; * code = EQ ; break ; default : cmp_code = * code ; * code = NE ; break ; } * op0 = ( ISA_HAS_8CC ? gen_reg_rtx ( CCmode ) : gen_rtx_REG ( CCmode , FPSW_REGNUM ) ) ; * op1 = const0_rtx ; mips_emit_binary ( cmp_code , * op0 , cmp_operands [ 0 ] , cmp_operands [ 1 ] ) ; } } </s>

Convert a comparison into something that can be used in a branch or conditional move . On entry , * OP0 and * OP1 are the values being compared and * CODE is the code used to compare them . Update * CODE , * OP0 and * OP1 so that they describe the final comparison . If NEED_EQ_NE_P , then only EQ or NE comparisons against zero are possible , otherwise any standard branch condition can be used . The standard branch conditions are : - EQ or NE between two registers . - any comparison between a register and zero .


<s> void mips_emit_fcc_reload ( rtx dest , rtx src , rtx scratch ) { rtx fp1 , fp2 ; if ( MEM_P ( src ) ) src = adjust_address ( src , SFmode , 0 ) ; else if ( REG_P ( src ) || GET_CODE ( src ) == SUBREG ) src = gen_rtx_REG ( SFmode , true_regnum ( src ) ) ; fp1 = gen_rtx_REG ( SFmode , REGNO ( scratch ) ) ; fp2 = gen_rtx_REG ( SFmode , REGNO ( scratch ) + FP_INC ) ; emit_move_insn ( copy_rtx ( fp1 ) , src ) ; emit_move_insn ( copy_rtx ( fp2 ) , CONST0_RTX ( SFmode ) ) ; emit_insn ( gen_slt_sf ( dest , fp2 , fp1 ) ) ; } </s>

Emit code to move general operand SRC into condition-code register DEST . SCRATCH is a scratch TFmode float register . The sequence is : FP1 = SRC FP2 = 0.0f DEST = FP2 < FP1 where FP1 and FP2 are single-precision float registers taken from SCRATCH .


<s> static void mips_emit_int_relational ( enum rtx_code code , bool * invert_ptr , rtx target , rtx cmp0 , rtx cmp1 ) { if ( mips_relational_operand_ok_p ( code , cmp1 ) ) mips_emit_binary ( code , target , cmp0 , cmp1 ) ; else if ( mips_canonicalize_comparison ( & code , & cmp1 , GET_MODE ( target ) ) ) mips_emit_binary ( code , target , cmp0 , cmp1 ) ; else { enum rtx_code inv_code = reverse_condition ( code ) ; if ( ! mips_relational_operand_ok_p ( inv_code , cmp1 ) ) { cmp1 = force_reg ( GET_MODE ( cmp0 ) , cmp1 ) ; mips_emit_int_relational ( code , invert_ptr , target , cmp0 , cmp1 ) ; } else if ( invert_ptr == 0 ) { rtx inv_target = gen_reg_rtx ( GET_MODE ( target ) ) ; mips_emit_binary ( inv_code , inv_target , cmp0 , cmp1 ) ; mips_emit_binary ( XOR , target , inv_target , const1_rtx ) ; } else { * invert_ptr = ! * invert_ptr ; mips_emit_binary ( inv_code , target , cmp0 , cmp1 ) ; } } } </s>

Compare CMP0 and CMP1 using relational operator CODE and store the result in TARGET . CMP0 and TARGET are register_operands that have the same integer mode . If INVERT_PTR is nonnull , it 's OK to set TARGET to the inverse of the result and flip * INVERT_PTR instead .


<s> static void mips_emit_loadgp ( void ) { if ( TARGET_ABICALLS && TARGET_NEWABI && cfun -> machine -> global_pointer > 0 ) { rtx addr , offset , incoming_address ; addr = XEXP ( DECL_RTL ( current_function_decl ) , 0 ) ; offset = mips_unspec_address ( addr , SYMBOL_GOTOFF_LOADGP ) ; incoming_address = gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) ; emit_insn ( gen_loadgp ( offset , incoming_address ) ) ; if ( ! TARGET_EXPLICIT_RELOCS ) emit_insn ( gen_loadgp_blockage ( ) ) ; } } </s>

If we 're generating n32 or n64 abicalls , emit instructions to set up the global pointer .


<s> bool mips_emit_scc ( enum rtx_code code , rtx target ) { if ( GET_MODE_CLASS ( GET_MODE ( cmp_operands [ 0 ] ) ) != MODE_INT ) return false ; target = gen_lowpart ( GET_MODE ( cmp_operands [ 0 ] ) , target ) ; if ( code == EQ || code == NE ) { rtx zie = mips_zero_if_equal ( cmp_operands [ 0 ] , cmp_operands [ 1 ] ) ; mips_emit_binary ( code , target , zie , const0_rtx ) ; } else mips_emit_int_relational ( code , 0 , target , cmp_operands [ 0 ] , cmp_operands [ 1 ] ) ; return true ; } </s>

Try comparing cmp_operands [ 0 ] and cmp_operands [ 1 ] using rtl code CODE . Store the result in TARGET and return true if successful . On 64-bit targets , TARGET may be wider than cmp_operands [ 0 ] .


<s> static void mips_encode_section_info ( tree decl , rtx rtl , int first ) { default_encode_section_info ( decl , rtl , first ) ; if ( TREE_CODE ( decl ) == FUNCTION_DECL && lookup_attribute ( "long_call" , TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ) ) { rtx symbol = XEXP ( rtl , 0 ) ; SYMBOL_REF_FLAGS ( symbol ) |= SYMBOL_FLAG_LONG_CALL ; } } </s>

Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL , which belongs to DECL . FIRST is true if this is the first time handling this decl .


<s> bool mips_expand_block_move ( rtx dest , rtx src , rtx length ) { if ( GET_CODE ( length ) == CONST_INT ) { if ( INTVAL ( length ) <= 2 * MAX_MOVE_BYTES ) { mips_block_move_straight ( dest , src , INTVAL ( length ) ) ; return true ; } else if ( optimize ) { mips_block_move_loop ( dest , src , INTVAL ( length ) ) ; return true ; } } return false ; } </s>

Expand a movmemsi instruction , which copies LENGTH bytes from memory reference SRC to memory reference DEST .


<s> rtx mips_expand_builtin ( tree exp , rtx target , rtx subtarget ATTRIBUTE_UNUSED , enum machine_mode mode ATTRIBUTE_UNUSED , int ignore ATTRIBUTE_UNUSED ) { enum insn_code icode ; enum mips_builtin_type type ; tree fndecl , arglist ; unsigned int fcode ; const struct builtin_description * bdesc ; const struct bdesc_map * m ; fndecl = TREE_OPERAND ( TREE_OPERAND ( exp , 0 ) , 0 ) ; arglist = TREE_OPERAND ( exp , 1 ) ; fcode = DECL_FUNCTION_CODE ( fndecl ) ; bdesc = NULL ; for ( m = bdesc_arrays ; m < & bdesc_arrays [ ARRAY_SIZE ( bdesc_arrays ) ] ; m ++ ) { if ( fcode < m -> size ) { bdesc = m -> bdesc ; icode = bdesc [ fcode ] . icode ; type = bdesc [ fcode ] . builtin_type ; break ; } fcode -= m -> size ; } if ( bdesc == NULL ) return 0 ; switch ( type ) { case MIPS_BUILTIN_DIRECT : return mips_expand_builtin_direct ( icode , target , arglist , true ) ; case MIPS_BUILTIN_DIRECT_NO_TARGET : return mips_expand_builtin_direct ( icode , target , arglist , false ) ; case MIPS_BUILTIN_MOVT : case MIPS_BUILTIN_MOVF : return mips_expand_builtin_movtf ( type , icode , bdesc [ fcode ] . cond , target , arglist ) ; case MIPS_BUILTIN_CMP_ANY : case MIPS_BUILTIN_CMP_ALL : case MIPS_BUILTIN_CMP_UPPER : case MIPS_BUILTIN_CMP_LOWER : case MIPS_BUILTIN_CMP_SINGLE : return mips_expand_builtin_compare ( type , icode , bdesc [ fcode ] . cond , target , arglist ) ; case MIPS_BUILTIN_BPOSGE32 : return mips_expand_builtin_bposge ( type , target ) ; default : return 0 ; } } </s>

Expand builtin functions . This is called from TARGET_EXPAND_BUILTIN .


<s> static rtx mips_expand_builtin_bposge ( enum mips_builtin_type builtin_type , rtx target ) { rtx label1 , label2 , if_then_else ; rtx cmp_result ; int cmp_value ; if ( target == 0 || GET_MODE ( target ) != SImode ) target = gen_reg_rtx ( SImode ) ; cmp_result = gen_rtx_REG ( CCDSPmode , CCDSP_PO_REGNUM ) ; if ( builtin_type == MIPS_BUILTIN_BPOSGE32 ) cmp_value = 32 ; else gcc_assert ( 0 ) ; emit_move_insn ( target , const0_rtx ) ; label1 = gen_label_rtx ( ) ; label2 = gen_label_rtx ( ) ; if_then_else = gen_rtx_IF_THEN_ELSE ( VOIDmode , gen_rtx_fmt_ee ( GE , CCDSPmode , cmp_result , GEN_INT ( cmp_value ) ) , gen_rtx_LABEL_REF ( VOIDmode , label1 ) , pc_rtx ) ; emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , if_then_else ) ) ; emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , gen_rtx_LABEL_REF ( VOIDmode , label2 ) ) ) ; emit_barrier ( ) ; emit_label ( label1 ) ; emit_move_insn ( target , const1_rtx ) ; emit_label ( label2 ) ; return target ; } </s>

Expand a bposge builtin of type BUILTIN_TYPE . TARGET , if nonnull , suggests a good place to put the boolean result . The sequence we want is li target , 0 bposge * label1 j label2 label1 : li target , 1 label2 :


<s> static rtx mips_expand_builtin_compare ( enum mips_builtin_type builtin_type , enum insn_code icode , enum mips_fp_condition cond , rtx target , tree arglist ) { rtx label1 , label2 , if_then_else ; rtx pat , cmp_result , ops [ MAX_RECOG_OPERANDS ] ; rtx target_if_equal , target_if_unequal ; int cmp_value , i ; if ( target == 0 || GET_MODE ( target ) != SImode ) target = gen_reg_rtx ( SImode ) ; cmp_result = mips_prepare_builtin_target ( icode , 0 , 0 ) ; for ( i = 1 ; i < insn_data [ icode ] . n_operands - 1 ; i ++ ) ops [ i ] = mips_prepare_builtin_arg ( icode , i , & arglist ) ; switch ( insn_data [ icode ] . n_operands ) { case 4 : pat = GEN_FCN ( icode ) ( cmp_result , ops [ 1 ] , ops [ 2 ] , GEN_INT ( cond ) ) ; break ; case 6 : pat = GEN_FCN ( icode ) ( cmp_result , ops [ 1 ] , ops [ 2 ] , ops [ 3 ] , ops [ 4 ] , GEN_INT ( cond ) ) ; break ; default : gcc_unreachable ( ) ; } if ( builtin_type == MIPS_BUILTIN_CMP_ALL ) { cmp_value = - 1 ; target_if_equal = const1_rtx ; target_if_unequal = const0_rtx ; } else { cmp_value = 0 ; target_if_equal = const0_rtx ; target_if_unequal = const1_rtx ; if ( builtin_type == MIPS_BUILTIN_CMP_UPPER ) cmp_result = simplify_gen_subreg ( CCmode , cmp_result , CCV2mode , 4 ) ; else if ( builtin_type == MIPS_BUILTIN_CMP_LOWER ) cmp_result = simplify_gen_subreg ( CCmode , cmp_result , CCV2mode , 0 ) ; } emit_move_insn ( target , target_if_equal ) ; emit_insn ( pat ) ; label1 = gen_label_rtx ( ) ; label2 = gen_label_rtx ( ) ; if_then_else = gen_rtx_IF_THEN_ELSE ( VOIDmode , gen_rtx_fmt_ee ( NE , GET_MODE ( cmp_result ) , cmp_result , GEN_INT ( cmp_value ) ) , gen_rtx_LABEL_REF ( VOIDmode , label1 ) , pc_rtx ) ; emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , if_then_else ) ) ; emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , gen_rtx_LABEL_REF ( VOIDmode , label2 ) ) ) ; emit_barrier ( ) ; emit_label ( label1 ) ; emit_move_insn ( target , target_if_unequal ) ; emit_label ( label2 ) ; return target ; } </s>

Expand a comparison builtin of type BUILTIN_TYPE . ICODE is the code of the comparison instruction and COND is the condition it should test . ARGLIST is the list of function arguments and TARGET , if nonnull , suggests a good place to put the boolean result .


<s> static rtx mips_expand_builtin_direct ( enum insn_code icode , rtx target , tree arglist , bool has_target ) { rtx ops [ MAX_RECOG_OPERANDS ] ; int i = 0 ; if ( has_target ) { ops [ 0 ] = mips_prepare_builtin_target ( icode , 0 , target ) ; i = 1 ; } for ( ; i < insn_data [ icode ] . n_operands && arglist != 0 ; i ++ ) ops [ i ] = mips_prepare_builtin_arg ( icode , i , & arglist ) ; switch ( i ) { case 2 : emit_insn ( GEN_FCN ( icode ) ( ops [ 0 ] , ops [ 1 ] ) ) ; break ; case 3 : emit_insn ( GEN_FCN ( icode ) ( ops [ 0 ] , ops [ 1 ] , ops [ 2 ] ) ) ; break ; case 4 : emit_insn ( GEN_FCN ( icode ) ( ops [ 0 ] , ops [ 1 ] , ops [ 2 ] , ops [ 3 ] ) ) ; break ; default : gcc_unreachable ( ) ; } return target ; } </s>

Expand a MIPS_BUILTIN_DIRECT function . ICODE is the code of the .md pattern and ARGLIST is the list of function arguments . TARGET , if nonnull , suggests a good place to put the result . HAS_TARGET indicates the function must return something .


<s> static rtx mips_expand_builtin_movtf ( enum mips_builtin_type type , enum insn_code icode , enum mips_fp_condition cond , rtx target , tree arglist ) { rtx cmp_result , op0 , op1 ; cmp_result = mips_prepare_builtin_target ( icode , 0 , 0 ) ; op0 = mips_prepare_builtin_arg ( icode , 1 , & arglist ) ; op1 = mips_prepare_builtin_arg ( icode , 2 , & arglist ) ; emit_insn ( GEN_FCN ( icode ) ( cmp_result , op0 , op1 , GEN_INT ( cond ) ) ) ; icode = CODE_FOR_mips_cond_move_tf_ps ; target = mips_prepare_builtin_target ( icode , 0 , target ) ; if ( type == MIPS_BUILTIN_MOVT ) { op1 = mips_prepare_builtin_arg ( icode , 2 , & arglist ) ; op0 = mips_prepare_builtin_arg ( icode , 1 , & arglist ) ; } else { op0 = mips_prepare_builtin_arg ( icode , 1 , & arglist ) ; op1 = mips_prepare_builtin_arg ( icode , 2 , & arglist ) ; } emit_insn ( gen_mips_cond_move_tf_ps ( target , op0 , op1 , cmp_result ) ) ; return target ; } </s>

Expand a __builtin_mips_movt_ * _ps ( ) or __builtin_mips_movf_ * _ps ( ) function ( TYPE says which ) . ARGLIST is the list of arguments to the function , ICODE is the instruction that should be used to compare the first two arguments , and COND is the condition it should test . TARGET , if nonnull , suggests a good place to put the result .


<s> void mips_expand_call ( rtx result , rtx addr , rtx args_size , rtx aux , int sibcall_p ) { rtx orig_addr , pattern , insn ; orig_addr = addr ; if ( ! call_insn_operand ( addr , VOIDmode ) ) { addr = gen_reg_rtx ( Pmode ) ; mips_load_call_address ( addr , orig_addr , sibcall_p ) ; } if ( TARGET_MIPS16 && mips16_hard_float && build_mips16_call_stub ( result , addr , args_size , aux == 0 ? 0 : ( int ) GET_MODE ( aux ) ) ) return ; if ( result == 0 ) pattern = ( sibcall_p ? gen_sibcall_internal ( addr , args_size ) : gen_call_internal ( addr , args_size ) ) ; else if ( GET_CODE ( result ) == PARALLEL && XVECLEN ( result , 0 ) == 2 ) { rtx reg1 , reg2 ; reg1 = XEXP ( XVECEXP ( result , 0 , 0 ) , 0 ) ; reg2 = XEXP ( XVECEXP ( result , 0 , 1 ) , 0 ) ; pattern = ( sibcall_p ? gen_sibcall_value_multiple_internal ( reg1 , addr , args_size , reg2 ) : gen_call_value_multiple_internal ( reg1 , addr , args_size , reg2 ) ) ; } else pattern = ( sibcall_p ? gen_sibcall_value_internal ( result , addr , args_size ) : gen_call_value_internal ( result , addr , args_size ) ) ; insn = emit_call_insn ( pattern ) ; if ( global_got_operand ( orig_addr , VOIDmode ) ) use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , pic_offset_table_rtx ) ; } </s>

Expand a call or call_value instruction . RESULT is where the result will go ( null for calls ) , ADDR is the address of the function , ARGS_SIZE is the size of the arguments and AUX is the value passed to us by mips_function_arg . SIBCALL_P is true if we are expanding a sibling call , false if we 're expanding a normal call .


<s> void mips_expand_epilogue ( int sibcall_p ) { HOST_WIDE_INT step1 , step2 ; rtx base , target ; if ( ! sibcall_p && mips_can_use_return_insn ( ) ) { emit_jump_insn ( gen_return ( ) ) ; return ; } step1 = cfun -> machine -> frame . total_size ; step2 = 0 ; if ( ! frame_pointer_needed ) base = stack_pointer_rtx ; else { base = hard_frame_pointer_rtx ; if ( TARGET_MIPS16 ) step1 -= cfun -> machine -> frame . args_size ; } if ( ( cfun -> machine -> frame . mask | cfun -> machine -> frame . fmask ) != 0 ) { step2 = MIN ( step1 , MIPS_MAX_FIRST_STACK_STEP ) ; step1 -= step2 ; } target = base ; if ( step1 > 0 ) { rtx adjust ; adjust = GEN_INT ( step1 ) ; if ( ! SMALL_OPERAND ( step1 ) ) { emit_move_insn ( MIPS_EPILOGUE_TEMP ( Pmode ) , adjust ) ; adjust = MIPS_EPILOGUE_TEMP ( Pmode ) ; } if ( ! TARGET_MIPS16 ) target = stack_pointer_rtx ; emit_insn ( gen_add3_insn ( target , base , adjust ) ) ; } if ( target != stack_pointer_rtx ) emit_move_insn ( stack_pointer_rtx , target ) ; if ( TARGET_ABICALLS && TARGET_NEWABI && ! TARGET_EXPLICIT_RELOCS ) emit_insn ( gen_blockage ( ) ) ; mips_for_each_saved_reg ( cfun -> machine -> frame . total_size - step2 , mips_restore_reg ) ; if ( step2 > 0 ) emit_insn ( gen_add3_insn ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( step2 ) ) ) ; if ( current_function_calls_eh_return ) { if ( TARGET_MIPS16 ) { emit_move_insn ( MIPS_EPILOGUE_TEMP ( Pmode ) , stack_pointer_rtx ) ; emit_insn ( gen_add3_insn ( MIPS_EPILOGUE_TEMP ( Pmode ) , MIPS_EPILOGUE_TEMP ( Pmode ) , EH_RETURN_STACKADJ_RTX ) ) ; emit_move_insn ( stack_pointer_rtx , MIPS_EPILOGUE_TEMP ( Pmode ) ) ; } else emit_insn ( gen_add3_insn ( stack_pointer_rtx , stack_pointer_rtx , EH_RETURN_STACKADJ_RTX ) ) ; } if ( ! sibcall_p ) { if ( TARGET_MIPS16 && ( cfun -> machine -> frame . mask & RA_MASK ) != 0 ) emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + 7 ) ) ) ; else emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + 31 ) ) ) ; } } </s>

Expand the epilogue into a bunch of separate insns . SIBCALL_P is true if this epilogue precedes a sibling call , false if it is for a normal `` epilogue '' pattern .


<s> void mips_expand_prologue ( void ) { HOST_WIDE_INT size ; if ( cfun -> machine -> global_pointer > 0 ) REGNO ( pic_offset_table_rtx ) = cfun -> machine -> global_pointer ; size = compute_frame_size ( get_frame_size ( ) ) ; if ( ( cfun -> machine -> frame . mask | cfun -> machine -> frame . fmask ) != 0 ) { HOST_WIDE_INT step1 ; step1 = MIN ( size , MIPS_MAX_FIRST_STACK_STEP ) ; RTX_FRAME_RELATED_P ( emit_insn ( gen_add3_insn ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( - step1 ) ) ) ) = 1 ; size -= step1 ; mips_for_each_saved_reg ( size , mips_save_reg ) ; } if ( size > 0 ) { if ( SMALL_OPERAND ( - size ) ) RTX_FRAME_RELATED_P ( emit_insn ( gen_add3_insn ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( - size ) ) ) ) = 1 ; else { emit_move_insn ( MIPS_PROLOGUE_TEMP ( Pmode ) , GEN_INT ( size ) ) ; if ( TARGET_MIPS16 ) { gcc_assert ( frame_pointer_needed ) ; emit_move_insn ( hard_frame_pointer_rtx , stack_pointer_rtx ) ; emit_insn ( gen_sub3_insn ( hard_frame_pointer_rtx , hard_frame_pointer_rtx , MIPS_PROLOGUE_TEMP ( Pmode ) ) ) ; emit_move_insn ( stack_pointer_rtx , hard_frame_pointer_rtx ) ; } else emit_insn ( gen_sub3_insn ( stack_pointer_rtx , stack_pointer_rtx , MIPS_PROLOGUE_TEMP ( Pmode ) ) ) ; mips_set_frame_expr ( gen_rtx_SET ( VOIDmode , stack_pointer_rtx , plus_constant ( stack_pointer_rtx , - size ) ) ) ; } } if ( frame_pointer_needed ) { if ( TARGET_MIPS16 && cfun -> machine -> frame . args_size != 0 ) { rtx offset = GEN_INT ( cfun -> machine -> frame . args_size ) ; if ( SMALL_OPERAND ( cfun -> machine -> frame . args_size ) ) RTX_FRAME_RELATED_P ( emit_insn ( gen_add3_insn ( hard_frame_pointer_rtx , stack_pointer_rtx , offset ) ) ) = 1 ; else { emit_move_insn ( MIPS_PROLOGUE_TEMP ( Pmode ) , offset ) ; emit_move_insn ( hard_frame_pointer_rtx , stack_pointer_rtx ) ; emit_insn ( gen_add3_insn ( hard_frame_pointer_rtx , hard_frame_pointer_rtx , MIPS_PROLOGUE_TEMP ( Pmode ) ) ) ; mips_set_frame_expr ( gen_rtx_SET ( VOIDmode , hard_frame_pointer_rtx , plus_constant ( stack_pointer_rtx , cfun -> machine -> frame . args_size ) ) ) ; } } else RTX_FRAME_RELATED_P ( emit_move_insn ( hard_frame_pointer_rtx , stack_pointer_rtx ) ) = 1 ; } if ( TARGET_ABICALLS && ! TARGET_NEWABI && ! current_function_is_leaf ) emit_insn ( gen_cprestore ( GEN_INT ( current_function_outgoing_args_size ) ) ) ; mips_emit_loadgp ( ) ; if ( current_function_profile ) emit_insn ( gen_blockage ( ) ) ; } </s>

Expand the prologue into a bunch of separate insns .


<s> bool mips_expand_unaligned_load ( rtx dest , rtx src , unsigned int width , int bitpos ) { rtx left , right , temp ; if ( GET_CODE ( dest ) == SUBREG && GET_MODE ( dest ) == DImode && SUBREG_BYTE ( dest ) == 0 && GET_MODE ( SUBREG_REG ( dest ) ) == SImode ) dest = SUBREG_REG ( dest ) ; if ( GET_MODE_BITSIZE ( GET_MODE ( dest ) ) != width ) return false ; if ( ! mips_get_unaligned_mem ( & src , width , bitpos , & left , & right ) ) return false ; temp = gen_reg_rtx ( GET_MODE ( dest ) ) ; if ( GET_MODE ( dest ) == DImode ) { emit_insn ( gen_mov_ldl ( temp , src , left ) ) ; emit_insn ( gen_mov_ldr ( dest , copy_rtx ( src ) , right , temp ) ) ; } else { emit_insn ( gen_mov_lwl ( temp , src , left ) ) ; emit_insn ( gen_mov_lwr ( dest , copy_rtx ( src ) , right , temp ) ) ; } return true ; } </s>

Try to emit the equivalent of ( set DEST ( zero_extract SRC WIDTH BITPOS ) ) . Return true on success . We only handle cases where zero_extract is equivalent to sign_extract .


<s> bool mips_expand_unaligned_store ( rtx dest , rtx src , unsigned int width , int bitpos ) { rtx left , right ; if ( ! mips_get_unaligned_mem ( & dest , width , bitpos , & left , & right ) ) return false ; src = gen_lowpart ( mode_for_size ( width , MODE_INT , 0 ) , src ) ; if ( GET_MODE ( src ) == DImode ) { emit_insn ( gen_mov_sdl ( dest , src , left ) ) ; emit_insn ( gen_mov_sdr ( copy_rtx ( dest ) , copy_rtx ( src ) , right ) ) ; } else { emit_insn ( gen_mov_swl ( dest , src , left ) ) ; emit_insn ( gen_mov_swr ( copy_rtx ( dest ) , copy_rtx ( src ) , right ) ) ; } return true ; } </s>

Try to expand ( set ( zero_extract DEST WIDTH BITPOS ) SRC ) . Return true on success .


<s>
static
void
mips_file_end
(
void
)
{
tree
name_tree
;
struct
extern_list
*
p
;
if
(
extern_head
)
{
fputs
(
"\n"
,
asm_out_file
)
;
for
(
p
=
extern_head
;
p
!=
0
;
p
=
p
->
next
)
{
name_tree
=
get_identifier
(
p
->
name
)
;
if
(
!
TREE_ASM_WRITTEN
(
name_tree
)
&&
TREE_SYMBOL_REFERENCED
(
name_tree
)
)
{
TREE_ASM_WRITTEN
(
name_tree
)
=
1
;
if
(
TARGET_IRIX
&&
mips_abi
==
ABI_32
&&
p
->
size
==
1
)
{
fputs
(
"\t.globl "
,
asm_out_file
)
;
assemble_name
(
asm_out_file
,
p
->
name
)
;
fputs
(
" .text\n"
,
asm_out_file
)
;
}
else
{
fputs
(
"\t.extern\t"
,
asm_out_file
)
;
assemble_name
(
asm_out_file
,
p
->
name
)
;
fprintf
(
asm_out_file
,
", %d\n"
,
p
->
size
)
;
}
}
}
}
}
</s>

Implement TARGET_ASM_FILE_END . When using assembler macros , emit .externs for any small-data variables that turned out to be external .


"\n%s -G value = %d, Arch = %s, ISA = %d\n"


<s> static void mips_for_each_saved_reg ( HOST_WIDE_INT sp_offset , mips_save_restore_fn fn ) { enum machine_mode fpr_mode ; HOST_WIDE_INT offset ; int regno ; offset = cfun -> machine -> frame . gp_sp_offset - sp_offset ; for ( regno = GP_REG_LAST ; regno >= GP_REG_FIRST ; regno -- ) if ( BITSET_P ( cfun -> machine -> frame . mask , regno - GP_REG_FIRST ) ) { mips_save_restore_reg ( gpr_mode , regno , offset , fn ) ; offset -= GET_MODE_SIZE ( gpr_mode ) ; } offset = cfun -> machine -> frame . fp_sp_offset - sp_offset ; fpr_mode = ( TARGET_SINGLE_FLOAT ? SFmode : DFmode ) ; for ( regno = ( FP_REG_LAST - FP_INC + 1 ) ; regno >= FP_REG_FIRST ; regno -= FP_INC ) if ( BITSET_P ( cfun -> machine -> frame . fmask , regno - FP_REG_FIRST ) ) { mips_save_restore_reg ( fpr_mode , regno , offset , fn ) ; offset -= GET_MODE_SIZE ( fpr_mode ) ; } } </s>

Call FN for each register that is saved by the current function . SP_OFFSET is the offset of the current stack pointer from the start of the frame .


<s> static int mips_fpr_return_fields ( tree valtype , tree * fields ) { tree field ; int i ; if ( ! TARGET_NEWABI ) return 0 ; if ( TREE_CODE ( valtype ) != RECORD_TYPE ) return 0 ; i = 0 ; for ( field = TYPE_FIELDS ( valtype ) ; field != 0 ; field = TREE_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( TREE_CODE ( TREE_TYPE ( field ) ) != REAL_TYPE ) return 0 ; if ( i == 2 ) return 0 ; fields [ i ++ ] = field ; } return i ; } </s>

See whether VALTYPE is a record whose fields should be returned in floating-point registers . If so , return the number of fields and list them in FIELDS ( which should have two elements ) . Return 0 otherwise . For n32 & n64 , a structure with one or two fields is returned in floating-point registers as long as every field has a floating-point type . The C++ FE used to remove zero-width bit-fields in GCC 11 and earlier . To make a proper diagnostic , this function will set HAS_CXX_ZERO_WIDTH_BF to true once a C++ zero-width bit-field shows up , and then ignore it . We had failed to ignore C++17 empty bases in GCC 7 , 8 , 9 , 10 , and 11 . This caused an ABI incompatibility between C++14 and C++17 . This is fixed now and to make a proper diagnostic , this function will set HAS_CXX17_EMPTY_BASE to true once a C++17 empty base shows up , and then ignore it . The caller should use the value of HAS_CXX17_EMPTY_BASE and/or HAS_CXX_ZERO_WIDTH_BF to emit a proper -Wpsabi inform .


<s> static rtx mips_frame_set ( rtx mem , rtx reg ) { rtx set ; if ( REGNO ( reg ) == GP_REG_FIRST + 31 && DWARF_FRAME_RETURN_COLUMN != GP_REG_FIRST + 31 ) reg = gen_rtx_REG ( GET_MODE ( reg ) , DWARF_FRAME_RETURN_COLUMN ) ; set = gen_rtx_SET ( VOIDmode , mem , reg ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; return set ; } </s>

Return a frame-related rtx that stores register REGNO at ( SP + OFFSET ) . The expression should only be used to store single registers .


<s> static bool mips_function_has_gp_insn ( void ) { if ( ! cfun -> machine -> has_gp_insn_p ) { rtx insn ; push_topmost_sequence ( ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) if ( INSN_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) != USE && GET_CODE ( PATTERN ( insn ) ) != CLOBBER && ( get_attr_got ( insn ) != GOT_UNSET || small_data_pattern ( PATTERN ( insn ) , VOIDmode ) ) ) break ; pop_topmost_sequence ( ) ; cfun -> machine -> has_gp_insn_p = ( insn != 0 ) ; } return cfun -> machine -> has_gp_insn_p ; } </s>

Return true if the current function has an insn that implicitly refers to $ gp .


<s> static bool mips_function_ok_for_sibcall ( tree decl ATTRIBUTE_UNUSED , tree exp ATTRIBUTE_UNUSED ) { return TARGET_SIBCALLS ; } </s>

We can handle any sibcall when TARGET_SIBCALLS is true .


<s> static void mips_function_rodata_section ( tree decl ) { if ( ! TARGET_ABICALLS || TARGET_GPWORD ) default_function_rodata_section ( decl ) ; else if ( decl && DECL_SECTION_NAME ( decl ) ) { const char * name = TREE_STRING_POINTER ( DECL_SECTION_NAME ( decl ) ) ; if ( DECL_ONE_ONLY ( decl ) && strncmp ( name , ".gnu.linkonce.t." , 16 ) == 0 ) { char * rname = ASTRDUP ( name ) ; rname [ 14 ] = 'd' ; named_section_real ( rname , SECTION_LINKONCE | SECTION_WRITE , decl ) ; } else if ( flag_function_sections && flag_data_sections && strncmp ( name , ".text." , 6 ) == 0 ) { char * rname = ASTRDUP ( name ) ; memcpy ( rname + 1 , "data" , 4 ) ; named_section_flags ( rname , SECTION_WRITE ) ; } else data_section ( ) ; } else data_section ( ) ; } </s>

Implement TARGET_ASM_FUNCTION_RODATA_SECTION . The complication here is that , with the combination TARGET_ABICALLS & & ! TARGET_GPWORD , jump tables will use absolute addresses , and should therefore not be included in the read-only part of a DSO . Handle such cases by selecting a normal data section instead of a read-only one . The logic apes that in default_function_rodata_section .


<s> rtx mips_function_value ( tree valtype , tree func ATTRIBUTE_UNUSED , enum machine_mode mode ) { if ( valtype ) { tree fields [ 2 ] ; int unsignedp ; mode = TYPE_MODE ( valtype ) ; unsignedp = TYPE_UNSIGNED ( valtype ) ; mode = promote_mode ( valtype , mode , & unsignedp , 1 ) ; switch ( mips_fpr_return_fields ( valtype , fields ) ) { case 1 : return gen_rtx_REG ( mode , FP_RETURN ) ; case 2 : return mips_return_fpr_pair ( mode , TYPE_MODE ( TREE_TYPE ( fields [ 0 ] ) ) , int_byte_position ( fields [ 0 ] ) , TYPE_MODE ( TREE_TYPE ( fields [ 1 ] ) ) , int_byte_position ( fields [ 1 ] ) ) ; } if ( mips_return_in_msb ( valtype ) ) { HOST_WIDE_INT size = int_size_in_bytes ( valtype ) ; if ( size % UNITS_PER_WORD != 0 ) { size += UNITS_PER_WORD - size % UNITS_PER_WORD ; mode = mode_for_size ( size * BITS_PER_UNIT , MODE_INT , 0 ) ; } } if ( mips_abi != ABI_EABI && ! FLOAT_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , GP_RETURN ) ; } if ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) && GET_MODE_SIZE ( mode ) <= UNITS_PER_HWFPVALUE ) return gen_rtx_REG ( mode , FP_RETURN ) ; if ( mode == TFmode ) return mips_return_fpr_pair ( mode , DImode , 0 , DImode , GET_MODE_SIZE ( mode ) / 2 ) ; if ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT && GET_MODE_SIZE ( mode ) <= UNITS_PER_HWFPVALUE * 2 ) return mips_return_fpr_pair ( mode , GET_MODE_INNER ( mode ) , 0 , GET_MODE_INNER ( mode ) , GET_MODE_SIZE ( mode ) / 2 ) ; return gen_rtx_REG ( mode , GP_RETURN ) ; } </s>

Implement FUNCTION_VALUE and LIBCALL_VALUE . For normal calls , VALTYPE is the return type and MODE is VOIDmode . For libcalls , VALTYPE is null and MODE is the mode of the return value .


<s> void mips_gen_conditional_trap ( rtx * operands ) { rtx op0 , op1 ; enum rtx_code cmp_code = GET_CODE ( operands [ 0 ] ) ; enum machine_mode mode = GET_MODE ( cmp_operands [ 0 ] ) ; switch ( cmp_code ) { case GT : cmp_code = LT ; break ; case LE : cmp_code = GE ; break ; case GTU : cmp_code = LTU ; break ; case LEU : cmp_code = GEU ; break ; default : break ; } if ( cmp_code == GET_CODE ( operands [ 0 ] ) ) { op0 = cmp_operands [ 0 ] ; op1 = cmp_operands [ 1 ] ; } else { op0 = cmp_operands [ 1 ] ; op1 = cmp_operands [ 0 ] ; } op0 = force_reg ( mode , op0 ) ; if ( ! arith_operand ( op1 , mode ) ) op1 = force_reg ( mode , op1 ) ; emit_insn ( gen_rtx_TRAP_IF ( VOIDmode , gen_rtx_fmt_ee ( cmp_code , mode , op0 , op1 ) , operands [ 1 ] ) ) ; } </s>

Emit a conditional trap . OPERANDS is the array of operands passed to the conditional_trap expander .


<s> static bool mips_get_unaligned_mem ( rtx * op , unsigned int width , int bitpos , rtx * left , rtx * right ) { rtx first , last ; if ( ! MEM_P ( * op ) ) return false ; if ( width != 32 && ( ! TARGET_64BIT || width != 64 ) ) return false ; if ( bitpos % BITS_PER_UNIT != 0 ) return false ; if ( MEM_ALIGN ( * op ) >= width ) return false ; * op = adjust_address ( * op , BLKmode , 0 ) ; set_mem_size ( * op , GEN_INT ( width / BITS_PER_UNIT ) ) ; first = adjust_address ( * op , QImode , 0 ) ; last = adjust_address ( * op , QImode , width / BITS_PER_UNIT - 1 ) ; if ( TARGET_BIG_ENDIAN ) * left = first , * right = last ; else * left = last , * right = first ; return true ; } </s>

Return true if it is possible to use left/right accesses for a bitfield of WIDTH bits starting BITPOS bits into * OP . When returning true , update * OP , * LEFT and * RIGHT as follows : * OP is a BLKmode reference to the whole field . * LEFT is a QImode reference to the first byte if big endian or the last byte if little endian . This address can be used in the left-side instructions ( lwl , swl , ldl , sdl ) . * RIGHT is a QImode reference to the opposite end of the field and can be used in the patterning right-side instruction .


<s> static unsigned int mips_global_pointer ( void ) { unsigned int regno ; if ( ! TARGET_ABICALLS ) return GLOBAL_POINTER_REGNUM ; if ( ! TARGET_EXPLICIT_RELOCS ) return GLOBAL_POINTER_REGNUM ; if ( current_function_profile ) return GLOBAL_POINTER_REGNUM ; if ( current_function_has_nonlocal_goto ) return GLOBAL_POINTER_REGNUM ; if ( ! regs_ever_live [ GLOBAL_POINTER_REGNUM ] && ! current_function_uses_const_pool && ! mips_function_has_gp_insn ( ) ) return 0 ; if ( TARGET_NEWABI && current_function_is_leaf ) for ( regno = GP_REG_FIRST ; regno <= GP_REG_LAST ; regno ++ ) if ( ! regs_ever_live [ regno ] && call_used_regs [ regno ] && ! fixed_regs [ regno ] && regno != PIC_FUNCTION_ADDR_REGNUM ) return regno ; return GLOBAL_POINTER_REGNUM ; } </s>

Return the register that should be used as the global pointer within this function . Return 0 if the function does n't need a global pointer .


<s> static bool mips_handle_option ( size_t code , const char * arg , int value ATTRIBUTE_UNUSED ) { switch ( code ) { case OPT_mabi_ : if ( strcmp ( arg , "32" ) == 0 ) mips_abi = ABI_32 ; else if ( strcmp ( arg , "o64" ) == 0 ) mips_abi = ABI_O64 ; else if ( strcmp ( arg , "n32" ) == 0 ) mips_abi = ABI_N32 ; else if ( strcmp ( arg , "64" ) == 0 ) mips_abi = ABI_64 ; else if ( strcmp ( arg , "eabi" ) == 0 ) mips_abi = ABI_EABI ; else return false ; return true ; case OPT_march_ : case OPT_mtune_ : return mips_parse_cpu ( arg ) != 0 ; case OPT_mips : mips_isa_info = mips_parse_cpu ( ACONCAT ( ( "mips" , arg , NULL ) ) ) ; return mips_isa_info != 0 ; case OPT_mno_flush_func : mips_cache_flush_func = NULL ; return true ; default : return true ; } } </s>


<s> unsigned int mips_hard_regno_nregs ( int regno , enum machine_mode mode ) { if ( ST_REG_P ( regno ) ) return ( ( GET_MODE_SIZE ( mode ) + 3 ) / 4 ) ; else if ( ! FP_REG_P ( regno ) ) return ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; else return ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_FPREG - 1 ) / UNITS_PER_FPREG ) ; } </s>


<s> HOST_WIDE_INT mips_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT offset ; compute_frame_size ( get_frame_size ( ) ) ; switch ( from ) { case FRAME_POINTER_REGNUM : offset = 0 ; break ; case ARG_POINTER_REGNUM : offset = ( cfun -> machine -> frame . total_size - current_function_pretend_args_size ) ; break ; default : gcc_unreachable ( ) ; } if ( TARGET_MIPS16 && to == HARD_FRAME_POINTER_REGNUM ) offset -= cfun -> machine -> frame . args_size ; return offset ; } </s>

Implement INITIAL_ELIMINATION_OFFSET . FROM is either the frame pointer or argument pointer . TO is either the stack pointer or hard frame pointer .


<s> static void mips_init_libfuncs ( void ) { if ( TARGET_FIX_VR4120 ) { set_optab_libfunc ( sdiv_optab , SImode , "__vr4120_divsi3" ) ; set_optab_libfunc ( smod_optab , SImode , "__vr4120_modsi3" ) ; } if ( TARGET_MIPS16 && mips16_hard_float ) { set_optab_libfunc ( add_optab , SFmode , "__mips16_addsf3" ) ; set_optab_libfunc ( sub_optab , SFmode , "__mips16_subsf3" ) ; set_optab_libfunc ( smul_optab , SFmode , "__mips16_mulsf3" ) ; set_optab_libfunc ( sdiv_optab , SFmode , "__mips16_divsf3" ) ; set_optab_libfunc ( eq_optab , SFmode , "__mips16_eqsf2" ) ; set_optab_libfunc ( ne_optab , SFmode , "__mips16_nesf2" ) ; set_optab_libfunc ( gt_optab , SFmode , "__mips16_gtsf2" ) ; set_optab_libfunc ( ge_optab , SFmode , "__mips16_gesf2" ) ; set_optab_libfunc ( lt_optab , SFmode , "__mips16_ltsf2" ) ; set_optab_libfunc ( le_optab , SFmode , "__mips16_lesf2" ) ; set_conv_libfunc ( sfix_optab , SImode , SFmode , "__mips16_fix_truncsfsi" ) ; set_conv_libfunc ( sfloat_optab , SFmode , SImode , "__mips16_floatsisf" ) ; if ( TARGET_DOUBLE_FLOAT ) { set_optab_libfunc ( add_optab , DFmode , "__mips16_adddf3" ) ; set_optab_libfunc ( sub_optab , DFmode , "__mips16_subdf3" ) ; set_optab_libfunc ( smul_optab , DFmode , "__mips16_muldf3" ) ; set_optab_libfunc ( sdiv_optab , DFmode , "__mips16_divdf3" ) ; set_optab_libfunc ( eq_optab , DFmode , "__mips16_eqdf2" ) ; set_optab_libfunc ( ne_optab , DFmode , "__mips16_nedf2" ) ; set_optab_libfunc ( gt_optab , DFmode , "__mips16_gtdf2" ) ; set_optab_libfunc ( ge_optab , DFmode , "__mips16_gedf2" ) ; set_optab_libfunc ( lt_optab , DFmode , "__mips16_ltdf2" ) ; set_optab_libfunc ( le_optab , DFmode , "__mips16_ledf2" ) ; set_conv_libfunc ( sext_optab , DFmode , SFmode , "__mips16_extendsfdf2" ) ; set_conv_libfunc ( trunc_optab , SFmode , DFmode , "__mips16_truncdfsf2" ) ; set_conv_libfunc ( sfix_optab , SImode , DFmode , "__mips16_fix_truncdfsi" ) ; set_conv_libfunc ( sfloat_optab , DFmode , SImode , "__mips16_floatsidf" ) ; } } else gofast_maybe_init_libfuncs ( ) ; } </s>


<s> static struct machine_function * mips_init_machine_status ( void ) { return ( ( struct machine_function * ) ggc_alloc_cleared ( sizeof ( struct machine_function ) ) ) ; } </s>

Allocate a chunk of memory for per-function machine-dependent data .


<s> static bool mips_in_small_data_p ( tree decl ) { HOST_WIDE_INT size ; if ( TREE_CODE ( decl ) == STRING_CST || TREE_CODE ( decl ) == FUNCTION_DECL ) return false ; if ( TARGET_ABICALLS ) return false ; if ( TREE_CODE ( decl ) == VAR_DECL && DECL_SECTION_NAME ( decl ) != 0 ) { const char * name ; name = TREE_STRING_POINTER ( DECL_SECTION_NAME ( decl ) ) ; if ( strcmp ( name , ".sdata" ) != 0 && strcmp ( name , ".sbss" ) != 0 ) return false ; if ( TARGET_EXPLICIT_RELOCS || ! DECL_EXTERNAL ( decl ) ) return true ; } else if ( TARGET_EMBEDDED_DATA ) { if ( TREE_CODE ( decl ) != VAR_DECL ) return false ; if ( TREE_READONLY ( decl ) && ! TREE_SIDE_EFFECTS ( decl ) && ( ! DECL_INITIAL ( decl ) || TREE_CONSTANT ( DECL_INITIAL ( decl ) ) ) ) return false ; } size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; return ( size > 0 && size <= mips_section_threshold ) ; } </s>

Implement TARGET_IN_SMALL_DATA_P . Return true if it would be safe to access DECL using % gp_rel ( ... ) ( $ gp ) .


<s> static int mips_issue_rate ( void ) { switch ( mips_tune ) { case PROCESSOR_R4130 : case PROCESSOR_R5400 : case PROCESSOR_R5500 : case PROCESSOR_R7000 : case PROCESSOR_R9000 : return 2 ; case PROCESSOR_SB1 : return 3 ; default : return 1 ; } } </s>

Return the number of instructions that can be issued per cycle .


<s> bool mips_legitimize_address ( rtx * xloc , enum machine_mode mode ) { enum mips_symbol_type symbol_type ; if ( mips_tls_operand_p ( * xloc ) ) { * xloc = mips_legitimize_tls_address ( * xloc ) ; return true ; } if ( mips_symbolic_constant_p ( * xloc , & symbol_type ) && mips_symbolic_address_p ( symbol_type , mode ) && mips_split_p [ symbol_type ] ) { * xloc = mips_split_symbol ( 0 , * xloc ) ; return true ; } if ( GET_CODE ( * xloc ) == PLUS && GET_CODE ( XEXP ( * xloc , 1 ) ) == CONST_INT ) { rtx reg ; reg = XEXP ( * xloc , 0 ) ; if ( ! mips_valid_base_register_p ( reg , mode , 0 ) ) reg = copy_to_mode_reg ( Pmode , reg ) ; * xloc = mips_add_offset ( 0 , reg , INTVAL ( XEXP ( * xloc , 1 ) ) ) ; return true ; } return false ; } </s>

This function is used to implement LEGITIMIZE_ADDRESS . If * XLOC can be legitimized in a way that the generic machinery might not expect , put the new address in * XLOC and return true . MODE is the mode of the memory being accessed .


<s> static void mips_legitimize_const_move ( enum machine_mode mode , rtx dest , rtx src ) { rtx base ; HOST_WIDE_INT offset ; enum mips_symbol_type symbol_type ; if ( GET_CODE ( src ) == CONST_INT && ! TARGET_MIPS16 ) { mips_move_integer ( dest , INTVAL ( src ) ) ; return ; } if ( mips_tls_operand_p ( src ) ) { emit_move_insn ( dest , mips_legitimize_tls_address ( src ) ) ; return ; } if ( ! TARGET_MIPS16 && mips_symbolic_constant_p ( src , & symbol_type ) && mips_split_p [ symbol_type ] ) { emit_move_insn ( dest , mips_split_symbol ( dest , src ) ) ; return ; } mips_split_const ( src , & base , & offset ) ; if ( ! TARGET_MIPS16 && offset != 0 && ( ! no_new_pseudos || SMALL_OPERAND ( offset ) ) ) { base = mips_force_temporary ( dest , base ) ; emit_move_insn ( dest , mips_add_offset ( 0 , base , offset ) ) ; return ; } src = force_const_mem ( mode , src ) ; if ( ! memory_operand ( src , VOIDmode ) ) src = replace_equiv_address ( src , mips_split_symbol ( dest , XEXP ( src , 0 ) ) ) ; emit_move_insn ( dest , src ) ; } </s>

Subroutine of mips_legitimize_move . Move constant SRC into register DEST given that SRC satisfies immediate_operand but does n't satisfy move_operand .


<s> bool mips_legitimize_move ( enum machine_mode mode , rtx dest , rtx src ) { if ( ! register_operand ( dest , mode ) && ! reg_or_0_operand ( src , mode ) ) { emit_move_insn ( dest , force_reg ( mode , src ) ) ; return true ; } if ( GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD && REG_P ( src ) && MD_REG_P ( REGNO ( src ) ) && REG_P ( dest ) && GP_REG_P ( REGNO ( dest ) ) ) { int other_regno = REGNO ( src ) == HI_REGNUM ? LO_REGNUM : HI_REGNUM ; if ( GET_MODE_SIZE ( mode ) <= 4 ) emit_insn ( gen_mfhilo_si ( gen_rtx_REG ( SImode , REGNO ( dest ) ) , gen_rtx_REG ( SImode , REGNO ( src ) ) , gen_rtx_REG ( SImode , other_regno ) ) ) ; else emit_insn ( gen_mfhilo_di ( gen_rtx_REG ( DImode , REGNO ( dest ) ) , gen_rtx_REG ( DImode , REGNO ( src ) ) , gen_rtx_REG ( DImode , other_regno ) ) ) ; return true ; } if ( CONSTANT_P ( src ) && ! move_operand ( src , mode ) ) { mips_legitimize_const_move ( mode , dest , src ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , copy_rtx ( src ) ) ; return true ; } return false ; } </s>

If ( set DEST SRC ) is not a valid instruction , emit an equivalent sequence that is valid .


<s> static rtx mips_legitimize_tls_address ( rtx loc ) { rtx dest , insn , v0 , v1 , tmp1 , tmp2 , eqv ; enum tls_model model ; v0 = gen_rtx_REG ( Pmode , GP_RETURN ) ; v1 = gen_rtx_REG ( Pmode , GP_RETURN + 1 ) ; model = SYMBOL_REF_TLS_MODEL ( loc ) ; switch ( model ) { case TLS_MODEL_GLOBAL_DYNAMIC : insn = mips_call_tls_get_addr ( loc , SYMBOL_TLSGD , v0 ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insn , dest , v0 , loc ) ; break ; case TLS_MODEL_LOCAL_DYNAMIC : insn = mips_call_tls_get_addr ( loc , SYMBOL_TLSLDM , v0 ) ; tmp1 = gen_reg_rtx ( Pmode ) ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_TLS_LDM ) ; emit_libcall_block ( insn , tmp1 , v0 , eqv ) ; tmp2 = mips_unspec_offset_high ( NULL , tmp1 , loc , SYMBOL_DTPREL ) ; dest = gen_rtx_LO_SUM ( Pmode , tmp2 , mips_unspec_address ( loc , SYMBOL_DTPREL ) ) ; break ; case TLS_MODEL_INITIAL_EXEC : tmp1 = gen_reg_rtx ( Pmode ) ; tmp2 = mips_unspec_address ( loc , SYMBOL_GOTTPREL ) ; if ( Pmode == DImode ) { emit_insn ( gen_tls_get_tp_di ( v1 ) ) ; emit_insn ( gen_load_gotdi ( tmp1 , pic_offset_table_rtx , tmp2 ) ) ; } else { emit_insn ( gen_tls_get_tp_si ( v1 ) ) ; emit_insn ( gen_load_gotsi ( tmp1 , pic_offset_table_rtx , tmp2 ) ) ; } dest = gen_reg_rtx ( Pmode ) ; emit_insn ( gen_add3_insn ( dest , tmp1 , v1 ) ) ; break ; case TLS_MODEL_LOCAL_EXEC : if ( Pmode == DImode ) emit_insn ( gen_tls_get_tp_di ( v1 ) ) ; else emit_insn ( gen_tls_get_tp_si ( v1 ) ) ; tmp1 = mips_unspec_offset_high ( NULL , v1 , loc , SYMBOL_TPREL ) ; dest = gen_rtx_LO_SUM ( Pmode , tmp1 , mips_unspec_address ( loc , SYMBOL_TPREL ) ) ; break ; default : gcc_unreachable ( ) ; } return dest ; } </s>

Generate the code to access LOC , a thread local SYMBOL_REF . The return value will be a valid address and move_operand ( either a REG or a LO_SUM ) .


<s> bool mips_linked_madd_p ( rtx prev , rtx insn ) { rtx x ; x = single_set ( insn ) ; if ( x == 0 ) return false ; x = SET_SRC ( x ) ; if ( GET_CODE ( x ) == PLUS && GET_CODE ( XEXP ( x , 0 ) ) == MULT && reg_set_p ( XEXP ( x , 1 ) , prev ) ) return true ; if ( GET_CODE ( x ) == MINUS && GET_CODE ( XEXP ( x , 1 ) ) == MULT && reg_set_p ( XEXP ( x , 0 ) , prev ) ) return true ; return false ; } </s>

Return true if INSN is a multiply-add or multiply-subtract instruction and PREV assigns to the accumulator operand .


<s> static void mips_load_call_address ( rtx dest , rtx addr , int sibcall_p ) { if ( TARGET_EXPLICIT_RELOCS && ! ( sibcall_p && TARGET_NEWABI ) && global_got_operand ( addr , VOIDmode ) ) { rtx high , lo_sum_symbol ; high = mips_unspec_offset_high ( dest , pic_offset_table_rtx , addr , SYMBOL_GOTOFF_CALL ) ; lo_sum_symbol = mips_unspec_address ( addr , SYMBOL_GOTOFF_CALL ) ; if ( Pmode == SImode ) emit_insn ( gen_load_callsi ( dest , high , lo_sum_symbol ) ) ; else emit_insn ( gen_load_calldi ( dest , high , lo_sum_symbol ) ) ; } else emit_move_insn ( dest , addr ) ; } </s>

Load function address ADDR into register DEST . SIBCALL_P is true if the address is needed for a sibling call .


<s> static void mips_macc_chains_record ( rtx insn ) { if ( get_attr_may_clobber_hilo ( insn ) ) mips_macc_chains_last_hilo = insn ; } </s>

A TUNE_MACC_CHAINS helper function . Record that instruction INSN has been scheduled , updating mips_macc_chains_last_hilo appropriately .


<s> static void mips_macc_chains_reorder ( rtx * ready , int nready ) { int i , j ; if ( mips_macc_chains_last_hilo != 0 ) for ( i = nready - 1 ; i >= 0 ; i -- ) if ( mips_linked_madd_p ( mips_macc_chains_last_hilo , ready [ i ] ) ) { for ( j = nready - 1 ; j > i ; j -- ) if ( recog_memoized ( ready [ j ] ) >= 0 && get_attr_may_clobber_hilo ( ready [ j ] ) ) { mips_promote_ready ( ready , i , j ) ; break ; } break ; } } </s>

A TUNE_MACC_CHAINS helper function . Search ready queue READY , which has NREADY elements , looking for a multiply-add or multiply-subtract instruction that is cumulative with mips_macc_chains_last_hilo . If there is one , promote it ahead of anything else that might clobber hi or lo .


<s> static bool mips_matching_cpu_name_p ( const char * canonical , const char * given ) { if ( mips_strict_matching_cpu_name_p ( canonical , given ) ) return true ; if ( TOLOWER ( * given ) == 'r' ) given ++ ; if ( ! ISDIGIT ( * given ) ) return false ; if ( TOLOWER ( canonical [ 0 ] ) == 'v' && TOLOWER ( canonical [ 1 ] ) == 'r' ) canonical += 2 ; else if ( TOLOWER ( canonical [ 0 ] ) == 'r' && TOLOWER ( canonical [ 1 ] ) == 'm' ) canonical += 2 ; else if ( TOLOWER ( canonical [ 0 ] ) == 'r' ) canonical += 1 ; return mips_strict_matching_cpu_name_p ( canonical , given ) ; } </s>

Return true if GIVEN matches CANONICAL , where GIVEN is a user-supplied CPU name . We 've traditionally allowed a lot of variation here . Note : this function is shared between GCC and GAS .


<s> static void mips_move_integer ( rtx dest , unsigned HOST_WIDE_INT value ) { struct mips_integer_op codes [ MIPS_MAX_INTEGER_OPS ] ; enum machine_mode mode ; unsigned int i , cost ; rtx x ; mode = GET_MODE ( dest ) ; cost = mips_build_integer ( codes , value ) ; x = GEN_INT ( codes [ 0 ] . value ) ; for ( i = 1 ; i < cost ; i ++ ) { if ( no_new_pseudos ) emit_move_insn ( dest , x ) , x = dest ; else x = force_reg ( mode , x ) ; x = gen_rtx_fmt_ee ( codes [ i ] . code , mode , x , GEN_INT ( codes [ i ] . value ) ) ; } emit_insn ( gen_rtx_SET ( VOIDmode , dest , x ) ) ; } </s>


<s> static int mips_multipass_dfa_lookahead ( void ) { if ( mips_tune == PROCESSOR_SB1 ) return 4 ; return 0 ; } </s>


<s> void mips_order_regs_for_local_alloc ( void ) { register int i ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) reg_alloc_order [ i ] = i ; if ( TARGET_MIPS16 ) { reg_alloc_order [ 0 ] = 24 ; reg_alloc_order [ 24 ] = 0 ; } } </s>

On the mips16 , we want to allocate $ 24 ( T_REG ) before other registers for instructions for which it is possible . This helps avoid shuffling registers around in order to set up for an xor , encouraging the compiler to use a cmp instead .


<s> void mips_output_aligned_bss ( FILE * stream , tree decl , const char * name , unsigned HOST_WIDE_INT size , int align ) { extern tree last_assemble_variable_decl ; if ( mips_in_small_data_p ( decl ) ) named_section ( 0 , ".sbss" , 0 ) ; else bss_section ( ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( align / BITS_PER_UNIT ) ) ; last_assemble_variable_decl = decl ; ASM_DECLARE_OBJECT_NAME ( stream , name , decl ) ; ASM_OUTPUT_SKIP ( stream , size != 0 ? size : 1 ) ; } </s>

Implement ASM_OUTPUT_ALIGNED_BSS . This differs from the default only in the use of sbss .


<s> void mips_output_aligned_decl_common ( FILE * stream , tree decl , const char * name , unsigned HOST_WIDE_INT size , unsigned int align ) { if ( TARGET_EMBEDDED_DATA && TARGET_UNINIT_CONST_IN_RODATA && TREE_CODE ( decl ) == VAR_DECL && TREE_READONLY ( decl ) && ( DECL_INITIAL ( decl ) == 0 || DECL_INITIAL ( decl ) == error_mark_node ) ) { if ( TREE_PUBLIC ( decl ) && DECL_NAME ( decl ) ) targetm . asm_out . globalize_label ( stream , name ) ; readonly_data_section ( ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( align / BITS_PER_UNIT ) ) ; mips_declare_object ( stream , name , "" , ":\n\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED "\n" , size ) ; } else mips_declare_common_object ( stream , name , "\n\t.comm\t" , size , align , true ) ; } </s>

Implement ASM_OUTPUT_ALIGNED_DECL_COMMON . This is usually the same as the elfos.h version , but we also need to handle -muninit-const-in-rodata .


<s> void mips_output_ascii ( FILE * stream , const char * string_param , size_t len , const char * prefix ) { size_t i ; int cur_pos = 17 ; register const unsigned char * string = ( const unsigned char * ) string_param ; fprintf ( stream , "%s\"" , prefix ) ; for ( i = 0 ; i < len ; i ++ ) { register int c = string [ i ] ; if ( ISPRINT ( c ) ) { if ( c == '\\' || c == '\"' ) { putc ( '\\' , stream ) ; cur_pos ++ ; } putc ( c , stream ) ; cur_pos ++ ; } else { fprintf ( stream , "\\%03o" , c ) ; cur_pos += 4 ; } if ( cur_pos > 72 && i + 1 < len ) { cur_pos = 17 ; fprintf ( stream , "\"\n%s\"" , prefix ) ; } } fprintf ( stream , "\"\n" ) ; } </s>

Output an ASCII string , in a space-saving way . PREFIX is the string that should be written before the opening quote , such as `` \t.ascii\t '' for real string data or `` \t # `` for a comment .


<s>
static
void
mips_output_cplocal
(
void
)
{
if
(
!
TARGET_EXPLICIT_RELOCS
&&
cfun
->
machine
->
global_pointer
>
0
&&
cfun
->
machine
->
global_pointer
!=
GLOBAL_POINTER_REGNUM
)
output_asm_insn
(
".cplocal %+"
,
0
)
;
}
</s>

If we 're generating n32 or n64 abicalls , and the current function does not use $ 28 as its global pointer , emit a cplocal directive . Use pic_offset_table_rtx as the argument to the directive .


<s>
void
mips_output_filename
(
FILE
*
stream
,
const
char
*
name
)
{
if
(
write_symbols
==
DWARF2_DEBUG
)
return
;
else
if
(
mips_output_filename_first_time
)
{
mips_output_filename_first_time
=
0
;
num_source_filenames
+=
1
;
current_function_file
=
name
;
fprintf
(
stream
,
"\t.file\t%d "
,
num_source_filenames
)
;
output_quoted_string
(
stream
,
name
)
;
putc
(
'\n'
,
stream
)
;
}
else
if
(
write_symbols
==
DBX_DEBUG
)
return
;
else
if
(
name
!=
current_function_file
&&
strcmp
(
name
,
current_function_file
)
!=
0
)
{
num_source_filenames
+=
1
;
current_function_file
=
name
;
fprintf
(
stream
,
"\t.file\t%d "
,
num_source_filenames
)
;
output_quoted_string
(
stream
,
name
)
;
putc
(
'\n'
,
stream
)
;
}
}
</s>

Emit a new filename to a stream . If we are smuggling stabs , try to put out a MIPS ECOFF file and a stab .