<s> void mips_expand_synci_loop ( rtx begin , rtx end ) { rtx inc , cmp_result , mask , length ; rtx_code_label * label , * end_label ; end_label = gen_label_rtx ( ) ; cmp_result = gen_rtx_EQ ( VOIDmode , begin , end ) ; emit_jump_insn ( gen_condjump ( cmp_result , end_label ) ) ; inc = gen_reg_rtx ( Pmode ) ; emit_insn ( PMODE_INSN ( gen_rdhwr_synci_step , ( inc ) ) ) ; cmp_result = gen_rtx_EQ ( VOIDmode , inc , const0_rtx ) ; emit_jump_insn ( gen_condjump ( cmp_result , end_label ) ) ; mask = mips_force_unary ( Pmode , NEG , inc ) ; begin = mips_force_binary ( Pmode , AND , begin , mask ) ; length = mips_force_binary ( Pmode , MINUS , end , begin ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; emit_insn ( gen_synci ( begin ) ) ; mips_emit_binary ( MINUS , length , length , inc ) ; mips_emit_binary ( PLUS , begin , begin , inc ) ; cmp_result = gen_rtx_GT ( VOIDmode , length , const0_rtx ) ; emit_jump_insn ( gen_condjump ( cmp_result , label ) ) ; emit_label ( end_label ) ; } </s>

Expand a loop of synci insns for the address range [ BEGIN , END ) .


<s> rtx mips_expand_thread_pointer ( rtx tp ) { rtx fn ; if ( TARGET_MIPS16 ) { if ( ! mips16_rdhwr_stub ) mips16_rdhwr_stub = new mips16_rdhwr_one_only_stub ( ) ; fn = mips16_stub_call_address ( mips16_rdhwr_stub ) ; emit_insn ( PMODE_INSN ( gen_tls_get_tp_mips16 , ( tp , fn ) ) ) ; } else emit_insn ( PMODE_INSN ( gen_tls_get_tp , ( tp ) ) ) ; return tp ; } </s>

Return a pseudo register that contains the current thread pointer .


<s> static void mips_expand_to_rtl_hook ( void ) { mips_set_tuning_info ( ) ; } </s>


<s> void mips_expand_vcondv2sf ( rtx dest , rtx true_src , rtx false_src , enum rtx_code cond , rtx cmp_op0 , rtx cmp_op1 ) { rtx cmp_result ; bool reversed_p ; reversed_p = mips_reversed_fp_cond ( & cond ) ; cmp_result = mips_allocate_fcc ( CCV2mode ) ; emit_insn ( gen_scc_ps ( cmp_result , gen_rtx_fmt_ee ( cond , VOIDmode , cmp_op0 , cmp_op1 ) ) ) ; if ( reversed_p ) emit_insn ( gen_mips_cond_move_tf_ps ( dest , false_src , true_src , cmp_result ) ) ; else emit_insn ( gen_mips_cond_move_tf_ps ( dest , true_src , false_src , cmp_result ) ) ; } </s>

Implement : ( set temp ( COND : CCV2 CMP_OP0 CMP_OP1 ) ) ( set DEST ( unspec [ TRUE_SRC FALSE_SRC temp ] UNSPEC_MOVE_TF_PS ) )


<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_lowpart ( vimode , operands [ 1 ] ) ) ; } 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_lowpart ( vimode , operands [ 2 ] ) ) ; } 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> void mips_expand_vec_minmax ( rtx target , rtx op0 , rtx op1 , rtx ( * cmp ) ( rtx , rtx , rtx ) , bool min_p ) { machine_mode vmode = GET_MODE ( target ) ; rtx tc , t0 , t1 , x ; tc = gen_reg_rtx ( vmode ) ; t0 = gen_reg_rtx ( vmode ) ; t1 = gen_reg_rtx ( vmode ) ; emit_insn ( cmp ( tc , op0 , op1 ) ) ; x = gen_rtx_AND ( vmode , tc , ( min_p ? op1 : op0 ) ) ; emit_insn ( gen_rtx_SET ( t0 , x ) ) ; x = gen_rtx_NOT ( vmode , tc ) ; x = gen_rtx_AND ( vmode , x , ( min_p ? op0 : op1 ) ) ; emit_insn ( gen_rtx_SET ( t1 , x ) ) ; x = gen_rtx_IOR ( vmode , t0 , t1 ) ; emit_insn ( gen_rtx_SET ( target , x ) ) ; } </s>


<s> void mips_expand_vec_reduc ( rtx target , rtx in , rtx ( * gen ) ( rtx , rtx , rtx ) ) { machine_mode vmode = GET_MODE ( in ) ; unsigned char perm2 [ 2 ] ; rtx last , next , fold , x ; bool ok ; last = in ; fold = gen_reg_rtx ( vmode ) ; switch ( vmode ) { case E_V2SFmode : perm2 [ 0 ] = 1 ; perm2 [ 1 ] = 2 ; ok = mips_expand_vselect_vconcat ( fold , last , last , perm2 , 2 ) ; gcc_assert ( ok ) ; break ; case E_V2SImode : emit_insn ( gen_loongson_punpckhwd ( fold , last , last ) ) ; break ; case E_V4HImode : emit_insn ( gen_loongson_punpckhwd_hi ( fold , last , last ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 16 ) ) ; emit_insn ( gen_vec_shr_v4hi ( fold , last , x ) ) ; break ; case E_V8QImode : emit_insn ( gen_loongson_punpckhwd_qi ( fold , last , last ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 16 ) ) ; emit_insn ( gen_vec_shr_v8qi ( fold , last , x ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 8 ) ) ; emit_insn ( gen_vec_shr_v8qi ( fold , last , x ) ) ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( target , last , fold ) ) ; } </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 ( MSA_SUPPORTED_MODE_P ( imode ) ) { switch ( imode ) { case E_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 E_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 E_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 E_V8QImode : if ( high_p ) unpack = gen_loongson_punpckhbh ; else unpack = gen_loongson_punpcklbh ; cmpFunc = gen_loongson_pcmpgtb ; break ; case E_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> static void mips_expand_vi_broadcast ( machine_mode vmode , rtx target , rtx elt ) { struct expand_vec_perm_d d ; rtx t1 ; bool ok ; if ( elt != const0_rtx ) elt = force_reg ( GET_MODE_INNER ( vmode ) , elt ) ; if ( REG_P ( elt ) ) elt = gen_lowpart ( DImode , elt ) ; t1 = gen_reg_rtx ( vmode ) ; switch ( vmode ) { case E_V8QImode : emit_insn ( gen_loongson_vec_init1_v8qi ( t1 , elt ) ) ; break ; case E_V4HImode : emit_insn ( gen_loongson_vec_init1_v4hi ( t1 , elt ) ) ; break ; default : gcc_unreachable ( ) ; } memset ( & d , 0 , sizeof ( d ) ) ; d . target = target ; d . op0 = t1 ; d . op1 = t1 ; d . vmode = vmode ; d . nelt = GET_MODE_NUNITS ( vmode ) ; d . one_vector_p = true ; ok = mips_expand_vec_perm_const_1 ( & d ) ; gcc_assert ( ok ) ; } </s>

A subroutine of mips_expand_vec_init , expand via broadcast .


<s> static void mips_expand_vi_constant ( machine_mode vmode , unsigned nelt , rtx target , rtx vals ) { rtvec vec = shallow_copy_rtvec ( XVEC ( vals , 0 ) ) ; unsigned i ; for ( i = 0 ; i < nelt ; ++ i ) { rtx elem = RTVEC_ELT ( vec , i ) ; if ( ! mips_constant_elt_p ( elem ) ) RTVEC_ELT ( vec , i ) = CONST0_RTX ( GET_MODE ( elem ) ) ; } emit_move_insn ( target , gen_rtx_CONST_VECTOR ( vmode , vec ) ) ; } </s>

A subroutine of mips_expand_vec_init , replacing all of the non-constant elements of VALS with zeros , copy the constant vector to TARGET .


<s> static void mips_expand_vi_general ( machine_mode vmode , machine_mode imode , unsigned nelt , unsigned nvar , rtx target , rtx vals ) { rtx mem = assign_stack_temp ( vmode , GET_MODE_SIZE ( vmode ) ) ; unsigned int i , isize = GET_MODE_SIZE ( imode ) ; if ( nvar < nelt ) mips_expand_vi_constant ( vmode , nelt , mem , vals ) ; for ( i = 0 ; i < nelt ; ++ i ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( ! mips_constant_elt_p ( x ) ) emit_move_insn ( adjust_address ( mem , imode , i * isize ) , x ) ; } emit_move_insn ( target , mem ) ; } </s>

A subroutine of mips_expand_vec_init , expand anything via memory .


<s> static void mips_expand_vi_loongson_one_pinsrh ( rtx target , rtx vals , unsigned one_var ) { mips_expand_vi_constant ( V4HImode , 4 , target , vals ) ; emit_insn ( gen_vec_setv4hi ( target , target , XVECEXP ( vals , 0 , one_var ) , GEN_INT ( one_var ) ) ) ; } </s>

A subroutine of mips_expand_vec_init , expand via pinsrh .


<s> static bool mips_expand_vpc_loongson_bcast ( struct expand_vec_perm_d * d ) { unsigned i , elt ; rtx t0 , t1 ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI ) ) return false ; if ( d -> vmode != V8QImode ) return false ; if ( ! d -> one_vector_p ) return false ; elt = d -> perm [ 0 ] ; for ( i = 1 ; i < 8 ; ++ i ) if ( d -> perm [ i ] != elt ) return false ; if ( d -> testing_p ) return true ; t0 = gen_reg_rtx ( V8QImode ) ; if ( elt < 4 ) emit_insn ( gen_loongson_punpcklbh ( t0 , d -> op0 , d -> op0 ) ) ; else emit_insn ( gen_loongson_punpckhbh ( t0 , d -> op0 , d -> op0 ) ) ; elt &= 3 ; elt *= 0x55 ; t1 = gen_reg_rtx ( V4HImode ) ; emit_insn ( gen_loongson_pshufh ( t1 , gen_lowpart ( V4HImode , t0 ) , force_reg ( SImode , GEN_INT ( elt ) ) ) ) ; emit_move_insn ( d -> target , gen_lowpart ( V8QImode , t1 ) ) ; return true ; } </s>

Recognize broadcast patterns for the Loongson .


<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_MMI ) ) 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_expand_vpc_loongson_pshufh ( struct expand_vec_perm_d * d ) { unsigned i , mask ; rtx rmask ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI ) ) 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_expand_vselect ( rtx target , rtx op0 , const unsigned char * perm , unsigned nelt ) { rtx rperm [ MAX_VECT_LEN ] , x ; rtx_insn * insn ; unsigned i ; for ( i = 0 ; i < nelt ; ++ i ) rperm [ i ] = GEN_INT ( perm [ i ] ) ; x = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( nelt , rperm ) ) ; x = gen_rtx_VEC_SELECT ( GET_MODE ( target ) , op0 , x ) ; x = gen_rtx_SET ( target , x ) ; insn = emit_insn ( x ) ; if ( recog_memoized ( insn ) < 0 ) { remove_insn ( insn ) ; return false ; } return true ; } </s>

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


<s> static bool mips_expand_vselect_vconcat ( rtx target , rtx op0 , rtx op1 , const unsigned char * perm , unsigned nelt ) { machine_mode v2mode ; rtx x ; if ( ! GET_MODE_2XWIDER_MODE ( GET_MODE ( op0 ) ) . exists ( & v2mode ) ) return false ; x = gen_rtx_VEC_CONCAT ( v2mode , op0 , op1 ) ; return mips_expand_vselect ( target , x , perm , nelt ) ; } </s>

Similar , but generate a vec_concat from op0 and op1 as well .


<s> static void mips_extra_live_on_entry ( bitmap regs ) { if ( TARGET_USE_GOT ) { if ( ! TARGET_ABSOLUTE_ABICALLS ) bitmap_set_bit ( regs , PIC_FUNCTION_ADDR_REGNUM ) ; if ( TARGET_MIPS16 ) bitmap_set_bit ( regs , MIPS16_PIC_TEMP_REGNUM ) ; bitmap_set_bit ( regs , GOT_VERSION_REGNUM ) ; } } </s>


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


<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_" , INTVAL ( XVECEXP ( PATTERN ( insn ) , 0 , 0 ) ) , FALSE ) ; if ( mips_need_noat_wrapper_p ( insn , opvec , noperands ) ) mips_push_asm_switch ( & mips_noat ) ; } </s>


<s> static bool mips_find_gp_ref ( bool * cache , bool ( * pred ) ( rtx_insn * ) ) { rtx_insn * insn , * subinsn ; if ( ! * cache ) { push_topmost_sequence ( ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) FOR_EACH_SUBINSN ( subinsn , insn ) if ( USEFUL_INSN_P ( subinsn ) && pred ( subinsn ) ) { * cache = true ; break ; } pop_topmost_sequence ( ) ; } return * cache ; } </s>

Return true if predicate PRED is true for at least one instruction . Cache the result in * CACHE , and assume that the result is true if * CACHE is already true .


<s> static rtx mips_find_pic_call_symbol ( rtx_insn * insn , rtx reg , bool recurse_p ) { df_ref use ; struct df_link * defs ; rtx symbol ; use = df_find_use ( insn , regno_reg_rtx [ REGNO ( reg ) ] ) ; if ( ! use ) return NULL_RTX ; defs = DF_REF_CHAIN ( use ) ; if ( ! defs ) return NULL_RTX ; symbol = mips_pic_call_symbol_from_set ( defs -> ref , reg , recurse_p ) ; if ( ! symbol ) return NULL_RTX ; for ( defs = defs -> next ; defs ; defs = defs -> next ) { rtx other ; other = mips_pic_call_symbol_from_set ( defs -> ref , reg , recurse_p ) ; if ( ! rtx_equal_p ( symbol , other ) ) return NULL_RTX ; } return symbol ; } </s>

Find the definition of the use of REG in INSN . See if the definition is one of the ways we load a register with a symbol address for a mips_use_pic_fn_addr_reg_p call . If it is return the symbol reference of the function , otherwise return NULL_RTX . RECURSE_P is as for mips_pic_call_symbol_from_set .


<s> void mips_finish_declare_object ( FILE * stream , tree decl , int top_level , int at_end ) { const char * name ; name = XSTR ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) ; if ( ! flag_inhibit_size_directive && DECL_SIZE ( decl ) != 0 && ! at_end && top_level && DECL_INITIAL ( decl ) == error_mark_node && ! size_directive_output ) { HOST_WIDE_INT size ; size_directive_output = 1 ; size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; ASM_OUTPUT_SIZE_DIRECTIVE ( stream , name , size ) ; } } </s>

Implement ASM_FINISH_DECLARE_OBJECT . This is generic ELF stuff .


<s> static void mips_finish_stub ( mips_one_only_stub * * stub_ptr ) { mips_one_only_stub * stub = * stub_ptr ; if ( ! stub ) return ; const char * name = stub -> get_name ( ) ; mips_start_unique_function ( name ) ; mips_start_function_definition ( name , false ) ; stub -> output_body ( ) ; mips_end_function_definition ( name ) ; delete stub ; * stub_ptr = 0 ; } </s>

If * STUB_PTR points to a stub , output a comdat-style definition for it , then free * STUB_PTR .


Return true if destination of IN_INSN is used as add source in OUT_INSN . Both IN_INSN and OUT_INSN are of type fmadd . Example : madd.s dst , x , y , z madd.s a , dst , b , c


<s> static rtx mips_force_address ( rtx x , machine_mode mode ) { if ( ! mips_legitimate_address_p ( mode , x , false ) ) x = force_reg ( Pmode , x ) ; return x ; } </s>

If X is not a valid address for mode MODE , force it into a register .


<s> static rtx mips_force_binary ( machine_mode mode , enum rtx_code code , rtx op0 , rtx op1 ) { rtx reg ; reg = gen_reg_rtx ( mode ) ; mips_emit_binary ( code , reg , op0 , op1 ) ; return reg ; } </s>

Compute ( CODE OP0 OP1 ) and store the result in a new register of mode MODE . Return that new register .


<s> static rtx mips_force_temporary ( rtx dest , rtx value ) { if ( can_create_pseudo_p ( ) ) return force_reg ( Pmode , value ) ; else { mips_emit_move ( dest , value ) ; return dest ; } } </s>

Copy VALUE to a register and return that register . If new psuedos are allowed , copy it into a new register , otherwise use DEST .


<s> static rtx mips_force_unary ( machine_mode mode , enum rtx_code code , rtx op0 ) { rtx reg ; reg = gen_reg_rtx ( mode ) ; mips_emit_unary ( code , reg , op0 ) ; return reg ; } </s>

Compute ( CODE OP0 ) and store the result in a new register of mode MODE . Return that new register .


<s> static void mips_for_each_saved_acc ( HOST_WIDE_INT sp_offset , mips_save_restore_fn fn ) { HOST_WIDE_INT offset ; int regno ; offset = cfun -> machine -> frame . acc_sp_offset - sp_offset ; if ( BITSET_P ( cfun -> machine -> frame . acc_mask , 0 ) ) { mips_save_restore_reg ( word_mode , LO_REGNUM , offset , fn ) ; offset -= UNITS_PER_WORD ; mips_save_restore_reg ( word_mode , HI_REGNUM , offset , fn ) ; offset -= UNITS_PER_WORD ; } for ( regno = DSP_ACC_REG_FIRST ; regno <= DSP_ACC_REG_LAST ; regno ++ ) if ( BITSET_P ( cfun -> machine -> frame . acc_mask , ( ( regno - DSP_ACC_REG_FIRST ) / 2 ) + 1 ) ) { mips_save_restore_reg ( word_mode , regno , offset , fn ) ; offset -= UNITS_PER_WORD ; } } </s>

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


<s> static void mips_for_each_saved_gpr_and_fpr ( HOST_WIDE_INT sp_offset , mips_save_restore_fn fn ) { machine_mode fpr_mode ; int regno ; const struct mips_frame_info * frame = & cfun -> machine -> frame ; HOST_WIDE_INT offset ; unsigned int mask ; offset = frame -> gp_sp_offset - sp_offset ; mask = frame -> mask ; if ( TARGET_MICROMIPS ) umips_build_save_restore ( fn , & mask , & offset ) ; for ( regno = GP_REG_LAST ; regno >= GP_REG_FIRST ; regno -- ) if ( BITSET_P ( mask , regno - GP_REG_FIRST ) ) { if ( regno == RETURN_ADDR_REGNUM ) cfun -> machine -> frame . ra_fp_offset = offset + sp_offset ; mips_save_restore_reg ( word_mode , regno , offset , fn ) ; offset -= UNITS_PER_WORD ; } offset = cfun -> machine -> frame . fp_sp_offset - sp_offset ; fpr_mode = ( TARGET_SINGLE_FLOAT ? SFmode : DFmode ) ; for ( regno = FP_REG_LAST - MAX_FPRS_PER_FMT + 1 ; regno >= FP_REG_FIRST ; regno -= MAX_FPRS_PER_FMT ) if ( BITSET_P ( cfun -> machine -> frame . fmask , regno - FP_REG_FIRST ) ) { if ( ! TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT && ( fixed_regs [ regno ] || fixed_regs [ regno + 1 ] ) ) { if ( fixed_regs [ regno ] ) mips_save_restore_reg ( SFmode , regno + 1 , offset , fn ) ; else mips_save_restore_reg ( SFmode , regno , offset , fn ) ; } else mips_save_restore_reg ( fpr_mode , regno , offset , fn ) ; offset -= GET_MODE_SIZE ( fpr_mode ) ; } } </s>

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


<s> static int mips_fpr_return_fields ( const_tree valtype , tree * fields , bool * has_cxx_zero_width_bf , bool * has_cxx17_empty_base ) { tree field ; int i ; if ( ! TARGET_NEWABI ) return 0 ; if ( TREE_CODE ( valtype ) != RECORD_TYPE ) return 0 ; i = 0 ; for ( field = TYPE_FIELDS ( valtype ) ; field != 0 ; field = DECL_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( cxx17_empty_base_field_p ( field ) ) { * has_cxx17_empty_base = true ; continue ; } if ( DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD ( field ) ) { * has_cxx_zero_width_bf = true ; continue ; } if ( ! SCALAR_FLOAT_TYPE_P ( TREE_TYPE ( field ) ) ) return 0 ; if ( i == 2 ) return 0 ; fields [ i ++ ] = field ; } return i ; } </s>

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


<s> static int mips_fp_div_cost ( machine_mode mode ) { return mode == DFmode ? mips_cost -> fp_div_df : mips_cost -> fp_div_sf ; } </s>

Return the cost of floating-point divisions of mode MODE .


<s> static int mips_fp_mult_cost ( machine_mode mode ) { return mode == DFmode ? mips_cost -> fp_mult_df : mips_cost -> fp_mult_sf ; } </s>

Return the cost of floating-point multiplications of mode MODE .


<s> static void mips_frame_barrier ( void ) { emit_clobber ( gen_frame_mem ( BLKmode , stack_pointer_rtx ) ) ; } </s>

Emit an optimisation barrier for accesses to the current frame .


<s> static bool mips_frame_pointer_required ( void ) { if ( cfun -> calls_alloca ) return true ; if ( TARGET_MIPS16 ) { mips_compute_frame_info ( ) ; if ( ! SMALL_OPERAND ( cfun -> machine -> frame . total_size ) ) return true ; } return false ; } </s>


<s> static rtx mips_frame_set ( rtx mem , rtx reg ) { rtx set ; set = gen_rtx_SET ( mem , reg ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; return set ; } </s>

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


<s> static void mips_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; struct mips_arg_info info ; mips_get_arg_info ( & info , cum , arg . mode , arg . type , arg . named ) ; if ( ! info . fpr_p ) cum -> gp_reg_found = true ; if ( cum -> arg_number < 2 && info . fpr_p ) cum -> fp_code += ( arg . mode == SFmode ? 1 : 2 ) << ( cum -> arg_number * 2 ) ; if ( mips_abi != ABI_EABI || ! info . fpr_p ) cum -> num_gprs = info . reg_offset + info . reg_words ; else if ( info . reg_words > 0 ) cum -> num_fprs += MAX_FPRS_PER_FMT ; if ( info . stack_words > 0 ) cum -> stack_words = info . stack_offset + info . stack_words ; cum -> arg_number ++ ; } </s>


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

Implement TARGET_FUNCTION_ARG_BOUNDARY . Every parameter gets at least PARM_BOUNDARY bits of alignment , but will be given anything up to STACK_BOUNDARY bits if the type requires it .


<s> static pad_direction mips_function_arg_padding ( machine_mode mode , const_tree type ) { if ( ! BYTES_BIG_ENDIAN ) return PAD_UPWARD ; 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 PAD_DOWNWARD ; if ( mips_abi == ABI_O64 ) if ( type != 0 ? FLOAT_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_FLOAT ) return PAD_DOWNWARD ; if ( mips_abi != ABI_EABI ) return PAD_UPWARD ; if ( mode != BLKmode ? GET_MODE_BITSIZE ( mode ) >= PARM_BOUNDARY : int_size_in_bytes ( type ) >= ( PARM_BOUNDARY / BITS_PER_UNIT ) ) return PAD_UPWARD ; return PAD_DOWNWARD ; } </s>

Implement TARGET_FUNCTION_ARG_PADDING ; return PAD_UPWARD if the first byte of the stack slot has useful data , PAD_DOWNWARD if the last byte does .


<s> static bool mips_function_ok_for_sibcall ( tree decl , tree exp ATTRIBUTE_UNUSED ) { if ( ! TARGET_SIBCALLS ) return false ; if ( mips_interrupt_type_p ( TREE_TYPE ( current_function_decl ) ) ) return false ; if ( decl && const_call_insn_operand ( XEXP ( DECL_RTL ( decl ) , 0 ) , VOIDmode ) && mips_call_may_need_jalx_p ( decl ) ) return false ; if ( decl && TARGET_CALL_SAVED_GP && ! TARGET_ABICALLS_PIC0 && ! targetm . binds_local_p ( decl ) ) return false ; return true ; } </s>

We can handle any sibcall when TARGET_SIBCALLS is true .


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

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


<s> static rtx mips_function_value ( const_tree valtype , const_tree fn_decl_or_type , bool outgoing ATTRIBUTE_UNUSED ) { return mips_function_value_1 ( valtype , fn_decl_or_type , VOIDmode ) ; } </s>

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


"the ABI for returning a value containing "

"zero-width bit-fields but otherwise an aggregate "

"with only one or two floating-point fields was "

"the ABI for returning a value with C++17 empty "

"bases but otherwise an aggregate with only one or "

"two floating-point fields was changed in GCC "

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


<s> static bool mips_function_value_regno_p ( const unsigned int regno ) { if ( regno == GP_RETURN || regno == FP_RETURN || ( FP_RETURN != GP_RETURN && regno == FP_RETURN + 2 ) ) return true ; if ( ( mips_abi == ABI_32 && TARGET_FLOAT32 ) && FP_RETURN != GP_RETURN && ( regno == FP_RETURN + 1 || regno == FP_RETURN + 3 ) ) return true ; return false ; } </s>

Implement TARGET_FUNCTION_VALUE_REGNO_P . On the MIPS , R2 R3 and F0 F2 are the only register thus used .


<s> rtx mips_gen_const_int_vector ( machine_mode mode , HOST_WIDE_INT val ) { rtx c = gen_int_mode ( val , GET_MODE_INNER ( mode ) ) ; return gen_const_vec_duplicate ( mode , c ) ; } </s>

Return a const_int vector of VAL with mode MODE .


<s> static rtx mips_gen_const_int_vector_shuffle ( machine_mode mode , int val ) { int nunits = GET_MODE_NUNITS ( mode ) ; int nsets = nunits / 4 ; rtx elts [ MAX_VECT_LEN ] ; int set = 0 ; int i , j ; for ( j = 0 ; j < nsets ; j ++ , set = 4 * j ) for ( i = 0 ; i < 4 ; i ++ ) elts [ set + i ] = GEN_INT ( set + ( ( val >> ( 2 * i ) ) & 0x3 ) ) ; return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( nunits , elts ) ) ; } </s>

Return a vector of repeated 4-element sets generated from immediate VAL in mode MODE .


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

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


<s> static unsigned int mips_get_compress_mode ( tree decl ) { unsigned int flags , force_on ; flags = mips_base_compression_flags ; if ( decl ) { tree parent = decl_function_context ( decl ) ; if ( parent ) decl = parent ; force_on = mips_get_compress_on_flags ( DECL_ATTRIBUTES ( decl ) ) ; if ( force_on ) return force_on ; flags &= ~ mips_get_compress_off_flags ( DECL_ATTRIBUTES ( decl ) ) ; } return flags ; } </s>

Return the compression mode that should be used for function DECL . Return the ambient setting if DECL is null .


<s> static unsigned int mips_get_compress_off_flags ( tree attributes ) { unsigned int flags = 0 ; if ( lookup_attribute ( "nocompression" , attributes ) != NULL ) flags |= MASK_MIPS16 | MASK_MICROMIPS ; if ( lookup_attribute ( "nomips16" , attributes ) != NULL ) flags |= MASK_MIPS16 ; if ( lookup_attribute ( "nomicromips" , attributes ) != NULL ) flags |= MASK_MICROMIPS ; return flags ; } </s>

Return the set of compression modes that are explicitly forbidden by the attributes in ATTRIBUTES .


<s> static const char * mips_get_compress_off_name ( unsigned int flags ) { if ( flags == MASK_MIPS16 ) return "nomips16" ; if ( flags == MASK_MICROMIPS ) return "nomicromips" ; return "nocompression" ; } </s>

Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS flags FLAGS .

mips "nomips16" "nomicromips" "nocompression"


<s> static unsigned int mips_get_compress_on_flags ( tree attributes ) { unsigned int flags = 0 ; if ( lookup_attribute ( "mips16" , attributes ) != NULL ) flags |= MASK_MIPS16 ; if ( lookup_attribute ( "micromips" , attributes ) != NULL ) flags |= MASK_MICROMIPS ; return flags ; } </s>

Return the set of compression modes that are explicitly required by the attributes in ATTRIBUTES .


<s> static const char * mips_get_compress_on_name ( unsigned int flags ) { if ( flags == MASK_MIPS16 ) return "mips16" ; return "micromips" ; } </s>

Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS flags FLAGS .


<s> static void mips_get_cprestore_base_and_offset ( rtx * base , HOST_WIDE_INT * offset , bool load_p ) { const struct mips_frame_info * frame ; frame = & cfun -> machine -> frame ; if ( frame_pointer_needed && ! ( TARGET_CPRESTORE_DIRECTIVE && ! load_p ) ) { * base = hard_frame_pointer_rtx ; * offset = frame -> args_size - frame -> hard_frame_pointer_offset ; } else { * base = stack_pointer_rtx ; * offset = frame -> args_size ; } } </s>

Fill * BASE and * OFFSET such that * BASE + * OFFSET refers to the cprestore slot . LOAD_P is true if the caller wants to load from the cprestore slot ; it is false if the caller wants to store to the slot .


<s> bool mips_get_pic_call_symbol ( rtx * operands , int args_size_opno ) { rtx args_size , symbol ; if ( ! TARGET_RELAX_PIC_CALLS || args_size_opno == - 1 ) return false ; args_size = operands [ args_size_opno ] ; if ( GET_CODE ( args_size ) != UNSPEC ) return false ; gcc_assert ( XINT ( args_size , 1 ) == UNSPEC_CALL_ATTR ) ; symbol = XVECEXP ( args_size , 0 , 1 ) ; gcc_assert ( GET_CODE ( symbol ) == SYMBOL_REF ) ; operands [ args_size_opno ] = symbol ; return true ; } </s>

OPERANDS [ ARGS_SIZE_OPNO ] is the arg_size operand of a CALL expression . See if instead of the arg_size argument it contains the call attributes . If yes return true along with setting OPERANDS [ ARGS_SIZE_OPNO ] to the function symbol from the call attributes . Also return false if ARGS_SIZE_OPNO is -1 .


<s> static fixed_size_mode mips_get_reg_raw_mode ( int regno ) { if ( TARGET_FLOATXX && FP_REG_P ( regno ) ) return DFmode ; return default_get_reg_raw_mode ( regno ) ; } </s>


<s> static rtx mips_get_sync_operand ( rtx * operands , int index , rtx default_value ) { if ( index > 0 ) default_value = operands [ index - 1 ] ; return default_value ; } </s>

OPERANDS are the operands to a sync loop instruction and INDEX is the value of the one of the sync_ * attributes . Return the operand referred to by the attribute , or DEFAULT_VALUE if the insn does n't have the associated attribute .


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

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


<s> static unsigned int mips_global_pointer ( void ) { unsigned int regno ; if ( ! TARGET_USE_GOT ) return GLOBAL_POINTER_REGNUM ; if ( mips_cfun_has_inflexible_gp_ref_p ( ) ) return GLOBAL_POINTER_REGNUM ; if ( TARGET_ABSOLUTE_JUMPS && ! mips_cfun_has_flexible_gp_ref_p ( ) ) return INVALID_REGNUM ; if ( TARGET_CALL_SAVED_GP && crtl -> is_leaf ) for ( regno = GP_REG_FIRST ; regno <= GP_REG_LAST ; regno ++ ) if ( ! df_regs_ever_live_p ( regno ) && call_used_regs [ regno ] && ! fixed_regs [ regno ] && regno != PIC_FUNCTION_ADDR_REGNUM ) return regno ; return GLOBAL_POINTER_REGNUM ; } </s>

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


<s> static bool mips_global_symbol_p ( const_rtx x ) { const_tree decl = SYMBOL_REF_DECL ( x ) ; if ( ! decl ) return ! SYMBOL_REF_LOCAL_P ( x ) || SYMBOL_REF_EXTERNAL_P ( x ) ; return DECL_P ( decl ) && ( TREE_PUBLIC ( decl ) || DECL_WEAK ( decl ) ) ; } </s>

Return true if SYMBOL_REF X is associated with a global symbol ( in the STB_GLOBAL sense ) .


<s> rtx mips_got_load ( rtx temp , rtx addr , enum mips_symbol_type type ) { rtx base , high , lo_sum_symbol ; base = mips_pic_base_register ( temp ) ; if ( temp != NULL && reg_overlap_mentioned_p ( base , temp ) ) temp = NULL ; high = mips_unspec_offset_high ( temp , base , addr , type ) ; lo_sum_symbol = mips_unspec_address ( addr , type ) ; if ( type == SYMBOL_GOTOFF_CALL ) return mips_unspec_call ( high , lo_sum_symbol ) ; else return PMODE_INSN ( gen_unspec_got , ( high , lo_sum_symbol ) ) ; } </s>

Create and return a GOT reference of type TYPE for address ADDR . TEMP , if nonnull , is a scratch Pmode base register .


<s> static bool mips_got_symbol_type_p ( enum mips_symbol_type type ) { switch ( type ) { case SYMBOL_GOT_PAGE_OFST : case SYMBOL_GOT_DISP : return true ; default : return false ; } } </s>

Return true if symbols of type TYPE require a GOT access .


<s> machine_mode mips_hard_regno_caller_save_mode ( unsigned int regno , unsigned int nregs , machine_mode mode ) { if ( mode == VOIDmode ) return choose_hard_reg_mode ( regno , nregs , NULL ) ; else return mode ; } </s>


<s> static bool mips_hard_regno_call_part_clobbered ( unsigned int , 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 ( unsigned int regno , machine_mode mode ) { return mips_hard_regno_mode_ok_p [ mode ] [ regno ] ; } </s>


<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_MMI && ( 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> static unsigned int mips_hard_regno_nregs ( unsigned 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> bool mips_hard_regno_rename_ok ( unsigned int old_reg ATTRIBUTE_UNUSED , unsigned int new_reg ) { if ( cfun -> machine -> interrupt_handler_p && ! df_regs_ever_live_p ( new_reg ) ) return false ; return true ; } </s>

Return nonzero if register OLD_REG can be renamed to register NEW_REG .


<s> bool mips_hard_regno_scratch_ok ( unsigned int regno ) { if ( cfun -> machine -> interrupt_handler_p && ! df_regs_ever_live_p ( regno ) ) return false ; return true ; } </s>

Return nonzero if register REGNO can be used as a scratch register in peephole2 .


<s> static hashval_t mips_hash_base ( rtx base ) { int do_not_record_p ; return hash_rtx ( base , GET_MODE ( base ) , & do_not_record_p , NULL , false ) ; } </s>

Return a hash value for SYMBOL_REF or LABEL_REF BASE .


<s> static bool mips_has_long_branch_p ( void ) { rtx_insn * insn , * subinsn ; int normal_length ; shorten_branches ( get_insns ( ) ) ; normal_length = ( TARGET_MIPS16 ? 4 : 8 ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) FOR_EACH_SUBINSN ( subinsn , insn ) if ( JUMP_P ( subinsn ) && get_attr_length ( subinsn ) > normal_length && ( any_condjump_p ( subinsn ) || any_uncondjump_p ( subinsn ) ) ) return true ; return false ; } </s>

Return true if the function has a long branch instruction .


<s> int mips_idiv_insns ( machine_mode mode ) { int count ; count = 1 ; if ( TARGET_CHECK_ZERO_DIV ) { if ( GENERATE_DIVIDE_TRAPS && ! MSA_SUPPORTED_MODE_P ( mode ) ) count ++ ; else count += 2 ; } if ( TARGET_FIX_R4000 || TARGET_FIX_R4400 ) count ++ ; return count ; } </s>

Return the number of instructions needed for an integer division .


<s> static int mips_immediate_operand_p ( int code , HOST_WIDE_INT x ) { switch ( code ) { case ASHIFT : case ASHIFTRT : case LSHIFTRT : return true ; case ROTATE : case ROTATERT : return ISA_HAS_ROR ; case AND : case IOR : case XOR : return SMALL_OPERAND_UNSIGNED ( x ) ; case PLUS : case LT : case LTU : return SMALL_OPERAND ( x ) ; case EQ : case NE : case GT : case GTU : return x == 0 ; case GE : case GEU : return x == 1 ; case LE : return SMALL_OPERAND ( x + 1 ) ; case LEU : return SMALL_OPERAND ( x + 1 ) && x + 1 != 0 ; case SIGN_EXTRACT : case ZERO_EXTRACT : return ISA_HAS_EXT_INS ; default : return x == 0 ; } } </s>

Return true if there is a non-MIPS16 instruction that implements CODE and if that instruction accepts X as an immediate operand .


<s> HOST_WIDE_INT mips_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT offset ; mips_compute_frame_info ( ) ; switch ( from ) { case FRAME_POINTER_REGNUM : if ( FRAME_GROWS_DOWNWARD ) offset = ( cfun -> machine -> frame . args_size + cfun -> machine -> frame . cprestore_size + cfun -> machine -> frame . var_size ) ; else offset = 0 ; break ; case ARG_POINTER_REGNUM : offset = cfun -> machine -> frame . arg_pointer_offset ; break ; default : gcc_unreachable ( ) ; } if ( to == HARD_FRAME_POINTER_REGNUM ) offset -= cfun -> machine -> frame . hard_frame_pointer_offset ; return offset ; } </s>

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


<s> static void mips_init_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 ) ; if ( mips_builtin_decls [ i ] && d -> is_pure ) DECL_PURE_P ( mips_builtin_decls [ i ] ) = 1 ; mips_get_builtin_decl_index [ d -> icode ] = i ; } } } </s>

Init builtin functions . This is called from TARGET_INIT_BUILTIN .


<s> void mips_init_cumulative_args ( CUMULATIVE_ARGS * cum , tree fntype ) { memset ( cum , 0 , sizeof ( * cum ) ) ; cum -> prototype = ( fntype && prototype_p ( fntype ) ) ; cum -> gp_reg_found = ( cum -> prototype && stdarg_p ( fntype ) ) ; } </s>

Initialize * CUM for a call to a function of type FNTYPE .


<s> static void mips_init_dfa_post_cycle_insn ( void ) { if ( TUNE_LOONGSON_2EF ) mips_ls2_init_dfa_post_cycle_insn ( ) ; } </s>

Implement TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN hook . Init data used in mips_dfa_post_advance_cycle .


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


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

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


<s> static void mips_init_print_operand_punct ( void ) { const char * p ; for ( p = "()[]<>*#/?~.@^+$:!" ; * p ; p ++ ) mips_print_operand_punct [ ( unsigned char ) * p ] = true ; } </s>


"%qs attribute only applies to functions"

"%qE cannot have both %qs and %qs attributes"


<s> static void mips_insert_insn_pseudos ( void ) { bool insn_pseudo_needed = TRUE ; rtx_insn * insn ; for ( insn = get_last_insn ( ) ; insn != NULL_RTX ; insn = PREV_INSN ( insn ) ) switch ( GET_CODE ( insn ) ) { case INSN : if ( GET_CODE ( PATTERN ( insn ) ) == UNSPEC_VOLATILE && XINT ( PATTERN ( insn ) , 1 ) == UNSPEC_CONSTTABLE ) { insn_pseudo_needed = TRUE ; break ; } case JUMP_INSN : case CALL_INSN : case JUMP_TABLE_DATA : insn_pseudo_needed = FALSE ; break ; case CODE_LABEL : if ( insn_pseudo_needed ) { emit_insn_after ( gen_insn_pseudo ( ) , insn ) ; insn_pseudo_needed = FALSE ; } break ; default : break ; } } </s>

Insert a ` .insn ' assembly pseudo-op after any labels followed by a MIPS16 constant pool or no insn at all . This is needed so that targets that have been optimized away are still marked as code and therefore branches that remained and point to them are known to retain the ISA mode and as such can be successfully assembled .


<s> static bool mips_insn_has_flexible_gp_ref_p ( rtx_insn * insn ) { return ( get_attr_got ( insn ) != GOT_UNSET || mips_small_data_pattern_p ( PATTERN ( insn ) ) || reg_overlap_mentioned_p ( pic_offset_table_rtx , PATTERN ( insn ) ) ) ; } </s>

Return true if INSN refers to the global pointer in a `` flexible '' way . See mips_cfun_has_flexible_gp_ref_p for details .


<s> static bool mips_insn_has_inflexible_gp_ref_p ( rtx_insn * insn ) { return find_reg_fusage ( insn , USE , pic_offset_table_rtx ) ; } </s>

Return true if INSN refers to the global pointer in an `` inflexible '' way . See mips_cfun_has_inflexible_gp_ref_p for details .


<s> static enum mips_split_type mips_insn_split_type ( rtx insn ) { basic_block bb = BLOCK_FOR_INSN ( insn ) ; if ( bb ) { if ( optimize_bb_for_speed_p ( bb ) ) return SPLIT_FOR_SPEED ; else return SPLIT_FOR_SIZE ; } return SPLIT_IF_NECESSARY ; } </s>

Return the split type for instruction INSN .


<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_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 enum mips_int_mask mips_interrupt_mask ( tree type ) { tree attr = lookup_attribute ( "interrupt" , TYPE_ATTRIBUTES ( type ) ) ; tree args , cst ; const char * str ; if ( attr == NULL ) return INT_MASK_EIC ; args = TREE_VALUE ( attr ) ; if ( args == NULL ) return INT_MASK_EIC ; cst = TREE_VALUE ( args ) ; if ( strcmp ( TREE_STRING_POINTER ( cst ) , "eic" ) == 0 ) return INT_MASK_EIC ; str = TREE_STRING_POINTER ( cst ) ; gcc_assert ( strlen ( str ) == strlen ( "vector=sw0" ) ) ; if ( str [ 7 ] == 's' ) return ( enum mips_int_mask ) ( INT_MASK_SW0 + ( str [ 9 ] - '0' ) ) ; return ( enum mips_int_mask ) ( INT_MASK_HW0 + ( str [ 9 ] - '0' ) ) ; } </s>

Return the mask for the `` interrupt '' attribute .


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

Check if the interrupt attribute is set for a function .


<s> static bool mips_int_order_operand_ok_p ( enum rtx_code code , rtx cmp1 ) { switch ( code ) { case GT : case GTU : return reg_or_0_operand ( cmp1 , VOIDmode ) ; case GE : case GEU : return ! TARGET_MIPS16 && cmp1 == const1_rtx ; case LT : case LTU : return arith_operand ( cmp1 , VOIDmode ) ; case LE : return sle_operand ( cmp1 , VOIDmode ) ; case LEU : return sleu_operand ( cmp1 , VOIDmode ) ; default : gcc_unreachable ( ) ; } } </s>

Return true if CMP1 is a suitable second operand for integer ordering test CODE . See also the * sCC patterns in mips.md .


<s> static bool mips_in_small_data_p ( const_tree decl ) { unsigned HOST_WIDE_INT size ; if ( TREE_CODE ( decl ) == STRING_CST || TREE_CODE ( decl ) == FUNCTION_DECL ) return false ; if ( TARGET_ABICALLS || TARGET_VXWORKS_RTP ) return false ; if ( TREE_CODE ( decl ) == VAR_DECL && DECL_SECTION_NAME ( decl ) != 0 ) { const char * name ; name = DECL_SECTION_NAME ( decl ) ; if ( strcmp ( name , ".sdata" ) != 0 && strcmp ( name , ".sbss" ) != 0 ) return false ; if ( mips_lo_relocs [ SYMBOL_GP_RELATIVE ] || ! DECL_EXTERNAL ( decl ) ) return true ; } else if ( TARGET_EMBEDDED_DATA ) { if ( TREE_CODE ( decl ) != VAR_DECL ) return false ; if ( TREE_READONLY ( decl ) && ! TREE_SIDE_EFFECTS ( decl ) && ( ! DECL_INITIAL ( decl ) || TREE_CONSTANT ( DECL_INITIAL ( decl ) ) ) ) return false ; } if ( ! TARGET_LOCAL_SDATA && ! TREE_PUBLIC ( decl ) ) return false ; if ( ! TARGET_EXTERN_SDATA && DECL_P ( decl ) ) { if ( DECL_EXTERNAL ( decl ) ) return false ; if ( DECL_COMMON ( decl ) && DECL_INITIAL ( decl ) == NULL ) return false ; } size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; return size > 0 && size <= mips_small_data_threshold ; } </s>

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


<s> static int mips_issue_rate ( void ) { switch ( mips_tune ) { case PROCESSOR_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 : case PROCESSOR_GS264E : return 2 ; case PROCESSOR_SB1 : case PROCESSOR_SB1A : return 3 ; case PROCESSOR_LOONGSON_2E : case PROCESSOR_LOONGSON_2F : case PROCESSOR_GS464 : case PROCESSOR_GS464E : case PROCESSOR_P5600 : case PROCESSOR_P6600 : 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 bool mips_keep_interrupts_masked_p ( tree type ) { return lookup_attribute ( "keep_interrupts_masked" , TYPE_ATTRIBUTES ( type ) ) != NULL ; } </s>

Check if the attribute to keep interrupts masked is set for a function .


<s> int mips_ldst_scaled_shift ( machine_mode mode ) { int shift = exact_log2 ( GET_MODE_UNIT_SIZE ( mode ) ) ; if ( shift < 0 || shift > 8 ) gcc_unreachable ( ) ; return shift ; } </s>

Return the scale shift that applied to MSA LD/ST address offset .


<s> static bool mips_legitimate_address_p ( machine_mode mode , rtx x , bool strict_p ) { struct mips_address_info addr ; return mips_classify_address ( & addr , x , mode , strict_p ) ; } </s>

This function is used to implement GO_IF_LEGITIMATE_ADDRESS . It returns a nonzero value if X is a legitimate address for a memory operand of the indicated MODE . STRICT is nonzero if this function is called during reload .


<s> static bool mips_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { return mips_const_insns ( x ) > 0 ; } </s>


<s> static rtx mips_legitimize_address ( rtx x , rtx oldx ATTRIBUTE_UNUSED , machine_mode mode ) { rtx base , addr ; HOST_WIDE_INT offset ; if ( mips_tls_symbol_p ( x ) ) return mips_legitimize_tls_address ( x ) ; if ( mips_split_symbol ( NULL , x , mode , & addr ) ) return mips_force_address ( addr , mode ) ; mips_split_plus ( x , & base , & offset ) ; if ( offset != 0 ) { if ( ! mips_valid_base_register_p ( base , mode , false ) ) base = copy_to_mode_reg ( Pmode , base ) ; addr = mips_add_offset ( NULL , base , offset ) ; return mips_force_address ( addr , mode ) ; } return x ; } </s>

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


<s> static void mips_legitimize_const_move ( machine_mode mode , rtx dest , rtx src ) { rtx base , offset ; if ( splittable_const_int_operand ( src , mode ) ) { mips_move_integer ( dest , dest , INTVAL ( src ) ) ; return ; } if ( mips_split_symbol ( dest , src , MAX_MACHINE_MODE , & src ) ) { emit_insn ( gen_rtx_SET ( dest , src ) ) ; return ; } if ( mips_tls_symbol_p ( src ) ) { mips_emit_move ( dest , mips_legitimize_tls_address ( src ) ) ; return ; } split_const ( src , & base , & offset ) ; if ( offset != const0_rtx && ( targetm . cannot_force_const_mem ( mode , src ) || ( ! TARGET_MIPS16 && can_create_pseudo_p ( ) ) ) ) { base = mips_force_temporary ( dest , base ) ; mips_emit_move ( dest , mips_add_offset ( NULL , base , INTVAL ( offset ) ) ) ; return ; } src = force_const_mem ( mode , src ) ; mips_split_symbol ( dest , XEXP ( src , 0 ) , mode , & XEXP ( src , 0 ) ) ; mips_emit_move ( dest , src ) ; } </s>

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


<s> bool mips_legitimize_move ( machine_mode mode , rtx dest , rtx src ) { if ( ! register_operand ( dest , mode ) && ! register_operand ( src , mode ) && ( TARGET_MIPS16 || ! const_0_operand ( src , mode ) || MSA_SUPPORTED_MODE_P ( mode ) ) ) { mips_emit_move ( dest , force_reg ( mode , src ) ) ; return true ; } if ( CONSTANT_P ( src ) && ! move_operand ( src , mode ) ) { mips_legitimize_const_move ( mode , dest , src ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , copy_rtx ( src ) ) ; return true ; } return false ; } </s>

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


<s> static rtx mips_legitimize_tls_address ( rtx loc ) { rtx dest , 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 ) ; rtx_insn * 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 ) ; rtx_insn * 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 rtx mips_libcall_value ( machine_mode mode , const_rtx fun ATTRIBUTE_UNUSED ) { return mips_function_value_1 ( NULL_TREE , NULL_TREE , mode ) ; } </s>


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


<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 ( 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 unsigned int mips_load_label_num_insns ( void ) { if ( cfun -> machine -> load_label_num_insns == 0 ) { mips_process_load_label ( pc_rtx ) ; cfun -> machine -> load_label_num_insns = mips_multi_num_insns ; } return cfun -> machine -> load_label_num_insns ; } </s>

Return the number of instructions needed to load a label into $ AT .


<s> int mips_load_store_insns ( rtx mem , rtx_insn * insn ) { machine_mode mode ; bool might_split_p ; rtx set ; gcc_assert ( MEM_P ( mem ) ) ; mode = GET_MODE ( mem ) ; might_split_p = GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ; if ( might_split_p ) { set = single_set ( insn ) ; if ( set && ! mips_split_move_insn_p ( SET_DEST ( set ) , SET_SRC ( set ) , insn ) ) might_split_p = false ; } return mips_address_insns ( XEXP ( mem , 0 ) , mode , might_split_p ) ; } </s>

Return the number of instructions needed to implement INSN , given that it loads from or stores to MEM . Assume that BASE_INSN_LENGTH is the length of one instruction .


<s> rtx mips_loongson_ext2_prefetch_cookie ( rtx write , rtx ) { if ( INTVAL ( write ) == 1 ) return GEN_INT ( INTVAL ( write ) ) ; if ( INTVAL ( write ) == 0 ) return GEN_INT ( INTVAL ( write ) ) ; gcc_unreachable ( ) ; } </s>

Loongson EXT2 only implements pref hint=0 ( prefetch for load ) and hint=1 ( prefetch for store ) , other hint just scale to hint = 0 and hint = 1 .


<s> static bool mips_lo_sum_offset_lookup ( mips_offset_table * htab , rtx x , enum insert_option option ) { rtx base , offset ; mips_lo_sum_offset * * slot ; struct mips_lo_sum_offset * entry ; split_const ( x , & base , & offset ) ; if ( UNSPEC_ADDRESS_P ( base ) ) base = UNSPEC_ADDRESS ( base ) ; slot = htab -> find_slot_with_hash ( base , mips_hash_base ( base ) , option ) ; if ( slot == NULL ) return false ; entry = ( struct mips_lo_sum_offset * ) * slot ; if ( option == INSERT ) { if ( entry == NULL ) { entry = XNEW ( struct mips_lo_sum_offset ) ; entry -> base = base ; entry -> offset = INTVAL ( offset ) ; * slot = entry ; } else { if ( INTVAL ( offset ) > entry -> offset ) entry -> offset = INTVAL ( offset ) ; } } return INTVAL ( offset ) <= entry -> offset ; } </s>

Look up symbolic constant X in HTAB , which is a hash table of mips_lo_sum_offsets . If OPTION is NO_INSERT , return true if X can be paired with a recorded LO_SUM , otherwise record X in the table .


<s> static bool mips_lra_p ( void ) { return mips_lra_flag ; } </s>


<s> static void mips_ls2_dfa_post_advance_cycle ( state_t state ) { if ( cpu_unit_reservation_p ( state , mips_ls2 . alu1_core_unit_code ) ) { gcc_assert ( mips_ls2 . cycle_has_multi_p ) ; mips_ls2 . alu1_turn_p = false ; } mips_ls2 . cycle_has_multi_p = false ; if ( cpu_unit_reservation_p ( state , mips_ls2 . alu2_core_unit_code ) ) mips_ls2 . alu1_turn_p = true ; if ( mips_ls2 . alu1_turn_p ) { if ( state_transition ( state , mips_ls2 . alu1_turn_enabled_insn ) >= 0 ) gcc_unreachable ( ) ; } else { if ( state_transition ( state , mips_ls2 . alu2_turn_enabled_insn ) >= 0 ) gcc_unreachable ( ) ; } if ( cpu_unit_reservation_p ( state , mips_ls2 . falu1_core_unit_code ) ) { gcc_unreachable ( ) ; mips_ls2 . falu1_turn_p = false ; } if ( cpu_unit_reservation_p ( state , mips_ls2 . falu2_core_unit_code ) ) mips_ls2 . falu1_turn_p = true ; if ( mips_ls2 . falu1_turn_p ) { if ( state_transition ( state , mips_ls2 . falu1_turn_enabled_insn ) >= 0 ) gcc_unreachable ( ) ; } else { if ( state_transition ( state , mips_ls2 . falu2_turn_enabled_insn ) >= 0 ) gcc_unreachable ( ) ; } } </s>

Initialize STATE when scheduling for Loongson 2E/2F . Support round-robin dispatch scheme by enabling only one of ALU1/ALU2 and one of FALU1/FALU2 units for ALU1/2 and FALU1/2 instructions respectively .


<s> static void mips_ls2_init_dfa_post_cycle_insn ( void ) { start_sequence ( ) ; emit_insn ( gen_ls2_alu1_turn_enabled_insn ( ) ) ; mips_ls2 . alu1_turn_enabled_insn = get_insns ( ) ; end_sequence ( ) ; start_sequence ( ) ; emit_insn ( gen_ls2_alu2_turn_enabled_insn ( ) ) ; mips_ls2 . alu2_turn_enabled_insn = get_insns ( ) ; end_sequence ( ) ; start_sequence ( ) ; emit_insn ( gen_ls2_falu1_turn_enabled_insn ( ) ) ; mips_ls2 . falu1_turn_enabled_insn = get_insns ( ) ; end_sequence ( ) ; start_sequence ( ) ; emit_insn ( gen_ls2_falu2_turn_enabled_insn ( ) ) ; mips_ls2 . falu2_turn_enabled_insn = get_insns ( ) ; end_sequence ( ) ; mips_ls2 . alu1_core_unit_code = get_cpu_unit_code ( "ls2_alu1_core" ) ; mips_ls2 . alu2_core_unit_code = get_cpu_unit_code ( "ls2_alu2_core" ) ; mips_ls2 . falu1_core_unit_code = get_cpu_unit_code ( "ls2_falu1_core" ) ; mips_ls2 . falu2_core_unit_code = get_cpu_unit_code ( "ls2_falu2_core" ) ; } </s>

Implement TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN hook for Loongson2 .


<s> static void mips_ls2_variable_issue ( rtx_insn * insn ) { if ( mips_ls2 . alu1_turn_p ) { if ( cpu_unit_reservation_p ( curr_state , mips_ls2 . alu1_core_unit_code ) ) mips_ls2 . alu1_turn_p = false ; } else { if ( cpu_unit_reservation_p ( curr_state , mips_ls2 . alu2_core_unit_code ) ) mips_ls2 . alu1_turn_p = true ; } if ( mips_ls2 . falu1_turn_p ) { if ( cpu_unit_reservation_p ( curr_state , mips_ls2 . falu1_core_unit_code ) ) mips_ls2 . falu1_turn_p = false ; } else { if ( cpu_unit_reservation_p ( curr_state , mips_ls2 . falu2_core_unit_code ) ) mips_ls2 . falu1_turn_p = true ; } if ( recog_memoized ( insn ) >= 0 ) mips_ls2 . cycle_has_multi_p |= ( get_attr_type ( insn ) == TYPE_MULTI ) ; } </s>

Update round-robin counters for ALU1/2 and FALU1/2 .


<s> static bool mips_lwxs_address_p ( rtx addr ) { if ( ISA_HAS_LWXS && GET_CODE ( addr ) == PLUS && REG_P ( XEXP ( addr , 1 ) ) ) { rtx offset = XEXP ( addr , 0 ) ; if ( GET_CODE ( offset ) == MULT && REG_P ( XEXP ( offset , 0 ) ) && CONST_INT_P ( XEXP ( offset , 1 ) ) && INTVAL ( XEXP ( offset , 1 ) ) == 4 ) return true ; } return false ; } </s>

Return true if ADDR matches the pattern for the LWXS load scaled 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 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 ; if ( MSA_SUPPORTED_MODE_P ( mode ) ) 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 void mips_macc_chains_record ( rtx_insn * insn ) { if ( get_attr_may_clobber_hilo ( insn ) ) mips_macc_chains_last_hilo = insn ; } </s>

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


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

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


<s> static 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 ( ) ; mips_insert_insn_pseudos ( ) ; return 0 ; } </s>

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


<s> static void mips_maybe_swap_ready ( rtx_insn * * ready , int pos1 , int pos2 , int limit ) { if ( pos1 < pos2 && INSN_PRIORITY ( ready [ pos1 ] ) + limit >= INSN_PRIORITY ( ready [ pos2 ] ) ) { rtx_insn * temp ; temp = ready [ pos1 ] ; ready [ pos1 ] = ready [ pos2 ] ; ready [ pos2 ] = temp ; } } </s>

If the priority of the instruction at POS2 in the ready queue READY is within LIMIT units of that of the instruction at POS1 , swap the instructions if POS2 is not already less than POS1 .


<s> static const char * mips_mdebug_abi_name ( void ) { switch ( mips_abi ) { case ABI_32 : return "abi32" ; case ABI_O64 : return "abiO64" ; case ABI_N32 : return "abiN32" ; case ABI_64 : return "abi64" ; case ABI_EABI : return TARGET_64BIT ? "eabi64" : "eabi32" ; default : gcc_unreachable ( ) ; } } </s>

Return the FOO in the name of the `` .mdebug.FOO '' section associated with the current ABI .


<s> static int mips_memory_move_cost ( machine_mode mode , reg_class_t rclass , bool in ) { return ( mips_cost -> memory_latency + memory_move_secondary_cost ( mode , rclass , in ) ) ; } </s>


<s> bool mips_mem_fits_mode_p ( machine_mode mode , rtx x ) { return ( MEM_P ( x ) && MEM_SIZE_KNOWN_P ( x ) && MEM_SIZE ( x ) == GET_MODE_SIZE ( mode ) ) ; } </s>

Return true if X is a MEM with the same size as MODE .


"%qE redeclared with conflicting %qs attributes"


<s> static 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 E_CCFmode : case E_SFmode : return TARGET_HARD_FLOAT ; case E_DFmode : return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT ; case E_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 int mips_mode_rep_extended ( scalar_int_mode mode , scalar_int_mode mode_rep ) { if ( TARGET_64BIT && mode == SImode && mode_rep == DImode ) return SIGN_EXTEND ; return UNKNOWN ; } </s>


<s> static int mips_move_from_gpr_cost ( reg_class_t to ) { switch ( to ) { case M16_REGS : case GENERAL_REGS : return 2 ; case ACC_REGS : return 6 ; case FP_REGS : return 4 ; case COP0_REGS : case COP2_REGS : case COP3_REGS : return 5 ; default : return 0 ; } } </s>

Return the cost of moving a value from a GPR to a register of class TO . Return 0 for classes that are unions of other classes handled by this function .


<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 ( 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 ( dest , x ) ) ; } </s>


<s> static int mips_move_to_gpr_cost ( reg_class_t from ) { switch ( from ) { case M16_REGS : case GENERAL_REGS : return 2 ; case ACC_REGS : return 6 ; case FP_REGS : return 4 ; case COP0_REGS : case COP2_REGS : case COP3_REGS : return 5 ; default : return 0 ; } } </s>

Return the cost of moving a value from a register of class FROM to a GPR . Return 0 for classes that are unions of other classes handled by this function .


<s> const char * mips_msa_output_division ( const char * division , rtx * operands ) { const char * s ; s = division ; if ( TARGET_CHECK_ZERO_DIV ) { output_asm_insn ( "%(bnz.%v0\t%w2,1f" , operands ) ; output_asm_insn ( s , operands ) ; s = "break\t7%)\n1:" ; } return s ; } </s>

Return the assembly code for MSA DIV_ { S , U } .DF or MOD_ { S , U } .DF instructions , which has the operands given by OPERANDS . Add in a divide-by-zero check if needed .


<s> const char * mips_msa_output_shift_immediate ( const char * shift , rtx * operands ) { rtx amount = operands [ 2 ] ; machine_mode mode = amount -> mode ; unsigned val = UINTVAL ( CONST_VECTOR_ELT ( amount , 0 ) ) ; val &= GET_MODE_UNIT_BITSIZE ( mode ) - 1 ; if ( ! val ) return "" ; rtx c = gen_int_mode ( val , GET_MODE_INNER ( mode ) ) ; operands [ 2 ] = gen_const_vec_duplicate ( mode , c ) ; return shift ; } </s>

Return the assembly code for MSA immediate shift instructions , which has the operands given by OPERANDS . Truncate the shift amount to make GAS happy .


<s> rtx mips_msa_vec_parallel_const_half ( machine_mode mode , bool high_p ) { int nunits = GET_MODE_NUNITS ( mode ) ; rtvec v = rtvec_alloc ( nunits / 2 ) ; int base ; int i ; if ( BYTES_BIG_ENDIAN ) base = high_p ? 0 : nunits / 2 ; else base = high_p ? nunits / 2 : 0 ; for ( i = 0 ; i < nunits / 2 ; i ++ ) RTVEC_ELT ( v , i ) = GEN_INT ( base + i ) ; return gen_rtx_PARALLEL ( VOIDmode , v ) ; } </s>

Construct and return PARALLEL RTX with CONST_INTs for HIGH ( high_p == TRUE ) or LOW ( high_p == FALSE ) half of a vector for mode MODE .


Return the function that is used to expand the < u > mulsidi3 pattern . EXT_CODE is the code of the extension used . Return NULL if widening multiplication should n't be used .


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


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

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


<s> static void mips_multi_add_insn ( const char * format , ... ) { struct mips_multi_member * member ; va_list ap ; unsigned int i ; rtx op ; member = mips_multi_add ( ) ; member -> is_label_p = false ; member -> format = format ; va_start ( ap , format ) ; i = 0 ; while ( ( op = va_arg ( ap , rtx ) ) ) member -> operands [ i ++ ] = op ; va_end ( ap ) ; mips_multi_num_insns ++ ; } </s>

Add a normal insn with the given asm format to the current multi-insn sequence . The other arguments are a null-terminated list of operands .


<s> static void mips_multi_add_label ( const char * label ) { struct mips_multi_member * member ; member = mips_multi_add ( ) ; member -> is_label_p = true ; member -> format = label ; } </s>

Add the given label definition to the current multi-insn sequence . The definition should include the colon .


<s> static void mips_multi_copy_insn ( unsigned int i ) { struct mips_multi_member * member ; member = mips_multi_add ( ) ; memcpy ( member , & mips_multi_members [ i ] , sizeof ( * member ) ) ; gcc_assert ( ! member -> is_label_p ) ; } </s>

Add a copy of an existing instruction to the current multi-insn sequence . I is the index of the instruction that should be copied .


<s> static unsigned int mips_multi_last_index ( void ) { return mips_multi_members . length ( ) - 1 ; } </s>

Return the index of the last member of the current multi-insn sequence .


<s> static void mips_multi_set_operand ( unsigned int i , unsigned int op , rtx x ) { mips_multi_members [ i ] . operands [ op ] = x ; } </s>

Change the operand of an existing instruction in the current multi-insn sequence . I is the index of the instruction , OP is the index of the operand , and X is the new value .


<s> static void mips_multi_start ( void ) { mips_multi_members . truncate ( 0 ) ; mips_multi_num_insns = 0 ; } </s>


<s> static void mips_multi_write ( void ) { struct mips_multi_member * member ; unsigned int i ; FOR_EACH_VEC_ELT ( mips_multi_members , i , member ) if ( member -> is_label_p ) fprintf ( asm_out_file , "%s\n" , member -> format ) ; else output_asm_insn ( member -> format , member -> operands ) ; } </s>

Write out the asm code for the current multi-insn sequence .


<s> static bool mips_mult_move_p ( rtx dest , rtx src , enum mips_split_type split_type ) { return ( ( split_type != SPLIT_FOR_SPEED || mips_tuning_info . fast_mult_zero_zero_p ) && src == const0_rtx && REG_P ( dest ) && GET_MODE_SIZE ( GET_MODE ( dest ) ) == 2 * UNITS_PER_WORD && ( ISA_HAS_DSP_MULT ? ACC_REG_P ( REGNO ( dest ) ) : MD_REG_P ( REGNO ( dest ) ) ) ) ; } </s>

Return true if SRC should be moved into DEST using `` MULT $ 0 , $ 0 '' . SPLIT_TYPE is the condition under which moves should be split .


<s> static unsigned int mips_mult_zero_zero_cost ( struct mips_sim * state , bool setting ) { mips_tuning_info . fast_mult_zero_zero_p = setting ; start_sequence ( ) ; machine_mode dword_mode = TARGET_64BIT ? TImode : DImode ; rtx hilo = gen_rtx_REG ( dword_mode , MD_REG_FIRST ) ; mips_emit_move_or_split ( hilo , const0_rtx , SPLIT_FOR_SPEED ) ; if ( dword_mode == DImode && HAVE_maddsidi4 ) { rtx gpr = gen_rtx_REG ( SImode , GP_REG_FIRST + 4 ) ; emit_insn ( gen_maddsidi4 ( hilo , gpr , gpr , hilo ) ) ; } unsigned int time = mips_seq_time ( state , get_insns ( ) ) ; end_sequence ( ) ; return time ; } </s>

Return the execution-time cost of mips_tuning_info.fast_mult_zero_zero_p setting SETTING , using STATE to simulate instruction sequences .


<s> static bool mips_near_type_p ( const_tree type ) { return ( lookup_attribute ( "short_call" , TYPE_ATTRIBUTES ( type ) ) != NULL || 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 bool mips_need_noat_wrapper_p ( rtx_insn * insn , rtx * opvec , int noperands ) { if ( recog_memoized ( insn ) >= 0 ) { subrtx_iterator :: array_type array ; for ( int i = 0 ; i < noperands ; i ++ ) FOR_EACH_SUBRTX ( iter , array , opvec [ i ] , NONCONST ) if ( REG_P ( * iter ) && REGNO ( * iter ) == AT_REGNUM ) return true ; } return false ; } </s>

Return true if INSN needs to be wrapped in `` .set noat '' . INSN has NOPERANDS operands , stored in OPVEC .


<s> static bool mips_no_speculation_in_delay_slots_p ( ) { return TARGET_CB_MAYBE ; } </s>


<s> static bool mips_offset_within_alignment_p ( rtx x , HOST_WIDE_INT offset ) { HOST_WIDE_INT align ; align = SYMBOL_REF_DECL ( x ) ? DECL_ALIGN_UNIT ( SYMBOL_REF_DECL ( x ) ) : 1 ; return IN_RANGE ( offset , 0 , align - 1 ) ; } </s>

Return true if OFFSET is within the range [ 0 , ALIGN ) , where ALIGN is the alignment in bytes of SYMBOL_REF X .


<s> static bool mips_ok_for_lazy_binding_p ( rtx x ) { return ( TARGET_USE_GOT && GET_CODE ( x ) == SYMBOL_REF && ! SYMBOL_REF_BIND_NOW_P ( x ) && ! mips_symbol_binds_local_p ( x ) ) ; } </s>

Return true if calls to X can use R_MIPS_CALL * relocations .


<s> static bool mips_orphaned_high_part_p ( mips_offset_table * htab , rtx_insn * insn ) { enum mips_symbol_type type ; rtx x , set ; set = single_set ( insn ) ; if ( set ) { x = SET_SRC ( set ) ; if ( GET_CODE ( x ) == HIGH && absolute_symbolic_operand ( XEXP ( x , 0 ) , VOIDmode ) ) return ! mips_lo_sum_offset_lookup ( htab , XEXP ( x , 0 ) , NO_INSERT ) ; if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_LOAD_GOT && mips_symbolic_constant_p ( XVECEXP ( x , 0 , 1 ) , SYMBOL_CONTEXT_LEA , & type ) && type == SYMBOL_GOTOFF_PAGE ) return ! mips_lo_sum_offset_lookup ( htab , XVECEXP ( x , 0 , 1 ) , NO_INSERT ) ; } return false ; } </s>

Return true if INSN is a SET of an orphaned high-part relocation . HTAB is a hash table of mips_lo_sum_offsets that describes all the LO_SUMs in the current function .


<s> static void mips_output_32bit_xfer ( char direction , unsigned int gpreg , unsigned int fpreg ) { fprintf ( asm_out_file , "\tm%cc1\t%s,%s\n" , direction , reg_names [ gpreg ] , reg_names [ fpreg ] ) ; } </s>

Write instructions to move a 32-bit value between general register GPREG and floating-point register FPREG . DIRECTION is 't ' to move from GPREG to FPREG and ' f ' to move in the opposite direction .


<s> static void mips_output_64bit_xfer ( char direction , unsigned int gpreg , unsigned int fpreg ) { if ( TARGET_64BIT ) fprintf ( asm_out_file , "\tdm%cc1\t%s,%s\n" , direction , reg_names [ gpreg ] , reg_names [ fpreg ] ) ; else if ( ISA_HAS_MXHC1 ) { fprintf ( asm_out_file , "\tm%cc1\t%s,%s\n" , direction , reg_names [ gpreg + TARGET_BIG_ENDIAN ] , reg_names [ fpreg ] ) ; fprintf ( asm_out_file , "\tm%chc1\t%s,%s\n" , direction , reg_names [ gpreg + TARGET_LITTLE_ENDIAN ] , reg_names [ fpreg ] ) ; } else if ( TARGET_FLOATXX && direction == 't' ) { fprintf ( asm_out_file , "\tsw\t%s,0($sp)\n" , reg_names [ gpreg ] ) ; fprintf ( asm_out_file , "\tsw\t%s,4($sp)\n" , reg_names [ gpreg + 1 ] ) ; fprintf ( asm_out_file , "\tldc1\t%s,0($sp)\n" , reg_names [ fpreg ] ) ; } else if ( TARGET_FLOATXX && direction == 'f' ) { fprintf ( asm_out_file , "\tsdc1\t%s,0($sp)\n" , reg_names [ fpreg ] ) ; fprintf ( asm_out_file , "\tlw\t%s,0($sp)\n" , reg_names [ gpreg ] ) ; fprintf ( asm_out_file , "\tlw\t%s,4($sp)\n" , reg_names [ gpreg + 1 ] ) ; } else { fprintf ( asm_out_file , "\tm%cc1\t%s,%s\n" , direction , reg_names [ gpreg + TARGET_BIG_ENDIAN ] , reg_names [ fpreg ] ) ; fprintf ( asm_out_file , "\tm%cc1\t%s,%s\n" , direction , reg_names [ gpreg + TARGET_LITTLE_ENDIAN ] , reg_names [ fpreg + 1 ] ) ; } } </s>


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

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


<s> 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 ) ; function_arg_info arg ( mode , true ) ; mips_function_arg_advance ( pack_cumulative_args ( & cum ) , arg ) ; } } </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> void mips_output_ascii ( FILE * stream , const char * string , size_t len ) { size_t i ; int cur_pos ; cur_pos = 17 ; fprintf ( stream , "\t.ascii\t\"" ) ; for ( i = 0 ; i < len ; i ++ ) { int c ; c = ( unsigned char ) string [ i ] ; if ( ISPRINT ( c ) ) { if ( c == '\\' || c == '\"' ) { putc ( '\\' , stream ) ; cur_pos ++ ; } putc ( c , stream ) ; cur_pos ++ ; } else { fprintf ( stream , "\\%03o" , c ) ; cur_pos += 4 ; } if ( cur_pos > 72 && i + 1 < len ) { cur_pos = 17 ; fprintf ( stream , "\"\n\t.ascii\t\"" ) ; } } fprintf ( stream , "\"\n" ) ; } </s>

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


<s>
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
,
)
;
final_sequence
->
insn
(
1
)
->
set_deleted
(
)
;
}
else
output_asm_insn
(
"nop"
,
0
)
;
fprintf
(
asm_out_file
,
"\n"
)
;
}
if
(
TARGET_ABSOLUTE_JUMPS
&&
TARGET_CB_MAYBE
)
{
if
(
!
final_sequence
)
{
output_asm_insn
(
"nop\t\t# hazard nop"
,
0
)
;
fprintf
(
asm_out_file
,
"\n"
)
;
}
output_asm_insn
(
MIPS_ABSOLUTE_JUMP
(
"bc\t%0"
)
,
&
taken
)
;
}
else
if
(
TARGET_ABSOLUTE_JUMPS
)
output_asm_insn
(
MIPS_ABSOLUTE_JUMP
(
"j\t%0%/"
)
,
&
taken
)
;
else
{
mips_output_load_label
(
taken
)
;
if
(
TARGET_CB_MAYBE
)
output_asm_insn
(
"jrc\t%@%]"
,
0
)
;
else
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
,
)
;
final_sequence
->
insn
(
1
)
->
set_deleted
(
)
;
}
else
if
(
TARGET_CB_NEVER
)
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_cplocal
(
void
)
{
if
(
!
TARGET_EXPLICIT_RELOCS
&&
mips_must_initialize_gp_p
(
)
&&
cfun
->
machine
->
global_pointer
!=
GLOBAL_POINTER_REGNUM
)
output_asm_insn
(
".cplocal %+"
,
0
)
;
}
</s>

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


<s> static void ATTRIBUTE_UNUSED mips_output_dwarf_dtprel ( FILE * file , int size , rtx x ) { switch ( size ) { case 4 : fputs ( "\t.dtprelword\t" , file ) ; break ; case 8 : fputs ( "\t.dtpreldword\t" , file ) ; break ; default : gcc_unreachable ( ) ; } output_addr_const ( file , x ) ; fputs ( "+0x8000" , file ) ; } </s>


<s>
const
char
*
mips_output_equal_conditional_branch
(
rtx_insn
*
insn
,
rtx
*
operands
,
bool
inverted_p
)
{
const
char
*
branch
[
2
]
;
if
(
TARGET_MICROMIPS
&&
mips_isa_rev
<=
5
&&
operands
[
3
]
==
const0_rtx
&&
get_attr_length
(
insn
)
<=
8
)
{
if
(
mips_cb
==
MIPS_CB_OPTIMAL
)
{
branch
[
!
inverted_p
]
=
"%*b%C1z%:\t%2,%0"
;
branch
[
inverted_p
]
=
"%*b%N1z%:\t%2,%0"
;
}
else
{
branch
[
!
inverted_p
]
=
"%*b%C1z\t%2,%0%/"
;
branch
[
inverted_p
]
=
"%*b%N1z\t%2,%0%/"
;
}
}
else
if
(
TARGET_CB_MAYBE
)
{
if
(
operands
[
3
]
==
const0_rtx
)
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b%C1z"
,
"%2,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH_C
(
"b%N1z"
,
"%2,%0"
)
;
}
else
if
(
REGNO
(
operands
[
2
]
)
!=
REGNO
(
operands
[
3
]
)
)
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b%C1"
,
"%2,%3,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH_C
(
"b%N1"
,
"%2,%3,%0"
)
;
}
else
{
if
(
GET_CODE
(
operands
[
1
]
)
==
NE
)
inverted_p
=
!
inverted_p
;
branch
[
!
inverted_p
]
=
MIPS_BRANCH_C
(
"b"
,
"%0"
)
;
branch
[
inverted_p
]
=
"%*\t\t# branch never"
;
}
}
else
{
branch
[
!
inverted_p
]
=
MIPS_BRANCH
(
"b%C1"
,
"%2,%z3,%0"
)
;
branch
[
inverted_p
]
=
MIPS_BRANCH
(
"b%N1"
,
"%2,%z3,%0"
)
;
}
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 equality 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 ; OPERANDS [ 3 ] is the second operand and may be zero or a register .


<s>
void
mips_output_external
(
FILE
*
file
,
tree
decl
,
const
char
*
name
)
{
default_elf_asm_output_external
(
file
,
decl
,
name
)
;
if
(
TREE_SYMBOL_REFERENCED
(
DECL_ASSEMBLER_NAME
(
decl
)
)
)
{
if
(
!
TARGET_EXPLICIT_RELOCS
&&
mips_in_small_data_p
(
decl
)
)
{
fputs
(
"\t.extern\t"
,
file
)
;
assemble_name
(
file
,
name
)
;
fprintf
(
file
,
", "
HOST_WIDE_INT_PRINT_DEC
"\n"
,
int_size_in_bytes
(
TREE_TYPE
(
decl
)
)
)
;
}
}
}
</s>

When using assembler macros , keep track of all of small-data externs so that mips_file_end can emit the appropriate declarations for them . In most cases it would be safe ( though pointless ) to emit .externs for other symbols too . One exception is when an object is within the -G limit but declared by the user to be in a section other than .sbss or .sdata .


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

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


<s> static void mips_output_function_epilogue ( FILE * ) { const char * fnname ; SET_REGNO ( pic_offset_table_rtx , GLOBAL_POINTER_REGNUM ) ; mips_output_cplocal ( ) ; if ( cfun -> machine -> all_noreorder_p ) { mips_pop_asm_switch ( & mips_nomacro ) ; mips_pop_asm_switch ( & mips_noreorder ) ; } fnname = XSTR ( XEXP ( DECL_RTL ( current_function_decl ) , 0 ) , 0 ) ; mips_end_function_definition ( fnname ) ; } </s>


<s>
static
void
mips_output_function_prologue
(
FILE
*
file
)
{
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> 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,%s,%%%d\n1:\t" , TARGET_MICROMIPS ? "R_MICROMIPS_JALR" : "R_MIPS_JALR" , size_opno ) ; 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> void mips_output_load_label ( rtx target ) { mips_push_asm_switch ( & mips_noat ) ; if ( TARGET_EXPLICIT_RELOCS ) { mips_process_load_label ( target ) ; mips_multi_write ( ) ; } else { if ( Pmode == DImode ) output_asm_insn ( "dla\t%@,%0" , & target ) ; else output_asm_insn ( "la\t%@,%0" , & target ) ; } } </s>

Return an asm sequence to start a noat block and load the address of a label into $ 1 .