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

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


<s> static bool mips_load_call_address ( enum mips_call_type type , rtx dest , rtx addr ) { if ( TARGET_EXPLICIT_RELOCS && ! ( type == MIPS_CALL_SIBCALL && TARGET_CALL_SAVED_GP ) && mips_ok_for_lazy_binding_p ( addr ) ) { addr = mips_got_load ( dest , addr , SYMBOL_GOTOFF_CALL ) ; emit_insn ( gen_rtx_SET ( VOIDmode , dest , addr ) ) ; return true ; } else { mips_emit_move ( dest , addr ) ; return false ; } } </s>

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


<s> static bool mips_lx_address_p ( rtx addr , machine_mode mode ) { if ( GET_CODE ( addr ) != PLUS || ! REG_P ( XEXP ( addr , 0 ) ) || ! REG_P ( XEXP ( addr , 1 ) ) ) return false ; if ( ISA_HAS_LBX && mode == QImode ) return true ; if ( ISA_HAS_LHX && mode == HImode ) return true ; if ( ISA_HAS_LWX && mode == SImode ) return true ; if ( ISA_HAS_LDX && mode == DImode ) return true ; return false ; } </s>

Return true if ADDR matches the pattern for the L { B , H , W , D } { , U } X load indexed address instruction . Note that such addresses are not considered legitimate in the TARGET_LEGITIMATE_ADDRESS_P sense , because their use is so restricted .


<s> static unsigned int mips_machine_reorg2 ( void ) { mips_reorg_process_insns ( ) ; if ( ! TARGET_MIPS16 && TARGET_EXPLICIT_RELOCS && TUNE_MIPS4130 && TARGET_VR4130_ALIGN ) vr4130_align_insns ( ) ; if ( mips_expand_ghost_gp_insns ( ) ) mips_reorg_process_insns ( ) ; mips16_split_long_branches ( ) ; return 0 ; } </s>

We use a machine specific pass to do a second machine dependent reorg pass after delay branch scheduling .


<s> bool mips_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { return ( mode1 == mode2 || ( ! mips_mode_ok_for_mov_fmt_p ( mode1 ) && ! mips_mode_ok_for_mov_fmt_p ( mode2 ) ) ) ; } </s>


<s> static bool mips_mode_ok_for_mov_fmt_p ( machine_mode mode ) { switch ( mode ) { case CCFmode : case SFmode : return TARGET_HARD_FLOAT ; case DFmode : return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT ; case V2SFmode : return TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT ; default : return false ; } } </s>

Return true if moves in mode MODE can use the FPU 's mov.fmt instruction .


<s> static int mips_mode_rep_extended ( machine_mode mode , machine_mode mode_rep ) { if ( TARGET_64BIT && mode == SImode && mode_rep == DImode ) return SIGN_EXTEND ; return UNKNOWN ; } </s>


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


<s> static int mips_multipass_dfa_lookahead ( void ) { if ( TUNE_SB1 ) return 4 ; if ( TUNE_LOONGSON_2EF || TUNE_LOONGSON_3A ) return 4 ; if ( TUNE_OCTEON ) return 2 ; if ( TUNE_P5600 ) return 4 ; return 0 ; } </s>


<s> static struct mips_multi_member * mips_multi_add ( void ) { mips_multi_member empty ; return mips_multi_members . safe_push ( empty ) ; } </s>

Add a new , uninitialized member to the current multi-insn sequence .


<s> static bool mips_near_type_p ( const_tree type ) { return lookup_attribute ( "near" , TYPE_ATTRIBUTES ( type ) ) != NULL ; } </s>

Predicates to test for presence of `` near '' and `` far '' / '' long_call '' attributes on the given TYPE .


<s> static void mips_output_args_xfer ( int fp_code , char direction ) { unsigned int gparg , fparg , f ; CUMULATIVE_ARGS cum ; gcc_assert ( TARGET_OLDABI ) ; mips_init_cumulative_args ( & cum , NULL ) ; for ( f = ( unsigned int ) fp_code ; f != 0 ; f >>= 2 ) { machine_mode mode ; struct mips_arg_info info ; if ( ( f & 3 ) == 1 ) mode = SFmode ; else if ( ( f & 3 ) == 2 ) mode = DFmode ; else gcc_unreachable ( ) ; mips_get_arg_info ( & info , & cum , mode , NULL , true ) ; gparg = mips_arg_regno ( & info , false ) ; fparg = mips_arg_regno ( & info , true ) ; if ( mode == SFmode ) mips_output_32bit_xfer ( direction , gparg , fparg ) ; else mips_output_64bit_xfer ( direction , gparg , fparg ) ; mips_function_arg_advance ( pack_cumulative_args ( & cum ) , mode , NULL , true ) ; } } </s>

Write out code to move floating-point arguments into or out of general registers . FP_CODE is the code describing which arguments are present ( see the comment above the definition of CUMULATIVE_ARGS in mips.h ) . DIRECTION is as for mips_output_32bit_xfer .


<s> mips_output_ascii ( STREAM , STRING , LEN ) { \ const char * p = STRING ; \ int size = strlen ( p ) + 1 ; \ rdata_section ( ) ; \ assemble_string ( p , size ) ; \ } </s>

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


<s> const char * mips_output_conditional_branch ( rtx_insn * insn , rtx * operands , const char * branch_if_true , const char * branch_if_false ) { unsigned int length ; rtx taken ; gcc_assert ( LABEL_P ( operands [ 0 ] ) ) ; length = get_attr_length ( insn ) ; if ( length <= 8 ) { mips_branch_likely = ( final_sequence && INSN_ANNULLED_BRANCH_P ( insn ) ) ; return branch_if_true ; } mips_branch_likely = false ; rtx_code_label * not_taken = gen_label_rtx ( ) ; taken = operands [ 0 ] ; operands [ 0 ] = not_taken ; output_asm_insn ( branch_if_false , operands ) ; if ( final_sequence ) { if ( ! INSN_ANNULLED_BRANCH_P ( insn ) ) { final_scan_insn ( final_sequence -> insn ( 1 ) , asm_out_file , optimize , 1 , NULL ) ; final_sequence -> insn ( 1 ) -> set_deleted ( ) ; } else output_asm_insn ( "nop" , 0 ) ; fprintf ( asm_out_file , "\n" ) ; } if ( TARGET_ABSOLUTE_JUMPS ) output_asm_insn ( MIPS_ABSOLUTE_JUMP ( "j\t%0%/" ) , & taken ) ; else { mips_output_load_label ( taken ) ; output_asm_insn ( "jr\t%@%]%/" , 0 ) ; } if ( final_sequence ) { if ( INSN_ANNULLED_BRANCH_P ( insn ) ) { final_scan_insn ( final_sequence -> insn ( 1 ) , asm_out_file , optimize , 1 , NULL ) ; final_sequence -> insn ( 1 ) -> set_deleted ( ) ; } else output_asm_insn ( "nop" , 0 ) ; fprintf ( asm_out_file , "\n" ) ; } targetm . asm_out . internal_label ( asm_out_file , "L" , CODE_LABEL_NUMBER ( not_taken ) ) ; return "" ; } </s>

Output assembly instructions to peform a conditional branch . INSN is the branch instruction . OPERANDS [ 0 ] is the condition . OPERANDS [ 1 ] is the target of the branch . OPERANDS [ 2 ] is the target of the first operand to the condition . If TWO_OPERANDS_P is nonzero the comparison takes two operands ; OPERANDS [ 3 ] will be the second operand . If INVERTED_P is nonzero we are to branch if the condition does not hold . If FLOAT_P is nonzero this is a floating-point comparison . LENGTH is the length ( in bytes ) of the sequence we are to generate . That tells us whether to generate a simple conditional branch , or a reversed conditional branch around a ` jr ' instruction .


<s>
static
void
mips_output_function_prologue
(
FILE
*
file
,
HOST_WIDE_INT
size
ATTRIBUTE_UNUSED
)
{
const
char
*
fnname
;
if
(
TARGET_MIPS16
&&
TARGET_HARD_FLOAT_ABI
&&
crtl
->
args
.
info
.
fp_code
!=
0
)
mips16_build_function_stub
(
)
;
fnname
=
XSTR
(
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
,
0
)
;
mips_start_function_definition
(
fnname
,
TARGET_MIPS16
)
;
if
(
!
flag_inhibit_size_directive
)
{
const
struct
mips_frame_info
*
frame
;
frame
=
&
cfun
->
machine
->
frame
;
fprintf
(
file
,
"\t.frame\t%s,"
HOST_WIDE_INT_PRINT_DEC
",%s\t\t"
"# vars= "
HOST_WIDE_INT_PRINT_DEC
", regs= %d/%d"
", args= "
HOST_WIDE_INT_PRINT_DEC
", gp= "
HOST_WIDE_INT_PRINT_DEC
"\n"
,
reg_names
[
frame_pointer_needed
HARD_FRAME_POINTER_REGNUM
:
STACK_POINTER_REGNUM
]
,
(
frame_pointer_needed
frame
->
total_size
frame
->
hard_frame_pointer_offset
:
frame
->
total_size
)
,
reg_names
[
RETURN_ADDR_REGNUM
]
,
frame
->
var_size
,
frame
->
num_gp
,
frame
->
num_fp
,
frame
->
args_size
,
frame
->
cprestore_size
)
;
fprintf
(
file
,
"\t.mask\t0x%08x,"
HOST_WIDE_INT_PRINT_DEC
"\n"
,
frame
->
mask
,
frame
->
gp_save_offset
)
;
fprintf
(
file
,
"\t.fmask\t0x%08x,"
HOST_WIDE_INT_PRINT_DEC
"\n"
,
frame
->
fmask
,
frame
->
fp_save_offset
)
;
}
if
(
mips_must_initialize_gp_p
(
)
&&
mips_current_loadgp_style
(
)
==
LOADGP_OLDABI
)
{
if
(
TARGET_MIPS16
)
{
output_asm_insn
(
"li\t$2,%%hi(_gp_disp)"
,
0
)
;
output_asm_insn
(
"addiu\t$3,$pc,%%lo(_gp_disp)"
,
0
)
;
output_asm_insn
(
"sll\t$2,16"
,
0
)
;
output_asm_insn
(
"addu\t$2,$3"
,
0
)
;
}
else
{
mips_push_asm_switch
(
&
mips_noreorder
)
;
output_asm_insn
(
".cpload\t%^"
,
0
)
;
if
(
!
cfun
->
machine
->
all_noreorder_p
)
mips_pop_asm_switch
(
&
mips_noreorder
)
;
else
mips_push_asm_switch
(
&
mips_nomacro
)
;
}
}
else
if
(
cfun
->
machine
->
all_noreorder_p
)
{
mips_push_asm_switch
(
&
mips_noreorder
)
;
mips_push_asm_switch
(
&
mips_nomacro
)
;
}
mips_output_cplocal
(
)
;
}
</s>

Set up the stack and frame ( if desired ) for the function .


<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 ) { 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 ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; 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 ] ; switch ( GET_CODE ( operands [ 1 ] ) ) { case LEU : inverted_p = ! inverted_p ; case GTU : 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 : branch [ ! inverted_p ] = MIPS_BRANCH ( "beq" , "%.,%.,%0" ) ; branch [ inverted_p ] = MIPS_BRANCH ( "bne" , "%.,%.,%0" ) ; break ; default : 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 ] , end_lab [ 32 ] , tmp [ 64 ] ; rtx xops [ 2 ] ; ASM_GENERATE_INTERNAL_LABEL ( loop_lab , "LPSRL" , labelno ) ; ASM_GENERATE_INTERNAL_LABEL ( end_lab , "LPSRE" , labelno ++ ) ; ASM_OUTPUT_INTERNAL_LABEL ( asm_out_file , loop_lab ) ; xops [ 0 ] = reg1 ; xops [ 1 ] = reg2 ; strcpy ( tmp , "%(%<beq\t%0,%1," ) ; output_asm_insn ( strcat ( tmp , & end_lab [ 1 ] ) , xops ) ; 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 ) ; fprintf ( asm_out_file , "\tb\t" ) ; assemble_name_raw ( asm_out_file , loop_lab ) ; fputc ( '\n' , asm_out_file ) ; if ( TARGET_64BIT ) output_asm_insn ( "sd\t$0,0(%0)%)" , xops ) ; else output_asm_insn ( "sw\t$0,0(%0)%)" , xops ) ; ASM_OUTPUT_INTERNAL_LABEL ( asm_out_file , end_lab ) ; return "" ; } </s>

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


<s> bool mips_pad_arg_upward ( machine_mode mode , const_tree type ) { if ( ! BYTES_BIG_ENDIAN ) return true ; if ( type != 0 ? ( INTEGRAL_TYPE_P ( type ) || POINTER_TYPE_P ( type ) || FIXED_POINT_TYPE_P ( type ) ) : ( SCALAR_INT_MODE_P ( mode ) || ALL_SCALAR_FIXED_POINT_MODE_P ( mode ) ) ) return false ; if ( mips_abi == ABI_O64 ) if ( type != 0 ? FLOAT_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_FLOAT ) return false ; if ( mips_abi != ABI_EABI ) return true ; if ( mode != BLKmode ) return GET_MODE_BITSIZE ( mode ) >= PARM_BOUNDARY ; else return int_size_in_bytes ( type ) >= ( PARM_BOUNDARY / BITS_PER_UNIT ) ; } </s>

Return true if FUNCTION_ARG_PADDING ( MODE , TYPE ) should return upward rather than downward . In other words , return true if the first byte of the stack slot has useful data , false if the last byte does .


<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_pad_arg_upward ( mode , type ) ; } </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 cum ATTRIBUTE_UNUSED , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { if ( mips_abi == ABI_EABI ) { int size ; if ( mode == DImode || mode == DFmode || mode == DQmode || mode == UDQmode || mode == DAmode || mode == UDAmode ) return 0 ; size = type ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; return size == - 1 || size > UNITS_PER_WORD ; } else { return targetm . calls . must_pass_in_stack ( mode , type ) ; } } </s>

Return nonzero when an argument must be passed by reference .


<s> static machine_mode mips_preferred_simd_mode ( machine_mode mode ATTRIBUTE_UNUSED ) { if ( TARGET_PAIRED_SINGLE_FLOAT && mode == SFmode ) return V2SFmode ; return word_mode ; } </s>


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


<s> static void mips_print_operand_address ( FILE * file , 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 void mips_reorg_process_insns ( void ) { rtx_insn * insn , * last_insn , * subinsn , * next_insn ; rtx lo_reg , delayed_reg ; int hilo_delay ; split_all_insns_noflow ( ) ; cfun -> machine -> ignore_hazard_length_p = true ; shorten_branches ( get_insns ( ) ) ; cfun -> machine -> all_noreorder_p = true ; if ( TARGET_MIPS16 ) cfun -> machine -> all_noreorder_p = false ; if ( ! TARGET_EXPLICIT_RELOCS ) cfun -> machine -> all_noreorder_p = false ; if ( crtl -> profile ) cfun -> machine -> all_noreorder_p = false ; if ( TARGET_FIX_VR4120 || TARGET_FIX_RM7000 || TARGET_FIX_24K || TARGET_MIPS5900 ) cfun -> machine -> all_noreorder_p = false ; if ( TARGET_FIX_VR4130 && ! ISA_HAS_MACCHI ) cfun -> machine -> all_noreorder_p = false ; mips_offset_table htab ( 37 ) ; for ( insn = get_insns ( ) ; insn != 0 ; insn = NEXT_INSN ( insn ) ) FOR_EACH_SUBINSN ( subinsn , insn ) if ( USEFUL_INSN_P ( subinsn ) ) { rtx body = PATTERN ( insn ) ; int noperands = asm_noperands ( body ) ; if ( noperands >= 0 ) { rtx * ops = XALLOCAVEC ( rtx , noperands ) ; bool * used = XALLOCAVEC ( bool , noperands ) ; const char * string = decode_asm_operands ( body , ops , NULL , NULL , NULL , NULL ) ; get_referenced_operands ( string , used , noperands ) ; for ( int i = 0 ; i < noperands ; ++ i ) if ( used [ i ] ) mips_record_lo_sums ( ops [ i ] , & htab ) ; } else mips_record_lo_sums ( PATTERN ( subinsn ) , & htab ) ; } last_insn = 0 ; hilo_delay = 2 ; delayed_reg = 0 ; lo_reg = gen_rtx_REG ( SImode , LO_REGNUM ) ; for ( insn = get_insns ( ) ; insn != 0 ; insn = next_insn ) { next_insn = NEXT_INSN ( insn ) ; if ( USEFUL_INSN_P ( insn ) ) { if ( GET_CODE ( PATTERN ( insn ) ) == SEQUENCE ) { FOR_EACH_SUBINSN ( subinsn , insn ) if ( INSN_P ( subinsn ) ) { if ( mips_orphaned_high_part_p ( & htab , subinsn ) ) { PATTERN ( subinsn ) = gen_nop ( ) ; INSN_CODE ( subinsn ) = CODE_FOR_nop ; } mips_avoid_hazard ( last_insn , subinsn , & hilo_delay , & delayed_reg , lo_reg ) ; } last_insn = insn ; } else { if ( mips_orphaned_high_part_p ( & htab , insn ) ) delete_insn ( insn ) ; else if ( recog_memoized ( insn ) == CODE_FOR_r10k_cache_barrier && last_insn && JUMP_P ( SEQ_BEGIN ( last_insn ) ) && INSN_ANNULLED_BRANCH_P ( SEQ_BEGIN ( last_insn ) ) ) delete_insn ( insn ) ; else { mips_avoid_hazard ( last_insn , insn , & hilo_delay , & delayed_reg , lo_reg ) ; last_insn = insn ; } } } } } </s>

Go through the instruction stream and insert nops where necessary . Also delete any high-part relocations whose partnering low parts are now all dead . See if the whole function can then be put into .set noreorder and .set nomacro .


<s> static bool mips_return_in_memory ( const_tree type , const_tree fndecl ATTRIBUTE_UNUSED ) { return ( TARGET_OLDABI ? TYPE_MODE ( type ) == BLKmode : ! 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_scalar_mode_supported_p ( machine_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> bool mips_secondary_memory_needed ( enum reg_class class1 , enum reg_class class2 , machine_mode mode ) { 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 ( 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 void mips_setup_incoming_varargs ( cumulative_args_t cum , machine_mode mode , tree type , 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 ) , mode , type , true ) ; 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 = ( - 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>


"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 unsigned HOST_WIDE_INT mips_shift_truncation_mask ( machine_mode mode ) { if ( TARGET_LOONGSON_VECTORS && 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> 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 ( PATTERN ( 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> void mips_split_move ( rtx dest , rtx src , enum mips_split_type split_type ) { rtx low_dest ; gcc_checking_assert ( mips_split_move_p ( dest , src , split_type ) ) ; if ( FP_REG_RTX_P ( dest ) || FP_REG_RTX_P ( src ) ) { if ( ! TARGET_64BIT && GET_MODE ( dest ) == DImode ) emit_insn ( gen_move_doubleword_fprdi ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == DFmode ) emit_insn ( gen_move_doubleword_fprdf ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V2SFmode ) emit_insn ( gen_move_doubleword_fprv2sf ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V2SImode ) emit_insn ( gen_move_doubleword_fprv2si ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V4HImode ) emit_insn ( gen_move_doubleword_fprv4hi ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V8QImode ) emit_insn ( gen_move_doubleword_fprv8qi ( dest , src ) ) ; else if ( TARGET_64BIT && GET_MODE ( dest ) == TFmode ) emit_insn ( gen_move_doubleword_fprtf ( dest , src ) ) ; else gcc_unreachable ( ) ; } else if ( REG_P ( dest ) && REGNO ( dest ) == MD_REG_FIRST ) { low_dest = mips_subword ( dest , false ) ; mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; if ( TARGET_64BIT ) emit_insn ( gen_mthidi_ti ( dest , mips_subword ( src , true ) , low_dest ) ) ; else emit_insn ( gen_mthisi_di ( dest , mips_subword ( src , true ) , low_dest ) ) ; } else if ( REG_P ( src ) && REGNO ( src ) == MD_REG_FIRST ) { mips_emit_move ( mips_subword ( dest , false ) , mips_subword ( src , false ) ) ; if ( TARGET_64BIT ) emit_insn ( gen_mfhidi_ti ( mips_subword ( dest , true ) , src ) ) ; else emit_insn ( gen_mfhisi_di ( mips_subword ( dest , true ) , src ) ) ; } else { low_dest = mips_subword ( dest , false ) ; if ( REG_P ( low_dest ) && reg_overlap_mentioned_p ( low_dest , src ) ) { mips_emit_move ( mips_subword ( dest , true ) , mips_subword ( src , true ) ) ; mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; } else { mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; mips_emit_move ( mips_subword ( dest , true ) , mips_subword ( src , true ) ) ; } } } </s>

Split a move from SRC to DEST , given that mips_split_move_p holds . SPLIT_TYPE describes the split condition .


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

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


<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 ; } 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> 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_by_reference ( NULL , TYPE_MODE ( type ) , type , false ) ; 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 ) ; 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_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 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_INT ( call_really_used_regs [ i ] , call_really_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> static int mips_symbol_insns ( enum mips_symbol_type type , machine_mode mode ) { 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> 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_movmemsi ) { 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_shadow_register_set_p ( tree type ) { return lookup_attribute ( "use_shadow_register_set" , TYPE_ATTRIBUTES ( type ) ) != NULL ; } </s>

Check if the attribute to use shadow register set is set for a function .


<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 ; 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 ; 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 ( machine_mode mode ) { return mode == SImode || ( TARGET_64BIT && mode == DImode ) ; } </s>


"\tmove\t%s,%s\t\t# save current return address\n"

"\t%s\t%s,%s,%d\t\t# _mcount pops 2 words from  stack\n"


<s> static bool mips_vectorize_vec_perm_const_ok ( machine_mode vmode , const unsigned char * sel ) { struct expand_vec_perm_d d ; unsigned int i , nelt , which ; bool ret ; d . vmode = vmode ; d . nelt = nelt = GET_MODE_NUNITS ( d . vmode ) ; d . testing_p = true ; memcpy ( d . perm , sel , nelt ) ; for ( i = which = 0 ; i < nelt ; ++ i ) { unsigned char e = d . perm [ i ] ; gcc_assert ( e < 2 * nelt ) ; which |= ( e < nelt ? 1 : 2 ) ; } if ( which == 2 ) for ( i = 0 ; i < nelt ; ++ i ) d . perm [ i ] -= nelt ; d . one_vector_p = ( which != 3 ) ; 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 ( ) ; ret = mips_expand_vec_perm_const_1 ( & d ) ; end_sequence ( ) ; return ret ; } </s>


<s> static bool mips_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case V2SFmode : return TARGET_PAIRED_SINGLE_FLOAT ; case V2HImode : case V4QImode : case V2HQmode : case V2UHQmode : case V2HAmode : case V2UHAmode : case V4QQmode : case V4UQQmode : return TARGET_DSP ; case V2SImode : case V4HImode : case V8QImode : return TARGET_LOONGSON_VECTORS ; default : return false ; } } </s>

Target hook for vector_mode_supported_p .


<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
(
)
,
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 ( PATTERN ( 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_safe_mem_expr_p ( tree expr , unsigned HOST_WIDE_INT offset ) { HOST_WIDE_INT bitoffset , bitsize ; tree inner , var_offset ; machine_mode mode ; int unsigned_p , volatile_p ; inner = get_inner_reference ( expr , & bitsize , & bitoffset , & var_offset , & mode , & unsigned_p , & volatile_p , false ) ; 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 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 ( VOIDmode , 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 ( VOIDmode , 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> 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 ) >= 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 mips_avoid_hazard ( rtx_insn * after , rtx_insn * insn , int * hilo_delay , rtx * delayed_reg , rtx lo_reg , bool * fs_delay ) { rtx pattern , set ; int nops , ninsns ; pattern = PATTERN ( insn ) ; if ( GET_CODE ( pattern ) == ASM_INPUT || asm_noperands ( pattern ) >= 0 ) cfun -> machine -> all_noreorder_p = false ; ninsns = get_attr_length ( insn ) / 4 ; if ( ninsns == 0 ) return ; if ( * hilo_delay < 2 && reg_set_p ( lo_reg , pattern ) ) nops = 2 - * hilo_delay ; else if ( * delayed_reg != 0 && reg_referenced_p ( * delayed_reg , pattern ) ) nops = 1 ; else if ( * fs_delay && get_attr_can_delay ( insn ) == CAN_DELAY_NO && GET_CODE ( PATTERN ( after ) ) != SEQUENCE && GET_CODE ( pattern ) != ASM_INPUT && asm_noperands ( pattern ) < 0 ) nops = 1 ; else nops = 0 ; * hilo_delay += nops ; while ( nops -- > 0 ) emit_insn_after ( gen_hazard_nop ( ) , after ) ; * hilo_delay += ninsns ; * delayed_reg = 0 ; * fs_delay = false ; if ( INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_FORBIDDEN_SLOT : if ( TARGET_CB_MAYBE ) * fs_delay = true ; break ; case HAZARD_HILO : * hilo_delay = 0 ; break ; case HAZARD_DELAY : set = single_set ( insn ) ; gcc_assert ( set ) ; * delayed_reg = SET_DEST ( set ) ; break ; } } </s>

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


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

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


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

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


"-fstack-check=specific not implemented for MIPS16"

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


<s> void mips_expand_vector_init ( rtx target , rtx vals ) { machine_mode vmode = GET_MODE ( target ) ; machine_mode imode = GET_MODE_INNER ( vmode ) ; unsigned i , nelt = GET_MODE_NUNITS ( vmode ) ; unsigned nvar = 0 , one_var = - 1u ; bool all_same = true ; rtx x ; for ( i = 0 ; i < nelt ; ++ i ) { x = XVECEXP ( vals , 0 , i ) ; if ( ! mips_constant_elt_p ( x ) ) nvar ++ , one_var = i ; if ( i > 0 && ! rtx_equal_p ( x , XVECEXP ( vals , 0 , 0 ) ) ) all_same = false ; } if ( nvar == 0 ) { emit_move_insn ( target , gen_rtx_CONST_VECTOR ( vmode , XVEC ( vals , 0 ) ) ) ; return ; } if ( nelt == 2 ) { rtx op0 = force_reg ( imode , XVECEXP ( vals , 0 , 0 ) ) ; rtx op1 = force_reg ( imode , XVECEXP ( vals , 0 , 1 ) ) ; x = gen_rtx_VEC_CONCAT ( vmode , op0 , op1 ) ; emit_insn ( gen_rtx_SET ( target , x ) ) ; return ; } gcc_assert ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ; if ( all_same ) { mips_expand_vi_broadcast ( vmode , target , XVECEXP ( vals , 0 , 0 ) ) ; return ; } if ( nvar == 1 && vmode == V4HImode ) { mips_expand_vi_loongson_one_pinsrh ( target , vals , one_var ) ; return ; } mips_expand_vi_general ( vmode , imode , nelt , nvar , target , vals ) ; } </s>


<s> static bool mips_expand_vpc_loongson_pshufh ( struct expand_vec_perm_d * d ) { unsigned i , mask ; rtx rmask ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ) return false ; if ( d -> vmode != V4HImode ) return false ; if ( d -> testing_p ) return true ; for ( i = mask = 0 ; i < 4 ; i ++ ) mask |= ( d -> perm [ i ] & 3 ) << ( i * 2 ) ; rmask = force_reg ( SImode , GEN_INT ( mask ) ) ; if ( d -> one_vector_p ) emit_insn ( gen_loongson_pshufh ( d -> target , d -> op0 , rmask ) ) ; else { rtx t0 , t1 , x , merge , rmerge [ 4 ] ; t0 = gen_reg_rtx ( V4HImode ) ; t1 = gen_reg_rtx ( V4HImode ) ; emit_insn ( gen_loongson_pshufh ( t1 , d -> op1 , rmask ) ) ; emit_insn ( gen_loongson_pshufh ( t0 , d -> op0 , rmask ) ) ; for ( i = 0 ; i < 4 ; ++ i ) rmerge [ i ] = ( d -> perm [ i ] & 4 ? constm1_rtx : const0_rtx ) ; merge = gen_rtx_CONST_VECTOR ( V4HImode , gen_rtvec_v ( 4 , rmerge ) ) ; merge = force_reg ( V4HImode , merge ) ; x = gen_rtx_AND ( V4HImode , merge , t1 ) ; emit_insn ( gen_rtx_SET ( t1 , x ) ) ; x = gen_rtx_NOT ( V4HImode , merge ) ; x = gen_rtx_AND ( V4HImode , x , t0 ) ; emit_insn ( gen_rtx_SET ( t0 , x ) ) ; x = gen_rtx_IOR ( V4HImode , t0 , t1 ) ; emit_insn ( gen_rtx_SET ( d -> target , x ) ) ; } return true ; } </s>

Recognize patterns for the Loongson PSHUFH instruction .


<s> static bool mips_interrupt_extra_call_saved_reg_p ( unsigned int regno ) { if ( ( ISA_HAS_HILO || TARGET_DSP ) && MD_REG_P ( regno ) ) return true ; if ( TARGET_DSP && DSP_ACC_REG_P ( regno ) ) return true ; if ( GP_REG_P ( regno ) && cfun -> machine -> use_shadow_register_set == SHADOW_SET_NO ) { if ( regno == GP_REG_FIRST ) return false ; if ( KERNEL_REG_P ( regno ) ) return false ; if ( regno == STACK_POINTER_REGNUM ) return false ; return call_really_used_regs [ regno ] ; } return false ; } </s>

Return true if REGNO is a register that is ordinarily call-clobbered but must nevertheless be preserved by an interrupt handler .


<s> static int mips_issue_rate ( void ) { switch ( mips_tune ) { case PROCESSOR_74KC : case PROCESSOR_74KF2_1 : case PROCESSOR_74KF1_1 : case PROCESSOR_74KF3_2 : case PROCESSOR_R10000 : return 4 ; case PROCESSOR_20KC : case PROCESSOR_R4130 : case PROCESSOR_R5400 : case PROCESSOR_R5500 : case PROCESSOR_R5900 : case PROCESSOR_R7000 : case PROCESSOR_R9000 : case PROCESSOR_OCTEON : case PROCESSOR_OCTEON2 : case PROCESSOR_OCTEON3 : case PROCESSOR_I6400 : return 2 ; case PROCESSOR_SB1 : case PROCESSOR_SB1A : return 3 ; case PROCESSOR_LOONGSON_2E : case PROCESSOR_LOONGSON_2F : case PROCESSOR_LOONGSON_3A : case PROCESSOR_P5600 : return 4 ; case PROCESSOR_XLP : return ( reload_completed ? 4 : 3 ) ; default : return 1 ; } } </s>

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


<s> static int mips_multipass_dfa_lookahead ( void ) { if ( TUNE_SB1 ) return 4 ; if ( TUNE_LOONGSON_2EF || TUNE_LOONGSON_3A ) return 4 ; if ( TUNE_OCTEON ) return 2 ; if ( TUNE_P5600 || TUNE_I6400 ) return 4 ; return 0 ; } </s>


<s> const char * mips_output_jump ( rtx * operands , int target_opno , int size_opno , bool link_p ) { static char buffer [ 300 ] ; char * s = buffer ; bool reg_p = REG_P ( operands [ target_opno ] ) ; const char * and_link = link_p ? "al" : "" ; const char * reg = reg_p ? "r" : "" ; const char * compact = "" ; const char * nop = "%/" ; const char * short_delay = link_p ? "%!" : "" ; const char * insn_name = TARGET_CB_NEVER || reg_p ? "j" : "b" ; if ( ! final_sequence && ( TARGET_CB_MAYBE || ( ISA_HAS_JRC && ! link_p && reg_p ) ) ) { compact = "c" ; nop = "" ; } if ( TARGET_USE_GOT && ! TARGET_EXPLICIT_RELOCS ) sprintf ( s , "%%*%s%s\t%%%d%%/" , insn_name , and_link , target_opno ) ; else { if ( ! reg_p && TARGET_ABICALLS_PIC2 ) s += sprintf ( s , ".option\tpic0\n\t" ) ; if ( reg_p && mips_get_pic_call_symbol ( operands , size_opno ) ) { s += sprintf ( s , "%%*.reloc\t1f,R_MIPS_JALR,%%%d\n1:\t" , size_opno ) ; short_delay = "" ; } else s += sprintf ( s , "%%*" ) ; s += sprintf ( s , "%s%s%s%s%s\t%%%d%s" , insn_name , and_link , reg , compact , short_delay , target_opno , nop ) ; if ( ! reg_p && TARGET_ABICALLS_PIC2 ) s += sprintf ( s , "\n\t.option\tpic2" ) ; } return buffer ; } </s>

Return the asm template for a call . OPERANDS are the operands , TARGET_OPNO is the operand number of the target . SIZE_OPNO is the operand number of the argument size operand that can optionally hold the call attributes . If SIZE_OPNO is not -1 and the call is indirect , use the function symbol from the call attributes to attach a R_MIPS_JALR relocation to the call . LINK_P indicates whether the jump is a call and needs to set the link register . When generating GOT code without explicit relocation operators , all calls should use assembly macros . Otherwise , all indirect calls should use `` jr '' or `` jalr '' ; we will arrange to restore $ gp afterwards if necessary . Finally , we can only generate direct calls for -mabicalls by temporarily switching to non-PIC mode . For microMIPS jal ( r ) , we try to generate jal ( r ) s when a 16-bit instruction is in the delay slot of jal ( r ) . Where compact branches are available , we try to use them if the delay slot has a NOP ( or equivalently delay slots were not enabled for the instruction anyway ) .


<s> static void mips_setup_incoming_varargs ( cumulative_args_t cum , machine_mode mode , tree type , 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 ) , mode , type , true ) ; 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>


"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 .


"\tmove\t%s,%s\t\t# save current return address\n"

"\t%s\t%s,%s,%d\t\t# _mcount pops 2 words from  stack\n"


<s> static bool r10k_safe_mem_expr_p ( tree expr , unsigned HOST_WIDE_INT offset ) { HOST_WIDE_INT 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 , false ) ; 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>


<s> static unsigned int mips_autovectorize_vector_sizes ( void ) { return ISA_HAS_MSA ? 16 : 0 ; } </s>


<s> bool mips_cannot_change_mode_class ( machine_mode from , machine_mode to , enum reg_class rclass ) { if ( GET_MODE_SIZE ( from ) == 8 && GET_MODE_SIZE ( to ) == 8 && INTEGRAL_MODE_P ( from ) && INTEGRAL_MODE_P ( to ) ) return false ; if ( MSA_SUPPORTED_MODE_P ( from ) && MSA_SUPPORTED_MODE_P ( to ) ) return false ; return reg_classes_intersect_p ( FP_REGS , rclass ) ; } </s>


<s> int mips_class_max_nregs ( enum reg_class rclass , machine_mode mode ) { int size ; HARD_REG_SET left ; size = 0x8000 ; COPY_HARD_REG_SET ( left , reg_class_contents [ ( int ) rclass ] ) ; if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) ST_REGS ] ) ) { if ( HARD_REGNO_MODE_OK ( ST_REG_FIRST , mode ) ) size = MIN ( size , 4 ) ; AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) ST_REGS ] ) ; } if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) FP_REGS ] ) ) { if ( HARD_REGNO_MODE_OK ( FP_REG_FIRST , mode ) ) { if ( MSA_SUPPORTED_MODE_P ( mode ) ) size = MIN ( size , UNITS_PER_MSA_REG ) ; else size = MIN ( size , UNITS_PER_FPREG ) ; } AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) FP_REGS ] ) ; } if ( ! hard_reg_set_empty_p ( left ) ) size = MIN ( size , UNITS_PER_WORD ) ; return ( GET_MODE_SIZE ( mode ) + size - 1 ) / size ; } </s>

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


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

Expand builtin functions . This is called from TARGET_EXPAND_BUILTIN .


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

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


<s> void mips_expand_vec_cond_expr ( machine_mode mode , machine_mode vimode , rtx * operands ) { rtx cond = operands [ 3 ] ; rtx cmp_op0 = operands [ 4 ] ; rtx cmp_op1 = operands [ 5 ] ; rtx cmp_res = gen_reg_rtx ( vimode ) ; mips_expand_msa_cmp ( cmp_res , GET_CODE ( cond ) , cmp_op0 , cmp_op1 ) ; if ( operands [ 1 ] == CONSTM1_RTX ( vimode ) && operands [ 2 ] == CONST0_RTX ( vimode ) ) emit_move_insn ( operands [ 0 ] , cmp_res ) ; else { rtx src1 = gen_reg_rtx ( vimode ) ; rtx src2 = gen_reg_rtx ( vimode ) ; rtx mask = gen_reg_rtx ( vimode ) ; rtx bsel ; emit_move_insn ( mask , cmp_res ) ; if ( register_operand ( operands [ 1 ] , mode ) ) { rtx xop1 = operands [ 1 ] ; if ( mode != vimode ) { xop1 = gen_reg_rtx ( vimode ) ; emit_move_insn ( xop1 , gen_rtx_SUBREG ( vimode , operands [ 1 ] , 0 ) ) ; } emit_move_insn ( src1 , xop1 ) ; } else { gcc_assert ( operands [ 1 ] == CONSTM1_RTX ( vimode ) ) ; emit_move_insn ( src1 , mask ) ; } if ( register_operand ( operands [ 2 ] , mode ) ) { rtx xop2 = operands [ 2 ] ; if ( mode != vimode ) { xop2 = gen_reg_rtx ( vimode ) ; emit_move_insn ( xop2 , gen_rtx_SUBREG ( vimode , operands [ 2 ] , 0 ) ) ; } emit_move_insn ( src2 , xop2 ) ; } else { gcc_assert ( operands [ 2 ] == CONST0_RTX ( mode ) ) ; emit_move_insn ( src2 , mask ) ; } bsel = gen_rtx_IOR ( vimode , gen_rtx_AND ( vimode , gen_rtx_NOT ( vimode , mask ) , src2 ) , gen_rtx_AND ( vimode , mask , src1 ) ) ; emit_insn ( gen_rtx_SET ( mask , bsel ) ) ; emit_move_insn ( operands [ 0 ] , gen_rtx_SUBREG ( mode , mask , 0 ) ) ; } } </s>

Expand VEC_COND_EXPR , where : MODE is mode of the result VIMODE equivalent integer mode OPERANDS operands of VEC_COND_EXPR .


<s> bool mips_expand_vec_perm_const ( rtx operands [ 4 ] ) { struct expand_vec_perm_d d ; int i , nelt , which ; unsigned char orig_perm [ MAX_VECT_LEN ] ; rtx sel ; bool ok ; d . target = operands [ 0 ] ; d . op0 = operands [ 1 ] ; d . op1 = operands [ 2 ] ; sel = operands [ 3 ] ; d . vmode = GET_MODE ( d . target ) ; gcc_assert ( VECTOR_MODE_P ( d . vmode ) ) ; d . nelt = nelt = GET_MODE_NUNITS ( d . vmode ) ; d . testing_p = false ; memset ( orig_perm , 0 , MAX_VECT_LEN ) ; for ( i = which = 0 ; i < nelt ; ++ i ) { rtx e = XVECEXP ( sel , 0 , i ) ; int ei = INTVAL ( e ) & ( 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 ( ! 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 ; } ok = mips_expand_vec_perm_const_1 ( & d ) ; if ( ! ok && which == 3 ) { d . op0 = operands [ 1 ] ; d . op1 = operands [ 2 ] ; 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> void mips_expand_vec_unpack ( rtx operands [ 2 ] , bool unsigned_p , bool high_p ) { machine_mode imode = GET_MODE ( operands [ 1 ] ) ; rtx ( * unpack ) ( rtx , rtx , rtx ) ; rtx ( * cmpFunc ) ( rtx , rtx , rtx ) ; rtx tmp , dest , zero ; if ( ISA_HAS_MSA ) { switch ( imode ) { case V4SImode : if ( BYTES_BIG_ENDIAN != high_p ) unpack = gen_msa_ilvl_w ; else unpack = gen_msa_ilvr_w ; cmpFunc = gen_msa_clt_s_w ; break ; case V8HImode : if ( BYTES_BIG_ENDIAN != high_p ) unpack = gen_msa_ilvl_h ; else unpack = gen_msa_ilvr_h ; cmpFunc = gen_msa_clt_s_h ; break ; case V16QImode : if ( BYTES_BIG_ENDIAN != high_p ) unpack = gen_msa_ilvl_b ; else unpack = gen_msa_ilvr_b ; cmpFunc = gen_msa_clt_s_b ; break ; default : gcc_unreachable ( ) ; break ; } if ( ! unsigned_p ) { tmp = gen_reg_rtx ( imode ) ; emit_insn ( cmpFunc ( tmp , operands [ 1 ] , CONST0_RTX ( imode ) ) ) ; } else tmp = force_reg ( imode , CONST0_RTX ( imode ) ) ; dest = gen_reg_rtx ( imode ) ; emit_insn ( unpack ( dest , operands [ 1 ] , tmp ) ) ; emit_move_insn ( operands [ 0 ] , gen_lowpart ( GET_MODE ( operands [ 0 ] ) , dest ) ) ; return ; } switch ( imode ) { case V8QImode : if ( high_p ) unpack = gen_loongson_punpckhbh ; else unpack = gen_loongson_punpcklbh ; cmpFunc = gen_loongson_pcmpgtb ; break ; case V4HImode : if ( high_p ) unpack = gen_loongson_punpckhhw ; else unpack = gen_loongson_punpcklhw ; cmpFunc = gen_loongson_pcmpgth ; break ; default : gcc_unreachable ( ) ; } zero = force_reg ( imode , CONST0_RTX ( imode ) ) ; if ( unsigned_p ) tmp = zero ; else { tmp = gen_reg_rtx ( imode ) ; emit_insn ( cmpFunc ( tmp , zero , operands [ 1 ] ) ) ; } dest = gen_reg_rtx ( imode ) ; emit_insn ( unpack ( dest , operands [ 1 ] , tmp ) ) ; emit_move_insn ( operands [ 0 ] , gen_lowpart ( GET_MODE ( operands [ 0 ] ) , dest ) ) ; } </s>

Expand an integral vector unpack operation .


<s> void mips_final_prescan_insn ( rtx_insn * insn , rtx * opvec , int noperands ) { if ( INSN_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) == UNSPEC_VOLATILE && XINT ( PATTERN ( insn ) , 1 ) == UNSPEC_CONSTTABLE ) mips_set_text_contents_type ( asm_out_file , "__pool_" , XINT ( XVECEXP ( PATTERN ( insn ) , 0 , 0 ) , 0 ) , FALSE ) ; if ( mips_need_noat_wrapper_p ( insn , opvec , noperands ) ) mips_push_asm_switch ( & mips_noat ) ; } </s>


<s> rtx mips_gen_const_int_vector ( machine_mode mode , HOST_WIDE_INT val ) { int nunits = GET_MODE_NUNITS ( mode ) ; rtvec v = rtvec_alloc ( nunits ) ; int i ; for ( i = 0 ; i < nunits ; i ++ ) RTVEC_ELT ( v , i ) = gen_int_mode ( val , GET_MODE_INNER ( mode ) ) ; return gen_rtx_CONST_VECTOR ( mode , v ) ; } </s>

Return a const_int vector of VAL with mode MODE .


<s> static bool mips_hard_regno_mode_ok_p ( unsigned int regno , machine_mode mode ) { unsigned int size ; enum mode_class mclass ; if ( mode == CCV2mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 2 == 0 ) ; if ( mode == CCV4mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 4 == 0 ) ; if ( mode == CCmode ) return ISA_HAS_8CC ? ST_REG_P ( regno ) : regno == FPSW_REGNUM ; size = GET_MODE_SIZE ( mode ) ; mclass = GET_MODE_CLASS ( mode ) ; if ( GP_REG_P ( regno ) && mode != CCFmode && ! MSA_SUPPORTED_MODE_P ( mode ) ) return ( ( regno - GP_REG_FIRST ) & 1 ) == 0 || size <= UNITS_PER_WORD ; if ( FP_REG_P ( regno ) && MSA_SUPPORTED_MODE_P ( mode ) ) return true ; if ( FP_REG_P ( regno ) && ( ( ( regno - FP_REG_FIRST ) % MAX_FPRS_PER_FMT ) == 0 || ( MIN_FPRS_PER_FMT == 1 && size <= UNITS_PER_FPREG ) ) ) { if ( TARGET_O32_FP64A_ABI && size <= 4 && ( regno & 1 ) != 0 ) return false ; if ( mode == CCFmode ) return ! ( TARGET_FLOATXX && ( regno & 1 ) != 0 ) ; if ( TARGET_LOONGSON_VECTORS && ( mode == V2SImode || mode == V4HImode || mode == V8QImode || mode == DImode ) ) return true ; if ( mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT || mclass == MODE_VECTOR_FLOAT ) return size <= UNITS_PER_FPVALUE ; if ( mclass == MODE_INT ) return size >= MIN_UNITS_PER_WORD && size <= UNITS_PER_FPREG ; } if ( ACC_REG_P ( regno ) && ! VECTOR_MODE_P ( mode ) && ( INTEGRAL_MODE_P ( mode ) || ALL_FIXED_POINT_MODE_P ( mode ) ) ) { if ( MD_REG_P ( regno ) ) { if ( size <= UNITS_PER_WORD * 2 ) return regno == ( size <= UNITS_PER_WORD ? LO_REGNUM : MD_REG_FIRST ) ; } else { if ( size <= UNITS_PER_WORD ) return true ; if ( size <= UNITS_PER_WORD * 2 && ( ( regno - DSP_ACC_REG_FIRST ) & 1 ) == 0 ) return true ; } } if ( ALL_COP_REG_P ( regno ) ) return mclass == MODE_INT && size <= UNITS_PER_WORD ; if ( regno == GOT_VERSION_REGNUM ) return mode == SImode ; return false ; } </s>

Return true if register REGNO can store a value of mode MODE . The result of this function is cached in mips_hard_regno_mode_ok .


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


<s> static void mips_init_builtins ( void ) { const struct mips_builtin_description * d ; unsigned int i ; for ( i = 0 ; i < ARRAY_SIZE ( mips_builtins ) ; i ++ ) { d = & mips_builtins [ i ] ; if ( d -> avail ( ) ) { mips_builtin_decls [ i ] = add_builtin_function ( d -> name , mips_build_function_type ( d -> function_type ) , i , BUILT_IN_MD , NULL , NULL ) ; mips_get_builtin_decl_index [ d -> icode ] = i ; } } } </s>

Init builtin functions . This is called from TARGET_INIT_BUILTIN .


<s> static bool mips_mode_ok_for_mov_fmt_p ( machine_mode mode ) { switch ( mode ) { case CCFmode : case SFmode : return TARGET_HARD_FLOAT ; case DFmode : return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT ; case V2SFmode : return TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT ; default : return MSA_SUPPORTED_MODE_P ( mode ) ; } } </s>

Return true if moves in mode MODE can use the FPU 's mov.fmt instruction .


<s> static machine_mode mips_preferred_simd_mode ( machine_mode mode ) { if ( TARGET_PAIRED_SINGLE_FLOAT && mode == SFmode ) return V2SFmode ; if ( ! ISA_HAS_MSA ) return word_mode ; switch ( mode ) { case QImode : return V16QImode ; case HImode : return V8HImode ; case SImode : return V4SImode ; case DImode : return V2DImode ; case SFmode : return V4SFmode ; case DFmode : return V2DFmode ; default : break ; } return word_mode ; } </s>


"MIPS16 PIC for ABIs other than o32 and o64"

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


<s> void mips_split_move ( rtx dest , rtx src , enum mips_split_type split_type ) { rtx low_dest ; gcc_checking_assert ( mips_split_move_p ( dest , src , split_type ) ) ; if ( MSA_SUPPORTED_MODE_P ( GET_MODE ( dest ) ) ) mips_split_128bit_move ( dest , src ) ; else if ( FP_REG_RTX_P ( dest ) || FP_REG_RTX_P ( src ) ) { if ( ! TARGET_64BIT && GET_MODE ( dest ) == DImode ) emit_insn ( gen_move_doubleword_fprdi ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == DFmode ) emit_insn ( gen_move_doubleword_fprdf ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V2SFmode ) emit_insn ( gen_move_doubleword_fprv2sf ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V2SImode ) emit_insn ( gen_move_doubleword_fprv2si ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V4HImode ) emit_insn ( gen_move_doubleword_fprv4hi ( dest , src ) ) ; else if ( ! TARGET_64BIT && GET_MODE ( dest ) == V8QImode ) emit_insn ( gen_move_doubleword_fprv8qi ( dest , src ) ) ; else if ( TARGET_64BIT && GET_MODE ( dest ) == TFmode ) emit_insn ( gen_move_doubleword_fprtf ( dest , src ) ) ; else gcc_unreachable ( ) ; } else if ( REG_P ( dest ) && REGNO ( dest ) == MD_REG_FIRST ) { low_dest = mips_subword ( dest , false ) ; mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; if ( TARGET_64BIT ) emit_insn ( gen_mthidi_ti ( dest , mips_subword ( src , true ) , low_dest ) ) ; else emit_insn ( gen_mthisi_di ( dest , mips_subword ( src , true ) , low_dest ) ) ; } else if ( REG_P ( src ) && REGNO ( src ) == MD_REG_FIRST ) { mips_emit_move ( mips_subword ( dest , false ) , mips_subword ( src , false ) ) ; if ( TARGET_64BIT ) emit_insn ( gen_mfhidi_ti ( mips_subword ( dest , true ) , src ) ) ; else emit_insn ( gen_mfhisi_di ( mips_subword ( dest , true ) , src ) ) ; } else { low_dest = mips_subword ( dest , false ) ; if ( REG_P ( low_dest ) && reg_overlap_mentioned_p ( low_dest , src ) ) { mips_emit_move ( mips_subword ( dest , true ) , mips_subword ( src , true ) ) ; mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; } else { mips_emit_move ( low_dest , mips_subword ( src , false ) ) ; mips_emit_move ( mips_subword ( dest , true ) , mips_subword ( src , true ) ) ; } } } </s>

Split a move from SRC to DEST , given that mips_split_move_p holds . SPLIT_TYPE describes the split condition .


<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_by_reference ( NULL , TYPE_MODE ( type ) , type , false ) ; 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> static bool mips_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case V2SFmode : return TARGET_PAIRED_SINGLE_FLOAT ; case V2HImode : case V4QImode : case V2HQmode : case V2UHQmode : case V2HAmode : case V2UHAmode : case V4QQmode : case V4UQQmode : return TARGET_DSP ; case V2SImode : case V4HImode : case V8QImode : return TARGET_LOONGSON_VECTORS ; default : return MSA_SUPPORTED_MODE_P ( mode ) ; } } </s>

Target hook for vector_mode_supported_p .


<s> static bool r10k_safe_mem_expr_p ( tree expr , unsigned HOST_WIDE_INT offset ) { HOST_WIDE_INT 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 void mips_autovectorize_vector_sizes ( vector_sizes * sizes ) { if ( ISA_HAS_MSA ) sizes -> safe_push ( 16 ) ; } </s>


<s> static void mips_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; machine_mode mode ; rtx * regs ; if ( ! ISA_HAS_LWL_LWR ) bits = MIN ( BITS_PER_WORD , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) ) ; else { if ( MEM_ALIGN ( src ) == BITS_PER_WORD / 2 && MEM_ALIGN ( dest ) == BITS_PER_WORD / 2 ) bits = BITS_PER_WORD / 2 ; else bits = BITS_PER_WORD ; } mode = int_mode_for_size ( bits , 0 ) . require ( ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( rtx , length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; if ( MEM_ALIGN ( src ) >= bits ) mips_emit_move ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; else { rtx part = adjust_address ( src , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ext_as_unaligned_load ( regs [ i ] , part , bits , 0 , 0 ) ) gcc_unreachable ( ) ; } } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) if ( MEM_ALIGN ( dest ) >= bits ) mips_emit_move ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; else { rtx part = adjust_address ( dest , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ins_as_unaligned_store ( part , regs [ i ] , bits , 0 ) ) gcc_unreachable ( ) ; } if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , 0 ) ; } } </s>

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


<s> int mips_class_max_nregs ( enum reg_class rclass , machine_mode mode ) { int size ; HARD_REG_SET left ; size = 0x8000 ; COPY_HARD_REG_SET ( left , reg_class_contents [ ( int ) rclass ] ) ; if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) ST_REGS ] ) ) { if ( mips_hard_regno_mode_ok ( ST_REG_FIRST , mode ) ) size = MIN ( size , 4 ) ; AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) ST_REGS ] ) ; } if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) FP_REGS ] ) ) { if ( mips_hard_regno_mode_ok ( FP_REG_FIRST , mode ) ) { if ( MSA_SUPPORTED_MODE_P ( mode ) ) size = MIN ( size , UNITS_PER_MSA_REG ) ; else size = MIN ( size , UNITS_PER_FPREG ) ; } AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) FP_REGS ] ) ; } if ( ! hard_reg_set_empty_p ( left ) ) size = MIN ( size , UNITS_PER_WORD ) ; return ( GET_MODE_SIZE ( mode ) + size - 1 ) / size ; } </s>


<s> static bool mips_expand_vpc_loongson_even_odd ( struct expand_vec_perm_d * d ) { unsigned i , odd , nelt = d -> nelt ; rtx t0 , t1 , t2 , t3 ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ) return false ; if ( nelt < 4 ) return false ; odd = d -> perm [ 0 ] ; if ( odd > 1 ) return false ; for ( i = 1 ; i < nelt ; ++ i ) if ( d -> perm [ i ] != i * 2 + odd ) return false ; if ( d -> testing_p ) return true ; t0 = gen_reg_rtx ( d -> vmode ) ; t1 = gen_reg_rtx ( d -> vmode ) ; switch ( d -> vmode ) { case E_V4HImode : emit_insn ( gen_loongson_punpckhhw ( t0 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpcklhw ( t1 , d -> op0 , d -> op1 ) ) ; if ( odd ) emit_insn ( gen_loongson_punpckhhw ( d -> target , t1 , t0 ) ) ; else emit_insn ( gen_loongson_punpcklhw ( d -> target , t1 , t0 ) ) ; break ; case E_V8QImode : t2 = gen_reg_rtx ( d -> vmode ) ; t3 = gen_reg_rtx ( d -> vmode ) ; emit_insn ( gen_loongson_punpckhbh ( t0 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpcklbh ( t1 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpckhbh ( t2 , t1 , t0 ) ) ; emit_insn ( gen_loongson_punpcklbh ( t3 , t1 , t0 ) ) ; if ( odd ) emit_insn ( gen_loongson_punpckhbh ( d -> target , t3 , t2 ) ) ; else emit_insn ( gen_loongson_punpcklbh ( d -> target , t3 , t2 ) ) ; break ; default : gcc_unreachable ( ) ; } return true ; } </s>

Recognize patterns for even-odd extraction .


<s> static bool mips_hard_regno_call_part_clobbered ( unsigned int regno , machine_mode mode ) { if ( TARGET_FLOATXX && hard_regno_nregs ( regno , mode ) == 1 && FP_REG_P ( regno ) && ( regno & 1 ) != 0 ) return true ; if ( ISA_HAS_MSA && FP_REG_P ( regno ) && GET_MODE_SIZE ( mode ) > 8 ) return true ; return false ; } </s>

Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED . Odd-numbered single-precision registers are not considered callee-saved for o32 FPXX as they will be clobbered when run on an FR=1 FPU . MSA vector registers with MODE > 64 bits are part clobbered too .


<s> static bool mips_hard_regno_mode_ok_uncached ( unsigned int regno , machine_mode mode ) { unsigned int size ; enum mode_class mclass ; if ( mode == CCV2mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 2 == 0 ) ; if ( mode == CCV4mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 4 == 0 ) ; if ( mode == CCmode ) return ISA_HAS_8CC ? ST_REG_P ( regno ) : regno == FPSW_REGNUM ; size = GET_MODE_SIZE ( mode ) ; mclass = GET_MODE_CLASS ( mode ) ; if ( GP_REG_P ( regno ) && mode != CCFmode && ! MSA_SUPPORTED_MODE_P ( mode ) ) return ( ( regno - GP_REG_FIRST ) & 1 ) == 0 || size <= UNITS_PER_WORD ; if ( FP_REG_P ( regno ) && MSA_SUPPORTED_MODE_P ( mode ) ) return true ; if ( FP_REG_P ( regno ) && ( ( ( regno - FP_REG_FIRST ) % MAX_FPRS_PER_FMT ) == 0 || ( MIN_FPRS_PER_FMT == 1 && size <= UNITS_PER_FPREG ) ) ) { if ( TARGET_O32_FP64A_ABI && size <= 4 && ( regno & 1 ) != 0 ) return false ; if ( mode == CCFmode ) return ! ( TARGET_FLOATXX && ( regno & 1 ) != 0 ) ; if ( TARGET_LOONGSON_VECTORS && ( mode == V2SImode || mode == V4HImode || mode == V8QImode || mode == DImode ) ) return true ; if ( mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT || mclass == MODE_VECTOR_FLOAT ) return size <= UNITS_PER_FPVALUE ; if ( mclass == MODE_INT ) return size >= MIN_UNITS_PER_WORD && size <= UNITS_PER_FPREG ; } if ( ACC_REG_P ( regno ) && ! VECTOR_MODE_P ( mode ) && ( INTEGRAL_MODE_P ( mode ) || ALL_FIXED_POINT_MODE_P ( mode ) ) ) { if ( MD_REG_P ( regno ) ) { if ( size <= UNITS_PER_WORD * 2 ) return regno == ( size <= UNITS_PER_WORD ? LO_REGNUM : MD_REG_FIRST ) ; } else { if ( size <= UNITS_PER_WORD ) return true ; if ( size <= UNITS_PER_WORD * 2 && ( ( regno - DSP_ACC_REG_FIRST ) & 1 ) == 0 ) return true ; } } if ( ALL_COP_REG_P ( regno ) ) return mclass == MODE_INT && size <= UNITS_PER_WORD ; if ( regno == GOT_VERSION_REGNUM ) return mode == SImode ; return false ; } </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_VECTORS ; default : return MSA_SUPPORTED_MODE_P ( mode ) ; } } </s>


<s> bool and_operands_ok ( machine_mode mode , rtx op1 , rtx op2 ) { if ( memory_operand ( op1 , mode ) ) { if ( TARGET_MIPS16 ) { struct mips_address_info addr ; if ( ! mips_classify_address ( & addr , op1 , mode , false ) ) return false ; } return and_load_operand ( op2 , mode ) ; } else return and_reg_operand ( op2 , mode ) ; } </s>

Return true iff OP1 and OP2 are valid operands together for the * and < MODE > 3 and * and < MODE > 3_mips16 patterns . For the cases to consider , see the table in the comment before the pattern .


<s> inline bool mips_lo_sum_offset_hasher :: equal ( const mips_lo_sum_offset * entry , const rtx_def * value ) { return rtx_equal_p ( entry -> base , value ) ; } </s>


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


<s> static rtx gen_load_const_gp ( rtx reg ) { return PMODE_INSN ( gen_load_const_gp , ( reg ) ) ; } </s>

Return an instruction that copies $ gp into register REG . We want GCC to treat the register 's value as constant , so that its value can be rematerialized on demand .


<s> const char * mips16_set_fcsr_one_only_stub :: get_name ( ) { return "__mips16_set_fcsr" ; } </s>

Return the overloaded or full function name for INSTANCE ; OVERLOADED_P selects which . Allocate the string on m_string_obstack ; the caller must use obstack_free to free it after use .


<s> inline hashval_t mips_lo_sum_offset_hasher :: hash ( const mips_lo_sum_offset * entry ) { return mips_hash_base ( entry -> base ) ; } </s>

Hash function for builtin functions with up to 3 arguments and a return type .


<s> bool lwsp_swsp_address_p ( rtx x , machine_mode mode ) { struct mips_address_info addr ; return ( mips_classify_address ( & addr , x , mode , false ) && addr . type == ADDRESS_REG && REGNO ( addr . reg ) == STACK_POINTER_REGNUM && uw5_operand ( addr . offset , mode ) ) ; } </s>

Return true if X is a legitimate address that conforms to the requirements for a microMIPS LWSP or SWSP insn .


<s> bool m16_based_address_p ( rtx x , machine_mode mode , insn_operand_predicate_fn offset_predicate ) { struct mips_address_info addr ; return ( mips_classify_address ( & addr , x , mode , false ) && addr . type == ADDRESS_REG && M16_REG_P ( REGNO ( addr . reg ) ) && offset_predicate ( addr . offset , mode ) ) ; } </s>

Return true if X is legitimate for accessing values of mode MODE , if it is based on a MIPS16 register , and if the offset satisfies OFFSET_PREDICATE .


<s> int mask_low_and_shift_len ( machine_mode mode , rtx mask , rtx shift ) { HOST_WIDE_INT shval ; shval = INTVAL ( shift ) & ( GET_MODE_BITSIZE ( mode ) - 1 ) ; return exact_log2 ( ( UINTVAL ( mask ) >> shval ) + 1 ) ; } </s>

The canonical form of a mask-low-and-shift-left operation is ( and ( ashift X SHIFT ) MASK ) where MASK has the lower SHIFT number of bits cleared . Thus we need to shift MASK to the right before checking if it is a valid mask value . MODE is the mode of the operation . If true return the length of the mask , otherwise return -1 .


<s> bool mask_low_and_shift_p ( machine_mode mode , rtx mask , rtx shift , int maxlen ) { return IN_RANGE ( mask_low_and_shift_len ( mode , mask , shift ) , 1 , maxlen ) ; } </s>

Check if MASK and SHIFT are valid in mask-low-and-shift-left operation if MAXLEN is the maxium length of consecutive bits that can make up MASK . MODE is the mode of the operation . See mask_low_and_shift_len for the actual definition .


<s> static bool mflip_mips16_use_mips16_p ( tree decl ) { const char * name ; bool base_is_mips16 = ( mips_base_compression_flags & MASK_MIPS16 ) != 0 ; if ( ! DECL_NAME ( decl ) ) return ! base_is_mips16 ; if ( ! mflip_mips16_htab ) mflip_mips16_htab = hash_map < nofree_string_hash , bool > :: create_ggc ( 37 ) ; name = IDENTIFIER_POINTER ( DECL_NAME ( decl ) ) ; bool existed ; bool * slot = & mflip_mips16_htab -> get_or_insert ( name , & existed ) ; if ( ! existed ) { mips16_flipper = ! mips16_flipper ; * slot = mips16_flipper ? ! base_is_mips16 : base_is_mips16 ; } return * slot ; } </s>

DECL is a function that needs a default `` mips16 '' or `` nomips16 '' attribute for -mflip-mips16 . Return true if it should use `` mips16 '' and false if it should use `` nomips16 '' .


<s> static char * mips16e_add_register_range ( char * s , unsigned int min_reg , unsigned int max_reg ) { if ( min_reg != max_reg ) s += sprintf ( s , ",%s-%s" , reg_names [ min_reg ] , reg_names [ max_reg ] ) ; else s += sprintf ( s , ",%s" , reg_names [ min_reg ] ) ; return s ; } </s>

Add a MIPS16e SAVE or RESTORE register-range argument to string S for the register range [ MIN_REG , MAX_REG ] . Return a pointer to the null terminator .


<s> static rtx mips16e_build_save_restore ( bool restore_p , unsigned int * mask_ptr , HOST_WIDE_INT * offset_ptr , unsigned int nargs , HOST_WIDE_INT size ) { rtx pattern , set ; HOST_WIDE_INT offset , top_offset ; unsigned int i , regno ; int n ; gcc_assert ( cfun -> machine -> frame . num_fp == 0 ) ; n = 1 + nargs ; for ( i = 0 ; i < ARRAY_SIZE ( mips16e_save_restore_regs ) ; i ++ ) if ( BITSET_P ( * mask_ptr , mips16e_save_restore_regs [ i ] ) ) n ++ ; pattern = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( n ) ) ; n = 0 ; set = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , restore_p ? size : - size ) ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; XVECEXP ( pattern , 0 , n ++ ) = set ; top_offset = restore_p ? size : 0 ; for ( i = 0 ; i < nargs ; i ++ ) { offset = top_offset + i * UNITS_PER_WORD ; set = mips16e_save_restore_reg ( restore_p , true , offset , GP_ARG_FIRST + i ) ; XVECEXP ( pattern , 0 , n ++ ) = set ; } offset = top_offset ; for ( i = 0 ; i < ARRAY_SIZE ( mips16e_save_restore_regs ) ; i ++ ) { regno = mips16e_save_restore_regs [ i ] ; if ( BITSET_P ( * mask_ptr , regno ) ) { offset -= UNITS_PER_WORD ; set = mips16e_save_restore_reg ( restore_p , false , offset , regno ) ; XVECEXP ( pattern , 0 , n ++ ) = set ; * mask_ptr &= ~ ( 1 << regno ) ; } } * offset_ptr = size + ( offset - top_offset ) ; gcc_assert ( n == XVECLEN ( pattern , 0 ) ) ; return pattern ; } </s>

Return RTL for a MIPS16e SAVE or RESTORE instruction ; RESTORE_P says which . The instruction must : - Allocate or deallocate SIZE bytes in total ; SIZE is known to be nonzero . - Save or restore as many registers in * MASK_PTR as possible . The instruction saves the first registers at the top of the allocated area , with the other registers below it . - Save NARGS argument registers above the allocated area . ( NARGS is always zero if RESTORE_P . ) The SAVE and RESTORE instructions can not save and restore all general registers , so there may be some registers left over for the caller to handle . Destructively modify * MASK_PTR so that it contains the registers that still need to be saved or restored . The caller can save these registers in the memory immediately below * OFFSET_PTR , which is a byte offset from the bottom of the allocated stack area .


<s> static unsigned int mips16e_collect_argument_saves ( void ) { rtx reg_values [ FIRST_PSEUDO_REGISTER ] ; rtx_insn * insn , * next ; rtx set , dest , src ; unsigned int nargs , regno ; push_topmost_sequence ( ) ; nargs = 0 ; memset ( reg_values , 0 , sizeof ( reg_values ) ) ; for ( insn = get_insns ( ) ; insn ; insn = next ) { next = NEXT_INSN ( insn ) ; if ( NOTE_P ( insn ) || DEBUG_INSN_P ( insn ) ) continue ; if ( ! INSN_P ( insn ) ) break ; set = PATTERN ( insn ) ; if ( GET_CODE ( set ) != SET ) break ; dest = SET_DEST ( set ) ; src = SET_SRC ( set ) ; if ( mips16e_collect_argument_save_p ( dest , src , reg_values , & regno ) ) { if ( ! BITSET_P ( cfun -> machine -> frame . mask , regno ) ) { delete_insn ( insn ) ; nargs = MAX ( nargs , ( regno - GP_ARG_FIRST ) + 1 ) ; } } else if ( REG_P ( dest ) && GET_MODE ( dest ) == word_mode ) reg_values [ REGNO ( dest ) ] = mips16e_collect_propagate_value ( src , reg_values ) ; else break ; } pop_topmost_sequence ( ) ; return nargs ; } </s>

A subroutine of mips_expand_prologue , called only when generating MIPS16e SAVE instructions . Search the start of the function for any instructions that save argument registers into their caller-allocated save slots . Delete such instructions and return a value N such that saving [ GP_ARG_FIRST , GP_ARG_FIRST + N ) would make all the deleted instructions redundant .


<s> static bool mips16e_collect_argument_save_p ( rtx dest , rtx src , rtx * reg_values , unsigned int * regno_ptr ) { unsigned int argno , regno ; HOST_WIDE_INT offset , required_offset ; rtx addr , base ; if ( ! MEM_P ( dest ) || ! REG_P ( src ) || GET_MODE ( dest ) != word_mode ) return false ; regno = REGNO ( src ) ; if ( ! IN_RANGE ( regno , GP_ARG_FIRST , GP_ARG_LAST ) || reg_values [ regno ] ) return false ; argno = regno - GP_ARG_FIRST ; addr = mips16e_collect_propagate_value ( XEXP ( dest , 0 ) , reg_values ) ; mips_split_plus ( addr , & base , & offset ) ; required_offset = cfun -> machine -> frame . total_size + argno * UNITS_PER_WORD ; if ( base == hard_frame_pointer_rtx ) required_offset -= cfun -> machine -> frame . hard_frame_pointer_offset ; else if ( base != stack_pointer_rtx ) return false ; if ( offset != required_offset ) return false ; * regno_ptr = regno ; return true ; } </s>

Return true if ( set DEST SRC ) stores an argument register into its caller-allocated save slot , storing the number of that argument register in * REGNO_PTR if so . REG_VALUES is as for mips16e_collect_propagate_value .


<s> static rtx mips16e_collect_propagate_value ( rtx x , rtx * reg_values ) { x = avoid_constant_pool_reference ( x ) ; if ( UNARY_P ( x ) ) { rtx x0 = mips16e_collect_propagate_value ( XEXP ( x , 0 ) , reg_values ) ; return simplify_gen_unary ( GET_CODE ( x ) , GET_MODE ( x ) , x0 , GET_MODE ( XEXP ( x , 0 ) ) ) ; } if ( ARITHMETIC_P ( x ) ) { rtx x0 = mips16e_collect_propagate_value ( XEXP ( x , 0 ) , reg_values ) ; rtx x1 = mips16e_collect_propagate_value ( XEXP ( x , 1 ) , reg_values ) ; return simplify_gen_binary ( GET_CODE ( x ) , GET_MODE ( x ) , x0 , x1 ) ; } if ( REG_P ( x ) && reg_values [ REGNO ( x ) ] && ! rtx_unstable_p ( reg_values [ REGNO ( x ) ] ) ) return reg_values [ REGNO ( x ) ] ; return x ; } </s>

Return a simplified form of X using the register values in REG_VALUES . REG_VALUES [ R ] is the last value assigned to hard register R , or null if R has not been modified . This function is rather limited , but is good enough for our purposes .


<s> static unsigned int mips16e_find_first_register ( unsigned int mask , const unsigned char * regs , unsigned int size ) { unsigned int i ; for ( i = 0 ; i < size ; i ++ ) if ( BITSET_P ( mask , regs [ i ] ) ) break ; return i ; } </s>

Return the index of the lowest X in the range [ 0 , SIZE ) for which bit REGS [ X ] is set in MASK . Return SIZE if there is no such X .


<s> static void mips16e_mask_registers ( unsigned int * mask_ptr , const unsigned char * regs , unsigned int size , unsigned int * num_regs_ptr ) { unsigned int i ; i = mips16e_find_first_register ( * mask_ptr , regs , size ) ; for ( i ++ ; i < size ; i ++ ) if ( ! BITSET_P ( * mask_ptr , regs [ i ] ) ) { * num_regs_ptr += 1 ; * mask_ptr |= 1 << regs [ i ] ; } } </s>

* MASK_PTR is a mask of general-purpose registers and * NUM_REGS_PTR is the number of set bits . If * MASK_PTR contains REGS [ X ] for some X in [ 0 , SIZE ) , adjust * MASK_PTR and * NUM_REGS_PTR so that the same is true for all indexes ( X , SIZE ) .


<s> const char * mips16e_output_save_restore ( rtx pattern , HOST_WIDE_INT adjust ) { static char buffer [ 300 ] ; struct mips16e_save_restore_info info ; unsigned int i , end ; char * s ; if ( ! mips16e_save_restore_pattern_p ( pattern , adjust , & info ) ) gcc_unreachable ( ) ; s = strcpy ( buffer , adjust > 0 ? "restore\t" : "save\t" ) ; s += strlen ( s ) ; if ( info . nargs > 1 ) s += sprintf ( s , "%s-%s," , reg_names [ GP_ARG_FIRST ] , reg_names [ GP_ARG_FIRST + info . nargs - 1 ] ) ; else if ( info . nargs == 1 ) s += sprintf ( s , "%s," , reg_names [ GP_ARG_FIRST ] ) ; s += sprintf ( s , "%d" , ( int ) info . size ) ; if ( BITSET_P ( info . mask , 16 ) ) s += sprintf ( s , ",%s" , reg_names [ GP_REG_FIRST + 16 ] ) ; if ( BITSET_P ( info . mask , 17 ) ) s += sprintf ( s , ",%s" , reg_names [ GP_REG_FIRST + 17 ] ) ; end = ARRAY_SIZE ( mips16e_s2_s8_regs ) ; i = mips16e_find_first_register ( info . mask , mips16e_s2_s8_regs , end ) ; if ( i < end ) s = mips16e_add_register_range ( s , mips16e_s2_s8_regs [ end - 1 ] , mips16e_s2_s8_regs [ i ] ) ; end = ARRAY_SIZE ( mips16e_a0_a3_regs ) ; i = mips16e_find_first_register ( info . mask , mips16e_a0_a3_regs , end ) ; if ( i < end ) s = mips16e_add_register_range ( s , mips16e_a0_a3_regs [ i ] , mips16e_a0_a3_regs [ end - 1 ] ) ; if ( BITSET_P ( info . mask , RETURN_ADDR_REGNUM ) ) s += sprintf ( s , ",%s" , reg_names [ RETURN_ADDR_REGNUM ] ) ; return buffer ; } </s>

Return the assembly instruction for a MIPS16e SAVE or RESTORE instruction . PATTERN and ADJUST are as for mips16e_save_restore_pattern_p .


<s> bool mips16e_save_restore_pattern_p ( rtx pattern , HOST_WIDE_INT adjust , struct mips16e_save_restore_info * info ) { unsigned int i , nargs , mask , extra ; HOST_WIDE_INT top_offset , save_offset , offset ; rtx set , reg , mem , base ; int n ; if ( ! GENERATE_MIPS16E_SAVE_RESTORE ) return false ; top_offset = adjust > 0 ? adjust : 0 ; save_offset = top_offset - UNITS_PER_WORD ; mask = 0 ; nargs = 0 ; i = 0 ; for ( n = 1 ; n < XVECLEN ( pattern , 0 ) ; n ++ ) { set = XVECEXP ( pattern , 0 , n ) ; if ( GET_CODE ( set ) != SET ) return false ; mem = adjust > 0 ? SET_SRC ( set ) : SET_DEST ( set ) ; if ( ! MEM_P ( mem ) ) return false ; mips_split_plus ( XEXP ( mem , 0 ) , & base , & offset ) ; if ( base != stack_pointer_rtx ) return false ; reg = adjust > 0 ? SET_DEST ( set ) : SET_SRC ( set ) ; if ( ! REG_P ( reg ) ) return false ; if ( offset == top_offset + nargs * UNITS_PER_WORD && REGNO ( reg ) == GP_ARG_FIRST + nargs ) nargs ++ ; else if ( offset == save_offset ) { while ( mips16e_save_restore_regs [ i ++ ] != REGNO ( reg ) ) if ( i == ARRAY_SIZE ( mips16e_save_restore_regs ) ) return false ; mask |= 1 << REGNO ( reg ) ; save_offset -= UNITS_PER_WORD ; } else return false ; } extra = 0 ; mips16e_mask_registers ( & mask , mips16e_s2_s8_regs , ARRAY_SIZE ( mips16e_s2_s8_regs ) , & extra ) ; mips16e_mask_registers ( & mask , mips16e_a0_a3_regs , ARRAY_SIZE ( mips16e_a0_a3_regs ) , & extra ) ; if ( extra != 0 ) return false ; if ( nargs > 0 && BITSET_P ( mask , GP_ARG_FIRST + nargs - 1 ) ) return false ; if ( info ) { info -> nargs = nargs ; info -> mask = mask ; info -> size = ( adjust > 0 ? adjust : - adjust ) ; } return true ; } </s>

PATTERN is a PARALLEL whose first element adds ADJUST to the stack pointer . Return true if PATTERN matches the kind of instruction generated by mips16e_build_save_restore . If INFO is nonnull , initialize it when returning true .


<s> static rtx mips16e_save_restore_reg ( bool restore_p , bool reg_parm_p , HOST_WIDE_INT offset , unsigned int regno ) { rtx reg , mem ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; reg = gen_rtx_REG ( SImode , regno ) ; if ( restore_p ) { mips_add_cfa_restore ( reg ) ; return gen_rtx_SET ( reg , mem ) ; } if ( reg_parm_p ) return gen_rtx_SET ( mem , reg ) ; return mips_frame_set ( mem , reg ) ; } </s>

Return a move between register REGNO and memory location SP + OFFSET . REG_PARM_P is true if SP + OFFSET belongs to REG_PARM_STACK_SPACE . Make the move a load if RESTORE_P , otherwise make it a store .


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

Add constant VALUE to POOL and return its label . MODE is the value 's mode ( used for CONST_INTs , etc . ) .