<s> static void mips_output_mi_thunk ( FILE * file , tree thunk_fndecl ATTRIBUTE_UNUSED , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { const char * fnname = IDENTIFIER_POINTER ( DECL_ASSEMBLER_NAME ( thunk_fndecl ) ) ; rtx this_rtx , temp1 , temp2 , fnaddr ; rtx_insn * insn ; bool use_sibcall_p ; reload_completed = 1 ; emit_note ( NOTE_INSN_PROLOGUE_END ) ; fnaddr = XEXP ( DECL_RTL ( function ) , 0 ) ; use_sibcall_p = ( mips_function_ok_for_sibcall ( function , NULL ) && const_call_insn_operand ( fnaddr , Pmode ) ) ; if ( ! use_sibcall_p && ( mips_got_symbol_type_p ( mips_classify_symbol ( fnaddr , SYMBOL_CONTEXT_LEA ) ) ) ) { cfun -> machine -> global_pointer = TARGET_CALL_SAVED_GP ? 15 : GLOBAL_POINTER_REGNUM ; cfun -> machine -> must_initialize_gp_p = true ; SET_REGNO ( pic_offset_table_rtx , cfun -> machine -> global_pointer ) ; mips_emit_loadgp ( ) ; } temp1 = gen_rtx_REG ( Pmode , 2 ) ; temp2 = gen_rtx_REG ( Pmode , 3 ) ; if ( aggregate_value_p ( TREE_TYPE ( TREE_TYPE ( function ) ) , function ) ) this_rtx = gen_rtx_REG ( Pmode , GP_ARG_FIRST + 1 ) ; else this_rtx = gen_rtx_REG ( Pmode , GP_ARG_FIRST ) ; if ( delta != 0 ) { rtx offset = GEN_INT ( delta ) ; if ( ! SMALL_OPERAND ( delta ) ) { mips_emit_move ( temp1 , offset ) ; offset = temp1 ; } emit_insn ( gen_add3_insn ( this_rtx , this_rtx , offset ) ) ; } if ( vcall_offset != 0 ) { rtx addr ; mips_emit_move ( temp1 , gen_rtx_MEM ( Pmode , this_rtx ) ) ; addr = mips_add_offset ( temp2 , temp1 , vcall_offset ) ; mips_emit_move ( temp1 , gen_rtx_MEM ( Pmode , addr ) ) ; emit_insn ( gen_add3_insn ( this_rtx , this_rtx , temp1 ) ) ; } if ( use_sibcall_p ) { insn = emit_call_insn ( gen_sibcall_internal ( fnaddr , const0_rtx ) ) ; SIBLING_CALL_P ( insn ) = 1 ; } else { if ( TARGET_USE_PIC_FN_ADDR_REG && ! TARGET_MIPS16 && ! mips_dangerous_for_la25_p ( fnaddr ) ) temp1 = gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) ; mips_load_call_address ( MIPS_CALL_SIBCALL , temp1 , fnaddr ) ; if ( TARGET_USE_PIC_FN_ADDR_REG && REGNO ( temp1 ) != PIC_FUNCTION_ADDR_REGNUM ) mips_emit_move ( gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) , temp1 ) ; emit_jump_insn ( gen_indirect_jump ( temp1 ) ) ; } insn = get_insns ( ) ; split_all_insns_noflow ( ) ; mips16_lay_out_constants ( true ) ; shorten_branches ( insn ) ; assemble_start_function ( thunk_fndecl , fnname ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; assemble_end_function ( thunk_fndecl , fnname ) ; reload_completed = 0 ; } </s>

Implement TARGET_ASM_OUTPUT_MI_THUNK . Generate rtl rather than asm text in order to avoid duplicating too much logic from elsewhere .


<s>
const
char
*
mips_output_order_conditional_branch
(
rtx_insn
*
insn
,
rtx
*
operands
,
bool
inverted_p
)
{
const
char
*
branch
[
2
]
;
if
(
operands
[
3
]
!=
const0_rtx
)
{
if
(
REGNO
(
operands
[
2
]
)
==
REGNO
(
operands
[
3
]
)
)
{
switch
(
GET_CODE
(
operands
[
1
]
)
)
{
case
LT
:
case
LTU
:
inverted_p
=
!
inverted_p
;
case
GE
:
case
GEU
:
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b"
,
"%0"
)
;
branch
[
inverted_p
]
=
"%*\t\t# branch never"
;
break
;
default
:
gcc_unreachable
(
)
;
}
}
else
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b%C1"
,
"%2,%3,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH_C
(
"b%N1"
,
"%2,%3,%0"
)
;
}
}
else
{
switch
(
GET_CODE
(
operands
[
1
]
)
)
{
case
LEU
:
inverted_p
=
!
inverted_p
;
case
GTU
:
if
(
TARGET_CB_MAYBE
)
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"bnez"
,
"%2,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH_C
(
"beqz"
,
"%2,%0"
)
;
}
else
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH
(
"bne"
,
"%2,%.,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH
(
"beq"
,
"%2,%.,%0"
)
;
}
break
;
case
LTU
:
inverted_p
=
!
inverted_p
;
case
GEU
:
if
(
TARGET_CB_MAYBE
)
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b"
,
"%0"
)
;
branch
[
inverted_p
]
=
"%*\t\t# branch never"
;
}
else
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH
(
"beq"
,
"%.,%.,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH
(
"bne"
,
"%.,%.,%0"
)
;
}
break
;
default
:
if
(
TARGET_CB_MAYBE
)
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b%C1z"
,
"%2,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH_C
(
"b%N1z"
,
"%2,%0"
)
;
}
else
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH
(
"b%C1z"
,
"%2,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH
(
"b%N1z"
,
"%2,%0"
)
;
}
break
;
}
}
return
mips_output_conditional_branch
(
insn
,
operands
,
branch
[
1
]
,
branch
[
0
]
)
;
}
</s>

Return the assembly code for INSN , which branches to OPERANDS [ 0 ] if some ordering condition is true . The condition is given by OPERANDS [ 1 ] if ! INVERTED_P , otherwise it is the inverse of OPERANDS [ 1 ] . OPERANDS [ 2 ] is the comparison 's first operand ; its second is always zero .


<s> const char * mips_output_probe_stack_range ( rtx reg1 , rtx reg2 ) { static int labelno = 0 ; char loop_lab [ 32 ] , tmp [ 64 ] ; rtx xops [ 2 ] ; ASM_GENERATE_INTERNAL_LABEL ( loop_lab , "LPSRL" , labelno ++ ) ; ASM_OUTPUT_INTERNAL_LABEL ( asm_out_file , loop_lab ) ; xops [ 0 ] = reg1 ; xops [ 1 ] = GEN_INT ( - PROBE_INTERVAL ) ; if ( TARGET_64BIT && TARGET_LONG64 ) output_asm_insn ( "daddiu\t%0,%0,%1" , xops ) ; else output_asm_insn ( "addiu\t%0,%0,%1" , xops ) ; xops [ 1 ] = reg2 ; strcpy ( tmp , "%(%<bne\t%0,%1," ) ; output_asm_insn ( strcat ( tmp , & loop_lab [ 1 ] ) , xops ) ; if ( TARGET_64BIT ) output_asm_insn ( "sd\t$0,0(%0)%)" , xops ) ; else output_asm_insn ( "sw\t$0,0(%0)%)" , xops ) ; return "" ; } </s>

Probe a range of stack addresses from REG1 to REG2 inclusive . These are absolute addresses .


<s> const char * mips_output_sync ( void ) { mips_start_ll_sc_sync_block ( ) ; output_asm_insn ( "sync" , 0 ) ; mips_end_ll_sc_sync_block ( ) ; return "" ; } </s>

Output and/or return the asm template for a sync instruction .


<s> const char * mips_output_sync_loop ( rtx_insn * insn , rtx * operands ) { mips_branch_likely = TARGET_FIX_R10000 ; mips_process_sync_loop ( insn , operands ) ; mips_push_asm_switch ( & mips_noreorder ) ; mips_push_asm_switch ( & mips_nomacro ) ; mips_push_asm_switch ( & mips_noat ) ; mips_start_ll_sc_sync_block ( ) ; mips_multi_write ( ) ; mips_end_ll_sc_sync_block ( ) ; mips_pop_asm_switch ( & mips_noat ) ; mips_pop_asm_switch ( & mips_nomacro ) ; mips_pop_asm_switch ( & mips_noreorder ) ; return "" ; } </s>

Output and/or return the asm template for sync loop INSN , which has the operands given by OPERANDS .


<s> const char * mips_output_tls_reloc_directive ( rtx * addr ) { enum mips_symbol_type type ; type = mips_classify_symbolic_expression ( * addr , SYMBOL_CONTEXT_LEA ) ; * addr = mips_strip_unspec_address ( * addr ) ; switch ( type ) { case SYMBOL_DTPREL : return Pmode == SImode ? ".dtprelword\t%0" : ".dtpreldword\t%0" ; case SYMBOL_TPREL : return Pmode == SImode ? ".tprelword\t%0" : ".tpreldword\t%0" ; default : gcc_unreachable ( ) ; } } </s>

Return the pseudo-op for full SYMBOL_ ( D ) TPREL address * ADDR . Update * ADDR with the operand that should be printed .


<s> bool mips_pad_reg_upward ( machine_mode mode , tree type ) { if ( type != 0 ? FLOAT_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_FLOAT ) return ! BYTES_BIG_ENDIAN ; return mips_function_arg_padding ( mode , type ) == PAD_UPWARD ; } </s>

Likewise BLOCK_REG_PADDING ( MODE , TYPE , ... ) . Return ! BYTES_BIG_ENDIAN if the least significant byte of the register has useful data . Return the opposite if the most significant byte does .


<s> static bool mips_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { if ( mips_abi == ABI_EABI ) { int size ; if ( arg . mode == DImode || arg . mode == DFmode || arg . mode == DQmode || arg . mode == UDQmode || arg . mode == DAmode || arg . mode == UDAmode ) return 0 ; size = arg . type_size_in_bytes ( ) ; return size == - 1 || size > UNITS_PER_WORD ; } else { return targetm . calls . must_pass_in_stack ( arg ) ; } } </s>

Return nonzero when an argument must be passed by reference .


<s> rtx mips_pic_base_register ( rtx temp ) { if ( ! TARGET_MIPS16 ) return pic_offset_table_rtx ; if ( currently_expanding_to_rtl ) return mips16_gp_pseudo_reg ( ) ; if ( can_create_pseudo_p ( ) ) temp = gen_reg_rtx ( Pmode ) ; if ( TARGET_USE_GOT ) mips_emit_move ( temp , pic_offset_table_rtx ) ; else emit_insn ( gen_load_const_gp ( temp ) ) ; return temp ; } </s>

Return a base register that holds pic_offset_table_rtx . TEMP , if nonnull , is a scratch Pmode base register .


<s> static rtx mips_pic_call_symbol_from_set ( df_ref def , rtx reg , bool recurse_p ) { rtx_insn * def_insn ; rtx set ; if ( DF_REF_IS_ARTIFICIAL ( def ) ) return NULL_RTX ; def_insn = DF_REF_INSN ( def ) ; set = single_set ( def_insn ) ; if ( set && rtx_equal_p ( SET_DEST ( set ) , reg ) ) { rtx note , src , symbol ; src = SET_SRC ( set ) ; if ( GET_CODE ( src ) == SYMBOL_REF ) return src ; symbol = mips_strip_unspec_call ( src ) ; if ( symbol ) { gcc_assert ( GET_CODE ( symbol ) == SYMBOL_REF ) ; return symbol ; } note = find_reg_equal_equiv_note ( def_insn ) ; if ( note && GET_CODE ( XEXP ( note , 0 ) ) == SYMBOL_REF ) return XEXP ( note , 0 ) ; if ( recurse_p && REG_P ( src ) ) return mips_find_pic_call_symbol ( def_insn , src , false ) ; } return NULL_RTX ; } </s>

REG is set in DEF . See if the definition is one of the ways we load a register with a symbol address for a mips_use_pic_fn_addr_reg_p call . If it is , return the symbol reference of the function , otherwise return NULL_RTX . If RECURSE_P is true , use mips_find_pic_call_symbol to interpret the values of source registers , otherwise treat such registers as having an unknown value .


<s> static void mips_pop_asm_switch_1 ( struct mips_asm_switch * asm_switch , const char * prefix , const char * suffix ) { gcc_assert ( asm_switch -> nesting_level ) ; asm_switch -> nesting_level -- ; if ( asm_switch -> nesting_level == 0 ) fprintf ( asm_out_file , "%s.set\t%s%s" , prefix , asm_switch -> name , suffix ) ; } </s>


<s> static reg_class_t mips_preferred_reload_class ( rtx x , reg_class_t rclass ) { if ( mips_dangerous_for_la25_p ( x ) && reg_class_subset_p ( LEA_REGS , rclass ) ) return LEA_REGS ; if ( reg_class_subset_p ( FP_REGS , rclass ) && mips_mode_ok_for_mov_fmt_p ( GET_MODE ( x ) ) ) return FP_REGS ; if ( reg_class_subset_p ( GR_REGS , rclass ) ) rclass = GR_REGS ; if ( TARGET_MIPS16 && reg_class_subset_p ( M16_REGS , rclass ) ) rclass = M16_REGS ; return rclass ; } </s>


<s> static machine_mode mips_preferred_simd_mode ( scalar_mode mode ) { if ( TARGET_PAIRED_SINGLE_FLOAT && mode == SFmode ) return V2SFmode ; if ( ! ISA_HAS_MSA ) return word_mode ; switch ( mode ) { case E_QImode : return V16QImode ; case E_HImode : return V8HImode ; case E_SImode : return V4SImode ; case E_DImode : return V2DImode ; case E_SFmode : return V4SFmode ; case E_DFmode : return V2DFmode ; default : break ; } return word_mode ; } </s>


<s> rtx mips_prefetch_cookie ( rtx write , rtx locality ) { if ( INTVAL ( locality ) <= 0 ) return GEN_INT ( INTVAL ( write ) + 4 ) ; if ( INTVAL ( locality ) <= 2 ) return write ; return GEN_INT ( INTVAL ( write ) + 6 ) ; } </s>

Given that we have an rtx of the form ( prefetch ... WRITE LOCALITY ) , return the first operand of the associated `` pref '' or `` prefx '' insn .


<s> static void mips_prepare_builtin_arg ( struct expand_operand * op , tree exp , unsigned int argno ) { tree arg ; rtx value ; arg = CALL_EXPR_ARG ( exp , argno ) ; value = expand_normal ( arg ) ; create_input_operand ( op , value , TYPE_MODE ( TREE_TYPE ( arg ) ) ) ; } </s>

Take the head of argument list * ARGLIST and convert it into a form suitable for input operand OP of instruction ICODE . Return the value and point * ARGLIST at the next element of the list .


<s> static void mips_prepare_pch_save ( void ) { mips_set_compression_mode ( 0 ) ; mips16_globals = 0 ; micromips_globals = 0 ; } </s>


<s>
static
void
mips_print_float_branch_condition
(
FILE
*
file
,
enum
rtx_code
code
,
int
letter
)
{
switch
(
code
)
{
case
EQ
:
if
(
ISA_HAS_CCF
)
fputs
(
"c1eqz"
,
file
)
;
else
fputs
(
"c1f"
,
file
)
;
break
;
case
NE
:
if
(
ISA_HAS_CCF
)
fputs
(
"c1nez"
,
file
)
;
else
fputs
(
"c1t"
,
file
)
;
break
;
default
:
output_operand_lossage
(
"'%%%c' is not a valid operand prefix"
,
letter
)
;
break
;
}
}
</s>


<s>
static
void
mips_print_int_branch_condition
(
FILE
*
file
,
enum
rtx_code
code
,
int
letter
)
{
switch
(
code
)
{
case
EQ
:
case
NE
:
case
GT
:
case
GE
:
case
LT
:
case
LE
:
case
GTU
:
case
GEU
:
case
LTU
:
case
LEU
:
fputs
(
GET_RTX_NAME
(
code
)
,
file
)
;
break
;
default
:
output_operand_lossage
(
"'%%%c' is not a valid operand prefix"
,
letter
)
;
break
;
}
}
</s>

PRINT_OPERAND prefix LETTER refers to the integer branch instruction associated with condition CODE . Print the condition part of the opcode to FILE .

mips
"'%%%c' is not a valid operand prefix"


<s> static void mips_print_operand_address ( FILE * file , machine_mode , rtx x ) { struct mips_address_info addr ; if ( mips_classify_address ( & addr , x , word_mode , true ) ) switch ( addr . type ) { case ADDRESS_REG : mips_print_operand ( file , addr . offset , 0 ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( addr . reg ) ] ) ; return ; case ADDRESS_LO_SUM : mips_print_operand_reloc ( file , addr . offset , SYMBOL_CONTEXT_MEM , mips_lo_relocs ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( addr . reg ) ] ) ; return ; case ADDRESS_CONST_INT : output_addr_const ( file , x ) ; fprintf ( file , "(%s)" , reg_names [ GP_REG_FIRST ] ) ; return ; case ADDRESS_SYMBOLIC : output_addr_const ( file , mips_strip_unspec_address ( x ) ) ; return ; } gcc_unreachable ( ) ; } </s>


<s> static bool mips_print_operand_punct_valid_p ( unsigned char code ) { return mips_print_operand_punct [ code ] ; } </s>


<s> static void mips_print_operand_reloc ( FILE * file , rtx op , enum mips_symbol_context context , const char * * relocs ) { enum mips_symbol_type symbol_type ; const char * p ; symbol_type = mips_classify_symbolic_expression ( op , context ) ; gcc_assert ( relocs [ symbol_type ] ) ; fputs ( relocs [ symbol_type ] , file ) ; output_addr_const ( file , mips_strip_unspec_address ( op ) ) ; for ( p = relocs [ symbol_type ] ; * p != 0 ; p ++ ) if ( * p == '(' ) fputc ( ')' , file ) ; } </s>

Print symbolic operand OP , which is part of a HIGH or LO_SUM in context CONTEXT . RELOCS is the array of relocations to use .


<s> static void mips_process_load_label ( rtx target ) { rtx base , gp , intop ; HOST_WIDE_INT offset ; mips_multi_start ( ) ; switch ( mips_abi ) { case ABI_N32 : mips_multi_add_insn ( "lw\t%@,%%got_page(%0)(%+)" , target , 0 ) ; mips_multi_add_insn ( "addiu\t%@,%@,%%got_ofst(%0)" , target , 0 ) ; break ; case ABI_64 : mips_multi_add_insn ( "ld\t%@,%%got_page(%0)(%+)" , target , 0 ) ; mips_multi_add_insn ( "daddiu\t%@,%@,%%got_ofst(%0)" , target , 0 ) ; break ; default : gp = pic_offset_table_rtx ; if ( mips_cfun_has_cprestore_slot_p ( ) ) { gp = gen_rtx_REG ( Pmode , AT_REGNUM ) ; mips_get_cprestore_base_and_offset ( & base , & offset , true ) ; if ( ! SMALL_OPERAND ( offset ) ) { intop = GEN_INT ( CONST_HIGH_PART ( offset ) ) ; mips_multi_add_insn ( "lui\t%0,%1" , gp , intop , 0 ) ; mips_multi_add_insn ( "addu\t%0,%0,%1" , gp , base , 0 ) ; base = gp ; offset = CONST_LOW_PART ( offset ) ; } intop = GEN_INT ( offset ) ; if ( ISA_HAS_LOAD_DELAY ) mips_multi_add_insn ( "lw\t%0,%1(%2)%#" , gp , intop , base , 0 ) ; else mips_multi_add_insn ( "lw\t%0,%1(%2)" , gp , intop , base , 0 ) ; } if ( ISA_HAS_LOAD_DELAY ) mips_multi_add_insn ( "lw\t%@,%%got(%0)(%1)%#" , target , gp , 0 ) ; else mips_multi_add_insn ( "lw\t%@,%%got(%0)(%1)" , target , gp , 0 ) ; mips_multi_add_insn ( "addiu\t%@,%@,%%lo(%0)" , target , 0 ) ; break ; } } </s>

Build up a multi-insn sequence that loads label TARGET into $ AT .


<s> static machine_mode mips_promote_function_mode ( const_tree type ATTRIBUTE_UNUSED , machine_mode mode , int * punsignedp ATTRIBUTE_UNUSED , const_tree fntype ATTRIBUTE_UNUSED , int for_return ATTRIBUTE_UNUSED ) { int unsignedp ; if ( type != NULL_TREE ) return promote_mode ( type , mode , punsignedp ) ; unsignedp = * punsignedp ; PROMOTE_MODE ( mode , unsignedp , type ) ; * punsignedp = unsignedp ; return mode ; } </s>


<s> static void mips_promote_ready ( rtx_insn * * ready , int lower , int higher ) { rtx_insn * new_head ; int i ; new_head = ready [ lower ] ; for ( i = lower ; i < higher ; i ++ ) ready [ i ] = ready [ i + 1 ] ; ready [ i ] = new_head ; } </s>

Remove the instruction at index LOWER from ready queue READY and reinsert it in front of the instruction at index HIGHER . LOWER must be < = HIGHER .


<s> void mips_push_asm_switch ( struct mips_asm_switch * asm_switch ) { mips_push_asm_switch_1 ( asm_switch , "\t" , "\n" ) ; } </s>

Wrappers around mips_push_asm_switch_1 and mips_pop_asm_switch_1 that either print a complete line or print nothing .


<s> static void mips_push_asm_switch_1 ( struct mips_asm_switch * asm_switch , const char * prefix , const char * suffix ) { if ( asm_switch -> nesting_level == 0 ) fprintf ( asm_out_file , "%s.set\tno%s%s" , prefix , asm_switch -> name , suffix ) ; asm_switch -> nesting_level ++ ; } </s>

Start a new block with the given asm switch enabled . If we need to print a directive , emit PREFIX before it and SUFFIX after it .


<s> static void mips_record_lo_sums ( const_rtx x , mips_offset_table * htab ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , NONCONST ) if ( GET_CODE ( * iter ) == LO_SUM ) mips_lo_sum_offset_lookup ( htab , XEXP ( * iter , 1 ) , INSERT ) ; } </s>

Search X for LO_SUMs and record them in HTAB .


<s> static bool mips_refers_to_kernel_reg_p ( const_rtx x ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , NONCONST ) if ( REG_P ( * iter ) && KERNEL_REG_P ( REGNO ( * iter ) ) ) return true ; return false ; } </s>

Return true if X contains a kernel register .


<s> static int mips_register_move_cost ( machine_mode mode , reg_class_t from , reg_class_t to ) { reg_class_t dregs ; int cost1 , cost2 ; from = mips_canonicalize_move_class ( from ) ; to = mips_canonicalize_move_class ( to ) ; if ( from == FP_REGS ) { if ( to == FP_REGS && mips_mode_ok_for_mov_fmt_p ( mode ) ) return 4 ; } dregs = TARGET_MIPS16 ? M16_REGS : GENERAL_REGS ; if ( from == dregs ) return mips_move_from_gpr_cost ( to ) ; if ( to == dregs ) return mips_move_to_gpr_cost ( from ) ; cost1 = mips_move_to_gpr_cost ( from ) ; if ( cost1 != 0 ) { cost2 = mips_move_from_gpr_cost ( to ) ; if ( cost2 != 0 ) return cost1 + cost2 ; } return 0 ; } </s>

Implement TARGET_REGISTER_MOVE_COST . Return 0 for classes that are the maximum of the move costs for subclasses ; regclass will work out the maximum for us .


<s> static int mips_register_priority ( int hard_regno ) { if ( TARGET_MIPS16 && TEST_HARD_REG_BIT ( reg_class_contents [ M16_REGS ] , hard_regno ) ) return 1 ; return 0 ; } </s>


<s> int mips_regno_mode_ok_for_base_p ( int regno , machine_mode mode , bool strict_p ) { if ( ! HARD_REGISTER_NUM_P ( regno ) ) { if ( ! strict_p ) return true ; regno = reg_renumber [ regno ] ; } if ( regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM ) return true ; if ( TARGET_MIPS16 && regno == STACK_POINTER_REGNUM ) return GET_MODE_SIZE ( mode ) == 4 || GET_MODE_SIZE ( mode ) == 8 ; return TARGET_MIPS16 ? M16_REG_P ( regno ) : GP_REG_P ( regno ) ; } </s>

This function is used to implement REG_MODE_OK_FOR_BASE_P .


<s> static void mips_reorg ( void ) { if ( mips_cfg_in_reorg ( ) ) compute_bb_for_insn ( ) ; mips16_lay_out_constants ( true ) ; if ( mips_cfg_in_reorg ( ) ) { mips_df_reorg ( ) ; free_bb_for_insn ( ) ; } } </s>


<s> void mips_restore_gp_from_cprestore_slot ( rtx temp ) { gcc_assert ( TARGET_ABICALLS && TARGET_OLDABI && epilogue_completed ) ; if ( ! cfun -> machine -> must_restore_gp_when_clobbered_p ) { emit_note ( NOTE_INSN_DELETED ) ; return ; } if ( TARGET_MIPS16 ) { mips_emit_move ( temp , mips_cprestore_slot ( temp , true ) ) ; mips_emit_move ( pic_offset_table_rtx , temp ) ; } else mips_emit_move ( pic_offset_table_rtx , mips_cprestore_slot ( temp , true ) ) ; if ( ! TARGET_EXPLICIT_RELOCS ) emit_insn ( gen_blockage ( ) ) ; } </s>

Restore $ gp from its save slot , using TEMP as a temporary base register if need be . This function is for o32 and o64 abicalls only . See mips_must_initialize_gp_p for details about how we manage the global pointer .


<s> static void mips_restore_reg ( rtx reg , rtx mem ) { if ( TARGET_MIPS16 && REGNO ( reg ) == RETURN_ADDR_REGNUM ) reg = gen_rtx_REG ( GET_MODE ( reg ) , GP_REG_FIRST + 7 ) ; else if ( GET_MODE ( reg ) == DFmode && ( ! TARGET_FLOAT64 || mips_abi == ABI_32 ) ) { mips_add_cfa_restore ( mips_subword ( reg , true ) ) ; mips_add_cfa_restore ( mips_subword ( reg , false ) ) ; } else mips_add_cfa_restore ( reg ) ; mips_emit_save_slot_move ( reg , mem , MIPS_EPILOGUE_TEMP ( GET_MODE ( reg ) ) ) ; if ( REGNO ( reg ) == REGNO ( mips_epilogue . cfa_reg ) ) mips_epilogue_set_cfa ( stack_pointer_rtx , mips_epilogue . cfa_restore_sp_offset ) ; } </s>

Emit instructions to restore register REG from slot MEM .


<s> rtx mips_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return const0_rtx ; return get_hard_reg_initial_val ( Pmode , RETURN_ADDR_REGNUM ) ; } </s>

Implement RETURN_ADDR_RTX . Note , we do not support moving back to a previous frame .


Return a composite value in a pair of floating-point registers . MODE1 and OFFSET1 are the mode and byte offset for the first value , likewise MODE2 and OFFSET2 for the second . MODE is the mode of the complete value . For n32 & n64 , $ f0 always holds the first value and $ f2 the second . Otherwise the values are packed together as closely as possible .


<s> static rtx mips_return_fpr_single ( machine_mode type_mode , machine_mode value_mode ) { rtx x ; x = gen_rtx_REG ( value_mode , FP_RETURN ) ; if ( type_mode != value_mode ) { x = gen_rtx_EXPR_LIST ( VOIDmode , x , const0_rtx ) ; x = gen_rtx_PARALLEL ( type_mode , gen_rtvec ( 1 , x ) ) ; } return x ; } </s>

Return the representation of an FPR return register when the value being returned in FP_RETURN has mode VALUE_MODE and the return type itself has mode TYPE_MODE . On NewABI targets , the two modes may be different for structures like : struct __attribute__ ( ( packed ) ) foo { float f ; } where we return the SFmode value of `` f '' in FP_RETURN , but where the structure itself has mode BLKmode .


<s> static bool mips_return_in_memory ( const_tree type , const_tree fndecl ATTRIBUTE_UNUSED ) { if ( TARGET_OLDABI ) return ( VECTOR_FLOAT_TYPE_P ( type ) || TYPE_MODE ( type ) == BLKmode ) ; return ( ! IN_RANGE ( int_size_in_bytes ( type ) , 0 , 2 * UNITS_PER_WORD ) ) ; } </s>

Implement TARGET_RETURN_IN_MEMORY . Under the old ( i.e. , 32 and O64 ABIs ) all BLKmode objects are returned in memory . Under the new ( N32 and 64-bit MIPS ABIs ) small structures are returned in a register . Objects with varying size must still be returned in memory , of course .


<s> static bool mips_return_in_msb ( const_tree valtype ) { if ( ! TARGET_NEWABI || ! TARGET_BIG_ENDIAN || ! AGGREGATE_TYPE_P ( valtype ) ) return false ; tree fields [ 2 ] ; bool has_cxx_zero_width_bf = false ; bool has_cxx17_empty_base = false ; return ( mips_fpr_return_fields ( valtype , fields , & has_cxx_zero_width_bf , & has_cxx17_empty_base ) == 0 || has_cxx_zero_width_bf ) ; } </s>

Implement TARGET_RETURN_IN_MSB . For n32 & n64 , we should return a value in the most significant part of $ 2/ $ 3 if : - the target is big-endian ; - the value has a structure or union type ( we generalize this to cover aggregates from other languages too ) ; and - the structure is not returned in floating-point registers .


<s> static bool mips_return_mode_in_fpr_p ( machine_mode mode ) { gcc_assert ( TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode ) ; return ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || mode == V2SFmode || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) && GET_MODE_UNIT_SIZE ( mode ) <= UNITS_PER_HWFPVALUE ) ; } </s>

Return true if the function return value MODE will get returned in a floating-point register .


<s> static bool mips_reversed_fp_cond ( enum rtx_code * code ) { switch ( * code ) { case NE : case LTGT : case ORDERED : * code = reverse_condition_maybe_unordered ( * code ) ; return true ; default : return false ; } } </s>

Convert * CODE into a code that can be used in a floating-point scc instruction ( C.cond.fmt ) . Return true if the values of the condition code registers will be inverted , with 0 indicating that the condition holds .


<s> rtx mips_rewrite_small_data ( rtx pattern ) { pattern = copy_insn ( pattern ) ; mips_rewrite_small_data_1 ( & pattern , SYMBOL_CONTEXT_LEA ) ; return pattern ; } </s>

If possible , rewrite OP so that it refers to small data using explicit relocations .


<s> static void mips_rewrite_small_data_1 ( rtx * loc , enum mips_symbol_context context ) { subrtx_ptr_iterator :: array_type array ; FOR_EACH_SUBRTX_PTR ( iter , array , loc , ALL ) { rtx * loc = * iter ; if ( MEM_P ( * loc ) ) { mips_rewrite_small_data_1 ( & XEXP ( * loc , 0 ) , SYMBOL_CONTEXT_MEM ) ; iter . skip_subrtxes ( ) ; } else if ( mips_rewrite_small_data_p ( * loc , context ) ) { * loc = gen_rtx_LO_SUM ( Pmode , pic_offset_table_rtx , * loc ) ; iter . skip_subrtxes ( ) ; } else if ( GET_CODE ( * loc ) == LO_SUM ) iter . skip_subrtxes ( ) ; } } </s>

A for_each_rtx callback , used by mips_rewrite_small_data .


<s> static bool mips_rewrite_small_data_p ( rtx x , enum mips_symbol_context context ) { enum mips_symbol_type symbol_type ; return ( mips_lo_relocs [ SYMBOL_GP_RELATIVE ] && ! mips_split_p [ SYMBOL_GP_RELATIVE ] && mips_symbolic_constant_p ( x , context , & symbol_type ) && symbol_type == SYMBOL_GP_RELATIVE ) ; } </s>

Return true if X is a small data address that can be rewritten as a LO_SUM .


<s> static bool mips_rtx_constant_in_small_data_p ( machine_mode mode ) { return ( ! TARGET_EMBEDDED_DATA && TARGET_LOCAL_SDATA && GET_MODE_SIZE ( mode ) <= mips_small_data_threshold ) ; } </s>

Return true if rtx constants of mode MODE should be put into a small data section .


<s> void mips_save_gp_to_cprestore_slot ( rtx mem , rtx offset , rtx gp , rtx temp ) { if ( TARGET_CPRESTORE_DIRECTIVE ) { gcc_assert ( gp == pic_offset_table_rtx ) ; emit_insn ( PMODE_INSN ( gen_cprestore , ( mem , offset ) ) ) ; } else mips_emit_move ( mips_cprestore_slot ( temp , false ) , gp ) ; } </s>

Emit instructions to save global pointer value GP into cprestore slot MEM . OFFSET is the offset that MEM applies to the base register . MEM may not be a legitimate address . If it is n't , TEMP is a temporary register that can be used , otherwise it is a SCRATCH .


<s> static void mips_save_reg ( rtx reg , rtx mem ) { if ( GET_MODE ( reg ) == DFmode && ( ! TARGET_FLOAT64 || mips_abi == ABI_32 ) ) { rtx x1 , x2 ; mips_emit_move_or_split ( mem , reg , SPLIT_IF_NECESSARY ) ; x1 = mips_frame_set ( mips_subword ( mem , false ) , mips_subword ( reg , false ) ) ; x2 = mips_frame_set ( mips_subword ( mem , true ) , mips_subword ( reg , true ) ) ; mips_set_frame_expr ( gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , x1 , x2 ) ) ) ; } else mips_emit_save_slot_move ( mem , reg , MIPS_PROLOGUE_TEMP ( GET_MODE ( reg ) ) ) ; } </s>

Save register REG to MEM . Make the instruction frame-related .


Return true if the current function must save REGNO .


<s> static void mips_save_restore_reg ( machine_mode mode , int regno , HOST_WIDE_INT offset , mips_save_restore_fn fn ) { rtx mem ; mem = gen_frame_mem ( mode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; fn ( gen_rtx_REG ( mode , regno ) , mem ) ; } </s>

Use FN to save or restore register REGNO . MODE is the register 's mode and OFFSET is the offset of its save slot from the current stack pointer .


<s> static bool mips_scalar_mode_supported_p ( scalar_mode mode ) { if ( ALL_FIXED_POINT_MODE_P ( mode ) && GET_MODE_PRECISION ( mode ) <= 2 * BITS_PER_WORD ) return true ; return default_scalar_mode_supported_p ( mode ) ; } </s>


<s> static int mips_sched_reassociation_width ( unsigned int opc ATTRIBUTE_UNUSED , machine_mode mode ) { if ( MSA_SUPPORTED_MODE_P ( mode ) ) return 2 ; return 1 ; } </s>


<s> static bool mips_secondary_memory_needed ( machine_mode mode , reg_class_t class1 , reg_class_t class2 ) { if ( lra_in_progress && ( class1 == NO_REGS || class2 == NO_REGS ) ) return false ; if ( ( ( class1 == FP_REGS ) != ( class2 == FP_REGS ) ) && ( ( TARGET_FLOATXX && ! ISA_HAS_MXHC1 ) || TARGET_O32_FP64A_ABI ) && GET_MODE_SIZE ( mode ) >= 8 ) return true ; return false ; } </s>


<s> enum reg_class mips_secondary_reload_class ( enum reg_class rclass , machine_mode mode , rtx x , bool ) { int regno ; if ( mips_dangerous_for_la25_p ( x ) ) return reg_class_subset_p ( rclass , LEA_REGS ) ? NO_REGS : LEA_REGS ; regno = true_regnum ( x ) ; if ( TARGET_MIPS16 ) { if ( ! reg_class_subset_p ( rclass , M16_REGS ) && ! M16_REG_P ( regno ) ) return M16_REGS ; return NO_REGS ; } if ( reg_class_subset_p ( rclass , ACC_REGS ) ) return GP_REG_P ( regno ) ? NO_REGS : GR_REGS ; if ( ACC_REG_P ( regno ) ) return reg_class_subset_p ( rclass , GR_REGS ) ? NO_REGS : GR_REGS ; if ( reg_class_subset_p ( rclass , FP_REGS ) ) { if ( regno < 0 || ( MEM_P ( x ) && ( GET_MODE_SIZE ( mode ) == 4 || GET_MODE_SIZE ( mode ) == 8 ) ) ) return NO_REGS ; if ( MEM_P ( x ) && MSA_SUPPORTED_MODE_P ( mode ) ) return NO_REGS ; if ( GP_REG_P ( regno ) || x == CONST0_RTX ( mode ) ) return NO_REGS ; if ( CONSTANT_P ( x ) && ! targetm . cannot_force_const_mem ( mode , x ) ) return NO_REGS ; if ( FP_REG_P ( regno ) && mips_mode_ok_for_mov_fmt_p ( mode ) ) return NO_REGS ; return GR_REGS ; } if ( FP_REG_P ( regno ) ) return reg_class_subset_p ( rclass , GR_REGS ) ? NO_REGS : GR_REGS ; return NO_REGS ; } </s>

This function returns the register class required for a secondary register when copying between one of the registers in CLASS , and X , using MODE . If IN_P is nonzero , the copy is going from X to the register , otherwise the register is the source . A return value of NO_REGS means that no secondary register is required .


<s> static section * mips_select_rtx_section ( machine_mode mode , rtx x , unsigned HOST_WIDE_INT align ) { if ( mips_rtx_constant_in_small_data_p ( mode ) ) return get_named_section ( NULL , ".sdata" , 0 ) ; return default_elf_select_rtx_section ( mode , x , align ) ; } </s>

Choose the section to use for the constant rtx expression X that has mode MODE .


<s> static unsigned int mips_seq_time ( struct mips_sim * state , rtx_insn * seq ) { mips_sim_reset ( state ) ; for ( rtx_insn * insn = seq ; insn ; insn = NEXT_INSN ( insn ) ) { mips_sim_wait_insn ( state , insn ) ; mips_sim_issue_insn ( state , insn ) ; } return state -> time ; } </s>

Use simulator state STATE to calculate the execution time of instruction sequence SEQ .


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


<s> static void mips_set_architecture ( const struct mips_cpu_info * info ) { if ( info != 0 ) { mips_arch_info = info ; mips_arch = info -> cpu ; mips_isa = info -> isa ; if ( mips_isa < MIPS_ISA_MIPS32 ) mips_isa_rev = 0 ; else mips_isa_rev = ( mips_isa & 31 ) + 1 ; } } </s>

Set up globals to generate code for the ISA or processor described by INFO .


"MIPS16 PIC for ABIs other than o32 and o64"

"%<hard-float%> MIPS16 code for ABIs other than o32 and o64"

Set up the target-dependent global state for ISA mode COMPRESSION_MODE , which is either MASK_MIPS16 or MASK_MICROMIPS .


<s> static void mips_set_current_function ( tree fndecl ) { mips_set_compression_mode ( mips_get_compress_mode ( fndecl ) ) ; } </s>

Implement TARGET_SET_CURRENT_FUNCTION . Decide whether the current function should use the MIPS16 or microMIPS ISA and switch modes accordingly .


<s> static void mips_set_fast_mult_zero_zero_p ( struct mips_sim * state ) { if ( TARGET_MIPS16 || ! ISA_HAS_HILO ) mips_tuning_info . fast_mult_zero_zero_p = true ; else { unsigned int true_time = mips_mult_zero_zero_cost ( state , true ) ; unsigned int false_time = mips_mult_zero_zero_cost ( state , false ) ; mips_tuning_info . fast_mult_zero_zero_p = ( true_time <= false_time ) ; } } </s>

Check the relative speeds of `` MULT $ 0 , $ 0 '' and `` MTLO $ 0 ; MTHI $ 0 '' and set up mips_tuning_info.fast_mult_zero_zero_p accordingly . Prefer MULT -- which is shorter -- in the event of a tie .


<s> static void mips_set_frame_expr ( rtx frame_pattern ) { rtx_insn * insn ; insn = get_last_insn ( ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; REG_NOTES ( insn ) = alloc_EXPR_LIST ( REG_FRAME_RELATED_EXPR , frame_pattern , REG_NOTES ( insn ) ) ; } </s>

Make the last instruction frame related and note that it performs the operation described by FRAME_PATTERN .


<s> static int mips_set_reg_reg_cost ( machine_mode mode ) { switch ( GET_MODE_CLASS ( mode ) ) { case MODE_CC : return mips_set_reg_reg_piece_cost ( mode , GET_MODE_SIZE ( CCmode ) ) ; case MODE_FLOAT : case MODE_COMPLEX_FLOAT : case MODE_VECTOR_FLOAT : if ( TARGET_HARD_FLOAT ) return mips_set_reg_reg_piece_cost ( mode , UNITS_PER_HWFPVALUE ) ; default : return mips_set_reg_reg_piece_cost ( mode , UNITS_PER_WORD ) ; } } </s>

Return the cost of moving between two registers of mode MODE .


<s> static int mips_set_reg_reg_piece_cost ( machine_mode mode , unsigned int units ) { return COSTS_N_INSNS ( ( GET_MODE_SIZE ( mode ) + units - 1 ) / units ) ; } </s>

Return the cost of moving between two registers of mode MODE , assuming that the move will be in pieces of at most UNITS bytes .


<s> void mips_set_return_address ( rtx address , rtx scratch ) { rtx slot_address ; gcc_assert ( BITSET_P ( cfun -> machine -> frame . mask , RETURN_ADDR_REGNUM ) ) ; slot_address = mips_add_offset ( scratch , stack_pointer_rtx , cfun -> machine -> frame . gp_sp_offset ) ; mips_emit_move ( gen_frame_mem ( GET_MODE ( address ) , slot_address ) , address ) ; } </s>

Emit code to change the current function 's return address to ADDRESS . SCRATCH is available as a scratch register , if needed . ADDRESS and SCRATCH are both word-mode GPRs .


<s> static void mips_set_tune ( const struct mips_cpu_info * info ) { if ( info != 0 ) { mips_tune_info = info ; mips_tune = info -> cpu ; } } </s>


<s> static void mips_set_tuning_info ( void ) { if ( mips_tuning_info . initialized_p && mips_tuning_info . arch == mips_arch && mips_tuning_info . tune == mips_tune && mips_tuning_info . mips16_p == TARGET_MIPS16 ) return ; mips_tuning_info . arch = mips_arch ; mips_tuning_info . tune = mips_tune ; mips_tuning_info . mips16_p = TARGET_MIPS16 ; mips_tuning_info . initialized_p = true ; dfa_start ( ) ; struct mips_sim state ; mips_sim_init ( & state , alloca ( state_size ( ) ) ) ; mips_set_fast_mult_zero_zero_p ( & state ) ; dfa_finish ( ) ; } </s>

Set up costs based on the current architecture and tuning settings .


<s> static unsigned HOST_WIDE_INT mips_shift_truncation_mask ( machine_mode mode ) { if ( TARGET_LOONGSON_MMI && VECTOR_MODE_P ( mode ) ) return 0 ; return GET_MODE_BITSIZE ( mode ) - 1 ; } </s>

Implement TARGET_SHIFT_TRUNCATION_MASK . We want to keep the default behavior of TARGET_SHIFT_TRUNCATION_MASK for non-vector modes even when TARGET_LOONGSON_VECTORS is true .


<s> bool mips_signed_immediate_p ( unsigned HOST_WIDE_INT x , int bits , int shift = 0 ) { x += 1 << ( bits + shift - 1 ) ; return mips_unsigned_immediate_p ( x , bits , shift ) ; } </s>

Return true if X fits within a signed field of BITS bits that is shifted left SHIFT bits before being used .


<s> static int mips_sign_extend_cost ( machine_mode mode , rtx op ) { if ( MEM_P ( op ) ) return 0 ; if ( TARGET_64BIT && mode == DImode && GET_MODE ( op ) == SImode ) return 0 ; if ( ISA_HAS_SEB_SEH || GENERATE_MIPS16E ) return COSTS_N_INSNS ( 1 ) ; return COSTS_N_INSNS ( TARGET_MIPS16 ? 4 : 2 ) ; } </s>

Return the cost of sign-extending OP to mode MODE , not including the cost of OP itself .


<s> static void mips_sim_finish_insn ( struct mips_sim * state , rtx_insn * insn ) { if ( JUMP_P ( insn ) ) mips_sim_issue_nop ( state ) ; switch ( GET_CODE ( SEQ_BEGIN ( insn ) ) ) { case CODE_LABEL : case CALL_INSN : mips_sim_reset ( state ) ; break ; case JUMP_INSN : if ( INSN_ANNULLED_BRANCH_P ( SEQ_BEGIN ( insn ) ) ) mips_sim_reset ( state ) ; break ; default : break ; } } </s>

Update simulation state STATE so that it 's ready to accept the instruction after INSN . INSN should be part of the main rtl chain , not a member of a SEQUENCE .


<s> static void mips_sim_init ( struct mips_sim * state , state_t dfa_state ) { if ( targetm . sched . init_dfa_pre_cycle_insn ) targetm . sched . init_dfa_pre_cycle_insn ( ) ; if ( targetm . sched . init_dfa_post_cycle_insn ) targetm . sched . init_dfa_post_cycle_insn ( ) ; state -> issue_rate = mips_issue_rate ( ) ; state -> dfa_state = dfa_state ; mips_sim_reset ( state ) ; } </s>

Initialize STATE before its first use . DFA_STATE points to an allocated but uninitialized DFA state .


<s> static void mips_sim_issue_insn ( struct mips_sim * state , rtx_insn * insn ) { curr_state = state -> dfa_state ; state_transition ( curr_state , insn ) ; state -> insns_left = targetm . sched . variable_issue ( 0 , false , insn , state -> insns_left ) ; mips_sim_insn = insn ; note_stores ( insn , mips_sim_record_set , state ) ; } </s>

Issue instruction INSN in scheduler state STATE . Assume that INSN can issue immediately ( i.e. , that mips_sim_wait_insn has already been called ) .


<s> static void mips_sim_issue_nop ( struct mips_sim * state ) { if ( state -> insns_left == 0 ) mips_sim_next_cycle ( state ) ; state -> insns_left -- ; } </s>


<s> static void mips_sim_next_cycle ( struct mips_sim * state ) { curr_state = state -> dfa_state ; state -> time ++ ; state -> insns_left = state -> issue_rate ; advance_state ( curr_state ) ; } </s>


<s> static void mips_sim_record_set ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data ) { struct mips_sim * state ; state = ( struct mips_sim * ) data ; if ( REG_P ( x ) ) { unsigned int regno , end_regno ; end_regno = END_REGNO ( x ) ; for ( regno = REGNO ( x ) ; regno < end_regno ; regno ++ ) { state -> last_set [ regno ] . insn = mips_sim_insn ; state -> last_set [ regno ] . time = state -> time ; } } } </s>

mips_sim_insn has just set X. Update the LAST_SET array in simulation state DATA .


<s> static void mips_sim_reset ( struct mips_sim * state ) { curr_state = state -> dfa_state ; state -> time = 0 ; state -> insns_left = state -> issue_rate ; memset ( & state -> last_set , 0 , sizeof ( state -> last_set ) ) ; state_reset ( curr_state ) ; targetm . sched . init ( 0 , false , 0 ) ; advance_state ( curr_state ) ; } </s>

Reset STATE to the initial simulation state .


<s> static void mips_sim_wait_insn ( struct mips_sim * state , rtx_insn * insn ) { mips_sim_wait_regs ( state , insn ) ; mips_sim_wait_units ( state , insn ) ; } </s>

Advance simulation state STATE until INSN is ready to issue .


<s> static void mips_sim_wait_reg ( struct mips_sim * state , rtx_insn * insn , rtx reg ) { unsigned int regno , end_regno ; end_regno = END_REGNO ( reg ) ; for ( regno = REGNO ( reg ) ; regno < end_regno ; regno ++ ) if ( state -> last_set [ regno ] . insn != 0 ) { unsigned int t ; t = ( state -> last_set [ regno ] . time + insn_latency ( state -> last_set [ regno ] . insn , insn ) ) ; while ( state -> time < t ) mips_sim_next_cycle ( state ) ; } } </s>

Advance simulation state STATE until instruction INSN can read register REG .


<s> static void mips_sim_wait_regs ( struct mips_sim * state , rtx_insn * insn ) { mips_sim_insn = insn ; note_uses ( & PATTERN ( insn ) , mips_sim_wait_regs_1 , state ) ; } </s>

Advance simulation state STATE until all of INSN 's register dependencies are satisfied .


<s> static void mips_sim_wait_regs_1 ( rtx * x , void * data ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , * x , NONCONST ) if ( REG_P ( * iter ) ) mips_sim_wait_reg ( ( struct mips_sim * ) data , mips_sim_insn , * iter ) ; } </s>

Call mips_sim_wait_regs_2 ( R , DATA ) for each register R mentioned in * X .


<s> static void mips_sim_wait_units ( struct mips_sim * state , rtx_insn * insn ) { state_t tmp_state ; tmp_state = alloca ( state_size ( ) ) ; while ( state -> insns_left == 0 || ( memcpy ( tmp_state , state -> dfa_state , state_size ( ) ) , state_transition ( tmp_state , insn ) >= 0 ) ) mips_sim_next_cycle ( state ) ; } </s>

Advance simulation state STATE until the units required by instruction INSN are available .


<s> static int mips_small_data_pattern_1 ( rtx x , enum mips_symbol_context context ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , x , ALL ) { rtx x = * iter ; if ( GET_CODE ( x ) == LO_SUM || GET_CODE ( x ) == ASM_OPERANDS ) iter . skip_subrtxes ( ) ; else if ( MEM_P ( x ) ) { if ( mips_small_data_pattern_1 ( XEXP ( x , 0 ) , SYMBOL_CONTEXT_MEM ) ) return true ; iter . skip_subrtxes ( ) ; } else if ( mips_rewrite_small_data_p ( x , context ) ) return true ; } return false ; } </s>

A for_each_rtx callback for mips_small_data_pattern_p .


<s> bool mips_small_data_pattern_p ( rtx op ) { return mips_small_data_pattern_1 ( op , SYMBOL_CONTEXT_LEA ) ; } </s>

Return true if OP refers to small data symbols directly , not through a LO_SUM .


<s> static bool mips_small_register_classes_for_mode_p ( machine_mode mode ATTRIBUTE_UNUSED ) { return TARGET_MIPS16 ; } </s>

Implement target hook small_register_classes_for_mode_p .


<s> void mips_split_128bit_move ( rtx dest , rtx src ) { int byte , index ; rtx low_dest , low_src , d , s ; if ( FP_REG_RTX_P ( dest ) ) { gcc_assert ( ! MEM_P ( src ) ) ; rtx new_dest = dest ; if ( ! TARGET_64BIT ) { if ( GET_MODE ( dest ) != V4SImode ) new_dest = simplify_gen_subreg ( V4SImode , dest , GET_MODE ( dest ) , 0 ) ; } else { if ( GET_MODE ( dest ) != V2DImode ) new_dest = simplify_gen_subreg ( V2DImode , dest , GET_MODE ( dest ) , 0 ) ; } for ( byte = 0 , index = 0 ; byte < GET_MODE_SIZE ( TImode ) ; byte += UNITS_PER_WORD , index ++ ) { s = mips_subword_at_byte ( src , byte ) ; if ( ! TARGET_64BIT ) emit_insn ( gen_msa_insert_w ( new_dest , s , new_dest , GEN_INT ( 1 << index ) ) ) ; else emit_insn ( gen_msa_insert_d ( new_dest , s , new_dest , GEN_INT ( 1 << index ) ) ) ; } } else if ( FP_REG_RTX_P ( src ) ) { gcc_assert ( ! MEM_P ( dest ) ) ; rtx new_src = src ; if ( ! TARGET_64BIT ) { if ( GET_MODE ( src ) != V4SImode ) new_src = simplify_gen_subreg ( V4SImode , src , GET_MODE ( src ) , 0 ) ; } else { if ( GET_MODE ( src ) != V2DImode ) new_src = simplify_gen_subreg ( V2DImode , src , GET_MODE ( src ) , 0 ) ; } for ( byte = 0 , index = 0 ; byte < GET_MODE_SIZE ( TImode ) ; byte += UNITS_PER_WORD , index ++ ) { d = mips_subword_at_byte ( dest , byte ) ; if ( ! TARGET_64BIT ) emit_insn ( gen_msa_copy_s_w ( d , new_src , GEN_INT ( index ) ) ) ; else emit_insn ( gen_msa_copy_s_d ( d , new_src , GEN_INT ( index ) ) ) ; } } else { low_dest = mips_subword_at_byte ( dest , 0 ) ; low_src = mips_subword_at_byte ( src , 0 ) ; gcc_assert ( REG_P ( low_dest ) && REG_P ( low_src ) ) ; if ( REGNO ( low_dest ) <= REGNO ( low_src ) ) { for ( byte = 0 ; byte < GET_MODE_SIZE ( TImode ) ; byte += UNITS_PER_WORD ) { d = mips_subword_at_byte ( dest , byte ) ; s = mips_subword_at_byte ( src , byte ) ; mips_emit_move ( d , s ) ; } } else { for ( byte = GET_MODE_SIZE ( TImode ) - UNITS_PER_WORD ; byte >= 0 ; byte -= UNITS_PER_WORD ) { d = mips_subword_at_byte ( dest , byte ) ; s = mips_subword_at_byte ( src , byte ) ; mips_emit_move ( d , s ) ; } } } } </s>


<s> bool mips_split_128bit_move_p ( rtx dest , rtx src ) { if ( FP_REG_RTX_P ( src ) && FP_REG_RTX_P ( dest ) ) return false ; if ( FP_REG_RTX_P ( dest ) && MEM_P ( src ) ) return false ; if ( FP_REG_RTX_P ( src ) && MEM_P ( dest ) ) return false ; if ( FP_REG_RTX_P ( dest ) && mips_const_vector_same_int_p ( src , GET_MODE ( src ) , - 512 , 511 ) ) return false ; if ( FP_REG_RTX_P ( dest ) && src == CONST0_RTX ( GET_MODE ( src ) ) ) return false ; return true ; } </s>

Return true if a 128-bit move from SRC to DEST should be split .


<s> static bool mips_split_addresses_p ( void ) { return ( TARGET_SPLIT_ADDRESSES && optimize && ! TARGET_MIPS16 && ! flag_pic && ! ABI_HAS_64BIT_SYMBOLS ) ; } </s>

Return true if -msplit-addresses is selected and should be honored . -msplit-addresses is a half-way house between explicit relocations and the traditional assembler macros . It can split absolute 32-bit symbolic constants into a high/lo_sum pair but uses macros for other sorts of access . Like explicit relocation support for REL targets , it relies on GNU extensions in the assembler and the linker . Although this code should work for -O0 , it has traditionally been treated as an optimization .


<s> void mips_split_call ( rtx insn , rtx call_pattern ) { emit_call_insn ( call_pattern ) ; if ( ! find_reg_note ( insn , REG_NORETURN , 0 ) ) mips_restore_gp_from_cprestore_slot ( gen_rtx_REG ( Pmode , POST_CALL_TMP_REG ) ) ; } </s>

Split call instruction INSN into a $ gp-clobbering call and ( where necessary ) an instruction to restore $ gp from its save slot . CALL_PATTERN is the pattern of the new call .


<s> int mips_split_const_insns ( rtx x ) { unsigned int low , high ; low = mips_const_insns ( mips_subword ( x , false ) ) ; high = mips_const_insns ( mips_subword ( x , true ) ) ; gcc_assert ( low > 0 && high > 0 ) ; return low + high ; } </s>

X is a doubleword constant that can be handled by splitting it into two words and loading each word separately . Return the number of instructions required to do this , assuming that BASE_INSN_LENGTH is the length of one instruction .


<s> void mips_split_move_insn ( rtx dest , rtx src , rtx insn ) { mips_split_move ( dest , src , mips_insn_split_type ( insn ) , insn ) ; } </s>

Split a move from SRC to DEST in INSN , given that mips_split_move_insn_p holds .


<s> bool mips_split_move_insn_p ( rtx dest , rtx src , rtx insn ) { return mips_split_move_p ( dest , src , mips_insn_split_type ( insn ) ) ; } </s>

Return true if a move from SRC to DEST in INSN should be split .


<s> bool mips_split_move_p ( rtx dest , rtx src , enum mips_split_type split_type ) { if ( mips_mult_move_p ( dest , src , split_type ) ) return false ; unsigned int size = GET_MODE_SIZE ( GET_MODE ( dest ) ) ; if ( size == 8 && FP_REG_RTX_P ( src ) && FP_REG_RTX_P ( dest ) ) return false ; if ( size == 8 && ISA_HAS_LDC1_SDC1 ) { if ( FP_REG_RTX_P ( dest ) && MEM_P ( src ) ) return false ; if ( FP_REG_RTX_P ( src ) && MEM_P ( dest ) ) return false ; } if ( MSA_SUPPORTED_MODE_P ( GET_MODE ( dest ) ) ) return mips_split_128bit_move_p ( dest , src ) ; return size > UNITS_PER_WORD ; } </s>

Return true if a move from SRC to DEST should be split into two . SPLIT_TYPE describes the split condition .


<s> void mips_split_msa_copy_d ( rtx dest , rtx src , rtx index , rtx ( * gen_fn ) ( rtx , rtx , rtx ) ) { gcc_assert ( ( GET_MODE ( src ) == V2DImode && GET_MODE ( dest ) == DImode ) || ( GET_MODE ( src ) == V2DFmode && GET_MODE ( dest ) == DFmode ) ) ; rtx low = mips_subword ( dest , false ) ; rtx high = mips_subword ( dest , true ) ; rtx new_src = simplify_gen_subreg ( V4SImode , src , GET_MODE ( src ) , 0 ) ; emit_insn ( gen_fn ( low , new_src , GEN_INT ( INTVAL ( index ) * 2 ) ) ) ; emit_insn ( gen_fn ( high , new_src , GEN_INT ( INTVAL ( index ) * 2 + 1 ) ) ) ; } </s>

Split a COPY_S.D with operands DEST , SRC and INDEX . GEN is a function used to generate subregs .


<s> void mips_split_msa_fill_d ( rtx dest , rtx src ) { gcc_assert ( ( GET_MODE ( dest ) == V2DImode && ( GET_MODE ( src ) == DImode || src == const0_rtx ) ) || ( GET_MODE ( dest ) == V2DFmode && GET_MODE ( src ) == DFmode ) ) ; rtx low , high ; if ( src == const0_rtx ) { low = src ; high = src ; } else { low = mips_subword ( src , false ) ; high = mips_subword ( src , true ) ; } rtx new_dest = simplify_gen_subreg ( V4SImode , dest , GET_MODE ( dest ) , 0 ) ; emit_insn ( gen_msa_fill_w ( new_dest , low ) ) ; emit_insn ( gen_msa_insert_w ( new_dest , high , new_dest , GEN_INT ( 1 << 1 ) ) ) ; emit_insn ( gen_msa_insert_w ( new_dest , high , new_dest , GEN_INT ( 1 << 3 ) ) ) ; } </s>


<s> void mips_split_msa_insert_d ( rtx dest , rtx src1 , rtx index , rtx src2 ) { int i ; gcc_assert ( GET_MODE ( dest ) == GET_MODE ( src1 ) ) ; gcc_assert ( ( GET_MODE ( dest ) == V2DImode && ( GET_MODE ( src2 ) == DImode || src2 == const0_rtx ) ) || ( GET_MODE ( dest ) == V2DFmode && GET_MODE ( src2 ) == DFmode ) ) ; rtx low = mips_subword ( src2 , false ) ; rtx high = mips_subword ( src2 , true ) ; rtx new_dest = simplify_gen_subreg ( V4SImode , dest , GET_MODE ( dest ) , 0 ) ; rtx new_src1 = simplify_gen_subreg ( V4SImode , src1 , GET_MODE ( src1 ) , 0 ) ; i = exact_log2 ( INTVAL ( index ) ) ; gcc_assert ( i != - 1 ) ; emit_insn ( gen_msa_insert_w ( new_dest , low , new_src1 , GEN_INT ( 1 << ( i * 2 ) ) ) ) ; emit_insn ( gen_msa_insert_w ( new_dest , high , new_dest , GEN_INT ( 1 << ( i * 2 + 1 ) ) ) ) ; } </s>

Split a INSERT.D with operand DEST , SRC1.INDEX and SRC2 .


<s> static void mips_split_plus ( rtx x , rtx * base_ptr , HOST_WIDE_INT * offset_ptr ) { if ( GET_CODE ( x ) == PLUS && CONST_INT_P ( XEXP ( x , 1 ) ) ) { * base_ptr = XEXP ( x , 0 ) ; * offset_ptr = INTVAL ( XEXP ( x , 1 ) ) ; } else { * base_ptr = x ; * offset_ptr = 0 ; } } </s>

If X is a PLUS of a CONST_INT , return the two terms in * BASE_PTR and * OFFSET_PTR . Return X in * BASE_PTR and 0 in * OFFSET_PTR otherwise .


<s> bool mips_split_symbol ( rtx temp , rtx addr , machine_mode mode , rtx * low_out ) { enum mips_symbol_context context ; enum mips_symbol_type symbol_type ; rtx high ; context = ( mode == MAX_MACHINE_MODE ? SYMBOL_CONTEXT_LEA : SYMBOL_CONTEXT_MEM ) ; if ( GET_CODE ( addr ) == HIGH && context == SYMBOL_CONTEXT_LEA ) { addr = XEXP ( addr , 0 ) ; if ( mips_symbolic_constant_p ( addr , context , & symbol_type ) && mips_symbol_insns ( symbol_type , mode ) > 0 && mips_split_hi_p [ symbol_type ] ) { if ( low_out ) switch ( symbol_type ) { case SYMBOL_GOT_PAGE_OFST : * low_out = mips_got_load ( temp , addr , SYMBOL_GOTOFF_PAGE ) ; break ; default : gcc_unreachable ( ) ; } return true ; } } else { if ( mips_symbolic_constant_p ( addr , context , & symbol_type ) && mips_symbol_insns ( symbol_type , mode ) > 0 && mips_split_p [ symbol_type ] ) { if ( low_out ) switch ( symbol_type ) { case SYMBOL_GOT_DISP : * low_out = mips_got_load ( temp , addr , SYMBOL_GOTOFF_DISP ) ; break ; case SYMBOL_GP_RELATIVE : high = mips_pic_base_register ( temp ) ; * low_out = gen_rtx_LO_SUM ( Pmode , high , addr ) ; break ; default : high = gen_rtx_HIGH ( Pmode , copy_rtx ( addr ) ) ; high = mips_force_temporary ( temp , high ) ; * low_out = gen_rtx_LO_SUM ( Pmode , high , addr ) ; break ; } return true ; } } return false ; } </s>

Return a LO_SUM expression for ADDR . TEMP is as for mips_force_temporary and is used to load the high part into a register .


<s> bool mips_stack_address_p ( rtx x , machine_mode mode ) { struct mips_address_info addr ; return ( mips_classify_address ( & addr , x , mode , false ) && addr . type == ADDRESS_REG && addr . reg == stack_pointer_rtx ) ; } </s>

Return true if X is a legitimate $ sp-based address for mode MDOE .


<s> static HOST_WIDE_INT mips_starting_frame_offset ( void ) { if ( FRAME_GROWS_DOWNWARD ) return 0 ; return crtl -> outgoing_args_size + MIPS_GP_SAVE_AREA_SIZE ; } </s>

Implement TARGET_STARTING_FRAME_OFFSET . See mips_compute_frame_info for details about the frame layout .


<s> static void mips_start_function_definition ( const char * name , bool mips16_p ) { if ( mips16_p ) fprintf ( asm_out_file , "\t.set\tmips16\n" ) ; else fprintf ( asm_out_file , "\t.set\tnomips16\n" ) ; if ( TARGET_MICROMIPS ) fprintf ( asm_out_file , "\t.set\tmicromips\n" ) ; else fprintf ( asm_out_file , "\t.set\tnomicromips\n" ) ; if ( ! flag_inhibit_size_directive ) { fputs ( "\t.ent\t" , asm_out_file ) ; assemble_name ( asm_out_file , name ) ; fputs ( "\n" , asm_out_file ) ; } ASM_OUTPUT_TYPE_DIRECTIVE ( asm_out_file , name , "function" ) ; assemble_name ( asm_out_file , name ) ; fputs ( ":\n" , asm_out_file ) ; } </s>

Start a definition of function NAME . MIPS16_P indicates whether the function contains MIPS16 code .


<s> static void mips_start_ll_sc_sync_block ( void ) { if ( ! ISA_HAS_LL_SC ) { output_asm_insn ( ".set\tpush" , 0 ) ; if ( TARGET_64BIT ) output_asm_insn ( ".set\tmips3" , 0 ) ; else output_asm_insn ( ".set\tmips2" , 0 ) ; } } </s>

Start a block of code that needs access to the LL , SC and SYNC instructions .


<s> static void mips_start_unique_function ( const char * name ) { tree decl ; decl = build_decl ( BUILTINS_LOCATION , FUNCTION_DECL , get_identifier ( name ) , build_function_type_list ( void_type_node , NULL_TREE ) ) ; DECL_RESULT ( decl ) = build_decl ( BUILTINS_LOCATION , RESULT_DECL , NULL_TREE , void_type_node ) ; TREE_PUBLIC ( decl ) = 1 ; TREE_STATIC ( decl ) = 1 ; cgraph_node :: create ( decl ) -> set_comdat_group ( DECL_ASSEMBLER_NAME ( decl ) ) ; targetm . asm_out . unique_section ( decl , 0 ) ; switch_to_section ( get_named_section ( decl , NULL , 0 ) ) ; targetm . asm_out . globalize_label ( asm_out_file , name ) ; fputs ( "\t.hidden\t" , asm_out_file ) ; assemble_name ( asm_out_file , name ) ; putc ( '\n' , asm_out_file ) ; } </s>

Declare a unique , locally-binding function called NAME , then start its definition .


<s> static tree mips_std_gimplify_va_arg_expr ( tree valist , tree type , gimple_seq * pre_p , gimple_seq * post_p ) { tree addr , t , type_size , rounded_size , valist_tmp ; unsigned HOST_WIDE_INT align , boundary ; bool indirect ; indirect = pass_va_arg_by_reference ( type ) ; if ( indirect ) type = build_pointer_type ( type ) ; align = PARM_BOUNDARY / BITS_PER_UNIT ; boundary = targetm . calls . function_arg_boundary ( TYPE_MODE ( type ) , type ) ; if ( boundary > MAX_SUPPORTED_STACK_ALIGNMENT ) boundary = MAX_SUPPORTED_STACK_ALIGNMENT ; boundary /= BITS_PER_UNIT ; valist_tmp = get_initialized_tmp_var ( valist , pre_p , NULL ) ; if ( boundary > align ) { t = build2 ( MODIFY_EXPR , TREE_TYPE ( valist ) , valist_tmp , fold_build_pointer_plus_hwi ( valist_tmp , boundary - 1 ) ) ; gimplify_and_add ( t , pre_p ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( valist ) , valist_tmp , fold_build2 ( BIT_AND_EXPR , TREE_TYPE ( valist ) , valist_tmp , build_int_cst ( TREE_TYPE ( valist ) , - boundary ) ) ) ; gimplify_and_add ( t , pre_p ) ; } else boundary = align ; boundary *= BITS_PER_UNIT ; if ( boundary < TYPE_ALIGN ( type ) ) { type = build_variant_type_copy ( type ) ; SET_TYPE_ALIGN ( type , boundary ) ; } type_size = size_in_bytes ( type ) ; rounded_size = round_up ( type_size , align ) ; gimplify_expr ( & rounded_size , pre_p , post_p , is_gimple_val , fb_rvalue ) ; addr = valist_tmp ; if ( PAD_VARARGS_DOWN && ! integer_zerop ( rounded_size ) ) { t = fold_build2_loc ( input_location , GT_EXPR , sizetype , rounded_size , size_int ( align ) ) ; t = fold_build3 ( COND_EXPR , sizetype , t , size_zero_node , size_binop ( MINUS_EXPR , rounded_size , type_size ) ) ; addr = fold_build_pointer_plus ( addr , t ) ; } t = fold_build_pointer_plus ( valist_tmp , rounded_size ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( valist ) , valist , t ) ; gimplify_and_add ( t , pre_p ) ; addr = fold_convert ( build_pointer_type ( type ) , addr ) ; if ( indirect ) addr = build_va_arg_indirect_ref ( addr ) ; return build_va_arg_indirect_ref ( addr ) ; } </s>

Like std_gimplify_va_arg_expr , but apply alignment to zero-sized types as well .


<s> bool mips_store_by_pieces_p ( unsigned HOST_WIDE_INT size , unsigned int align ) { if ( align <= BITS_PER_UNIT ) return size < 4 ; return size < 8 ; } </s>


<s> bool mips_store_data_bypass_p ( rtx_insn * out_insn , rtx_insn * in_insn ) { if ( GET_CODE ( PATTERN ( in_insn ) ) == UNSPEC_VOLATILE ) return false ; return store_data_bypass_p ( out_insn , in_insn ) ; } </s>

True if the dependency between OUT_INSN and IN_INSN is on the store data rather than the address . We need this because the cprestore pattern is type `` store '' , but is defined using an UNSPEC_VOLATILE , which causes the default routine to abort . We just return false for that case .


<s> static bool mips_strict_argument_naming ( cumulative_args_t ca ATTRIBUTE_UNUSED ) { return ! TARGET_OLDABI ; } </s>


<s> rtx mips_strip_unspec_address ( rtx op ) { rtx base , offset ; split_const ( op , & base , & offset ) ; if ( UNSPEC_ADDRESS_P ( base ) ) op = plus_constant ( Pmode , UNSPEC_ADDRESS ( base ) , INTVAL ( offset ) ) ; return op ; } </s>

If OP is an UNSPEC address , return the address to which it refers , otherwise return OP itself .


<s> static rtx mips_strip_unspec_call ( rtx src ) { if ( GET_CODE ( src ) == UNSPEC && XINT ( src , 1 ) == UNSPEC_LOAD_CALL ) return mips_strip_unspec_address ( XVECEXP ( src , 0 , 1 ) ) ; return NULL_RTX ; } </s>

If SRC is the RHS of a load_call < mode > insn , return the underlying symbol reference . Return NULL_RTX otherwise .


<s> rtx mips_subword ( rtx op , bool high_p ) { unsigned int byte , offset ; machine_mode mode ; mode = GET_MODE ( op ) ; if ( mode == VOIDmode ) mode = TARGET_64BIT ? TImode : DImode ; if ( TARGET_BIG_ENDIAN ? ! high_p : high_p ) byte = UNITS_PER_WORD ; else byte = 0 ; if ( FP_REG_RTX_P ( op ) ) { offset = ( UNITS_PER_WORD < UNITS_PER_HWFPVALUE ? high_p : byte != 0 ) ; return gen_rtx_REG ( word_mode , REGNO ( op ) + offset ) ; } if ( MEM_P ( op ) ) return mips_rewrite_small_data ( adjust_address ( op , word_mode , byte ) ) ; return simplify_gen_subreg ( word_mode , op , mode , byte ) ; } </s>

Return one word of double-word value OP , taking into account the fixed endianness of certain registers . HIGH_P is true to select the high part , false to select the low part .


<s> rtx mips_subword_at_byte ( rtx op , unsigned int byte ) { machine_mode mode ; mode = GET_MODE ( op ) ; if ( mode == VOIDmode ) mode = TImode ; gcc_assert ( ! FP_REG_RTX_P ( op ) ) ; if ( MEM_P ( op ) ) return mips_rewrite_small_data ( adjust_address ( op , word_mode , byte ) ) ; return simplify_gen_subreg ( word_mode , op , mode , byte ) ; } </s>

Return one word of 128-bit value OP , taking into account the fixed endianness of certain registers . BYTE selects from the byte address .


<s> static void mips_swap_registers ( unsigned int i ) { int tmpi ; const char * tmps ; SWAP_INT ( fixed_regs [ i ] , fixed_regs [ i + 1 ] ) ; SWAP_INT ( call_used_regs [ i ] , call_used_regs [ i + 1 ] ) ; SWAP_STRING ( reg_names [ i ] , reg_names [ i + 1 ] ) ; } </s>

Swap the register information for registers I and I + 1 , which currently have the wrong endianness . Note that the registers ' fixedness and call-clobberedness might have been set on the command line .


<s> bool mips_symbolic_constant_p ( rtx x , enum mips_symbol_context context , enum mips_symbol_type * symbol_type ) { rtx offset ; split_const ( x , & x , & offset ) ; if ( UNSPEC_ADDRESS_P ( x ) ) { * symbol_type = UNSPEC_ADDRESS_TYPE ( x ) ; x = UNSPEC_ADDRESS ( x ) ; } else if ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) { * symbol_type = mips_classify_symbol ( x , context ) ; if ( * symbol_type == SYMBOL_TLS ) return false ; } else return false ; if ( offset == const0_rtx ) return true ; switch ( * symbol_type ) { case SYMBOL_ABSOLUTE : case SYMBOL_64_HIGH : case SYMBOL_64_MID : case SYMBOL_64_LOW : if ( Pmode == DImode && ! ABI_HAS_64BIT_SYMBOLS ) return offset_within_block_p ( x , INTVAL ( offset ) ) ; return true ; case SYMBOL_PC_RELATIVE : if ( GET_CODE ( x ) == LABEL_REF ) return true ; case SYMBOL_GP_RELATIVE : return offset_within_block_p ( x , INTVAL ( offset ) ) ; case SYMBOL_GOT_PAGE_OFST : case SYMBOL_GOTOFF_PAGE : return SMALL_INT ( offset ) ; case SYMBOL_TPREL : case SYMBOL_DTPREL : return mips_offset_within_alignment_p ( x , INTVAL ( offset ) ) ; case SYMBOL_GOT_DISP : case SYMBOL_GOTOFF_DISP : case SYMBOL_GOTOFF_CALL : case SYMBOL_GOTOFF_LOADGP : case SYMBOL_TLSGD : case SYMBOL_TLSLDM : case SYMBOL_GOTTPREL : case SYMBOL_TLS : case SYMBOL_HALF : return false ; } gcc_unreachable ( ) ; } </s>

Return true if X is a symbolic constant that can be calculated in the same way as a bare symbol . If it is , store the type of the symbol in * SYMBOL_TYPE .


<s> static bool mips_symbol_binds_local_p ( const_rtx x ) { return ( SYMBOL_REF_DECL ( x ) ? targetm . binds_local_p ( SYMBOL_REF_DECL ( x ) ) : SYMBOL_REF_LOCAL_P ( x ) ) ; } </s>

Return true if SYMBOL_REF X binds locally .


<s> static int mips_symbol_insns ( enum mips_symbol_type type , machine_mode mode ) { if ( mode != MAX_MACHINE_MODE && MSA_SUPPORTED_MODE_P ( mode ) ) return 0 ; return mips_symbol_insns_1 ( type , mode ) * ( TARGET_MIPS16 ? 2 : 1 ) ; } </s>

Return the number of instructions needed to load a symbol of the given type into a register . If valid in an address , the same number of instructions are needed for loads and stores . Treat extended mips16 instructions as two instructions .


<s> static int mips_symbol_insns_1 ( enum mips_symbol_type type , machine_mode mode ) { if ( mips_use_pcrel_pool_p [ ( int ) type ] ) { if ( mode == MAX_MACHINE_MODE ) type = SYMBOL_PC_RELATIVE ; else return 0 ; } switch ( type ) { case SYMBOL_ABSOLUTE : return ABI_HAS_64BIT_SYMBOLS ? 6 : TARGET_MIPS16 ? 3 : 2 ; case SYMBOL_GP_RELATIVE : return 1 ; case SYMBOL_PC_RELATIVE : if ( mode == MAX_MACHINE_MODE || GET_MODE_SIZE ( mode ) == 4 || GET_MODE_SIZE ( mode ) == 8 ) return 1 ; return 0 ; case SYMBOL_GOT_DISP : if ( mode != MAX_MACHINE_MODE ) return 0 ; case SYMBOL_GOT_PAGE_OFST : return 3 ; case SYMBOL_GOTOFF_PAGE : case SYMBOL_GOTOFF_DISP : case SYMBOL_GOTOFF_CALL : case SYMBOL_GOTOFF_LOADGP : case SYMBOL_64_HIGH : case SYMBOL_64_MID : case SYMBOL_64_LOW : case SYMBOL_TLSGD : case SYMBOL_TLSLDM : case SYMBOL_DTPREL : case SYMBOL_GOTTPREL : case SYMBOL_TPREL : case SYMBOL_HALF : return ! mips_split_p [ type ] ? 1 : TARGET_MIPS16 ? 3 : 2 ; case SYMBOL_TLS : return 0 ; } gcc_unreachable ( ) ; } </s>

Like mips_symbol_insns , but treat extended MIPS16 instructions as a single instruction . We rely on the fact that , in the worst case , all instructions involved in a MIPS16 address calculation are usually extended ones .


<s> static const char * mips_sync_insn1_template ( enum attr_sync_insn1 type , bool is_64bit_p ) { switch ( type ) { case SYNC_INSN1_MOVE : return "move\t%0,%z2" ; case SYNC_INSN1_LI : return "li\t%0,%2" ; case SYNC_INSN1_ADDU : return is_64bit_p ? "daddu\t%0,%1,%z2" : "addu\t%0,%1,%z2" ; case SYNC_INSN1_ADDIU : return is_64bit_p ? "daddiu\t%0,%1,%2" : "addiu\t%0,%1,%2" ; case SYNC_INSN1_SUBU : return is_64bit_p ? "dsubu\t%0,%1,%z2" : "subu\t%0,%1,%z2" ; case SYNC_INSN1_AND : return "and\t%0,%1,%z2" ; case SYNC_INSN1_ANDI : return "andi\t%0,%1,%2" ; case SYNC_INSN1_OR : return "or\t%0,%1,%z2" ; case SYNC_INSN1_ORI : return "ori\t%0,%1,%2" ; case SYNC_INSN1_XOR : return "xor\t%0,%1,%z2" ; case SYNC_INSN1_XORI : return "xori\t%0,%1,%2" ; } gcc_unreachable ( ) ; } </s>

Return the asm template associated with sync_insn1 value TYPE . IS_64BIT_P is true if we want a 64-bit rather than 32-bit operation .


<s> static const char * mips_sync_insn2_template ( enum attr_sync_insn2 type ) { switch ( type ) { case SYNC_INSN2_NOP : gcc_unreachable ( ) ; case SYNC_INSN2_AND : return "and\t%0,%1,%z2" ; case SYNC_INSN2_XOR : return "xor\t%0,%1,%z2" ; case SYNC_INSN2_NOT : return "nor\t%0,%1,%." ; } gcc_unreachable ( ) ; } </s>

Return the asm template associated with sync_insn2 value TYPE .


<s> unsigned int mips_sync_loop_insns ( rtx_insn * insn , rtx * operands ) { mips_branch_likely = TARGET_FIX_R10000 ; mips_process_sync_loop ( insn , operands ) ; return mips_multi_num_insns ; } </s>

Return the number of individual instructions in sync loop INSN , which has the operands given by OPERANDS .


<s> static bool mips_tls_symbol_p ( rtx x ) { return GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) != 0 ; } </s>

Return true if X is a thread-local symbol .


<s> int mips_trampoline_code_size ( void ) { if ( TARGET_USE_PIC_FN_ADDR_REG ) return 4 * 4 ; else if ( ptr_mode == DImode ) return 8 * 4 ; else if ( ISA_HAS_LOAD_DELAY ) return 6 * 4 ; else return 4 * 4 ; } </s>

Return the size in bytes of the trampoline code , padded to TRAMPOLINE_ALIGNMENT bits . The static chain pointer and target function address immediately follow .


<s> static bool mips_truly_noop_truncation ( poly_uint64 outprec , poly_uint64 inprec ) { return ! TARGET_64BIT || inprec <= 32 || outprec > 32 ; } </s>


<s> bool mips_unsigned_immediate_p ( unsigned HOST_WIDE_INT x , int bits , int shift = 0 ) { return ( x & ( ( 1 << shift ) - 1 ) ) == 0 && x < ( ( unsigned ) 1 << ( shift + bits ) ) ; } </s>

Return true if X fits within an unsigned field of BITS bits that is shifted left SHIFT bits before being used .


<s> rtx mips_unspec_address ( rtx address , enum mips_symbol_type symbol_type ) { rtx base , offset ; split_const ( address , & base , & offset ) ; return mips_unspec_address_offset ( base , offset , symbol_type ) ; } </s>

Return an UNSPEC address with underlying address ADDRESS and symbol type SYMBOL_TYPE .


<s> static rtx mips_unspec_address_offset ( rtx base , rtx offset , enum mips_symbol_type symbol_type ) { base = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , base ) , UNSPEC_ADDRESS_FIRST + symbol_type ) ; if ( offset != const0_rtx ) base = gen_rtx_PLUS ( Pmode , base , offset ) ; return gen_rtx_CONST ( Pmode , base ) ; } </s>

Wrap symbol or label BASE in an UNSPEC address of type SYMBOL_TYPE , then add CONST_INT OFFSET to the result .


<s> static rtx mips_unspec_call ( rtx reg , rtx symbol ) { rtvec vec ; vec = gen_rtvec ( 3 , reg , symbol , gen_rtx_REG ( SImode , GOT_VERSION_REGNUM ) ) ; return gen_rtx_UNSPEC ( Pmode , vec , UNSPEC_LOAD_CALL ) ; } </s>

Return the RHS of a load_call < mode > insn .


<s> static rtx mips_unspec_offset_high ( rtx temp , rtx base , rtx addr , enum mips_symbol_type symbol_type ) { if ( mips_split_p [ symbol_type ] ) { addr = gen_rtx_HIGH ( Pmode , mips_unspec_address ( addr , symbol_type ) ) ; addr = mips_force_temporary ( temp , addr ) ; base = mips_force_temporary ( temp , gen_rtx_PLUS ( Pmode , addr , base ) ) ; } return base ; } </s>

If mips_unspec_address ( ADDR , SYMBOL_TYPE ) is a 32-bit value , add the high part to BASE and return the result . Just return BASE otherwise . TEMP is available as a temporary register if needed . The returned expression can be used as the first operand to a LO_SUM .


<s> static bool mips_use_anchors_for_symbol_p ( const_rtx symbol ) { switch ( mips_classify_symbol ( symbol , SYMBOL_CONTEXT_MEM ) ) { case SYMBOL_PC_RELATIVE : case SYMBOL_GP_RELATIVE : return false ; default : return default_use_anchors_for_symbol_p ( symbol ) ; } } </s>

Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P . We do n't want to use anchors for small data : the GP register acts as an anchor in that case . We also do n't want to use them for PC-relative accesses , where the PC acts as an anchor .


<s> static bool mips_use_blocks_for_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , const_rtx x ATTRIBUTE_UNUSED ) { return ! TARGET_MIPS16_PCREL_LOADS ; } </s>

Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P . We ca n't use blocks for constants when we 're using a per-function constant pool .


<s> bool mips_use_by_pieces_infrastructure_p ( unsigned HOST_WIDE_INT size , unsigned int align , enum by_pieces_operation op , bool speed_p ) { if ( op == STORE_BY_PIECES ) return mips_store_by_pieces_p ( size , align ) ; if ( op == MOVE_BY_PIECES && HAVE_cpymemsi ) { if ( currently_expanding_to_rtl ) return false ; if ( align < BITS_PER_WORD ) return size < UNITS_PER_WORD ; return size <= MIPS_MAX_MOVE_BYTES_STRAIGHT ; } return default_use_by_pieces_infrastructure_p ( size , align , op , speed_p ) ; } </s>


<s> static bool mips_use_debug_exception_return_p ( tree type ) { return lookup_attribute ( "use_debug_exception_return" , TYPE_ATTRIBUTES ( type ) ) != NULL ; } </s>

Check if the attribute to use debug exception return is set for a function .


<s> bool mips_use_ins_ext_p ( rtx op , HOST_WIDE_INT width , HOST_WIDE_INT bitpos ) { if ( ! ISA_HAS_EXT_INS || ! register_operand ( op , VOIDmode ) || GET_MODE_BITSIZE ( GET_MODE ( op ) ) > BITS_PER_WORD ) return false ; if ( ! IN_RANGE ( width , 1 , GET_MODE_BITSIZE ( GET_MODE ( op ) ) - 1 ) ) return false ; if ( bitpos < 0 || bitpos + width > GET_MODE_BITSIZE ( GET_MODE ( op ) ) ) return false ; return true ; } </s>

Return true if ( zero_extract OP SIZE POSITION ) can be used as the source of an `` ext '' instruction or the destination of an `` ins '' instruction . OP must be a register operand and the following conditions must hold : 0 < = POSITION < GET_MODE_BITSIZE ( GET_MODE ( op ) ) 0 < SIZE < = GET_MODE_BITSIZE ( GET_MODE ( op ) ) 0 < POSITION + SIZE < = GET_MODE_BITSIZE ( GET_MODE ( op ) ) Also reject lengths equal to a word as they are better handled by the move patterns .


<s> bool mips_use_pic_fn_addr_reg_p ( const_rtx x ) { if ( ! TARGET_USE_PIC_FN_ADDR_REG ) return false ; if ( mips16_stub_function_p ( x ) ) return false ; if ( GET_CODE ( x ) == SYMBOL_REF ) { if ( TARGET_ABICALLS_PIC0 ) return false ; if ( TARGET_ABSOLUTE_ABICALLS && mips_symbol_binds_local_p ( x ) && ! SYMBOL_REF_EXTERNAL_P ( x ) ) return false ; } return true ; } </s>

Return true if calls to X might need $ 25 to be valid on entry .


<s> static enum mips_shadow_set mips_use_shadow_register_set ( tree type ) { tree attr = lookup_attribute ( "use_shadow_register_set" , TYPE_ATTRIBUTES ( type ) ) ; tree args ; if ( attr == NULL ) return SHADOW_SET_NO ; args = TREE_VALUE ( attr ) ; if ( args == NULL ) return SHADOW_SET_YES ; return SHADOW_SET_INTSTACK ; } </s>

Return the mips_shadow_set if the `` use_shadow_register_set '' attribute is set for a function .


<s> static bool mips_valid_base_register_p ( rtx x , machine_mode mode , bool strict_p ) { if ( ! strict_p && GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; return ( REG_P ( x ) && mips_regno_mode_ok_for_base_p ( REGNO ( x ) , mode , strict_p ) ) ; } </s>

Return true if X is a valid base register for the given mode . Allow only hard registers if STRICT .


<s> static bool mips_valid_lo_sum_p ( enum mips_symbol_type symbol_type , machine_mode mode ) { if ( mips_symbol_insns ( symbol_type , mode ) == 0 ) return false ; if ( mips_lo_relocs [ symbol_type ] == NULL ) return false ; if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD && GET_MODE_BITSIZE ( mode ) > GET_MODE_ALIGNMENT ( mode ) ) return false ; if ( MSA_SUPPORTED_MODE_P ( mode ) ) return false ; return true ; } </s>

Return true if a LO_SUM can address a value of mode MODE when the LO_SUM symbol has type SYMBOL_TYPE .


<s> static bool mips_valid_offset_p ( rtx x , machine_mode mode ) { if ( ! const_arith_operand ( x , Pmode ) ) return false ; if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD && ! SMALL_OPERAND ( INTVAL ( x ) + GET_MODE_SIZE ( mode ) - UNITS_PER_WORD ) ) return false ; if ( MSA_SUPPORTED_MODE_P ( mode ) && ! mips_signed_immediate_p ( INTVAL ( x ) , 10 , mips_ldst_scaled_shift ( mode ) ) ) return false ; return true ; } </s>

Return true if , for every base register BASE_REG , ( plus BASE_REG X ) can address a value of mode MODE .


<s> static bool mips_valid_pointer_mode ( scalar_int_mode mode ) { return mode == SImode || ( TARGET_64BIT && mode == DImode ) ; } </s>


<s> static void mips_va_start ( tree valist , rtx nextarg ) { if ( EABI_FLOAT_VARARGS_P ) { const CUMULATIVE_ARGS * cum ; tree f_ovfl , f_gtop , f_ftop , f_goff , f_foff ; tree ovfl , gtop , ftop , goff , foff ; tree t ; int gpr_save_area_size ; int fpr_save_area_size ; int fpr_offset ; cum = & crtl -> args . info ; gpr_save_area_size = ( MAX_ARGS_IN_REGISTERS - cum -> num_gprs ) * UNITS_PER_WORD ; fpr_save_area_size = ( MAX_ARGS_IN_REGISTERS - cum -> num_fprs ) * UNITS_PER_FPREG ; f_ovfl = TYPE_FIELDS ( va_list_type_node ) ; f_gtop = DECL_CHAIN ( f_ovfl ) ; f_ftop = DECL_CHAIN ( f_gtop ) ; f_goff = DECL_CHAIN ( f_ftop ) ; f_foff = DECL_CHAIN ( f_goff ) ; ovfl = build3 ( COMPONENT_REF , TREE_TYPE ( f_ovfl ) , valist , f_ovfl , NULL_TREE ) ; gtop = build3 ( COMPONENT_REF , TREE_TYPE ( f_gtop ) , valist , f_gtop , NULL_TREE ) ; ftop = build3 ( COMPONENT_REF , TREE_TYPE ( f_ftop ) , valist , f_ftop , NULL_TREE ) ; goff = build3 ( COMPONENT_REF , TREE_TYPE ( f_goff ) , valist , f_goff , NULL_TREE ) ; foff = build3 ( COMPONENT_REF , TREE_TYPE ( f_foff ) , valist , f_foff , NULL_TREE ) ; t = make_tree ( TREE_TYPE ( ovfl ) , virtual_incoming_args_rtx ) ; if ( cum -> stack_words > 0 ) t = fold_build_pointer_plus_hwi ( t , cum -> stack_words * UNITS_PER_WORD ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( ovfl ) , ovfl , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( gtop ) , virtual_incoming_args_rtx ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( gtop ) , gtop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( ftop ) , virtual_incoming_args_rtx ) ; fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1 ; fpr_offset &= - UNITS_PER_FPVALUE ; if ( fpr_offset ) t = fold_build_pointer_plus_hwi ( t , - fpr_offset ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( ftop ) , ftop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( goff ) , goff , build_int_cst ( TREE_TYPE ( goff ) , gpr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( foff ) , foff , build_int_cst ( TREE_TYPE ( foff ) , fpr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; } else { nextarg = plus_constant ( Pmode , nextarg , - cfun -> machine -> varargs_size ) ; std_expand_builtin_va_start ( valist , nextarg ) ; } } </s>


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


<s> static bool mips_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case E_V2SFmode : return TARGET_PAIRED_SINGLE_FLOAT ; case E_V2HImode : case E_V4QImode : case E_V2HQmode : case E_V2UHQmode : case E_V2HAmode : case E_V2UHAmode : case E_V4QQmode : case E_V4UQQmode : return TARGET_DSP ; case E_V2SImode : case E_V4HImode : case E_V8QImode : return TARGET_LOONGSON_MMI ; default : return MSA_SUPPORTED_MODE_P ( mode ) ; } } </s>

Target hook for vector_mode_supported_p .


<s> static int mips_zero_extend_cost ( machine_mode mode , rtx op ) { if ( MEM_P ( op ) ) return 0 ; if ( TARGET_64BIT && mode == DImode && GET_MODE ( op ) == SImode ) return COSTS_N_INSNS ( TARGET_MIPS16 ? 4 : 2 ) ; if ( GENERATE_MIPS16E ) return COSTS_N_INSNS ( 1 ) ; if ( TARGET_MIPS16 ) return COSTS_N_INSNS ( GET_MODE ( op ) == QImode ? 2 : 3 ) ; return COSTS_N_INSNS ( 1 ) ; } </s>

Return the cost of zero-extending OP to mode MODE , not including the cost of OP itself .


Return a register that is zero iff CMP0 and CMP1 are equal . The register will have the same mode as CMP0 .


<s>
static
void
r10k_insert_cache_barriers
(
void
)
{
int
*
rev_post_order
;
unsigned
int
i
,
n
;
basic_block
bb
;
sbitmap
protected_bbs
;
rtx_insn
*
insn
,
*
end
;
rtx
unprotected_region
;
if
(
TARGET_MIPS16
)
{
sorry
(
"%qs does not support MIPS16 code"
,
"-mr10k-cache-barrier"
)
;
return
;
}
calculate_dominance_info
(
CDI_DOMINATORS
)
;
protected_bbs
=
sbitmap_alloc
(
last_basic_block_for_fn
(
cfun
)
)
;
bitmap_clear
(
protected_bbs
)
;
rev_post_order
=
XNEWVEC
(
int
,
last_basic_block_for_fn
(
cfun
)
)
;
n
=
pre_and_rev_post_order_compute
(
,
rev_post_order
,
false
)
;
for
(
i
=
0
;
i
<
n
;
i
++
)
{
bb
=
BASIC_BLOCK_FOR_FN
(
cfun
,
rev_post_order
[
i
]
)
;
if
(
r10k_protected_bb_p
(
bb
,
protected_bbs
)
)
unprotected_region
=
NULL_RTX
;
else
unprotected_region
=
pc_rtx
;
end
=
NEXT_INSN
(
BB_END
(
bb
)
)
;
for
(
insn
=
BB_HEAD
(
bb
)
;
insn
!=
end
;
insn
=
NEXT_INSN
(
insn
)
)
{
if
(
unprotected_region
&&
USEFUL_INSN_P
(
insn
)
)
{
if
(
recog_memoized
(
insn
)
==
CODE_FOR_mips_cache
)
unprotected_region
=
NULL_RTX
;
else
{
if
(
unprotected_region
==
pc_rtx
)
unprotected_region
=
insn
;
if
(
r10k_needs_protection_p
(
insn
)
)
{
emit_insn_before
(
gen_r10k_cache_barrier
(
)
,
as_a
<
rtx_insn
*
>
(
unprotected_region
)
)
;
unprotected_region
=
NULL_RTX
;
}
}
}
if
(
CALL_P
(
insn
)
)
unprotected_region
=
pc_rtx
;
}
if
(
unprotected_region
==
NULL_RTX
)
bitmap_set_bit
(
protected_bbs
,
bb
->
index
)
;
}
XDELETEVEC
(
rev_post_order
)
;
sbitmap_free
(
protected_bbs
)
;
free_dominance_info
(
CDI_DOMINATORS
)
;
}
</s>

Implement -mr10k-cache-barrier= for the current function .


<s> static bool r10k_needs_protection_p ( rtx_insn * insn ) { if ( CALL_P ( insn ) ) return r10k_needs_protection_p_call ( PATTERN ( insn ) ) ; if ( mips_r10k_cache_barrier == R10K_CACHE_BARRIER_STORE ) { note_stores ( insn , r10k_needs_protection_p_store , & insn ) ; return insn == NULL_RTX ; } return r10k_needs_protection_p_1 ( PATTERN ( insn ) , insn ) ; } </s>

Return true if instruction INSN needs to be protected by an R10K cache barrier .


<s> static bool r10k_needs_protection_p_1 ( rtx x , rtx_insn * insn ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , x , NONCONST ) { rtx mem = * iter ; if ( MEM_P ( mem ) ) { if ( ( MEM_EXPR ( mem ) && MEM_OFFSET_KNOWN_P ( mem ) && r10k_safe_mem_expr_p ( MEM_EXPR ( mem ) , MEM_OFFSET ( mem ) ) ) || r10k_safe_address_p ( XEXP ( mem , 0 ) , insn ) ) iter . skip_subrtxes ( ) ; else return true ; } } return false ; } </s>

Return true if X contains a MEM that is not safe from R10K speculation . INSN is the instruction that contains X .


<s> static bool r10k_needs_protection_p_call ( const_rtx x ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , NONCONST ) { const_rtx mem = * iter ; if ( MEM_P ( mem ) ) { const_rtx addr = XEXP ( mem , 0 ) ; if ( GET_CODE ( addr ) == SYMBOL_REF && SYMBOL_REF_DECL ( addr ) ) iter . skip_subrtxes ( ) ; else return true ; } } return false ; } </s>

X is the pattern of a call instruction . Return true if the call is not to a declared function .


<s> static void r10k_needs_protection_p_store ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data ) { rtx_insn * * insn_ptr ; insn_ptr = ( rtx_insn * * ) data ; if ( * insn_ptr && r10k_needs_protection_p_1 ( x , * insn_ptr ) ) * insn_ptr = NULL ; } </s>

A note_stores callback for which DATA points to an instruction pointer . If * DATA is nonnull , make it null if it X contains a MEM that is not safe from R10K speculation .


<s> static bool r10k_protected_bb_p ( basic_block bb , sbitmap protected_bbs ) { edge_iterator ei ; edge e ; FOR_EACH_EDGE ( e , ei , bb -> preds ) if ( ! single_succ_p ( e -> src ) || ! bitmap_bit_p ( protected_bbs , e -> src -> index ) || ( e -> flags & EDGE_COMPLEX ) != 0 ) return false ; return true ; } </s>

Return true if BB is only reached by blocks in PROTECTED_BBS and if every edge is unconditional .


<s> static bool r10k_safe_address_p ( rtx x , rtx_insn * insn ) { rtx base , offset ; HOST_WIDE_INT offset_val ; x = r10k_simplify_address ( x , insn ) ; mips_split_plus ( x , & base , & offset_val ) ; if ( base == virtual_incoming_args_rtx && offset_val >= - cfun -> machine -> frame . total_size && offset_val < cfun -> machine -> frame . args_size ) return true ; if ( CONST_INT_P ( x ) ) return r10k_uncached_address_p ( INTVAL ( x ) ) ; split_const ( x , & base , & offset ) ; return offset_within_block_p ( base , INTVAL ( offset ) ) ; } </s>

Return true if we can prove that an access to address X in instruction INSN would be safe from R10K speculation . This X is a general expression ; it might not be a legitimate address .


<s> static bool r10k_safe_mem_expr_p ( tree expr , unsigned HOST_WIDE_INT offset ) { poly_int64 bitoffset , bitsize ; tree inner , var_offset ; machine_mode mode ; int unsigned_p , reverse_p , volatile_p ; inner = get_inner_reference ( expr , & bitsize , & bitoffset , & var_offset , & mode , & unsigned_p , & reverse_p , & volatile_p ) ; if ( ! DECL_P ( inner ) || ! DECL_SIZE_UNIT ( inner ) || var_offset ) return false ; offset += bitoffset / BITS_PER_UNIT ; return offset < tree_to_uhwi ( DECL_SIZE_UNIT ( inner ) ) ; } </s>

Return true if a MEM with MEM_EXPR EXPR and MEM_OFFSET OFFSET is an in-range access to an automatic variable , or to an object with a link-time-constant address .


<s> static bool r10k_simplified_address_p ( rtx x ) { if ( GET_CODE ( x ) == PLUS && CONST_INT_P ( XEXP ( x , 1 ) ) ) x = XEXP ( x , 0 ) ; return x == virtual_incoming_args_rtx || CONSTANT_P ( x ) ; } </s>

Return true if it is worth r10k_simplify_address 's while replacing an address with X . We are looking for constants , and for addresses at a known offset from the incoming stack pointer .


<s> static rtx r10k_simplify_address ( rtx x , rtx_insn * insn ) { rtx newx , op0 , op1 , set , note ; rtx_insn * def_insn ; df_ref use , def ; struct df_link * defs ; newx = NULL_RTX ; if ( UNARY_P ( x ) ) { op0 = r10k_simplify_address ( XEXP ( x , 0 ) , insn ) ; if ( op0 != XEXP ( x , 0 ) ) newx = simplify_gen_unary ( GET_CODE ( x ) , GET_MODE ( x ) , op0 , GET_MODE ( XEXP ( x , 0 ) ) ) ; } else if ( BINARY_P ( x ) ) { op0 = r10k_simplify_address ( XEXP ( x , 0 ) , insn ) ; op1 = r10k_simplify_address ( XEXP ( x , 1 ) , insn ) ; if ( op0 != XEXP ( x , 0 ) || op1 != XEXP ( x , 1 ) ) newx = simplify_gen_binary ( GET_CODE ( x ) , GET_MODE ( x ) , op0 , op1 ) ; } else if ( GET_CODE ( x ) == LO_SUM ) { op0 = r10k_simplify_address ( XEXP ( x , 0 ) , insn ) ; if ( GET_CODE ( op0 ) == HIGH ) newx = XEXP ( x , 1 ) ; } else if ( REG_P ( x ) ) { use = df_find_use ( insn , regno_reg_rtx [ REGNO ( x ) ] ) ; gcc_assert ( use ) ; defs = DF_REF_CHAIN ( use ) ; if ( defs && defs -> next == NULL ) { def = defs -> ref ; if ( DF_REF_IS_ARTIFICIAL ( def ) ) { if ( x == stack_pointer_rtx && DF_REF_BB ( def ) == ENTRY_BLOCK_PTR_FOR_FN ( cfun ) ) newx = virtual_incoming_args_rtx ; } else if ( dominated_by_p ( CDI_DOMINATORS , DF_REF_BB ( use ) , DF_REF_BB ( def ) ) ) { def_insn = DF_REF_INSN ( def ) ; if ( NONJUMP_INSN_P ( def_insn ) ) { set = single_set ( def_insn ) ; if ( set && rtx_equal_p ( SET_DEST ( set ) , x ) ) { note = find_reg_equal_equiv_note ( def_insn ) ; if ( note ) newx = XEXP ( note , 0 ) ; else newx = SET_SRC ( set ) ; newx = r10k_simplify_address ( newx , def_insn ) ; } } } } } if ( newx && r10k_simplified_address_p ( newx ) ) return newx ; return x ; } </s>

X is an expression that appears in INSN . Try to use the UD chains to simplify it , returning the simplified form on success and the original form otherwise . Replace the incoming value of $ sp with virtual_incoming_args_rtx ( which should never occur in X otherwise ) .


<s> static bool r10k_uncached_address_p ( unsigned HOST_WIDE_INT address ) { unsigned HOST_WIDE_INT upper ; if ( address + 0x60000000 < 0x20000000 ) return true ; if ( Pmode == DImode ) { upper = ( address >> 40 ) & 0xf9ffff ; if ( upper == 0x900000 || upper == 0xb80000 ) return true ; } return false ; } </s>

Return true if ADDRESS is known to be an uncached address on R10K systems .


<s> bool umips_12bit_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 ) && UMIPS_12BIT_OFFSET_P ( INTVAL ( addr . offset ) ) ) ; } </s>

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


<s> static bool umips_build_save_restore ( mips_save_restore_fn fn , unsigned * mask , HOST_WIDE_INT * offset ) { int nregs ; unsigned int i , j ; rtx pattern , set , reg , mem ; HOST_WIDE_INT this_offset ; rtx this_base ; for ( i = 0 ; i < ARRAY_SIZE ( umips_swm_mask ) ; i ++ ) if ( ( * mask & 0xffff0000 ) == umips_swm_mask [ i ] ) break ; if ( i == ARRAY_SIZE ( umips_swm_mask ) ) return false ; nregs = ( umips_swm_encoding [ i ] & 0xf ) + ( umips_swm_encoding [ i ] >> 4 ) ; this_offset = * offset - UNITS_PER_WORD * ( nregs - 1 ) ; if ( ! UMIPS_12BIT_OFFSET_P ( this_offset ) ) return false ; pattern = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( nregs ) ) ; this_base = stack_pointer_rtx ; for ( j = 0 ; j < ( umips_swm_encoding [ i ] & 0xf ) ; j ++ ) { HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , this_base , offset ) ) ; unsigned int regno = ( j != 8 ) ? 16 + j : 30 ; * mask &= ~ ( 1 << regno ) ; reg = gen_rtx_REG ( SImode , regno ) ; if ( fn == mips_save_reg ) set = mips_frame_set ( mem , reg ) ; else { set = gen_rtx_SET ( reg , mem ) ; mips_add_cfa_restore ( reg ) ; } XVECEXP ( pattern , 0 , j ) = set ; } if ( umips_swm_encoding [ i ] >> 4 ) { HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD ; * mask &= ~ ( 1 << 31 ) ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , this_base , offset ) ) ; reg = gen_rtx_REG ( SImode , 31 ) ; if ( fn == mips_save_reg ) set = mips_frame_set ( mem , reg ) ; else { set = gen_rtx_SET ( reg , mem ) ; mips_add_cfa_restore ( reg ) ; } XVECEXP ( pattern , 0 , j ) = set ; } pattern = emit_insn ( pattern ) ; if ( fn == mips_save_reg ) RTX_FRAME_RELATED_P ( pattern ) = 1 ; * offset -= UNITS_PER_WORD * nregs ; return true ; } </s>

Try to use a microMIPS LWM or SWM instruction to save or restore as many GPRs in * MASK as possible . * OFFSET is the offset from the stack pointer of the topmost save slot . Remove from * MASK all registers that were handled using LWM and SWM . Update * OFFSET so that it points to the first unused save slot .


<s> bool umips_load_store_pair_p ( bool load_p , rtx * operands ) { rtx reg1 , reg2 , mem1 , mem2 ; if ( load_p ) { reg1 = operands [ 0 ] ; reg2 = operands [ 2 ] ; mem1 = operands [ 1 ] ; mem2 = operands [ 3 ] ; } else { reg1 = operands [ 1 ] ; reg2 = operands [ 3 ] ; mem1 = operands [ 0 ] ; mem2 = operands [ 2 ] ; } if ( REGNO ( reg2 ) == REGNO ( reg1 ) + 1 ) return umips_load_store_pair_p_1 ( load_p , false , reg1 , mem1 , mem2 ) ; if ( REGNO ( reg1 ) == REGNO ( reg2 ) + 1 ) return umips_load_store_pair_p_1 ( load_p , true , reg2 , mem2 , mem1 ) ; return false ; } </s>

OPERANDS describes the operands to a pair of SETs , in the order dest1 , src1 , dest2 , src2 . Return true if the operands can be used in an LWP or SWP instruction ; LOAD_P says which .


<s> static bool umips_load_store_pair_p_1 ( bool load_p , bool swap_p , rtx first_reg , rtx mem1 , rtx mem2 ) { rtx base1 , base2 ; HOST_WIDE_INT offset1 , offset2 ; if ( ! MEM_P ( mem1 ) || ! MEM_P ( mem2 ) ) return false ; mips_split_plus ( XEXP ( mem1 , 0 ) , & base1 , & offset1 ) ; mips_split_plus ( XEXP ( mem2 , 0 ) , & base2 , & offset2 ) ; if ( ! REG_P ( base1 ) || ! rtx_equal_p ( base1 , base2 ) ) return false ; if ( load_p && REGNO ( first_reg ) == REGNO ( base1 ) ) return false ; if ( load_p && swap_p && REGNO ( first_reg ) + 1 == REGNO ( base1 ) ) return false ; if ( offset2 != offset1 + 4 ) return false ; if ( ! UMIPS_12BIT_OFFSET_P ( offset1 ) ) return false ; return true ; } </s>

Return true if MEM1 and MEM2 use the same base register , and the offset of MEM2 equals the offset of MEM1 plus 4 . FIRST_REG is the register into ( from ) which the contents of MEM1 will be loaded ( stored ) , depending on the value of LOAD_P . SWAP_P is true when the 1st and 2nd instructions are swapped .


<s> bool umips_movep_target_p ( rtx reg1 , rtx reg2 ) { int regno1 , regno2 , pair ; unsigned int i ; static const int match [ 8 ] = { 0x00000060 , 0x000000a0 , 0x000000c0 , 0x00200010 , 0x00400010 , 0x00000030 , 0x00000050 , 0x00000090 } ; if ( ! REG_P ( reg1 ) || ! REG_P ( reg2 ) ) return false ; regno1 = REGNO ( reg1 ) ; regno2 = REGNO ( reg2 ) ; if ( ! GP_REG_P ( regno1 ) || ! GP_REG_P ( regno2 ) ) return false ; pair = ( 1 << regno1 ) | ( 1 << regno2 ) ; for ( i = 0 ; i < ARRAY_SIZE ( match ) ; i ++ ) if ( pair == match [ i ] ) return true ; return false ; } </s>

Return true if REG1 and REG2 match the criteria for a movep insn .


<s> void umips_output_load_store_pair ( bool load_p , rtx * operands ) { rtx reg1 , reg2 , mem1 , mem2 ; if ( load_p ) { reg1 = operands [ 0 ] ; reg2 = operands [ 2 ] ; mem1 = operands [ 1 ] ; mem2 = operands [ 3 ] ; } else { reg1 = operands [ 1 ] ; reg2 = operands [ 3 ] ; mem1 = operands [ 0 ] ; mem2 = operands [ 2 ] ; } if ( REGNO ( reg2 ) == REGNO ( reg1 ) + 1 ) { umips_output_load_store_pair_1 ( load_p , reg1 , mem1 ) ; return ; } gcc_assert ( REGNO ( reg1 ) == REGNO ( reg2 ) + 1 ) ; umips_output_load_store_pair_1 ( load_p , reg2 , mem2 ) ; } </s>

Output the assembly instruction for a microMIPS LWP or SWP instruction . LOAD_P and OPERANDS are as for umips_load_store_pair_p .


<s> static void umips_output_load_store_pair_1 ( bool load_p , rtx reg , rtx mem ) { rtx ops [ ] = { reg , mem } ; if ( load_p ) output_asm_insn ( "lwp\t%0,%1" , ops ) ; else output_asm_insn ( "swp\t%0,%1" , ops ) ; } </s>

Return the assembly instruction for a microMIPS LWP or SWP in which the first register is REG and the first memory slot is MEM . LOAD_P is true for LWP .


<s> const char * umips_output_save_restore ( bool save_p , rtx pattern ) { static char buffer [ 300 ] ; char * s ; int n ; HOST_WIDE_INT offset ; rtx base , mem , set , last_set , last_reg ; gcc_assert ( umips_save_restore_pattern_p ( save_p , pattern ) ) ; s = strcpy ( buffer , save_p ? "swm\t" : "lwm\t" ) ; s += strlen ( s ) ; n = XVECLEN ( pattern , 0 ) ; set = XVECEXP ( pattern , 0 , 0 ) ; mem = save_p ? SET_DEST ( set ) : SET_SRC ( set ) ; mips_split_plus ( XEXP ( mem , 0 ) , & base , & offset ) ; last_set = XVECEXP ( pattern , 0 , n - 1 ) ; last_reg = save_p ? SET_SRC ( last_set ) : SET_DEST ( last_set ) ; if ( REGNO ( last_reg ) == 31 ) n -- ; gcc_assert ( n <= 9 ) ; if ( n == 0 ) ; else if ( n == 1 ) s += sprintf ( s , "%s," , reg_names [ 16 ] ) ; else if ( n < 9 ) s += sprintf ( s , "%s-%s," , reg_names [ 16 ] , reg_names [ 15 + n ] ) ; else if ( n == 9 ) s += sprintf ( s , "%s-%s,%s," , reg_names [ 16 ] , reg_names [ 23 ] , reg_names [ 30 ] ) ; if ( REGNO ( last_reg ) == 31 ) s += sprintf ( s , "%s," , reg_names [ 31 ] ) ; s += sprintf ( s , "%d(%s)" , ( int ) offset , reg_names [ REGNO ( base ) ] ) ; return buffer ; } </s>

Return the assembly instruction for microMIPS LWM or SWM . SAVE_P and PATTERN are as for umips_save_restore_pattern_p .


<s> bool umips_save_restore_pattern_p ( bool save_p , rtx pattern ) { int n ; unsigned int i ; HOST_WIDE_INT first_offset = 0 ; rtx first_base = 0 ; unsigned int regmask = 0 ; for ( n = 0 ; n < XVECLEN ( pattern , 0 ) ; n ++ ) { rtx set , reg , mem , this_base ; HOST_WIDE_INT this_offset ; set = XVECEXP ( pattern , 0 , n ) ; if ( GET_CODE ( set ) != SET ) return false ; mem = save_p ? SET_DEST ( set ) : SET_SRC ( set ) ; if ( ! MEM_P ( mem ) || MEM_VOLATILE_P ( mem ) ) return false ; mips_split_plus ( XEXP ( mem , 0 ) , & this_base , & this_offset ) ; if ( ! REG_P ( this_base ) ) return false ; if ( n == 0 ) { if ( ! UMIPS_12BIT_OFFSET_P ( this_offset ) ) return false ; first_base = this_base ; first_offset = this_offset ; } else { if ( REGNO ( this_base ) != REGNO ( first_base ) || this_offset != first_offset + UNITS_PER_WORD * n ) return false ; } reg = save_p ? SET_SRC ( set ) : SET_DEST ( set ) ; if ( ! REG_P ( reg ) ) return false ; regmask |= 1 << REGNO ( reg ) ; } for ( i = 0 ; i < ARRAY_SIZE ( umips_swm_mask ) ; i ++ ) if ( regmask == umips_swm_mask [ i ] ) return true ; return false ; } </s>

Return true if PATTERN matches the kind of instruction generated by umips_build_save_restore . SAVE_P is true for store .


<s> static void vr4130_align_insns ( void ) { struct mips_sim state ; rtx_insn * insn , * subinsn , * last , * last2 , * next ; bool aligned_p ; dfa_start ( ) ; last = 0 ; last2 = 0 ; aligned_p = true ; mips_sim_init ( & state , alloca ( state_size ( ) ) ) ; for ( insn = get_insns ( ) ; insn != 0 ; insn = next ) { unsigned int length ; next = NEXT_INSN ( insn ) ; vr4130_avoid_branch_rt_conflict ( insn ) ; length = get_attr_length ( insn ) ; if ( length > 0 && USEFUL_INSN_P ( insn ) ) FOR_EACH_SUBINSN ( subinsn , insn ) { mips_sim_wait_insn ( & state , subinsn ) ; if ( state . insns_left != state . issue_rate && ! CALL_P ( subinsn ) ) { if ( subinsn == SEQ_BEGIN ( insn ) && aligned_p ) { gcc_assert ( last2 ) ; emit_insn_after ( gen_nop ( ) , last2 ) ; aligned_p = false ; } else if ( subinsn != SEQ_BEGIN ( insn ) && ! aligned_p ) { gcc_assert ( last ) ; emit_insn_after ( gen_nop ( ) , last ) ; aligned_p = true ; } } mips_sim_issue_insn ( & state , subinsn ) ; } mips_sim_finish_insn ( & state , insn ) ; length = get_attr_length ( insn ) ; if ( length > 0 ) { if ( NONJUMP_INSN_P ( SEQ_BEGIN ( insn ) ) && ( recog_memoized ( insn ) < 0 || length >= 8 ) ) { next = emit_insn_after ( gen_align ( GEN_INT ( 3 ) ) , insn ) ; next = NEXT_INSN ( next ) ; mips_sim_next_cycle ( & state ) ; aligned_p = true ; } else if ( length & 4 ) aligned_p = ! aligned_p ; last2 = last ; last = insn ; } if ( LABEL_P ( insn ) && label_to_alignment ( insn ) . levels [ 0 ] . log >= 3 ) aligned_p = true ; } dfa_finish ( ) ; } </s>

Implement -mvr4130-align . Go through each basic block and simulate the processor pipeline . If we find that a pair of instructions could execute in parallel , and the first of those instruction is not 8-byte aligned , insert a nop to make it aligned .


<s> static void vr4130_avoid_branch_rt_conflict ( rtx_insn * insn ) { rtx_insn * first , * second ; first = SEQ_BEGIN ( insn ) ; second = SEQ_END ( insn ) ; if ( JUMP_P ( first ) && NONJUMP_INSN_P ( second ) && GET_CODE ( PATTERN ( first ) ) == SET && GET_CODE ( SET_DEST ( PATTERN ( first ) ) ) == PC && GET_CODE ( SET_SRC ( PATTERN ( first ) ) ) == IF_THEN_ELSE ) { rtx cond = XEXP ( SET_SRC ( PATTERN ( first ) ) , 0 ) ; if ( ( GET_CODE ( cond ) == EQ || GET_CODE ( cond ) == NE ) && REG_P ( XEXP ( cond , 0 ) ) && REG_P ( XEXP ( cond , 1 ) ) && reg_referenced_p ( XEXP ( cond , 1 ) , PATTERN ( second ) ) && ! reg_referenced_p ( XEXP ( cond , 0 ) , PATTERN ( second ) ) ) { rtx tmp = XEXP ( cond , 0 ) ; XEXP ( cond , 0 ) = XEXP ( cond , 1 ) ; XEXP ( cond , 1 ) = tmp ; } } } </s>

The VR4130 pipeline issues aligned pairs of instructions together , but it stalls the second instruction if it depends on the first . In order to cut down the amount of logic required , this dependence check is not based on a full instruction decode . Instead , any non-SPECIAL instruction is assumed to modify the register specified by bits 20-16 ( which is usually the `` rt '' field ) . In beq , beql , bne and bnel instructions , the rt field is actually an input , so we can end up with a false dependence between the branch and its delay slot . If this situation occurs in instruction INSN , try to avoid it by swapping rs and rt .


<s> static void vr4130_reorder ( rtx_insn * * ready , int nready ) { if ( vr4130_swap_insns_p ( ready [ nready - 1 ] , ready [ nready - 2 ] ) ) mips_promote_ready ( ready , nready - 2 , nready - 1 ) ; } </s>

A TUNE_MIPS4130 helper function . ( READY , NREADY ) describes a ready queue with at least two instructions . Swap the first two if vr4130_swap_insns_p says that it could be worthwhile .


A TUNE_MIPS4130 helper function . Given that INSN1 is at the head of the ready queue and that INSN2 is the instruction after it , return true if it is worth promoting INSN2 ahead of INSN1 . Look for cases in which INSN1 and INSN2 can probably issue in parallel , but for which ( INSN2 , INSN1 ) should be less sensitive to instruction alignment than ( INSN1 , INSN2 ) . See 4130.md for more details .


<s> static bool vr4130_true_reg_dependence_p ( rtx insn ) { note_stores ( vr4130_last_insn , vr4130_true_reg_dependence_p_1 , & insn ) ; return insn == 0 ; } </s>

Return true if there is true register dependence between vr4130_last_insn and INSN .


<s> static void vr4130_true_reg_dependence_p_1 ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data ) { rtx * insn_ptr ; insn_ptr = ( rtx * ) data ; if ( REG_P ( x ) && * insn_ptr != 0 && reg_referenced_p ( x , PATTERN ( * insn_ptr ) ) ) * insn_ptr = 0 ; } </s>

A note_stores callback used by vr4130_true_reg_dependence_p . DATA points to an rtx that is initially an instruction . Nullify the rtx if the instruction uses the value of register X .