<s>
static
void
mips16_build_function_stub
(
void
)
{
const
char
*
fnname
,
*
alias_name
,
*
separator
;
char
*
secname
,
*
stubname
;
tree
stubdecl
;
unsigned
int
f
;
rtx
symbol
,
alias
;
symbol
=
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
;
alias
=
mips16_local_alias
(
symbol
)
;
fnname
=
targetm
.
strip_name_encoding
(
XSTR
(
symbol
,
0
)
)
;
alias_name
=
targetm
.
strip_name_encoding
(
XSTR
(
alias
,
0
)
)
;
secname
=
ACONCAT
(
(
".mips16.fn."
,
fnname
,
)
)
;
stubname
=
ACONCAT
(
(
"__fn_stub_"
,
fnname
,
)
)
;
stubdecl
=
build_decl
(
BUILTINS_LOCATION
,
FUNCTION_DECL
,
get_identifier
(
stubname
)
,
build_function_type_list
(
void_type_node
,
NULL_TREE
)
)
;
set_decl_section_name
(
stubdecl
,
secname
)
;
DECL_RESULT
(
stubdecl
)
=
build_decl
(
BUILTINS_LOCATION
,
RESULT_DECL
,
NULL_TREE
,
void_type_node
)
;
fprintf
(
asm_out_file
,
"\t# Stub function for %s ("
,
current_function_name
(
)
)
;
separator
=
""
;
for
(
f
=
(
unsigned
int
)
crtl
->
args
.
info
.
fp_code
;
f
!=
0
;
f
>>=
2
)
{
fprintf
(
asm_out_file
,
"%s%s"
,
separator
,
(
f
&
3
)
==
1
"float"
:
"double"
)
;
separator
=
", "
;
}
fprintf
(
asm_out_file
,
")\n"
)
;
assemble_start_function
(
stubdecl
,
stubname
)
;
mips_start_function_definition
(
stubname
,
false
)
;
if
(
TARGET_ABICALLS_PIC2
)
{
if
(
TARGET_ABSOLUTE_ABICALLS
)
fprintf
(
asm_out_file
,
"\t.option\tpic0\n"
)
;
else
{
output_asm_insn
(
"%(.cpload\t%^%)"
,
)
;
output_asm_insn
(
".reloc\t0,R_MIPS_NONE,%0"
,
&
symbol
)
;
symbol
=
alias
;
}
}
output_asm_insn
(
"la\t%^,%0"
,
&
symbol
)
;
mips_output_args_xfer
(
crtl
->
args
.
info
.
fp_code
,
'f'
)
;
output_asm_insn
(
"jr\t%^"
,
)
;
if
(
TARGET_ABICALLS_PIC2
&&
TARGET_ABSOLUTE_ABICALLS
)
fprintf
(
asm_out_file
,
"\t.option\tpic2\n"
)
;
mips_end_function_definition
(
stubname
)
;
ASM_OUTPUT_DEF
(
asm_out_file
,
alias_name
,
fnname
)
;
switch_to_section
(
function_section
(
current_function_decl
)
)
;
}
</s>

Write a MIPS16 stub for the current function . This stub is used for functions which take arguments in the floating-point registers . It is normal-mode code that moves the floating-point arguments into the general registers and then jumps to the MIPS16 code .


<s> static const char * mips16_call_stub_mode_suffix ( machine_mode mode ) { if ( mode == SFmode ) return "sf" ; else if ( mode == DFmode ) return "df" ; else if ( mode == SCmode ) return "sc" ; else if ( mode == DCmode ) return "dc" ; else if ( mode == V2SFmode ) { gcc_assert ( TARGET_PAIRED_SINGLE_FLOAT ) ; return "df" ; } else gcc_unreachable ( ) ; } </s>

Return the two-character string that identifies floating-point return mode MODE in the name of a MIPS16 function stub .


<s> static bool mips16_cfun_returns_in_fpr_p ( void ) { tree return_type = DECL_RESULT ( current_function_decl ) ; return ( TARGET_MIPS16 && TARGET_HARD_FLOAT_ABI && ! aggregate_value_p ( return_type , current_function_decl ) && mips_return_mode_in_fpr_p ( DECL_MODE ( return_type ) ) ) ; } </s>

Return true if the current function returns its value in a floating-point register in MIPS16 mode .


<s> static int mips16_constant_cost ( int code , HOST_WIDE_INT x ) { switch ( code ) { case ASHIFT : case ASHIFTRT : case LSHIFTRT : if ( IN_RANGE ( x , 1 , 8 ) ) return 0 ; return COSTS_N_INSNS ( 1 ) ; case PLUS : if ( IN_RANGE ( x , - 128 , 127 ) ) return 0 ; if ( SMALL_OPERAND ( x ) ) return COSTS_N_INSNS ( 1 ) ; return - 1 ; case LEU : if ( x == - 1 ) return - 1 ; case LE : x += 1 ; case XOR : case LT : case LTU : if ( IN_RANGE ( x , 0 , 255 ) ) return 0 ; if ( SMALL_OPERAND_UNSIGNED ( x ) ) return COSTS_N_INSNS ( 1 ) ; return - 1 ; case EQ : case NE : if ( x == 0 ) return 0 ; return - 1 ; default : return - 1 ; } } </s>

Return the cost of X when used as an operand to the MIPS16 instruction that implements CODE . Return -1 if there is no such instruction , or if X is not a valid immediate operand for it .


<s> static void mips16_copy_fpr_return_value ( void ) { rtx fn , insn , retval ; tree return_type ; machine_mode return_mode ; const char * name ; return_type = DECL_RESULT ( current_function_decl ) ; return_mode = DECL_MODE ( return_type ) ; name = ACONCAT ( ( "__mips16_ret_" , mips16_call_stub_mode_suffix ( return_mode ) , NULL ) ) ; fn = mips16_stub_function ( name ) ; SYMBOL_REF_FLAGS ( fn ) |= SYMBOL_FLAG_BIND_NOW ; retval = gen_rtx_REG ( return_mode , GP_RETURN ) ; insn = mips_expand_call ( MIPS_CALL_EPILOGUE , retval , fn , const0_rtx , NULL_RTX , false ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , retval ) ; } </s>

The current function is a MIPS16 function that returns a value in an FPR . Copy the return value from its soft-float to its hard-float location . libgcc2 has special non-MIPS16 helper functions for each case .


<s> static void mips16_emit_constants ( struct mips16_constant * constants , rtx_insn * insn ) { int label_num = constants ? CODE_LABEL_NUMBER ( constants -> label ) : 0 ; struct mips16_constant * c , * next ; int align ; align = 0 ; if ( constants ) insn = emit_insn_after ( gen_consttable ( GEN_INT ( label_num ) ) , insn ) ; 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 = mips16_emit_constants_1 ( c -> mode , c -> value , insn ) ; next = c -> next ; free ( c ) ; } if ( constants ) insn = emit_insn_after ( gen_consttable_end ( GEN_INT ( label_num ) ) , insn ) ; emit_barrier_after ( insn ) ; } </s>

Dump out the constants in CONSTANTS after INSN .


<s> static rtx_insn * mips16_emit_constants_1 ( machine_mode mode , rtx value , rtx_insn * insn ) { if ( SCALAR_INT_MODE_P ( mode ) || ALL_SCALAR_FIXED_POINT_MODE_P ( mode ) ) { rtx size = GEN_INT ( GET_MODE_SIZE ( mode ) ) ; return emit_insn_after ( gen_consttable_int ( value , size ) , insn ) ; } if ( SCALAR_FLOAT_MODE_P ( mode ) ) return emit_insn_after ( gen_consttable_float ( value ) , insn ) ; if ( VECTOR_MODE_P ( mode ) ) { int i ; for ( i = 0 ; i < CONST_VECTOR_NUNITS ( value ) ; i ++ ) insn = mips16_emit_constants_1 ( GET_MODE_INNER ( mode ) , CONST_VECTOR_ELT ( value , i ) , insn ) ; return insn ; } gcc_unreachable ( ) ; } </s>

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


<s> void mips16_expand_get_fcsr ( rtx target ) { if ( ! mips16_get_fcsr_stub ) mips16_get_fcsr_stub = new mips16_get_fcsr_one_only_stub ( ) ; rtx fn = mips16_stub_call_address ( mips16_get_fcsr_stub ) ; emit_insn ( PMODE_INSN ( gen_mips_get_fcsr_mips16 , ( fn ) ) ) ; emit_move_insn ( target , gen_rtx_REG ( SImode , GET_FCSR_REGNUM ) ) ; } </s>

Implement `` TARGET = __builtin_mips_get_fcsr ( ) '' for MIPS16 , using a stub .


<s> void mips16_expand_set_fcsr ( rtx newval ) { if ( ! mips16_set_fcsr_stub ) mips16_set_fcsr_stub = new mips16_set_fcsr_one_only_stub ( ) ; rtx fn = mips16_stub_call_address ( mips16_set_fcsr_stub ) ; emit_move_insn ( gen_rtx_REG ( SImode , SET_FCSR_REGNUM ) , newval ) ; emit_insn ( PMODE_INSN ( gen_mips_set_fcsr_mips16 , ( fn ) ) ) ; } </s>

Implement __builtin_mips_set_fcsr ( TARGET ) for MIPS16 , using a stub .


<s> static rtx mips16_gp_pseudo_reg ( void ) { if ( cfun -> machine -> mips16_gp_pseudo_rtx == NULL_RTX ) { rtx_insn * scan ; cfun -> machine -> mips16_gp_pseudo_rtx = gen_reg_rtx ( Pmode ) ; push_topmost_sequence ( ) ; scan = get_insns ( ) ; while ( NEXT_INSN ( scan ) && ! INSN_P ( NEXT_INSN ( scan ) ) ) scan = NEXT_INSN ( scan ) ; rtx set = gen_load_const_gp ( cfun -> machine -> mips16_gp_pseudo_rtx ) ; rtx_insn * insn = emit_insn_after ( set , scan ) ; INSN_LOCATION ( insn ) = 0 ; pop_topmost_sequence ( ) ; } return cfun -> machine -> 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 int mips16_insn_length ( rtx_insn * insn ) { if ( JUMP_TABLE_DATA_P ( insn ) ) { rtx body = PATTERN ( insn ) ; if ( GET_CODE ( body ) == ADDR_VEC ) return GET_MODE_SIZE ( GET_MODE ( body ) ) * XVECLEN ( body , 0 ) ; else if ( GET_CODE ( body ) == ADDR_DIFF_VEC ) return GET_MODE_SIZE ( GET_MODE ( body ) ) * XVECLEN ( body , 1 ) ; else gcc_unreachable ( ) ; } return get_attr_length ( insn ) ; } </s>


<s> static void mips16_lay_out_constants ( bool split_p ) { struct mips16_constant_pool pool ; rtx_insn * insn , * barrier ; if ( ! TARGET_MIPS16_PCREL_LOADS ) return ; if ( split_p ) { if ( mips_cfg_in_reorg ( ) ) split_all_insns ( ) ; else split_all_insns_noflow ( ) ; } barrier = 0 ; memset ( & pool , 0 , sizeof ( pool ) ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( USEFUL_INSN_P ( insn ) ) mips16_rewrite_pool_refs ( insn , & pool ) ; pool . insn_address += mips16_insn_length ( insn ) ; if ( pool . first != NULL ) { if ( barrier == 0 && pool . insn_address + 4 > pool . highest_address ) { rtx_code_label * label ; rtx_insn * 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 ) { mips16_emit_constants ( pool . first , barrier ) ; pool . first = NULL ; barrier = 0 ; } else if ( BARRIER_P ( insn ) ) barrier = insn ; } } mips16_emit_constants ( pool . first , get_last_insn ( ) ) ; } </s>


<s> static void mips16_load_branch_target ( rtx dest , rtx src ) { if ( TARGET_ABICALLS && ! TARGET_ABSOLUTE_ABICALLS ) { rtx page , low ; if ( mips_cfun_has_cprestore_slot_p ( ) ) mips_emit_move ( dest , mips_cprestore_slot ( dest , true ) ) ; else mips_emit_move ( dest , pic_offset_table_rtx ) ; page = mips_unspec_address ( src , SYMBOL_GOTOFF_PAGE ) ; low = mips_unspec_address ( src , SYMBOL_GOT_PAGE_OFST ) ; emit_insn ( gen_rtx_SET ( dest , PMODE_INSN ( gen_unspec_got , ( dest , page ) ) ) ) ; emit_insn ( gen_rtx_SET ( dest , gen_rtx_LO_SUM ( Pmode , dest , low ) ) ) ; } else { src = mips_unspec_address ( src , SYMBOL_ABSOLUTE ) ; mips_emit_move ( dest , src ) ; } } </s>

Emit code to load LABEL_REF SRC into MIPS16 register DEST . This is called very late in mips_reorg , but the caller is required to run mips16_lay_out_constants on the result .


<s> static rtx mips16_local_alias ( rtx func ) { if ( mips16_local_aliases == NULL ) mips16_local_aliases = hash_map < nofree_string_hash , rtx > :: create_ggc ( 37 ) ; bool existed ; const char * func_name = XSTR ( func , 0 ) ; rtx * slot = & mips16_local_aliases -> get_or_insert ( func_name , & existed ) ; gcc_assert ( slot != NULL ) ; if ( ! existed ) { rtx local ; func_name = targetm . strip_name_encoding ( XSTR ( func , 0 ) ) ; const char * local_name = ACONCAT ( ( "__fn_local_" , func_name , NULL ) ) ; local = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( local_name ) ) ; SYMBOL_REF_FLAGS ( local ) = SYMBOL_REF_FLAGS ( func ) | SYMBOL_FLAG_LOCAL ; * slot = local ; } return * slot ; } </s>

FUNC is the symbol for a locally-defined hard-float MIPS16 function . Return a local alias for it , creating a new one if necessary .


<s> static bool mips16_local_function_p ( const_rtx x ) { return ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_LOCAL_P ( x ) && ! SYMBOL_REF_EXTERNAL_P ( x ) && ( mips_get_compress_mode ( SYMBOL_REF_DECL ( x ) ) & MASK_MIPS16 ) ) ; } </s>

Return true if function X is a locally-defined and locally-binding MIPS16 function .


<s> static void mips16_rewrite_pool_constant ( struct mips16_constant_pool * pool , rtx * x ) { rtx base , offset ; rtx_code_label * label ; split_const ( * x , & base , & offset ) ; if ( GET_CODE ( base ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( base ) ) { label = mips16_add_constant ( pool , copy_rtx ( get_pool_constant ( base ) ) , get_pool_mode ( base ) ) ; base = gen_rtx_LABEL_REF ( Pmode , label ) ; * x = mips_unspec_address_offset ( base , offset , SYMBOL_PC_RELATIVE ) ; } } </s>

If * X is a symbolic constant that refers to the constant pool , add the constant to POOL and rewrite * X to use the constant 's label .


<s> static void mips16_rewrite_pool_refs ( rtx_insn * insn , struct mips16_constant_pool * pool ) { subrtx_ptr_iterator :: array_type array ; FOR_EACH_SUBRTX_PTR ( iter , array , & PATTERN ( insn ) , ALL ) { rtx * loc = * iter ; if ( force_to_mem_operand ( * loc , Pmode ) ) { rtx mem = force_const_mem ( GET_MODE ( * loc ) , * loc ) ; validate_change ( insn , loc , mem , false ) ; } if ( MEM_P ( * loc ) ) { mips16_rewrite_pool_constant ( pool , & XEXP ( * loc , 0 ) ) ; iter . skip_subrtxes ( ) ; } else { if ( TARGET_MIPS16_TEXT_LOADS ) mips16_rewrite_pool_constant ( pool , loc ) ; if ( GET_CODE ( * loc ) == CONST || ( GET_CODE ( * loc ) == UNSPEC && XINT ( * loc , 1 ) == UNSPEC_TLS_GET_TP ) ) iter . skip_subrtxes ( ) ; } } } </s>

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


<s> static void mips16_split_long_branches ( void ) { bool something_changed ; if ( ! TARGET_MIPS16 ) return ; do { rtx_insn * insn ; rtx_jump_insn * jump_insn ; shorten_branches ( get_insns ( ) ) ; something_changed = false ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) if ( ( jump_insn = dyn_cast < rtx_jump_insn * > ( insn ) ) && get_attr_length ( jump_insn ) > 4 && ( any_condjump_p ( jump_insn ) || any_uncondjump_p ( jump_insn ) ) ) { rtx old_label , temp , saved_temp ; rtx_code_label * new_label ; rtx target ; rtx_insn * jump , * jump_sequence ; start_sequence ( ) ; saved_temp = gen_rtx_REG ( Pmode , AT_REGNUM ) ; temp = gen_rtx_REG ( Pmode , GP_REG_FIRST + 2 ) ; emit_move_insn ( saved_temp , temp ) ; old_label = JUMP_LABEL ( jump_insn ) ; target = gen_rtx_LABEL_REF ( Pmode , old_label ) ; mips16_load_branch_target ( temp , target ) ; jump = emit_jump_insn ( PMODE_INSN ( gen_indirect_jump_and_restore , ( temp , temp , saved_temp ) ) ) ; JUMP_LABEL ( jump ) = old_label ; LABEL_NUSES ( old_label ) ++ ; mips16_lay_out_constants ( false ) ; if ( simplejump_p ( jump_insn ) ) new_label = NULL ; else { new_label = gen_label_rtx ( ) ; emit_label ( new_label ) ; } jump_sequence = get_insns ( ) ; end_sequence ( ) ; emit_insn_after ( jump_sequence , jump_insn ) ; if ( new_label ) invert_jump ( jump_insn , new_label , false ) ; else delete_insn ( jump_insn ) ; something_changed = true ; } } while ( something_changed ) ; } </s>

If we 're compiling a MIPS16 function , look for and split any long branches . This must be called after all other instruction modifications in mips_reorg .


<s> static rtx mips16_stub_call_address ( mips_one_only_stub * stub ) { rtx fn = mips16_stub_function ( stub -> get_name ( ) ) ; SYMBOL_REF_FLAGS ( fn ) |= SYMBOL_FLAG_LOCAL ; if ( ! call_insn_operand ( fn , VOIDmode ) ) fn = force_reg ( Pmode , fn ) ; return fn ; } </s>

Return a legitimate call address for STUB , given that STUB is a MIPS16 support function .


<s> static rtx mips16_stub_function ( const char * name ) { rtx x ; x = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( name ) ) ; SYMBOL_REF_FLAGS ( x ) |= ( SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION ) ; return x ; } </s>

Return a SYMBOL_REF for a MIPS16 function called NAME .


<s> static bool mips16_stub_function_p ( const_rtx x ) { return ( GET_CODE ( x ) == SYMBOL_REF && startswith ( XSTR ( x , 0 ) , "__mips16_" ) ) ; } </s>

Return true if function X is a libgcc MIPS16 stub function .


<s> static bool mips16_unextended_reference_p ( machine_mode mode , rtx base , unsigned HOST_WIDE_INT offset ) { if ( mode != BLKmode && offset % GET_MODE_SIZE ( mode ) == 0 ) { if ( GET_MODE_SIZE ( mode ) == 4 && base == stack_pointer_rtx ) return offset < 256U * GET_MODE_SIZE ( mode ) ; return offset < 32U * GET_MODE_SIZE ( mode ) ; } return false ; } </s>

Return true if a value at OFFSET bytes from BASE can be accessed using an unextended mips16 instruction . MODE is the mode of the value . Usually the offset in an unextended instruction is a 5-bit field . The offset is unsigned and shifted left once for HIs , twice for SIs , and so on . An exception is SImode accesses off the stack pointer , which have an 8-bit immediate field .


<s> static void mips_74k_agen_init ( rtx_insn * insn ) { if ( ! insn || CALL_P ( insn ) || JUMP_P ( insn ) ) mips_last_74k_agen_insn = TYPE_UNKNOWN ; else { enum attr_type type = get_attr_type ( insn ) ; if ( type == TYPE_LOAD || type == TYPE_STORE ) mips_last_74k_agen_insn = type ; } } </s>

Initialize mips_last_74k_agen_insn from INSN . A null argument resets to TYPE_UNKNOWN state .


<s> static void mips_74k_agen_reorder ( rtx_insn * * ready , int nready ) { int i ; int store_pos , load_pos ; store_pos = - 1 ; load_pos = - 1 ; for ( i = nready - 1 ; i >= 0 ; i -- ) { rtx_insn * insn = ready [ i ] ; if ( USEFUL_INSN_P ( insn ) ) switch ( get_attr_type ( insn ) ) { case TYPE_STORE : if ( store_pos == - 1 ) store_pos = i ; break ; case TYPE_LOAD : if ( load_pos == - 1 ) load_pos = i ; break ; default : break ; } } if ( load_pos == - 1 || store_pos == - 1 ) return ; switch ( mips_last_74k_agen_insn ) { case TYPE_UNKNOWN : case TYPE_LOAD : mips_maybe_swap_ready ( ready , load_pos , store_pos , 4 ) ; break ; case TYPE_STORE : mips_maybe_swap_ready ( ready , store_pos , load_pos , 4 ) ; break ; default : break ; } } </s>

A TUNE_74K helper function . The 74K AGEN pipeline likes multiple loads to be grouped together , and multiple stores to be grouped together . Swap things around in the ready queue to make this happen .


<s> bool mips_9bit_offset_address_p ( rtx x , machine_mode mode ) { struct mips_address_info addr ; return ( mips_classify_address ( & addr , x , mode , false ) && addr . type == ADDRESS_REG && CONST_INT_P ( addr . offset ) && MIPS_9BIT_OFFSET_P ( INTVAL ( addr . offset ) ) ) ; } </s>

Return true if X is a legitimate address with a 9-bit offset . MODE is the mode of the value being accessed .


<s> static int mips_address_cost ( rtx addr , machine_mode mode , addr_space_t as ATTRIBUTE_UNUSED , bool speed ATTRIBUTE_UNUSED ) { return mips_address_insns ( addr , mode , false ) ; } </s>

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


<s> int mips_address_insns ( rtx x , machine_mode mode , bool might_split_p ) { struct mips_address_info addr ; int factor ; bool msa_p = ( ! might_split_p && MSA_SUPPORTED_MODE_P ( mode ) ) ; if ( mode != BLKmode && might_split_p ) factor = ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; else factor = 1 ; if ( mips_classify_address ( & addr , x , mode , false ) ) switch ( addr . type ) { case ADDRESS_REG : if ( msa_p ) { if ( mips_signed_immediate_p ( INTVAL ( addr . offset ) , 10 , mips_ldst_scaled_shift ( mode ) ) ) return 1 ; else return 0 ; } if ( TARGET_MIPS16 && ! mips16_unextended_reference_p ( mode , addr . reg , UINTVAL ( addr . offset ) ) ) return factor * 2 ; return factor ; case ADDRESS_LO_SUM : return msa_p ? 0 : TARGET_MIPS16 ? factor * 2 : factor ; case ADDRESS_CONST_INT : return msa_p ? 0 : factor ; case ADDRESS_SYMBOLIC : return msa_p ? 0 : factor * mips_symbol_insns ( addr . symbol_type , mode ) ; } return 0 ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at X . Return 0 if X is n't valid for MODE . For mips16 code , count extended instructions as two instructions .


<s> static void mips_add_cfa_restore ( rtx reg ) { mips_epilogue . cfa_restores = alloc_reg_note ( REG_CFA_RESTORE , reg , mips_epilogue . cfa_restores ) ; } </s>

Record that the epilogue has restored call-saved register REG .


<s> static rtx mips_add_offset ( rtx temp , rtx reg , HOST_WIDE_INT offset ) { if ( ! SMALL_OPERAND ( offset ) ) { rtx high ; if ( TARGET_MIPS16 ) { high = GEN_INT ( offset ) ; offset = 0 ; } else { high = gen_int_mode ( CONST_HIGH_PART ( offset ) , Pmode ) ; offset = CONST_LOW_PART ( offset ) ; } high = mips_force_temporary ( temp , high ) ; reg = mips_force_temporary ( temp , gen_rtx_PLUS ( Pmode , high , reg ) ) ; } return plus_constant ( Pmode , reg , offset ) ; } </s>

Return a legitimate address for REG + OFFSET . TEMP is as for mips_force_temporary ; it is only needed when OFFSET is not a SMALL_OPERAND .


<s> static void mips_adjust_block_mem ( rtx mem , HOST_WIDE_INT length , rtx * loop_reg , rtx * loop_mem ) { * loop_reg = copy_addr_to_reg ( XEXP ( mem , 0 ) ) ; * loop_mem = change_address ( mem , BLKmode , * loop_reg ) ; set_mem_align ( * loop_mem , MIN ( MEM_ALIGN ( mem ) , length * BITS_PER_UNIT ) ) ; } </s>

Helper function for doing a loop-based block operation on memory reference MEM . Each iteration of the loop will operate on LENGTH bytes of MEM . Create a new base register for use within the loop and point it to the start of MEM . Create a new memory reference that uses this register . Store them in * LOOP_REG and * LOOP_MEM respectively .


<s> static int mips_adjust_cost ( rtx_insn * , int dep_type , rtx_insn * , int cost , unsigned int ) { if ( dep_type != 0 && ( dep_type != REG_DEP_OUTPUT || ! TUNE_20KC ) ) 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 * insn , int length ) { if ( length == MAX_PIC_BRANCH_LENGTH && JUMP_P ( insn ) && INSN_CODE ( insn ) >= 0 && get_attr_type ( insn ) == TYPE_BRANCH ) { length = simplejump_p ( insn ) ? 0 : 8 ; length += BASE_INSN_LENGTH * mips_load_label_num_insns ( ) ; length += TARGET_COMPRESSION ? 2 : 4 ; } if ( CALL_P ( insn ) || ( TARGET_MIPS16 ? simplejump_p ( insn ) : JUMP_P ( insn ) ) ) length += TARGET_MIPS16 ? 2 : 4 ; if ( ! cfun -> machine -> ignore_hazard_length_p && INSN_P ( insn ) && INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_DELAY : case HAZARD_FORBIDDEN_SLOT : length += NOP_INSN_LENGTH ; break ; case HAZARD_HILO : length += NOP_INSN_LENGTH * 2 ; break ; } 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_annotate_pic_calls ( void ) { basic_block bb ; rtx_insn * insn ; FOR_EACH_BB_FN ( bb , cfun ) FOR_BB_INSNS ( bb , insn ) { rtx call , reg , symbol , second_call ; second_call = 0 ; call = mips_call_expr_from_insn ( insn , & second_call ) ; if ( ! call ) continue ; gcc_assert ( MEM_P ( XEXP ( call , 0 ) ) ) ; reg = XEXP ( XEXP ( call , 0 ) , 0 ) ; if ( ! REG_P ( reg ) ) continue ; symbol = mips_find_pic_call_symbol ( insn , reg , true ) ; if ( symbol ) { mips_annotate_pic_call_expr ( call , symbol ) ; if ( second_call ) mips_annotate_pic_call_expr ( second_call , symbol ) ; } } } </s>

Use DF to annotate PIC indirect calls with the function symbol they dispatch to .


<s> static void mips_annotate_pic_call_expr ( rtx call , rtx symbol ) { rtx args_size ; args_size = XEXP ( call , 1 ) ; XEXP ( call , 1 ) = gen_rtx_UNSPEC ( GET_MODE ( args_size ) , gen_rtvec ( 2 , args_size , symbol ) , UNSPEC_CALL_ATTR ) ; } </s>

Replace the args_size operand of the call expression CALL with the call-attribute UNSPEC and fill in SYMBOL as the function symbol .


<s> static int mips_arg_partial_bytes ( cumulative_args_t cum , const function_arg_info & arg ) { struct mips_arg_info info ; mips_get_arg_info ( & info , get_cumulative_args ( cum ) , arg . mode , arg . type , arg . named ) ; return info . stack_words > 0 ? info . reg_words * UNITS_PER_WORD : 0 ; } </s>


<s> static unsigned int mips_arg_regno ( const struct mips_arg_info * info , bool hard_float_p ) { if ( ! info -> fpr_p || ! hard_float_p ) return GP_ARG_FIRST + info -> reg_offset ; else if ( mips_abi == ABI_32 && TARGET_DOUBLE_FLOAT && info -> reg_offset > 0 ) return FP_ARG_FIRST + 2 ; else return FP_ARG_FIRST + info -> reg_offset ; } </s>

INFO describes a register argument that has the normal format for the argument 's mode . Return the register it uses , assuming that FPRs are available if HARD_FLOAT_P .


<s> static unsigned HOST_WIDE_INT mips_asan_shadow_offset ( void ) { return SUBTARGET_SHADOW_OFFSET ; } </s>

Implement the TARGET_ASAN_SHADOW_OFFSET hook .


<s> static void mips_asm_file_end ( void ) { if ( NEED_INDICATE_EXEC_STACK ) file_end_indicate_exec_stack ( ) ; } </s>

If we are optimizing the global pointer , emit the text section now and any small externs which did not have .comm , etc that are needed . Also , give a warning if the data area is more than 32K and -pic because 3 instructions are needed to reference the data pointers .


<s> static unsigned int mips_autovectorize_vector_modes ( vector_modes * modes , bool ) { if ( ISA_HAS_MSA ) modes -> safe_push ( V16QImode ) ; return 0 ; } </s>


<s> static void mips_avoid_hazard ( rtx_insn * after , rtx_insn * insn , int * hilo_delay , rtx * delayed_reg , rtx lo_reg , bool * fs_delay ) { rtx pattern , set ; int nops , ninsns ; 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 if ( * fs_delay && get_attr_can_delay ( insn ) == CAN_DELAY_NO && GET_CODE ( PATTERN ( after ) ) != SEQUENCE && GET_CODE ( pattern ) != ASM_INPUT && asm_noperands ( pattern ) < 0 ) nops = 1 ; else if ( TUNE_P6600 && TARGET_CB_MAYBE && ! optimize_size && ( ( mips_classify_branch_p6600 ( after ) == UC_BALC && mips_classify_branch_p6600 ( insn ) == UC_OTHER ) || ( mips_classify_branch_p6600 ( insn ) == UC_BALC && mips_classify_branch_p6600 ( after ) == UC_OTHER ) ) ) nops = 1 ; else nops = 0 ; * hilo_delay += nops ; rtx_insn * real_after = after ; if ( real_after && nops && CALL_P ( real_after ) ) while ( real_after && ( NOTE_P ( NEXT_INSN ( real_after ) ) || BARRIER_P ( NEXT_INSN ( real_after ) ) ) ) real_after = NEXT_INSN ( real_after ) ; while ( nops -- > 0 ) emit_insn_after ( gen_hazard_nop ( ) , real_after ) ; * hilo_delay += ninsns ; * delayed_reg = 0 ; * fs_delay = false ; if ( INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : if ( TUNE_P6600 && ! optimize_size && TARGET_CB_MAYBE && mips_classify_branch_p6600 ( insn ) == UC_OTHER ) * fs_delay = true ; break ; case HAZARD_FORBIDDEN_SLOT : if ( TARGET_CB_MAYBE ) * fs_delay = true ; break ; case HAZARD_HILO : * hilo_delay = 0 ; break ; case HAZARD_DELAY : set = single_set ( insn ) ; gcc_assert ( set ) ; * 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 int mips_binary_cost ( rtx x , int single_cost , int double_cost , bool speed ) { int cost ; if ( GET_MODE_SIZE ( GET_MODE ( x ) ) == UNITS_PER_WORD * 2 ) cost = double_cost ; else cost = single_cost ; return ( cost + set_src_cost ( XEXP ( x , 0 ) , GET_MODE ( x ) , speed ) + rtx_cost ( XEXP ( x , 1 ) , GET_MODE ( x ) , GET_CODE ( x ) , 1 , speed ) ) ; } </s>

Return the cost of binary operation X , given that the instruction sequence for a word-sized or smaller operation has cost SINGLE_COST and that the sequence of a double-word operation has cost DOUBLE_COST . If SPEED is true , optimize for speed otherwise optimize for size .


<s> static void mips_block_move_loop ( rtx dest , rtx src , HOST_WIDE_INT length , HOST_WIDE_INT bytes_per_iter ) { rtx_code_label * label ; rtx src_reg , dest_reg , final_src , test ; HOST_WIDE_INT leftover ; leftover = length % bytes_per_iter ; length -= leftover ; mips_adjust_block_mem ( src , bytes_per_iter , & src_reg , & src ) ; mips_adjust_block_mem ( dest , bytes_per_iter , & 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 , bytes_per_iter ) ; mips_emit_move ( src_reg , plus_constant ( Pmode , src_reg , bytes_per_iter ) ) ; mips_emit_move ( dest_reg , plus_constant ( Pmode , dest_reg , bytes_per_iter ) ) ; test = gen_rtx_NE ( VOIDmode , src_reg , final_src ) ; if ( Pmode == DImode ) emit_jump_insn ( gen_cbranchdi4 ( test , src_reg , final_src , label ) ) ; else emit_jump_insn ( gen_cbranchsi4 ( test , src_reg , final_src , label ) ) ; if ( leftover ) mips_block_move_straight ( dest , src , leftover ) ; else emit_insn ( gen_nop ( ) ) ; } </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 ; machine_mode mode ; rtx * regs ; if ( ! ISA_HAS_LWL_LWR ) bits = MIN ( BITS_PER_WORD , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) ) ; else { 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 = int_mode_for_size ( bits , 0 ) . require ( ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( 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 ) mips_emit_move ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; else { rtx part = adjust_address ( src , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ext_as_unaligned_load ( regs [ i ] , part , bits , 0 , 0 ) ) gcc_unreachable ( ) ; } } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) if ( MEM_ALIGN ( dest ) >= bits ) mips_emit_move ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; else { rtx part = adjust_address ( dest , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ins_as_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 ) ) , RETURN_BEGIN ) ; } } </s>

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


<s> static bool mips_breakable_sequence_p ( rtx_insn * insn ) { return ( insn && GET_CODE ( PATTERN ( insn ) ) == SEQUENCE && TARGET_CB_MAYBE && get_attr_compact_form ( SEQ_BEGIN ( insn ) ) != COMPACT_FORM_NEVER ) ; } </s>

A SEQUENCE is breakable iff the branch inside it has a compact form and the target has compact branches .


<s> static rtx_insn * mips_break_sequence ( rtx_insn * insn ) { rtx_insn * before = PREV_INSN ( insn ) ; rtx_insn * branch = SEQ_BEGIN ( insn ) ; rtx_insn * ds = SEQ_END ( insn ) ; remove_insn ( insn ) ; add_insn_after ( ds , before , NULL ) ; add_insn_after ( branch , ds , NULL ) ; return ds ; } </s>

Remove a SEQUENCE and replace it with the delay slot instruction followed by the branch and return the instruction in the delay slot . Return the first of the two new instructions . Subroutine of mips_reorg_process_insns .


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 tree mips_build_cvpointer_type ( void ) { static tree cache ; if ( cache == NULL_TREE ) cache = build_pointer_type ( build_qualified_type ( void_type_node , TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE ) ) ; return cache ; } </s>

Return a type for 'const volatile void * ' .


<s> static unsigned int mips_build_integer ( struct mips_integer_op * codes , unsigned HOST_WIDE_INT value ) { if ( SMALL_OPERAND ( value ) || SMALL_OPERAND_UNSIGNED ( value ) || LUI_OPERAND ( value ) ) { codes [ 0 ] . code = UNKNOWN ; codes [ 0 ] . value = value ; return 1 ; } else if ( ( value & 1 ) != 0 || LUI_OPERAND ( CONST_HIGH_PART ( value ) ) ) { return mips_build_lower ( codes , value ) ; } else if ( ( value & 0xffff ) == 0 ) { return mips_build_shift ( codes , value ) ; } else { struct mips_integer_op alt_codes [ MIPS_MAX_INTEGER_OPS ] ; unsigned int cost , alt_cost ; cost = mips_build_shift ( codes , value ) ; alt_cost = mips_build_lower ( alt_codes , value ) ; if ( alt_cost < cost ) { memcpy ( codes , alt_codes , alt_cost * sizeof ( codes [ 0 ] ) ) ; cost = alt_cost ; } return cost ; } } </s>

Fill CODES with a sequence of rtl operations to load VALUE . Return the number of operations needed .


<s> static unsigned int mips_build_lower ( struct mips_integer_op * codes , unsigned HOST_WIDE_INT value ) { unsigned HOST_WIDE_INT high ; unsigned int i ; high = value & ~ ( unsigned HOST_WIDE_INT ) 0xffff ; if ( ! LUI_OPERAND ( high ) && ( value & 0x18000 ) == 0x18000 ) { i = mips_build_integer ( codes , CONST_HIGH_PART ( value ) ) ; codes [ i ] . code = PLUS ; codes [ i ] . value = CONST_LOW_PART ( value ) ; } else { i = mips_build_integer ( codes , high ) ; codes [ i ] . code = IOR ; codes [ i ] . value = value & 0xffff ; } return i + 1 ; } </s>

As for mips_build_shift , but assume that the final action will be an IOR or PLUS operation .


<s> static unsigned int mips_build_shift ( struct mips_integer_op * codes , HOST_WIDE_INT value ) { unsigned int i , shift ; shift = 0 ; while ( ( value & 1 ) == 0 ) value /= 2 , shift ++ ; i = mips_build_integer ( codes , value ) ; codes [ i ] . code = ASHIFT ; codes [ i ] . value = shift ; return i + 1 ; } </s>

Subroutine of mips_build_integer ( with the same interface ) . Assume that the final action in the sequence should be a left shift .


<s> static rtx mips_builtin_branch_and_move ( rtx condition , rtx target , rtx value_if_true , rtx value_if_false ) { rtx_code_label * true_label , * done_label ; true_label = gen_label_rtx ( ) ; done_label = gen_label_rtx ( ) ; mips_emit_move ( target , value_if_false ) ; emit_jump_insn ( gen_condjump ( condition , true_label ) ) ; emit_jump_insn ( gen_jump ( done_label ) ) ; emit_barrier ( ) ; emit_label ( true_label ) ; mips_emit_move ( target , value_if_true ) ; emit_label ( done_label ) ; return target ; } </s>

Move VALUE_IF_TRUE into TARGET if CONDITION is true ; move VALUE_IF_FALSE into TARGET otherwise . Return TARGET .


<s> static tree mips_builtin_decl ( unsigned int code , bool initialize_p ATTRIBUTE_UNUSED ) { if ( code >= ARRAY_SIZE ( mips_builtins ) ) return error_mark_node ; return mips_builtin_decls [ code ] ; } </s>


<s> static tree mips_builtin_vectorized_function ( unsigned int fn , tree type_out , tree type_in ) { machine_mode in_mode , out_mode ; int in_n , out_n ; if ( TREE_CODE ( type_out ) != VECTOR_TYPE || TREE_CODE ( type_in ) != VECTOR_TYPE || ! ISA_HAS_MSA ) return NULL_TREE ; out_mode = TYPE_MODE ( TREE_TYPE ( type_out ) ) ; out_n = TYPE_VECTOR_SUBPARTS ( type_out ) ; in_mode = TYPE_MODE ( TREE_TYPE ( type_in ) ) ; in_n = TYPE_VECTOR_SUBPARTS ( type_in ) ; mips_builtin_decls [ mips_get_builtin_decl_index [ CODE_FOR_ ## INSN ] ] switch ( fn ) { case BUILT_IN_SQRT : if ( out_mode == DFmode && out_n == 2 && in_mode == DFmode && in_n == 2 ) return MIPS_GET_BUILTIN ( msa_fsqrt_d ) ; break ; case BUILT_IN_SQRTF : if ( out_mode == SFmode && out_n == 4 && in_mode == SFmode && in_n == 4 ) return MIPS_GET_BUILTIN ( msa_fsqrt_w ) ; break ; default : break ; } </s>


<s> static tree mips_builtin_vector_type ( tree type , machine_mode mode ) { static tree types [ 2 * ( int ) MAX_MACHINE_MODE ] ; int mode_index ; mode_index = ( int ) mode ; if ( TREE_CODE ( type ) == INTEGER_TYPE && TYPE_UNSIGNED ( type ) ) mode_index += MAX_MACHINE_MODE ; if ( types [ mode_index ] == NULL_TREE ) types [ mode_index ] = build_vector_type_for_mode ( type , mode ) ; return types [ mode_index ] ; } </s>

MODE is a vector mode whose elements have type TYPE . Return the type of the vector itself .


<s> static bool mips_callee_copies ( cumulative_args_t , const function_arg_info & arg ) { return mips_abi == ABI_EABI && arg . named ; } </s>


<s> static rtx mips_call_expr_from_insn ( rtx_insn * insn , rtx * second_call ) { rtx x ; rtx x2 ; if ( ! CALL_P ( insn ) ) return NULL_RTX ; x = PATTERN ( insn ) ; if ( GET_CODE ( x ) == PARALLEL ) { x2 = XVECEXP ( x , 0 , 1 ) ; if ( GET_CODE ( x2 ) == SET ) x2 = XEXP ( x2 , 1 ) ; if ( GET_CODE ( x2 ) == CALL ) * second_call = x2 ; x = XVECEXP ( x , 0 , 0 ) ; } if ( GET_CODE ( x ) == SET ) x = XEXP ( x , 1 ) ; gcc_assert ( GET_CODE ( x ) == CALL ) ; return x ; } </s>

If INSN is a call , return the underlying CALL expr . Return NULL_RTX otherwise . If INSN has two call rtx , then store the second one in SECOND_CALL .


<s> static bool mips_call_may_need_jalx_p ( tree decl ) { if ( mips_get_compress_mode ( decl ) != TARGET_COMPRESSION ) return true ; if ( ! DECL_EXTERNAL ( decl ) && targetm . binds_local_p ( decl ) ) return false ; if ( TARGET_INTERLINK_COMPRESSED ) { if ( ! TARGET_COMPRESSION && mips_get_compress_off_flags ( DECL_ATTRIBUTES ( decl ) ) == 0 ) return true ; if ( TARGET_COMPRESSION && mips_get_compress_on_flags ( DECL_ATTRIBUTES ( decl ) ) == 0 ) return true ; } return false ; } </s>

Return true if a call to DECL may need to use JALX .


<s> static rtx_insn * mips_call_tls_get_addr ( rtx sym , enum mips_symbol_type type , rtx v0 ) { rtx loc , a0 ; rtx_insn * insn ; 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 ( a0 , gen_rtx_LO_SUM ( Pmode , pic_offset_table_rtx , loc ) ) ) ; insn = mips_expand_call ( MIPS_CALL_NORMAL , v0 , mips_tls_symbol , const0_rtx , NULL_RTX , false ) ; RTL_CONST_CALL_P ( insn ) = 1 ; 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> static bool mips_cannot_force_const_mem ( machine_mode mode , rtx x ) { enum mips_symbol_type type ; rtx base , offset ; if ( GET_CODE ( x ) == HIGH ) return true ; if ( ( CONST_INT_P ( x ) || GET_CODE ( x ) == CONST_VECTOR ) && mips_legitimate_constant_p ( mode , x ) ) return true ; split_const ( x , & base , & offset ) ; if ( mips_symbolic_constant_p ( base , SYMBOL_CONTEXT_LEA , & type ) ) { if ( mips_use_pcrel_pool_p [ ( int ) type ] ) return false ; if ( SMALL_INT ( offset ) && mips_symbol_insns ( type , MAX_MACHINE_MODE ) > 0 ) return true ; if ( TARGET_MIPS16_PCREL_LOADS && mips_got_symbol_type_p ( type ) ) return true ; } if ( tls_referenced_p ( x ) ) return true ; return false ; } </s>

Return true if X can not be forced into a constant pool .


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

Return true if * CMP1 ( of mode MODE ) is a valid second operand for integer ordering test * CODE , or if an equivalent combination can be formed by adjusting * CODE and * CMP1 . When returning true , update * CODE and * CMP1 with the chosen code and operand , otherwise leave them alone .


<s> static reg_class_t mips_canonicalize_move_class ( reg_class_t rclass ) { if ( reg_class_subset_p ( rclass , ACC_REGS ) ) rclass = ACC_REGS ; if ( TARGET_MIPS16 && reg_class_subset_p ( rclass , M16_REGS ) ) rclass = M16_REGS ; else if ( reg_class_subset_p ( rclass , GENERAL_REGS ) ) rclass = GENERAL_REGS ; return rclass ; } </s>

RCLASS is a class involved in a REGISTER_MOVE_COST calculation . Return a `` canonical '' class to represent it in later calculations .


<s> static bool mips_can_change_mode_class ( machine_mode from , machine_mode to , reg_class_t rclass ) { if ( GET_MODE_SIZE ( from ) == 8 && GET_MODE_SIZE ( to ) == 8 && INTEGRAL_MODE_P ( from ) && INTEGRAL_MODE_P ( to ) ) return true ; if ( MSA_SUPPORTED_MODE_P ( from ) && MSA_SUPPORTED_MODE_P ( to ) ) return true ; return ! reg_classes_intersect_p ( FP_REGS , rclass ) ; } </s>


<s> static bool mips_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( to == HARD_FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM ) ; } </s>

Make sure that we 're not trying to eliminate to the wrong hard frame pointer .


<s> static bool mips_can_inline_p ( tree caller , tree callee ) { if ( mips_get_compress_mode ( callee ) != mips_get_compress_mode ( caller ) ) return false ; return default_target_can_inline_p ( caller , callee ) ; } </s>


<s> bool mips_can_use_return_insn ( void ) { if ( cfun -> machine -> interrupt_handler_p ) return false ; if ( ! reload_completed ) return false ; if ( crtl -> profile ) return false ; if ( mips16_cfun_returns_in_fpr_p ( ) ) return false ; return ( cfun -> machine -> frame . total_size == 0 && ! cfun -> machine -> use_frame_header_for_callee_saved_regs ) ; } </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> unsigned int mips_case_values_threshold ( void ) { if ( TARGET_MIPS16 && optimize_size ) return 10 ; else return default_case_values_threshold ( ) ; } </s>


<s> static bool mips_cfg_in_reorg ( void ) { return ( mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE || TARGET_RELAX_PIC_CALLS ) ; } </s>

Return whether CFG is used in mips_reorg .


<s> static bool mips_cfun_call_saved_reg_p ( unsigned int regno ) { if ( global_regs [ regno ] ) return false ; if ( cfun -> machine -> interrupt_handler_p && mips_interrupt_extra_call_saved_reg_p ( regno ) ) return true ; return ( regno == GLOBAL_POINTER_REGNUM ? TARGET_CALL_SAVED_GP : ! call_used_regs [ regno ] ) ; } </s>

Return true if the current function should treat register REGNO as call-saved .


<s> bool mips_cfun_has_cprestore_slot_p ( void ) { return ( cfun -> machine -> global_pointer != INVALID_REGNUM && cfun -> machine -> frame . cprestore_size > 0 ) ; } </s>

Return true if the current function has a cprestore slot .


<s> static bool mips_cfun_has_flexible_gp_ref_p ( void ) { if ( TARGET_ABICALLS_PIC2 && ! reload_completed && crtl -> uses_const_pool ) return true ; return mips_find_gp_ref ( & cfun -> machine -> has_flexible_gp_insn_p , mips_insn_has_flexible_gp_ref_p ) ; } </s>

Return true if the current function references the global pointer , but if those references do not inherently require the global pointer to be $ 28 . Assume ! mips_cfun_has_inflexible_gp_ref_p ( ) .


<s> static bool mips_cfun_has_inflexible_gp_ref_p ( void ) { if ( crtl -> has_nonlocal_goto ) return true ; if ( TARGET_ABICALLS_PIC2 ) { if ( ! TARGET_EXPLICIT_RELOCS ) return true ; if ( crtl -> profile ) return true ; if ( mips16_cfun_returns_in_fpr_p ( ) ) return true ; } return mips_find_gp_ref ( & cfun -> machine -> has_inflexible_gp_insn_p , mips_insn_has_inflexible_gp_ref_p ) ; } </s>

Return true if the current function refers to the global pointer in a way that forces $ 28 to be valid . This means that we ca n't change the choice of global pointer , even for NewABI code . One example of this ( and one which needs several checks ) is that $ 28 must be valid when calling traditional MIPS lazy-binding stubs . ( This restriction does not apply to PLTs . )


Return true if the function body might clobber register REGNO . We know that REGNO is call-saved .


<s> static bool mips_classify_address ( struct mips_address_info * info , rtx x , machine_mode mode , bool strict_p ) { switch ( GET_CODE ( x ) ) { case REG : case SUBREG : info -> type = ADDRESS_REG ; info -> reg = x ; info -> offset = const0_rtx ; return mips_valid_base_register_p ( info -> reg , mode , strict_p ) ; case PLUS : info -> type = ADDRESS_REG ; info -> reg = XEXP ( x , 0 ) ; info -> offset = XEXP ( x , 1 ) ; return ( mips_valid_base_register_p ( info -> reg , mode , strict_p ) && mips_valid_offset_p ( info -> offset , mode ) ) ; case LO_SUM : info -> type = ADDRESS_LO_SUM ; info -> reg = XEXP ( x , 0 ) ; info -> offset = XEXP ( x , 1 ) ; info -> symbol_type = mips_classify_symbolic_expression ( info -> offset , SYMBOL_CONTEXT_MEM ) ; return ( mips_valid_base_register_p ( info -> reg , mode , strict_p ) && mips_valid_lo_sum_p ( info -> symbol_type , mode ) ) ; case CONST_INT : info -> type = ADDRESS_CONST_INT ; return ! TARGET_MIPS16 && SMALL_INT ( x ) ; case CONST : case LABEL_REF : case SYMBOL_REF : info -> type = ADDRESS_SYMBOLIC ; return ( mips_symbolic_constant_p ( x , SYMBOL_CONTEXT_MEM , & info -> symbol_type ) && mips_symbol_insns ( info -> symbol_type , mode ) > 0 && ! mips_split_p [ info -> symbol_type ] ) ; default : return false ; } } </s>

Return true if X is a valid address for machine mode MODE . If it is , fill in INFO appropriately . STRICT is true if we should only accept hard base registers .


<s> static enum mips_ucbranch_type mips_classify_branch_p6600 ( rtx_insn * insn ) { if ( ! insn || ! USEFUL_INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == SEQUENCE ) return UC_UNDEFINED ; if ( get_attr_jal ( insn ) == JAL_INDIRECT || get_attr_type ( insn ) == TYPE_JUMP ) return UC_OTHER ; if ( CALL_P ( insn ) && get_attr_jal ( insn ) == JAL_DIRECT ) return UC_BALC ; return UC_UNDEFINED ; } </s>

Subroutine of mips_avoid_hazard . We classify unconditional branches of interest for the P6600 for performance reasons . We 're interested in differentiating BALC from JIC , JIALC and BC .


<s> static enum mips_symbol_type mips_classify_symbol ( const_rtx x , enum mips_symbol_context context ) { if ( TARGET_RTP_PIC ) return SYMBOL_GOT_DISP ; if ( GET_CODE ( x ) == LABEL_REF ) { if ( TARGET_MIPS16_SHORT_JUMP_TABLES && ! LABEL_REF_NONLOCAL_P ( x ) ) return SYMBOL_PC_RELATIVE ; if ( TARGET_ABICALLS && ! TARGET_ABSOLUTE_ABICALLS ) return SYMBOL_GOT_PAGE_OFST ; return SYMBOL_ABSOLUTE ; } gcc_assert ( GET_CODE ( x ) == SYMBOL_REF ) ; if ( SYMBOL_REF_TLS_MODEL ( x ) ) return SYMBOL_TLS ; if ( CONSTANT_POOL_ADDRESS_P ( x ) ) { if ( TARGET_MIPS16_TEXT_LOADS ) return SYMBOL_PC_RELATIVE ; if ( TARGET_MIPS16_PCREL_LOADS && context == SYMBOL_CONTEXT_MEM ) return SYMBOL_PC_RELATIVE ; if ( mips_rtx_constant_in_small_data_p ( get_pool_mode ( x ) ) ) return SYMBOL_GP_RELATIVE ; } if ( TARGET_GPOPT && SYMBOL_REF_SMALL_P ( x ) && ! SYMBOL_REF_WEAK ( x ) ) return SYMBOL_GP_RELATIVE ; if ( TARGET_ABICALLS_PIC2 && ! ( TARGET_ABSOLUTE_ABICALLS && mips_symbol_binds_local_p ( x ) ) ) { if ( mips_global_symbol_p ( x ) ) return SYMBOL_GOT_DISP ; return SYMBOL_GOT_PAGE_OFST ; } return SYMBOL_ABSOLUTE ; } </s>

Classify symbol X , which must be a SYMBOL_REF or a LABEL_REF .


<s> static enum mips_symbol_type mips_classify_symbolic_expression ( rtx x , enum mips_symbol_context context ) { rtx offset ; split_const ( x , & x , & offset ) ; if ( UNSPEC_ADDRESS_P ( x ) ) return UNSPEC_ADDRESS_TYPE ( x ) ; return mips_classify_symbol ( x , context ) ; } </s>

Classify the base of symbolic expression X , given that X appears in context CONTEXT .


<s> int mips_class_max_nregs ( enum reg_class rclass , machine_mode mode ) { int size ; HARD_REG_SET left ; size = 0x8000 ; left = reg_class_contents [ rclass ] ; if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) ST_REGS ] ) ) { if ( mips_hard_regno_mode_ok ( ST_REG_FIRST , mode ) ) size = MIN ( size , 4 ) ; left &= ~ reg_class_contents [ ST_REGS ] ; } if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) FP_REGS ] ) ) { if ( mips_hard_regno_mode_ok ( FP_REG_FIRST , mode ) ) { if ( MSA_SUPPORTED_MODE_P ( mode ) ) size = MIN ( size , UNITS_PER_MSA_REG ) ; else size = MIN ( size , UNITS_PER_FPREG ) ; } left &= ~ reg_class_contents [ FP_REGS ] ; } if ( ! hard_reg_set_empty_p ( left ) ) size = MIN ( size , UNITS_PER_WORD ) ; return ( GET_MODE_SIZE ( mode ) + size - 1 ) / size ; } </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> static void mips_code_end ( void ) { mips_finish_stub ( & mips16_rdhwr_stub ) ; mips_finish_stub ( & mips16_get_fcsr_stub ) ; mips_finish_stub ( & mips16_set_fcsr_stub ) ; } </s>


<s> static void mips_conditional_register_usage ( void ) { if ( ISA_HAS_DSP ) { global_regs [ CCDSP_PO_REGNUM ] = 1 ; global_regs [ CCDSP_SC_REGNUM ] = 1 ; } else accessible_reg_set &= ~ reg_class_contents [ DSP_ACC_REGS ] ; if ( ! ISA_HAS_HILO ) accessible_reg_set &= ~ reg_class_contents [ MD_REGS ] ; if ( ! TARGET_HARD_FLOAT ) accessible_reg_set &= ~ ( reg_class_contents [ FP_REGS ] | reg_class_contents [ ST_REGS ] ) ; else if ( ! ISA_HAS_8CC ) { accessible_reg_set &= ~ reg_class_contents [ ST_REGS ] ; if ( ! ISA_HAS_CCF ) SET_HARD_REG_BIT ( accessible_reg_set , FPSW_REGNUM ) ; fixed_regs [ FPSW_REGNUM ] = 1 ; } if ( TARGET_MIPS16 ) { fixed_regs [ 18 ] = 1 ; fixed_regs [ 19 ] = 1 ; fixed_regs [ 20 ] = 1 ; fixed_regs [ 21 ] = 1 ; fixed_regs [ 22 ] = 1 ; fixed_regs [ 23 ] = 1 ; fixed_regs [ 26 ] = 1 ; fixed_regs [ 27 ] = 1 ; fixed_regs [ 30 ] = 1 ; if ( optimize_size ) { fixed_regs [ 8 ] = 1 ; fixed_regs [ 9 ] = 1 ; fixed_regs [ 10 ] = 1 ; fixed_regs [ 11 ] = 1 ; fixed_regs [ 12 ] = 1 ; fixed_regs [ 13 ] = 1 ; fixed_regs [ 14 ] = 1 ; fixed_regs [ 15 ] = 1 ; } operand_reg_set &= ~ reg_class_contents [ MD_REGS ] ; } if ( mips_abi == ABI_64 ) { int regno ; for ( regno = FP_REG_FIRST + 20 ; regno < FP_REG_FIRST + 24 ; regno ++ ) call_used_regs [ regno ] = 1 ; } if ( mips_abi == ABI_N32 || ( mips_abi == ABI_32 && TARGET_FLOAT64 ) ) { int regno ; for ( regno = FP_REG_FIRST + 21 ; regno <= FP_REG_FIRST + 31 ; regno += 2 ) call_used_regs [ regno ] = 1 ; } if ( TARGET_LITTLE_ENDIAN ) { unsigned int regno ; mips_swap_registers ( MD_REG_FIRST ) ; for ( regno = DSP_ACC_REG_FIRST ; regno <= DSP_ACC_REG_LAST ; regno += 2 ) mips_swap_registers ( regno ) ; } } </s>


<s> static HOST_WIDE_INT mips_constant_alignment ( const_tree exp , HOST_WIDE_INT align ) { if ( TREE_CODE ( exp ) == STRING_CST || TREE_CODE ( exp ) == CONSTRUCTOR ) return MAX ( align , BITS_PER_WORD ) ; return align ; } </s>


<s> static inline bool mips_constant_elt_p ( rtx x ) { return CONST_INT_P ( x ) || GET_CODE ( x ) == CONST_DOUBLE ; } </s>

A subroutine of mips_expand_vec_init , match constant vector elements .


<s> int mips_const_insns ( rtx x ) { struct mips_integer_op codes [ MIPS_MAX_INTEGER_OPS ] ; enum mips_symbol_type symbol_type ; rtx offset ; switch ( GET_CODE ( x ) ) { case HIGH : if ( ! mips_symbolic_constant_p ( XEXP ( x , 0 ) , SYMBOL_CONTEXT_LEA , & symbol_type ) || ! mips_split_p [ symbol_type ] ) return 0 ; return TARGET_MIPS16 ? 4 : 1 ; case CONST_INT : if ( TARGET_MIPS16 ) return ( IN_RANGE ( INTVAL ( x ) , 0 , 255 ) ? 1 : SMALL_OPERAND_UNSIGNED ( INTVAL ( x ) ) ? 2 : IN_RANGE ( - INTVAL ( x ) , 0 , 255 ) ? 2 : SMALL_OPERAND_UNSIGNED ( - INTVAL ( x ) ) ? 3 : 0 ) ; return mips_build_integer ( codes , INTVAL ( x ) ) ; case CONST_VECTOR : if ( MSA_SUPPORTED_MODE_P ( GET_MODE ( x ) ) && mips_const_vector_same_int_p ( x , GET_MODE ( x ) , - 512 , 511 ) ) return 1 ; case CONST_DOUBLE : return ! TARGET_MIPS16 && x == CONST0_RTX ( GET_MODE ( x ) ) ? 1 : 0 ; case CONST : if ( CONST_GP_P ( x ) ) return 1 ; if ( mips_symbolic_constant_p ( x , SYMBOL_CONTEXT_LEA , & symbol_type ) ) return mips_symbol_insns ( symbol_type , MAX_MACHINE_MODE ) ; split_const ( x , & x , & offset ) ; if ( offset != 0 ) { int n = mips_const_insns ( x ) ; if ( n != 0 ) { if ( SMALL_INT ( offset ) ) return n + 1 ; else if ( ! targetm . cannot_force_const_mem ( GET_MODE ( x ) , x ) ) return n + 1 + mips_build_integer ( codes , INTVAL ( offset ) ) ; } } return 0 ; case SYMBOL_REF : case LABEL_REF : return mips_symbol_insns ( mips_classify_symbol ( x , SYMBOL_CONTEXT_LEA ) , MAX_MACHINE_MODE ) ; default : return 0 ; } } </s>


<s> bool mips_const_vector_bitimm_clr_p ( rtx op , machine_mode mode ) { if ( GET_CODE ( op ) == CONST_VECTOR && op != CONSTM1_RTX ( mode ) ) { unsigned HOST_WIDE_INT val = ~ UINTVAL ( CONST_VECTOR_ELT ( op , 0 ) ) ; int vlog2 = exact_log2 ( val & GET_MODE_MASK ( GET_MODE_INNER ( mode ) ) ) ; if ( vlog2 != - 1 ) { gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT ) ; gcc_assert ( vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE ( mode ) - 1 ) ; return mips_const_vector_same_val_p ( op , mode ) ; } } return false ; } </s>

Return true if OP is a constant vector with the number of units in MODE , and each unit has the same bit clear .


<s> bool mips_const_vector_bitimm_set_p ( rtx op , machine_mode mode ) { if ( GET_CODE ( op ) == CONST_VECTOR && op != CONST0_RTX ( mode ) ) { unsigned HOST_WIDE_INT val = UINTVAL ( CONST_VECTOR_ELT ( op , 0 ) ) ; int vlog2 = exact_log2 ( val & GET_MODE_MASK ( GET_MODE_INNER ( mode ) ) ) ; if ( vlog2 != - 1 ) { gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT ) ; gcc_assert ( vlog2 >= 0 && vlog2 <= GET_MODE_UNIT_BITSIZE ( mode ) - 1 ) ; return mips_const_vector_same_val_p ( op , mode ) ; } } return false ; } </s>

Return true if OP is a constant vector with the number of units in MODE , and each unit has the same bit set .


<s> bool mips_const_vector_same_bytes_p ( rtx op , machine_mode mode ) { int i , bytes ; HOST_WIDE_INT val , first_byte ; rtx first ; if ( ! mips_const_vector_same_val_p ( op , mode ) ) return false ; first = CONST_VECTOR_ELT ( op , 0 ) ; bytes = GET_MODE_UNIT_SIZE ( mode ) ; val = INTVAL ( first ) ; first_byte = val & 0xff ; for ( i = 1 ; i < bytes ; i ++ ) { val >>= 8 ; if ( ( val & 0xff ) != first_byte ) return false ; } return true ; } </s>

Return true if OP is a constant vector with the number of units in MODE , and each unit has the same value as well as replicated bytes in the value .


<s> bool mips_const_vector_same_int_p ( rtx op , machine_mode mode , HOST_WIDE_INT low , HOST_WIDE_INT high ) { HOST_WIDE_INT value ; rtx elem0 ; if ( ! mips_const_vector_same_val_p ( op , mode ) ) return false ; elem0 = CONST_VECTOR_ELT ( op , 0 ) ; if ( ! CONST_INT_P ( elem0 ) ) return false ; value = INTVAL ( elem0 ) ; return ( value >= low && value <= high ) ; } </s>

Return true if OP is a constant vector with the number of units in MODE , and each unit has the same integer value in the range [ LOW , HIGH ] .


<s> bool mips_const_vector_same_val_p ( rtx op , machine_mode mode ) { int i , nunits = GET_MODE_NUNITS ( mode ) ; rtx first ; if ( GET_CODE ( op ) != CONST_VECTOR || GET_MODE ( op ) != mode ) return false ; first = CONST_VECTOR_ELT ( op , 0 ) ; for ( i = 1 ; i < nunits ; i ++ ) if ( ! rtx_equal_p ( first , CONST_VECTOR_ELT ( op , i ) ) ) return false ; return true ; } </s>

Return true if OP is a constant vector with the number of units in MODE , and each unit has the same value .


<s> bool mips_const_vector_shuffle_set_p ( rtx op , machine_mode mode ) { int nunits = GET_MODE_NUNITS ( mode ) ; int nsets = nunits / 4 ; int set = 0 ; int i , j ; for ( j = 0 ; j < nsets ; j ++ , set = 4 * j ) for ( i = 0 ; i < 4 ; i ++ ) if ( ( INTVAL ( XVECEXP ( op , 0 , i ) ) != ( INTVAL ( XVECEXP ( op , 0 , set + i ) ) - set ) ) || ! IN_RANGE ( INTVAL ( XVECEXP ( op , 0 , set + i ) ) , 0 , set + 3 ) ) return false ; return true ; } </s>

Return true if OP is a constant vector with repeated 4-element sets in mode MODE .


<s> bool mips_cprestore_address_p ( rtx x , bool load_p ) { rtx given_base , required_base ; HOST_WIDE_INT given_offset , required_offset ; mips_split_plus ( x , & given_base , & given_offset ) ; mips_get_cprestore_base_and_offset ( & required_base , & required_offset , load_p ) ; return given_base == required_base && given_offset == required_offset ; } </s>

Return true if X is the load or store address of the cprestore slot ; LOAD_P says which .


<s> static rtx mips_cprestore_slot ( rtx temp , bool load_p ) { rtx base ; HOST_WIDE_INT offset ; mips_get_cprestore_base_and_offset ( & base , & offset , load_p ) ; return gen_frame_mem ( Pmode , mips_add_offset ( temp , base , offset ) ) ; } </s>

Return a MEM rtx for the cprestore slot . LOAD_P is true if we are going to load from it , false if we are going to store to it . Use TEMP as a temporary register if need be .


<s> static const struct mips_cpu_info * mips_cpu_info_from_isa ( int isa ) { unsigned int i ; for ( i = 0 ; i < ARRAY_SIZE ( mips_cpu_info_table ) ; i ++ ) if ( mips_cpu_info_table [ i ] . isa == isa ) return mips_cpu_info_table + i ; return NULL ; } </s>

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


<s> static const struct mips_cpu_info * mips_cpu_info_from_opt ( int opt ) { switch ( opt ) { case MIPS_ARCH_OPTION_FROM_ABI : return mips_cpu_info_from_isa ( ABI_NEEDS_32BIT_REGS ? 1 : ABI_NEEDS_64BIT_REGS ? 3 : ( TARGET_64BIT ? 3 : 1 ) ) ; case MIPS_ARCH_OPTION_NATIVE : gcc_unreachable ( ) ; default : return & mips_cpu_info_table [ opt ] ; } } </s>

Return a mips_cpu_info entry determined by an option valued OPT .


<s> enum mips_loadgp_style mips_current_loadgp_style ( void ) { if ( ! TARGET_USE_GOT || cfun -> machine -> global_pointer == INVALID_REGNUM ) return LOADGP_NONE ; if ( TARGET_RTP_PIC ) return LOADGP_RTP ; if ( TARGET_ABSOLUTE_ABICALLS ) return LOADGP_ABSOLUTE ; return TARGET_NEWABI ? LOADGP_NEWABI : LOADGP_OLDABI ; } </s>

Return the style of GP load sequence that is being used for the current function .


<s> bool mips_dangerous_for_la25_p ( rtx x ) { return ( ! TARGET_EXPLICIT_RELOCS && TARGET_USE_GOT && GET_CODE ( x ) == SYMBOL_REF && mips_global_symbol_p ( x ) ) ; } </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 .


<s> static void mips_deallocate_stack ( rtx base , rtx offset , HOST_WIDE_INT new_frame_size ) { if ( base == stack_pointer_rtx && offset == const0_rtx ) return ; mips_frame_barrier ( ) ; if ( offset == const0_rtx ) { emit_move_insn ( stack_pointer_rtx , base ) ; mips_epilogue_set_cfa ( stack_pointer_rtx , new_frame_size ) ; } else if ( TARGET_MIPS16 && base != stack_pointer_rtx ) { emit_insn ( gen_add3_insn ( base , base , offset ) ) ; mips_epilogue_set_cfa ( base , new_frame_size ) ; emit_move_insn ( stack_pointer_rtx , base ) ; } else { emit_insn ( gen_add3_insn ( stack_pointer_rtx , base , offset ) ) ; mips_epilogue_set_cfa ( stack_pointer_rtx , new_frame_size ) ; } } </s>

Emit code to set the stack pointer to BASE + OFFSET , given that BASE + OFFSET is NEW_FRAME_SIZE bytes below the top of the frame . BASE , if not the stack pointer , is available as a temporary .


<s> HOST_WIDE_INT mips_debugger_offset ( rtx addr , HOST_WIDE_INT offset ) { rtx offset2 = const0_rtx ; rtx reg = eliminate_constant_term ( addr , & offset2 ) ; if ( offset == 0 ) offset = INTVAL ( offset2 ) ; if ( reg == stack_pointer_rtx || reg == frame_pointer_rtx || reg == hard_frame_pointer_rtx ) { offset -= cfun -> machine -> frame . total_size ; if ( reg == hard_frame_pointer_rtx ) offset += cfun -> machine -> frame . hard_frame_pointer_offset ; } return offset ; } </s>

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_common_object ( FILE * stream , const char * name , const char * init_string , unsigned HOST_WIDE_INT size , unsigned int align , bool takes_alignment_p ) { if ( ! takes_alignment_p ) { size += ( align / BITS_PER_UNIT ) - 1 ; size -= size % ( align / BITS_PER_UNIT ) ; mips_declare_object ( stream , name , init_string , "," HOST_WIDE_INT_PRINT_UNSIGNED "\n" , size ) ; } else mips_declare_object ( stream , name , init_string , "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n" , size , align / BITS_PER_UNIT ) ; } </s>

Declare a common object of SIZE bytes using asm directive INIT_STRING . NAME is the name of the object and ALIGN is the required alignment in bytes . TAKES_ALIGNMENT_P is true if the directive takes a third alignment argument .


<s> void mips_declare_object ( FILE * stream , const char * name , const char * init_string , const char * final_string , ... ) { va_list ap ; fputs ( init_string , stream ) ; assemble_name ( stream , name ) ; va_start ( ap , final_string ) ; vfprintf ( stream , final_string , ap ) ; va_end ( ap ) ; if ( ! TARGET_EXPLICIT_RELOCS ) { tree name_tree = get_identifier ( name ) ; TREE_ASM_WRITTEN ( name_tree ) = 1 ; } } </s>

Emit either a label , .comm , or .lcomm directive . When using assembler macros , mark the symbol as written so that mips_file_end wo n't emit an .extern for it . STREAM is the output file , NAME is the name of the symbol , INIT_STRING is the string that should be written before the symbol and FINAL_STRING is the string that should be written after it . FINAL_STRING is a printf ( ) format that consumes the remaining arguments .


<s> void mips_declare_object_name ( FILE * stream , const char * name , tree decl ATTRIBUTE_UNUSED ) { if ( USE_GNU_UNIQUE_OBJECT && DECL_ONE_ONLY ( decl ) && ( ! DECL_ARTIFICIAL ( decl ) || ! TREE_READONLY ( decl ) ) ) ASM_OUTPUT_TYPE_DIRECTIVE ( stream , name , "gnu_unique_object" ) ; else 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 const struct mips_cpu_info * mips_default_arch ( void ) { unsigned int i ; for ( i = 0 ; i < ARRAY_SIZE ( mips_cpu_info_table ) ; i ++ ) if ( strcmp ( mips_cpu_info_table [ i ] . name , MIPS_CPU_STRING_DEFAULT ) == 0 ) return mips_cpu_info_table + i ; gcc_unreachable ( ) ; return mips_cpu_info_from_isa ( MIPS_ISA_DEFAULT ) ; return mips_cpu_info_from_opt ( MIPS_ARCH_OPTION_FROM_ABI ) ; } </s>

Return a default mips_cpu_info entry , given that no -march= option was explicitly specified .


<s> static void mips_dfa_post_advance_cycle ( void ) { if ( TUNE_LOONGSON_2EF ) mips_ls2_dfa_post_advance_cycle ( curr_state ) ; } </s>

Implement TARGET_SCHED_DFA_POST_ADVANCE_CYCLE . This hook is being called at the start of each cycle .


<s> static void mips_df_reorg ( void ) { df_set_flags ( DF_EQ_NOTES ) ; df_chain_add_problem ( DF_UD_CHAIN ) ; df_analyze ( ) ; if ( TARGET_RELAX_PIC_CALLS ) mips_annotate_pic_calls ( ) ; if ( mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE ) r10k_insert_cache_barriers ( ) ; df_finish_pass ( false ) ; } </s>

Subroutine of mips_reorg to manage passes that require DF .


<s> static bool mips_direct_save_slot_move_p ( unsigned int regno , rtx mem , bool load_p ) { if ( TARGET_MIPS16 && ! load_p && regno == RETURN_ADDR_REGNUM ) return false ; return mips_secondary_reload_class ( REGNO_REG_CLASS ( regno ) , GET_MODE ( mem ) , mem , load_p ) == NO_REGS ; } </s>

Return true if a move between register REGNO and its save slot ( MEM ) can be done in a single move . LOAD_P is true if we are loading from the slot , false if we are storing to it .


<s> static machine_mode mips_dwarf_frame_reg_mode ( int regno ) { machine_mode mode = default_dwarf_frame_reg_mode ( regno ) ; if ( FP_REG_P ( regno ) && mips_abi == ABI_32 && ! TARGET_FLOAT32 ) mode = SImode ; return mode ; } </s>


<s> static rtx mips_dwarf_register_span ( rtx reg ) { rtx high , low ; machine_mode mode ; mode = GET_MODE ( reg ) ; if ( FP_REG_P ( REGNO ( reg ) ) && TARGET_FLOATXX && GET_MODE_SIZE ( mode ) > UNITS_PER_FPREG ) { return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 1 , reg ) ) ; } else if ( FP_REG_P ( REGNO ( reg ) ) && TARGET_BIG_ENDIAN && MAX_FPRS_PER_FMT > 1 && GET_MODE_SIZE ( mode ) > UNITS_PER_FPREG ) { gcc_assert ( GET_MODE_SIZE ( mode ) == UNITS_PER_HWFPVALUE ) ; high = mips_subword ( reg , true ) ; low = mips_subword ( reg , false ) ; return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , high , low ) ) ; } return NULL_RTX ; } </s>


<s> bool mips_eh_uses ( unsigned int regno ) { if ( reload_completed && ! TARGET_ABSOLUTE_JUMPS ) { if ( mips_cfun_has_cprestore_slot_p ( ) ) { if ( regno == CPRESTORE_SLOT_REGNUM ) return true ; } else { if ( cfun -> machine -> global_pointer == regno ) return true ; } } return false ; } </s>


<s> void mips_emit_binary ( enum rtx_code code , rtx target , rtx op0 , rtx op1 ) { emit_insn ( gen_rtx_SET ( 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 rtx_insn * mips_emit_call_insn ( rtx pattern , rtx orig_addr , rtx addr , bool lazy_p ) { rtx_insn * insn ; rtx reg ; insn = emit_call_insn ( pattern ) ; if ( TARGET_MIPS16 && mips_use_pic_fn_addr_reg_p ( orig_addr ) ) { reg = gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) ; emit_insn_before ( gen_move_insn ( reg , addr ) , insn ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , reg ) ; } if ( lazy_p ) use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , pic_offset_table_rtx ) ; if ( TARGET_USE_GOT ) { use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , gen_rtx_REG ( Pmode , GOT_VERSION_REGNUM ) ) ; emit_insn ( gen_update_got_version ( ) ) ; } if ( TARGET_MIPS16 && TARGET_EXPLICIT_RELOCS && TARGET_CALL_CLOBBERED_GP ) { rtx post_call_tmp_reg = gen_rtx_REG ( word_mode , POST_CALL_TMP_REG ) ; clobber_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , post_call_tmp_reg ) ; } return insn ; } </s>

Emit a call sequence with call pattern PATTERN and return the call instruction itself ( which is not necessarily the last instruction emitted ) . ORIG_ADDR is the original , unlegitimized address , ADDR is the legitimized form , and LAZY_P is true if the call address is lazily-bound .


<s> static void mips_emit_compare ( enum rtx_code * code , rtx * op0 , rtx * op1 , bool need_eq_ne_p ) { rtx cmp_op0 = * op0 ; rtx cmp_op1 = * op1 ; if ( GET_MODE_CLASS ( GET_MODE ( * op0 ) ) == MODE_INT ) { if ( ! need_eq_ne_p && * op1 == const0_rtx ) ; else if ( * code == EQ || * code == NE ) { if ( need_eq_ne_p ) { * op0 = mips_zero_if_equal ( cmp_op0 , cmp_op1 ) ; * op1 = const0_rtx ; } else * op1 = force_reg ( GET_MODE ( cmp_op0 ) , cmp_op1 ) ; } else if ( ! need_eq_ne_p && TARGET_CB_MAYBE ) { bool swap = false ; switch ( * code ) { case LE : swap = true ; * code = GE ; break ; case GT : swap = true ; * code = LT ; break ; case LEU : swap = true ; * code = GEU ; break ; case GTU : swap = true ; * code = LTU ; break ; case GE : case LT : case GEU : case LTU : break ; default : gcc_unreachable ( ) ; } * op1 = force_reg ( GET_MODE ( cmp_op0 ) , cmp_op1 ) ; if ( swap ) { rtx tmp = * op1 ; * op1 = * op0 ; * op0 = tmp ; } } else { bool invert = false ; * op0 = gen_reg_rtx ( GET_MODE ( cmp_op0 ) ) ; mips_emit_int_order_test ( * code , & invert , * op0 , cmp_op0 , cmp_op1 ) ; * code = ( invert ? EQ : NE ) ; * op1 = const0_rtx ; } } else if ( ALL_FIXED_POINT_MODE_P ( GET_MODE ( cmp_op0 ) ) ) { * op0 = gen_rtx_REG ( CCDSPmode , CCDSP_CC_REGNUM ) ; mips_emit_binary ( * code , * op0 , cmp_op0 , cmp_op1 ) ; * code = NE ; * op1 = const0_rtx ; } else { enum rtx_code cmp_code ; cmp_code = * code ; if ( ISA_HAS_CCF ) { * code = NE ; * op0 = gen_reg_rtx ( CCFmode ) ; } else { * code = mips_reversed_fp_cond ( & cmp_code ) ? EQ : NE ; if ( ISA_HAS_8CC ) * op0 = mips_allocate_fcc ( CCmode ) ; else * op0 = gen_rtx_REG ( CCmode , FPSW_REGNUM ) ; } * op1 = const0_rtx ; mips_emit_binary ( cmp_code , * op0 , cmp_op0 , cmp_op1 ) ; } } </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> static void mips_emit_int_order_test ( enum rtx_code code , bool * invert_ptr , rtx target , rtx cmp0 , rtx cmp1 ) { machine_mode mode ; mode = GET_MODE ( cmp0 ) ; if ( mips_canonicalize_int_order_test ( & code , & cmp1 , mode ) ) mips_emit_binary ( code , target , cmp0 , cmp1 ) ; else { enum rtx_code inv_code = reverse_condition ( code ) ; if ( ! mips_canonicalize_int_order_test ( & inv_code , & cmp1 , mode ) ) { cmp1 = force_reg ( mode , cmp1 ) ; mips_emit_int_order_test ( code , invert_ptr , target , cmp0 , cmp1 ) ; } else if ( invert_ptr == 0 ) { rtx inv_target ; inv_target = mips_force_binary ( GET_MODE ( target ) , inv_code , 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 ordering test CODE and store the result in TARGET . CMP0 and TARGET are register_operands . 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 ) { rtx addr , offset , incoming_address , base , index , pic_reg ; pic_reg = TARGET_MIPS16 ? MIPS16_PIC_TEMP : pic_offset_table_rtx ; switch ( mips_current_loadgp_style ( ) ) { case LOADGP_ABSOLUTE : if ( mips_gnu_local_gp == NULL ) { mips_gnu_local_gp = gen_rtx_SYMBOL_REF ( Pmode , "__gnu_local_gp" ) ; SYMBOL_REF_FLAGS ( mips_gnu_local_gp ) |= SYMBOL_FLAG_LOCAL ; } emit_insn ( PMODE_INSN ( gen_loadgp_absolute , ( pic_reg , mips_gnu_local_gp ) ) ) ; break ; case LOADGP_OLDABI : break ; case LOADGP_NEWABI : 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 ( PMODE_INSN ( gen_loadgp_newabi , ( pic_reg , offset , incoming_address ) ) ) ; break ; case LOADGP_RTP : base = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( VXWORKS_GOTT_BASE ) ) ; index = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( VXWORKS_GOTT_INDEX ) ) ; emit_insn ( PMODE_INSN ( gen_loadgp_rtp , ( pic_reg , base , index ) ) ) ; break ; default : return ; } if ( TARGET_MIPS16 ) emit_insn ( PMODE_INSN ( gen_copygp_mips16 , ( pic_offset_table_rtx , pic_reg ) ) ) ; if ( ! TARGET_EXPLICIT_RELOCS || crtl -> profile ) emit_insn ( gen_loadgp_blockage ( ) ) ; } </s>

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


<s> rtx_insn * mips_emit_move ( rtx dest , rtx src ) { return ( can_create_pseudo_p ( ) ? emit_move_insn ( dest , src ) : emit_move_insn_1 ( dest , src ) ) ; } </s>

Emit a move from SRC to DEST . Assume that the move expanders can handle all moves if ! can_create_pseudo_p ( ) . The distinction is important because , unlike emit_move_insn , the move expanders know how to force Pmode objects into the constant pool even when the constant pool address is not itself legitimate .


<s> static void mips_emit_move_or_split ( rtx dest , rtx src , enum mips_split_type split_type ) { if ( mips_split_move_p ( dest , src , split_type ) ) mips_split_move ( dest , src , split_type , NULL ) ; else mips_emit_move ( dest , src ) ; } </s>

Emit a move from SRC to DEST , splitting compound moves into individual instructions . SPLIT_TYPE is the type of split to perform .


"%<-fstack-check=specific%> not implemented for MIPS16"

Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE , inclusive . These are offsets from the current stack pointer .


<s> void mips_emit_save_slot_move ( rtx dest , rtx src , rtx temp ) { unsigned int regno ; rtx mem ; if ( REG_P ( src ) ) { regno = REGNO ( src ) ; mem = dest ; } else { regno = REGNO ( dest ) ; mem = src ; } if ( regno == cfun -> machine -> global_pointer && ! mips_must_initialize_gp_p ( ) ) { if ( TARGET_64BIT ) emit_insn ( gen_move_gpdi ( dest , src ) ) ; else emit_insn ( gen_move_gpsi ( dest , src ) ) ; return ; } if ( regno == HI_REGNUM ) { if ( REG_P ( dest ) ) { mips_emit_move ( temp , src ) ; if ( TARGET_64BIT ) emit_insn ( gen_mthidi_ti ( gen_rtx_REG ( TImode , MD_REG_FIRST ) , temp , gen_rtx_REG ( DImode , LO_REGNUM ) ) ) ; else emit_insn ( gen_mthisi_di ( gen_rtx_REG ( DImode , MD_REG_FIRST ) , temp , gen_rtx_REG ( SImode , LO_REGNUM ) ) ) ; } else { if ( TARGET_64BIT ) emit_insn ( gen_mfhidi_ti ( temp , gen_rtx_REG ( TImode , MD_REG_FIRST ) ) ) ; else emit_insn ( gen_mfhisi_di ( temp , gen_rtx_REG ( DImode , MD_REG_FIRST ) ) ) ; mips_emit_move ( dest , temp ) ; } } else if ( mips_direct_save_slot_move_p ( regno , mem , mem == src ) ) mips_emit_move ( dest , src ) ; else { gcc_assert ( ! reg_overlap_mentioned_p ( dest , temp ) ) ; mips_emit_move ( temp , src ) ; mips_emit_move ( dest , temp ) ; } if ( MEM_P ( dest ) ) mips_set_frame_expr ( mips_frame_set ( dest , src ) ) ; } </s>

Emit a move from SRC to DEST , given that one of them is a register save slot and that the other is a register . TEMP is a temporary GPR of the same mode that is available if need be .


<s> static void mips_emit_unary ( enum rtx_code code , rtx target , rtx op0 ) { emit_insn ( gen_rtx_SET ( target , gen_rtx_fmt_e ( code , GET_MODE ( op0 ) , op0 ) ) ) ; } </s>

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


<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 ) { rtx symbol = XEXP ( rtl , 0 ) ; tree type = TREE_TYPE ( decl ) ; if ( ( TARGET_LONG_CALLS && ! mips_near_type_p ( type ) ) || mips_far_type_p ( type ) ) 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> static void mips_end_function_definition ( const char * name ) { if ( ! flag_inhibit_size_directive ) { fputs ( "\t.end\t" , asm_out_file ) ; assemble_name ( asm_out_file , name ) ; fputs ( "\n" , asm_out_file ) ; } } </s>

End a function definition started by mips_start_function_definition .


<s> static void mips_end_ll_sc_sync_block ( void ) { if ( ! ISA_HAS_LL_SC ) output_asm_insn ( ".set\tpop" , 0 ) ; } </s>

End a block started by mips_start_ll_sc_sync_block .


<s> static rtx_insn * mips_epilogue_emit_cfa_restores ( void ) { rtx_insn * insn ; insn = get_last_insn ( ) ; if ( mips_epilogue . cfa_restores ) { gcc_assert ( insn && ! REG_NOTES ( insn ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; REG_NOTES ( insn ) = mips_epilogue . cfa_restores ; mips_epilogue . cfa_restores = 0 ; } return insn ; } </s>

Attach all pending register saves to the previous instruction . Return that instruction .


<s> static void mips_epilogue_set_cfa ( rtx reg , HOST_WIDE_INT offset ) { rtx_insn * insn ; insn = mips_epilogue_emit_cfa_restores ( ) ; if ( reg != mips_epilogue . cfa_reg || offset != mips_epilogue . cfa_offset ) { RTX_FRAME_RELATED_P ( insn ) = 1 ; REG_NOTES ( insn ) = alloc_reg_note ( REG_CFA_DEF_CFA , plus_constant ( Pmode , reg , offset ) , REG_NOTES ( insn ) ) ; mips_epilogue . cfa_reg = reg ; mips_epilogue . cfa_offset = offset ; } } </s>

Like mips_epilogue_emit_cfa_restores , but also record that the CFA is now at REG + OFFSET .


<s> bool mips_epilogue_uses ( unsigned int regno ) { if ( regno == RETURN_ADDR_REGNUM ) return true ; if ( TARGET_USE_GOT && ( regno ) == GOT_VERSION_REGNUM ) return true ; if ( cfun -> machine -> interrupt_handler_p && mips_interrupt_extra_call_saved_reg_p ( regno ) ) return true ; return false ; } </s>


<s> void mips_expand_atomic_qihi ( union mips_gen_fn_ptrs generator , rtx result , rtx mem , rtx oldval , rtx newval ) { rtx orig_addr , memsi_addr , memsi , shift , shiftsi , unshifted_mask ; rtx unshifted_mask_reg , mask , inverted_mask , si_op ; rtx res = NULL ; machine_mode mode ; mode = GET_MODE ( mem ) ; orig_addr = force_reg ( Pmode , XEXP ( mem , 0 ) ) ; memsi_addr = mips_force_binary ( Pmode , AND , orig_addr , force_reg ( Pmode , GEN_INT ( - 4 ) ) ) ; memsi = gen_rtx_MEM ( SImode , memsi_addr ) ; set_mem_alias_set ( memsi , ALIAS_SET_MEMORY_BARRIER ) ; MEM_VOLATILE_P ( memsi ) = MEM_VOLATILE_P ( mem ) ; shift = mips_force_binary ( Pmode , AND , orig_addr , GEN_INT ( 3 ) ) ; if ( TARGET_BIG_ENDIAN ) mips_emit_binary ( XOR , shift , shift , GEN_INT ( mode == QImode ? 3 : 2 ) ) ; mips_emit_binary ( ASHIFT , shift , shift , GEN_INT ( 3 ) ) ; shiftsi = force_reg ( SImode , gen_lowpart ( SImode , shift ) ) ; unshifted_mask = GEN_INT ( GET_MODE_MASK ( mode ) ) ; unshifted_mask_reg = force_reg ( SImode , unshifted_mask ) ; mask = mips_force_binary ( SImode , ASHIFT , unshifted_mask_reg , shiftsi ) ; inverted_mask = gen_reg_rtx ( SImode ) ; emit_insn ( gen_rtx_SET ( inverted_mask , gen_rtx_NOT ( SImode , mask ) ) ) ; if ( oldval != const0_rtx ) { oldval = convert_modes ( SImode , mode , oldval , true ) ; oldval = force_reg ( SImode , oldval ) ; oldval = mips_force_binary ( SImode , ASHIFT , oldval , shiftsi ) ; } if ( newval && newval != const0_rtx ) { newval = convert_modes ( SImode , mode , newval , true ) ; newval = force_reg ( SImode , newval ) ; newval = mips_force_binary ( SImode , ASHIFT , newval , shiftsi ) ; } if ( result ) res = gen_reg_rtx ( SImode ) ; if ( newval ) si_op = generator . fn_6 ( res , memsi , mask , inverted_mask , oldval , newval ) ; else if ( result ) si_op = generator . fn_5 ( res , memsi , mask , inverted_mask , oldval ) ; else si_op = generator . fn_4 ( memsi , mask , inverted_mask , oldval ) ; emit_insn ( si_op ) ; if ( result ) { mips_emit_binary ( AND , res , res , mask ) ; mips_emit_binary ( LSHIFTRT , res , res , shiftsi ) ; mips_emit_move ( result , gen_lowpart ( GET_MODE ( result ) , res ) ) ; } } </s>

Expand a QI or HI mode atomic memory operation . GENERATOR contains a pointer to the gen_ * function that generates the SI mode underlying atomic operation using masks that we calculate . RESULT is the return register for the operation . Its value is NULL if unused . MEM is the location of the atomic access . OLDVAL is the first operand for the operation . NEWVAL is the optional second operand for the operation . Its value is NULL if unused .


<s> void mips_expand_before_return ( void ) { if ( TARGET_CALL_CLOBBERED_GP ) emit_clobber ( pic_offset_table_rtx ) ; } </s>

Emit any instructions needed before a return .


<s> bool mips_expand_block_move ( rtx dest , rtx src , rtx length ) { if ( ! ISA_HAS_LWL_LWR && ( MEM_ALIGN ( src ) < MIPS_MIN_MOVE_MEM_ALIGN || MEM_ALIGN ( dest ) < MIPS_MIN_MOVE_MEM_ALIGN ) ) return false ; if ( CONST_INT_P ( length ) ) { if ( INTVAL ( length ) <= MIPS_MAX_MOVE_BYTES_STRAIGHT ) { mips_block_move_straight ( dest , src , INTVAL ( length ) ) ; return true ; } else if ( optimize ) { mips_block_move_loop ( dest , src , INTVAL ( length ) , MIPS_MAX_MOVE_BYTES_PER_LOOP_ITER ) ; return true ; } } return false ; } </s>

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


"built-in function %qE not supported for MIPS16"

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 condition , 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 ) ; condition = gen_rtx_GE ( VOIDmode , cmp_result , GEN_INT ( cmp_value ) ) ; return mips_builtin_branch_and_move ( condition , target , const1_rtx , const0_rtx ) ; } </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 exp ) { rtx offset , condition , cmp_result ; if ( target == 0 || GET_MODE ( target ) != SImode ) target = gen_reg_rtx ( SImode ) ; cmp_result = mips_expand_builtin_compare_1 ( icode , cond , exp , call_expr_nargs ( exp ) ) ; switch ( builtin_type ) { case MIPS_BUILTIN_CMP_ALL : condition = gen_rtx_NE ( VOIDmode , cmp_result , constm1_rtx ) ; return mips_builtin_branch_and_move ( condition , target , const0_rtx , const1_rtx ) ; case MIPS_BUILTIN_CMP_UPPER : case MIPS_BUILTIN_CMP_LOWER : offset = GEN_INT ( builtin_type == MIPS_BUILTIN_CMP_UPPER ) ; condition = gen_single_cc ( cmp_result , offset ) ; return mips_builtin_branch_and_move ( condition , target , const1_rtx , const0_rtx ) ; default : condition = gen_rtx_NE ( VOIDmode , cmp_result , const0_rtx ) ; return mips_builtin_branch_and_move ( condition , target , const1_rtx , const0_rtx ) ; } } </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_compare_1 ( enum insn_code icode , enum mips_fp_condition cond , tree exp , int nargs ) { struct expand_operand ops [ MAX_RECOG_OPERANDS ] ; rtx output ; int opno , argno ; gcc_assert ( nargs + 2 == insn_data [ ( int ) icode ] . n_generator_args ) ; output = mips_allocate_fcc ( insn_data [ ( int ) icode ] . operand [ 0 ] . mode ) ; opno = 0 ; create_fixed_operand ( & ops [ opno ++ ] , output ) ; for ( argno = 0 ; argno < nargs ; argno ++ ) mips_prepare_builtin_arg ( & ops [ opno ++ ] , exp , argno ) ; create_integer_operand ( & ops [ opno ++ ] , ( int ) cond ) ; return mips_expand_builtin_insn ( icode , opno , ops , true ) ; } </s>

Expand a floating-point comparison for built-in function call EXP . The first NARGS arguments are the values to be compared . ICODE is the .md pattern that does the comparison and COND is the condition that is being tested . Return an rtx for the result .


<s> static rtx mips_expand_builtin_direct ( enum insn_code icode , rtx target , tree exp , bool has_target_p ) { struct expand_operand ops [ MAX_RECOG_OPERANDS ] ; int opno , argno ; opno = 0 ; if ( has_target_p ) create_output_operand ( & ops [ opno ++ ] , target , TYPE_MODE ( TREE_TYPE ( exp ) ) ) ; gcc_assert ( opno + call_expr_nargs ( exp ) == insn_data [ icode ] . n_generator_args ) ; for ( argno = 0 ; argno < call_expr_nargs ( exp ) ; argno ++ ) mips_prepare_builtin_arg ( & ops [ opno ++ ] , exp , argno ) ; return mips_expand_builtin_insn ( icode , opno , ops , has_target_p ) ; } </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 exp ) { struct expand_operand ops [ 4 ] ; rtx cmp_result ; cmp_result = mips_expand_builtin_compare_1 ( icode , cond , exp , 2 ) ; create_output_operand ( & ops [ 0 ] , target , TYPE_MODE ( TREE_TYPE ( exp ) ) ) ; if ( type == MIPS_BUILTIN_MOVT ) { mips_prepare_builtin_arg ( & ops [ 2 ] , exp , 2 ) ; mips_prepare_builtin_arg ( & ops [ 1 ] , exp , 3 ) ; } else { mips_prepare_builtin_arg ( & ops [ 1 ] , exp , 2 ) ; mips_prepare_builtin_arg ( & ops [ 2 ] , exp , 3 ) ; } create_fixed_operand ( & ops [ 3 ] , cmp_result ) ; return mips_expand_builtin_insn ( CODE_FOR_mips_cond_move_tf_ps , 4 , ops , true ) ; } </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>
static
rtx
mips_expand_builtin_msa_test_branch
(
enum
insn_code
icode
,
tree
exp
)
{
struct
expand_operand
ops
[
3
]
;
rtx_insn
*
cbranch
;
rtx_code_label
*
true_label
,
*
done_label
;
rtx
cmp_result
;
true_label
=
gen_label_rtx
(
)
;
done_label
=
gen_label_rtx
(
)
;
create_input_operand
(
&
ops
[
0
]
,
true_label
,
TYPE_MODE
(
TREE_TYPE
(
exp
)
)
)
;
mips_prepare_builtin_arg
(
&
ops
[
1
]
,
exp
,
0
)
;
create_fixed_operand
(
&
ops
[
2
]
,
const0_rtx
)
;
if
(
GET_CODE
(
ops
[
1
]
.
value
)
!=
REG
)
ops
[
1
]
.
value
=
force_reg
(
ops
[
1
]
.
mode
,
ops
[
1
]
.
value
)
;
if
(
(
cbranch
=
maybe_gen_insn
(
icode
,
3
,
ops
)
)
==
NULL_RTX
)
error
(
"failed to expand built-in function"
)
;
cmp_result
=
gen_reg_rtx
(
SImode
)
;
mips_emit_move
(
cmp_result
,
const0_rtx
)
;
emit_jump_insn
(
cbranch
)
;
emit_jump_insn
(
gen_jump
(
done_label
)
)
;
emit_barrier
(
)
;
emit_label
(
true_label
)
;
mips_emit_move
(
cmp_result
,
const1_rtx
)
;
emit_label
(
done_label
)
;
return
cmp_result
;
}
</s>

Expand an MSA built-in for a compare and branch instruction specified by ICODE , set a general-purpose register to 1 if the branch was taken , 0 otherwise .


<s> rtx_insn * mips_expand_call ( enum mips_call_type type , rtx result , rtx addr , rtx args_size , rtx aux , bool lazy_p ) { rtx orig_addr , pattern ; rtx_insn * insn ; int fp_code ; fp_code = aux == 0 ? 0 : ( int ) GET_MODE ( aux ) ; insn = mips16_build_call_stub ( result , & addr , args_size , fp_code ) ; if ( insn ) { gcc_assert ( ! lazy_p && type == MIPS_CALL_NORMAL ) ; return insn ; } orig_addr = addr ; if ( ! call_insn_operand ( addr , VOIDmode ) ) { if ( type == MIPS_CALL_EPILOGUE ) addr = MIPS_EPILOGUE_TEMP ( Pmode ) ; else addr = gen_reg_rtx ( Pmode ) ; lazy_p |= mips_load_call_address ( type , addr , orig_addr ) ; } if ( result == 0 ) { rtx ( * fn ) ( rtx , rtx ) ; if ( type == MIPS_CALL_SIBCALL ) fn = gen_sibcall_internal ; else fn = gen_call_internal ; pattern = fn ( addr , args_size ) ; } else if ( GET_CODE ( result ) == PARALLEL && XVECLEN ( result , 0 ) == 2 ) { rtx ( * fn ) ( rtx , rtx , rtx , rtx ) ; rtx reg1 , reg2 ; if ( type == MIPS_CALL_SIBCALL ) fn = gen_sibcall_value_multiple_internal ; else fn = gen_call_value_multiple_internal ; reg1 = XEXP ( XVECEXP ( result , 0 , 0 ) , 0 ) ; reg2 = XEXP ( XVECEXP ( result , 0 , 1 ) , 0 ) ; pattern = fn ( reg1 , addr , args_size , reg2 ) ; } else { rtx ( * fn ) ( rtx , rtx , rtx ) ; if ( type == MIPS_CALL_SIBCALL ) fn = gen_sibcall_value_internal ; else fn = gen_call_value_internal ; if ( GET_CODE ( result ) == PARALLEL && XVECLEN ( result , 0 ) == 1 ) result = XEXP ( XVECEXP ( result , 0 , 0 ) , 0 ) ; pattern = fn ( result , addr , args_size ) ; } return mips_emit_call_insn ( pattern , orig_addr , addr , lazy_p ) ; } </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_conditional_branch ( rtx * operands ) { enum rtx_code code = GET_CODE ( operands [ 0 ] ) ; rtx op0 = operands [ 1 ] ; rtx op1 = operands [ 2 ] ; rtx condition ; mips_emit_compare ( & code , & op0 , & op1 , TARGET_MIPS16 ) ; condition = gen_rtx_fmt_ee ( code , VOIDmode , op0 , op1 ) ; emit_jump_insn ( gen_condjump ( condition , operands [ 3 ] ) ) ; } </s>

Compare OPERANDS [ 1 ] with OPERANDS [ 2 ] using comparison code CODE and jump to OPERANDS [ 3 ] if the condition holds .


<s> void mips_expand_conditional_move ( rtx * operands ) { rtx cond ; enum rtx_code code = GET_CODE ( operands [ 1 ] ) ; rtx op0 = XEXP ( operands [ 1 ] , 0 ) ; rtx op1 = XEXP ( operands [ 1 ] , 1 ) ; mips_emit_compare ( & code , & op0 , & op1 , true ) ; cond = gen_rtx_fmt_ee ( code , GET_MODE ( op0 ) , op0 , op1 ) ; if ( ISA_HAS_SEL && INTEGRAL_MODE_P ( GET_MODE ( operands [ 2 ] ) ) && register_operand ( operands [ 2 ] , VOIDmode ) && register_operand ( operands [ 3 ] , VOIDmode ) ) { machine_mode mode = GET_MODE ( operands [ 0 ] ) ; rtx temp = gen_reg_rtx ( mode ) ; rtx temp2 = gen_reg_rtx ( mode ) ; emit_insn ( gen_rtx_SET ( temp , gen_rtx_IF_THEN_ELSE ( mode , cond , operands [ 2 ] , const0_rtx ) ) ) ; cond = gen_rtx_fmt_ee ( ( code == EQ ) ? NE : EQ , GET_MODE ( op0 ) , op0 , op1 ) ; emit_insn ( gen_rtx_SET ( temp2 , gen_rtx_IF_THEN_ELSE ( mode , cond , operands [ 3 ] , const0_rtx ) ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( mode , temp , temp2 ) ) ) ; } else { if ( FLOAT_MODE_P ( GET_MODE ( operands [ 2 ] ) ) && ! ISA_HAS_SEL ) { operands [ 2 ] = force_reg ( GET_MODE ( operands [ 0 ] ) , operands [ 2 ] ) ; operands [ 3 ] = force_reg ( GET_MODE ( operands [ 0 ] ) , operands [ 3 ] ) ; } emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IF_THEN_ELSE ( GET_MODE ( operands [ 0 ] ) , cond , operands [ 2 ] , operands [ 3 ] ) ) ) ; } } </s>

Perform the comparison in OPERANDS [ 1 ] . Move OPERANDS [ 2 ] into OPERANDS [ 0 ] if the condition holds , otherwise move OPERANDS [ 3 ] into OPERANDS [ 0 ] .


<s> void mips_expand_conditional_trap ( rtx comparison ) { rtx op0 , op1 ; machine_mode mode ; enum rtx_code code ; code = GET_CODE ( comparison ) ; switch ( code ) { case GT : case LE : case GTU : case LEU : code = swap_condition ( code ) ; op0 = XEXP ( comparison , 1 ) ; op1 = XEXP ( comparison , 0 ) ; break ; default : op0 = XEXP ( comparison , 0 ) ; op1 = XEXP ( comparison , 1 ) ; break ; } mode = GET_MODE ( XEXP ( comparison , 0 ) ) ; op0 = force_reg ( mode , op0 ) ; if ( ! ( ISA_HAS_COND_TRAPI ? arith_operand ( op1 , mode ) : reg_or_0_operand ( op1 , mode ) ) ) op1 = force_reg ( mode , op1 ) ; emit_insn ( gen_rtx_TRAP_IF ( VOIDmode , gen_rtx_fmt_ee ( code , mode , op0 , op1 ) , const0_rtx ) ) ; } </s>

Perform the comparison in COMPARISON , then trap if the condition holds .


<s> bool mips_expand_ext_as_unaligned_load ( rtx dest , rtx src , HOST_WIDE_INT width , HOST_WIDE_INT bitpos , bool unsigned_p ) { rtx left , right , temp ; rtx dest1 = NULL_RTX ; if ( GET_MODE ( dest ) == DImode && ( REG_P ( dest ) || ( SUBREG_P ( dest ) && ! MEM_P ( SUBREG_REG ( dest ) ) ) ) && GET_MODE_BITSIZE ( SImode ) == width ) { dest1 = dest ; dest = gen_reg_rtx ( SImode ) ; } 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 ) ) ; } if ( dest1 ) { if ( unsigned_p ) emit_insn ( gen_zero_extendsidi2 ( dest1 , dest ) ) ; else emit_insn ( gen_extendsidi2 ( dest1 , dest ) ) ; } return true ; } </s>

Try to use left/right loads to expand an `` extv '' or `` extzv '' pattern . DEST , SRC , WIDTH and BITPOS are the operands passed to the expander ; the operation is the equivalent of : ( set DEST ( * _extract SRC WIDTH BITPOS ) ) Return true on success .


<s> static bool mips_expand_ghost_gp_insns ( void ) { if ( ! TARGET_USE_GOT || cfun -> machine -> global_pointer == INVALID_REGNUM || mips_must_initialize_gp_p ( ) ) return false ; if ( ! mips_has_long_branch_p ( ) ) return false ; cfun -> machine -> must_initialize_gp_p = true ; split_all_insns_noflow ( ) ; return true ; } </s>

If we are using a GOT , but have not decided to use a global pointer yet , see whether we need one to implement long branches . Convert the ghost global-pointer instructions into real ones if so .


<s> bool mips_expand_ins_as_unaligned_store ( rtx dest , rtx src , HOST_WIDE_INT width , HOST_WIDE_INT bitpos ) { rtx left , right ; machine_mode mode ; if ( ! mips_get_unaligned_mem ( dest , width , bitpos , & left , & right ) ) return false ; mode = int_mode_for_size ( width , 0 ) . require ( ) ; src = gen_lowpart ( mode , src ) ; if ( mode == 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 use left/right stores to expand an `` ins '' pattern . DEST , WIDTH , BITPOS and SRC are the operands passed to the expander ; the operation is the equivalent of : ( set ( zero_extract DEST WIDTH BITPOS ) SRC ) Return true on success .


<s> static void mips_expand_msa_cmp ( rtx dest , enum rtx_code cond , rtx op0 , rtx op1 ) { machine_mode cmp_mode = GET_MODE ( op0 ) ; int unspec = - 1 ; bool negate = false ; switch ( cmp_mode ) { case E_V16QImode : case E_V8HImode : case E_V4SImode : case E_V2DImode : switch ( cond ) { case NE : cond = reverse_condition ( cond ) ; negate = true ; break ; case EQ : case LT : case LE : case LTU : case LEU : break ; case GE : case GT : case GEU : case GTU : std :: swap ( op0 , op1 ) ; cond = swap_condition ( cond ) ; break ; default : gcc_unreachable ( ) ; } mips_emit_binary ( cond , dest , op0 , op1 ) ; if ( negate ) emit_move_insn ( dest , gen_rtx_NOT ( GET_MODE ( dest ) , dest ) ) ; break ; case E_V4SFmode : case E_V2DFmode : switch ( cond ) { case UNORDERED : case ORDERED : case EQ : case NE : case UNEQ : case UNLE : case UNLT : break ; case LTGT : cond = NE ; break ; case UNGE : cond = UNLE ; std :: swap ( op0 , op1 ) ; break ; case UNGT : cond = UNLT ; std :: swap ( op0 , op1 ) ; break ; case LE : unspec = UNSPEC_MSA_FSLE ; break ; case LT : unspec = UNSPEC_MSA_FSLT ; break ; case GE : unspec = UNSPEC_MSA_FSLE ; std :: swap ( op0 , op1 ) ; break ; case GT : unspec = UNSPEC_MSA_FSLT ; std :: swap ( op0 , op1 ) ; break ; default : gcc_unreachable ( ) ; } if ( unspec < 0 ) mips_emit_binary ( cond , dest , op0 , op1 ) ; else { rtx x = gen_rtx_UNSPEC ( GET_MODE ( dest ) , gen_rtvec ( 2 , op0 , op1 ) , unspec ) ; emit_insn ( gen_rtx_SET ( dest , x ) ) ; } break ; default : gcc_unreachable ( ) ; break ; } } </s>

Generate RTL for comparing CMP_OP0 and CMP_OP1 using condition COND and store the result -1 or 0 in DEST .


<s> static bool mips_expand_msa_shuffle ( struct expand_vec_perm_d * d ) { rtx x , elts [ MAX_VECT_LEN ] ; rtvec v ; rtx_insn * insn ; unsigned i ; if ( ! ISA_HAS_MSA ) return false ; for ( i = 0 ; i < d -> nelt ; i ++ ) elts [ i ] = GEN_INT ( d -> perm [ i ] ) ; v = gen_rtvec_v ( d -> nelt , elts ) ; x = gen_rtx_PARALLEL ( VOIDmode , v ) ; if ( ! mips_const_vector_shuffle_set_p ( x , d -> vmode ) ) return false ; x = gen_rtx_VEC_SELECT ( d -> vmode , d -> op0 , x ) ; x = gen_rtx_SET ( d -> target , x ) ; insn = emit_insn ( x ) ; if ( recog_memoized ( insn ) < 0 ) { remove_insn ( insn ) ; return false ; } return true ; } </s>

Construct ( set target ( vec_select op0 ( parallel selector ) ) ) and return true if that 's a valid instruction in the active ISA .


<s> void mips_expand_scc ( rtx operands [ ] ) { rtx target = operands [ 0 ] ; enum rtx_code code = GET_CODE ( operands [ 1 ] ) ; rtx op0 = operands [ 2 ] ; rtx op1 = operands [ 3 ] ; gcc_assert ( GET_MODE_CLASS ( GET_MODE ( op0 ) ) == MODE_INT ) ; if ( code == EQ || code == NE ) { if ( ISA_HAS_SEQ_SNE && reg_imm10_operand ( op1 , GET_MODE ( op1 ) ) ) mips_emit_binary ( code , target , op0 , op1 ) ; else { rtx zie = mips_zero_if_equal ( op0 , op1 ) ; mips_emit_binary ( code , target , zie , const0_rtx ) ; } } else mips_emit_int_order_test ( code , 0 , target , op0 , op1 ) ; } </s>

Try performing the comparison in OPERANDS [ 1 ] , whose arms are OPERANDS [ 2 ] and OPERAND [ 3 ] . Store the result in OPERANDS [ 0 ] . On 64-bit targets , the mode of the comparison and target will always be SImode , thus possibly narrower than that of the comparison 's operands .