<s> static void add_to_sp ( rtx spreg , HOST_WIDE_INT value , int frame ) { if ( value == 0 ) return ; if ( value > 120 || value < - 120 ) { rtx tmpreg = gen_rtx_REG ( SImode , REG_P1 ) ; rtx insn ; if ( frame ) frame_related_constant_load ( tmpreg , value , TRUE ) ; else { insn = emit_move_insn ( tmpreg , GEN_INT ( value ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; } insn = emit_insn ( gen_addsi3 ( spreg , spreg , tmpreg ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; } else do { int size = value ; rtx insn ; if ( size > 60 ) size = 60 ; else if ( size < - 60 ) size = - 60 ; insn = emit_insn ( gen_addsi3 ( spreg , spreg , GEN_INT ( size ) ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; value -= size ; } while ( value != 0 ) ; } </s>

Generate efficient code to add a value to the frame pointer . We can use P1 as a scratch register . Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero .


<s> static HOST_WIDE_INT arg_area_size ( void ) { if ( current_function_outgoing_args_size ) { if ( current_function_outgoing_args_size >= FIXED_STACK_AREA ) return current_function_outgoing_args_size ; else return FIXED_STACK_AREA ; } return 0 ; } </s>

Return the number of bytes we must reserve for outgoing arguments in the current function 's stack frame .


<s> void asm_conditional_branch ( rtx insn , rtx * operands , int n_nops , int predict_taken ) { int offset = branch_dest ( insn ) - INSN_ADDRESSES ( INSN_UID ( insn ) ) ; int len = ( offset >= - 1024 && offset <= 1022 ? 0 : offset >= - 4094 && offset <= 4096 ? 1 : 2 ) ; int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p ( insn ) ; int idx = ( bp << 1 ) | ( GET_CODE ( operands [ 0 ] ) == EQ ? BRF : BRT ) ; output_asm_insn ( ccbranch_templates [ idx ] [ len ] , operands ) ; gcc_assert ( n_nops == 0 || ! bp ) ; if ( len == 0 ) while ( n_nops -- > 0 ) output_asm_insn ( "nop;" , NULL ) ; } </s>

Output INSN , which is a conditional branch instruction with operands OPERANDS . We deal with the various forms of conditional branches that can be generated by bfin_reorg to prevent the hardware from doing speculative loads , by - emitting a sufficient number of nops , if N_NOPS is nonzero , or - always emitting the branch as predicted taken , if PREDICT_TAKEN is true . Either of these is only necessary if the branch is short , otherwise the template we use ends in an unconditional jump which flushes the pipeline anyway .


<s> static int bfin_address_cost ( rtx addr ATTRIBUTE_UNUSED ) { return 1 ; } </s>

Return cost of the memory address ADDR . All addressing modes are equally cheap on the Blackfin .


<s> static int bfin_arg_partial_bytes ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { int bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; int bytes_left = cum -> nregs * UNITS_PER_WORD ; if ( bytes == - 1 ) return 0 ; if ( bytes_left == 0 ) return 0 ; if ( bytes > bytes_left ) return bytes_left ; return 0 ; } </s>

For an arg passed partly in registers and partly in memory , this is the number of bytes passed in registers . For args passed entirely in registers or entirely in memory , zero . Refer VDSP C Compiler manual , our ABI . First 3 words are in registers . So , if a an argument is larger than the registers available , it will span the register and stack .


<s> static int bfin_comp_type_attributes ( tree type1 , tree type2 ) { e_funkind kind1 , kind2 ; if ( TREE_CODE ( type1 ) != FUNCTION_TYPE ) return 1 ; kind1 = funkind ( type1 ) ; kind2 = funkind ( type2 ) ; if ( kind1 != kind2 ) return 0 ; if ( ! lookup_attribute ( "nesting" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "nesting" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "saveall" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "saveall" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "kspisusp" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "kspisusp" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "longcall" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "longcall" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; return 1 ; } </s>

Return 0 if the attributes for two types are incompatible , 1 if they are compatible , and 2 if they are nearly compatible ( which causes a warning to be generated ) .


<s> static rtx bfin_expand_builtin ( tree exp , rtx target ATTRIBUTE_UNUSED , rtx subtarget ATTRIBUTE_UNUSED , enum machine_mode mode ATTRIBUTE_UNUSED , int ignore ATTRIBUTE_UNUSED ) { tree fndecl = TREE_OPERAND ( TREE_OPERAND ( exp , 0 ) , 0 ) ; unsigned int fcode = DECL_FUNCTION_CODE ( fndecl ) ; switch ( fcode ) { case BFIN_BUILTIN_CSYNC : emit_insn ( gen_csync ( ) ) ; return 0 ; case BFIN_BUILTIN_SSYNC : emit_insn ( gen_ssync ( ) ) ; return 0 ; default : gcc_unreachable ( ) ; } } </s>

Expand an expression EXP that calls a built-in function , with result going to TARGET if that 's convenient ( and in mode MODE if that 's convenient ) . SUBTARGET may be used as the target for computing one of EXP 's operands . IGNORE is nonzero if the value is to be ignored .


<s> void bfin_expand_call ( rtx retval , rtx fnaddr , rtx callarg1 , rtx cookie , int sibcall ) { rtx use = NULL , call ; rtx callee = XEXP ( fnaddr , 0 ) ; rtx pat = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( sibcall ? 3 : 2 ) ) ; if ( cookie == NULL_RTX ) cookie = const0_rtx ; if ( flag_pic && GET_CODE ( callee ) == SYMBOL_REF && ! SYMBOL_REF_LOCAL_P ( callee ) ) use_reg ( & use , pic_offset_table_rtx ) ; if ( ( ! register_no_elim_operand ( callee , Pmode ) && GET_CODE ( callee ) != SYMBOL_REF ) || ( GET_CODE ( callee ) == SYMBOL_REF && ( flag_pic || bfin_longcall_p ( callee , INTVAL ( cookie ) ) ) ) ) { callee = copy_to_mode_reg ( Pmode , callee ) ; fnaddr = gen_rtx_MEM ( Pmode , callee ) ; } call = gen_rtx_CALL ( VOIDmode , fnaddr , callarg1 ) ; if ( retval ) call = gen_rtx_SET ( VOIDmode , retval , call ) ; XVECEXP ( pat , 0 , 0 ) = call ; XVECEXP ( pat , 0 , 1 ) = gen_rtx_USE ( VOIDmode , cookie ) ; if ( sibcall ) XVECEXP ( pat , 0 , 2 ) = gen_rtx_RETURN ( VOIDmode ) ; call = emit_call_insn ( pat ) ; if ( use ) CALL_INSN_FUNCTION_USAGE ( call ) = use ; } </s>

Expand a call instruction . FNADDR is the call target , RETVAL the return value . COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args . SIBCALL is nonzero if this is a sibling call .


<s> void bfin_expand_epilogue ( int need_return , int eh_return ) { rtx spreg = gen_rtx_REG ( Pmode , REG_SP ) ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; if ( fkind != SUBROUTINE ) { expand_interrupt_handler_epilogue ( spreg , fkind ) ; return ; } do_unlink ( spreg , get_frame_size ( ) , false ) ; expand_epilogue_reg_restore ( spreg , false , false ) ; if ( ! need_return ) return ; if ( eh_return ) emit_insn ( gen_addsi3 ( spreg , spreg , gen_rtx_REG ( Pmode , REG_P2 ) ) ) ; emit_jump_insn ( gen_return_internal ( GEN_INT ( SUBROUTINE ) ) ) ; } </s>

Generate RTL for the epilogue of the current function . NEED_RETURN is zero if this is for a sibcall . EH_RETURN is nonzero if we 're expanding an eh_return pattern .


<s> void bfin_expand_prologue ( void ) { rtx insn ; HOST_WIDE_INT frame_size = get_frame_size ( ) ; rtx spreg = gen_rtx_REG ( Pmode , REG_SP ) ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; rtx pic_reg_loaded = NULL_RTX ; if ( fkind != SUBROUTINE ) { expand_interrupt_handler_prologue ( spreg , fkind ) ; return ; } if ( current_function_limit_stack ) { HOST_WIDE_INT offset = bfin_initial_elimination_offset ( ARG_POINTER_REGNUM , STACK_POINTER_REGNUM ) ; rtx lim = stack_limit_rtx ; if ( GET_CODE ( lim ) == SYMBOL_REF ) { rtx p2reg = gen_rtx_REG ( Pmode , REG_P2 ) ; if ( TARGET_ID_SHARED_LIBRARY ) { rtx p1reg = gen_rtx_REG ( Pmode , REG_P1 ) ; rtx val ; pic_reg_loaded = bfin_load_pic_reg ( p2reg ) ; val = legitimize_pic_address ( stack_limit_rtx , p1reg , pic_reg_loaded ) ; emit_move_insn ( p1reg , val ) ; frame_related_constant_load ( p2reg , offset , FALSE ) ; emit_insn ( gen_addsi3 ( p2reg , p2reg , p1reg ) ) ; lim = p2reg ; } else { rtx limit = plus_constant ( stack_limit_rtx , offset ) ; emit_move_insn ( p2reg , limit ) ; lim = p2reg ; } } emit_insn ( gen_compare_lt ( bfin_cc_rtx , spreg , lim ) ) ; emit_insn ( gen_trapifcc ( ) ) ; } expand_prologue_reg_save ( spreg , 0 , false ) ; do_link ( spreg , frame_size , false ) ; if ( TARGET_ID_SHARED_LIBRARY && ( current_function_uses_pic_offset_table || ! current_function_is_leaf ) ) bfin_load_pic_reg ( pic_offset_table_rtx ) ; } </s>

Generate RTL for the prologue of the current function .


<s> bool bfin_expand_strmov ( rtx dst , rtx src , rtx count_exp , rtx align_exp ) { rtx srcreg , destreg , countreg ; HOST_WIDE_INT align = 0 ; unsigned HOST_WIDE_INT count = 0 ; if ( GET_CODE ( align_exp ) == CONST_INT ) align = INTVAL ( align_exp ) ; if ( GET_CODE ( count_exp ) == CONST_INT ) { count = INTVAL ( count_exp ) ; if ( ! TARGET_INLINE_ALL_STRINGOPS && count > 64 ) return false ; } if ( optimize_size ) { if ( count == 2 && align < 2 ) return false ; if ( count == 4 && align < 4 ) return false ; if ( count != 1 && count != 2 && count != 4 ) return false ; } if ( align < 2 && count != 1 ) return false ; destreg = copy_to_mode_reg ( Pmode , XEXP ( dst , 0 ) ) ; if ( destreg != XEXP ( dst , 0 ) ) dst = replace_equiv_address_nv ( dst , destreg ) ; srcreg = copy_to_mode_reg ( Pmode , XEXP ( src , 0 ) ) ; if ( srcreg != XEXP ( src , 0 ) ) src = replace_equiv_address_nv ( src , srcreg ) ; if ( count != 0 && align >= 2 ) { unsigned HOST_WIDE_INT offset = 0 ; if ( align >= 4 ) { if ( ( count & ~ 3 ) == 4 ) { single_move_for_strmov ( dst , src , SImode , offset ) ; offset = 4 ; } else if ( count & ~ 3 ) { HOST_WIDE_INT new_count = ( ( count >> 2 ) & 0x3fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movsi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; } if ( count & 2 ) { single_move_for_strmov ( dst , src , HImode , offset ) ; offset += 2 ; } } else { if ( ( count & ~ 1 ) == 2 ) { single_move_for_strmov ( dst , src , HImode , offset ) ; offset = 2 ; } else if ( count & ~ 1 ) { HOST_WIDE_INT new_count = ( ( count >> 1 ) & 0x7fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movhi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; } } if ( count & 1 ) { single_move_for_strmov ( dst , src , QImode , offset ) ; } return true ; } return false ; } </s>

Expand a string move operation of COUNT_EXP bytes from SRC to DST , with alignment ALIGN_EXP . Return true if successful , false if we should fall back on a different method .


<s> int bfin_frame_pointer_required ( void ) { e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; if ( fkind != SUBROUTINE ) return 1 ; if ( TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf ) return 1 ; return 0 ; } </s>

Value should be nonzero if functions must have frame pointers . Zero means the frame pointer need not be set up ( and parms may be accessed via the stack pointer ) in functions that seem suitable .


<s> static bool bfin_function_ok_for_sibcall ( tree decl ATTRIBUTE_UNUSED , tree exp ATTRIBUTE_UNUSED ) { e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; return fkind == SUBROUTINE ; } </s>

Decide whether we can make a sibling call to a function . DECL is the declaration of the function being targeted by the call and EXP is the CALL_EXPR representing the call .


<s> rtx bfin_gen_compare ( rtx cmp , enum machine_mode mode ATTRIBUTE_UNUSED ) { enum rtx_code code1 , code2 ; rtx op0 = bfin_compare_op0 , op1 = bfin_compare_op1 ; rtx tem = bfin_cc_rtx ; enum rtx_code code = GET_CODE ( cmp ) ; if ( GET_MODE ( op0 ) == BImode ) { gcc_assert ( ( code == NE || code == EQ ) && op1 == const0_rtx ) ; tem = op0 , code2 = code ; } else { switch ( code ) { case EQ : case LT : case LE : case LEU : case LTU : code1 = code ; code2 = NE ; break ; default : code1 = reverse_condition ( code ) ; code2 = EQ ; break ; } emit_insn ( gen_rtx_SET ( BImode , tem , gen_rtx_fmt_ee ( code1 , BImode , op0 , op1 ) ) ) ; } return gen_rtx_fmt_ee ( code2 , BImode , tem , CONST0_RTX ( BImode ) ) ; } </s>

Emit rtl for a comparison operation CMP in mode MODE . Operands have been stored in bfin_compare_op0 and bfin_compare_op1 already .


"`%s' attribute only applies to functions"

"can't apply both longcall and shortcall attributes to the same function"

Handle a `` longcall '' or `` shortcall '' attribute ; arguments as in struct attribute_spec.handler .


"-mshared-library-id=%s is not between 0 and %d"


<s> int bfin_hard_regno_rename_ok ( unsigned int old_reg ATTRIBUTE_UNUSED , unsigned int new_reg ) { if ( funkind ( TREE_TYPE ( current_function_decl ) ) != SUBROUTINE && ! regs_ever_live [ new_reg ] ) return 0 ; return 1 ; } </s>

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


<s> HOST_WIDE_INT bfin_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT offset = 0 ; if ( from == ARG_POINTER_REGNUM ) offset = n_regs_saved_by_prologue ( ) * 4 ; if ( to == STACK_POINTER_REGNUM ) { if ( current_function_outgoing_args_size >= FIXED_STACK_AREA ) offset += current_function_outgoing_args_size ; else if ( current_function_outgoing_args_size ) offset += FIXED_STACK_AREA ; offset += get_frame_size ( ) ; } return offset ; } </s>

Return the offset between two registers , one to be eliminated , and the other its replacement , at the start of a routine .


Set up all builtin functions for this target .


<s> bool bfin_legitimate_address_p ( enum machine_mode mode , rtx x , int strict ) { switch ( GET_CODE ( x ) ) { case REG : if ( bfin_valid_reg_p ( REGNO ( x ) , strict ) ) return true ; break ; case PLUS : if ( REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict ) && ( GET_CODE ( XEXP ( x , 1 ) ) == UNSPEC || ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && bfin_valid_add ( mode , INTVAL ( XEXP ( x , 1 ) ) ) ) ) ) return true ; break ; case POST_INC : case POST_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict ) ) return true ; case PRE_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && XEXP ( x , 0 ) == stack_pointer_rtx && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict ) ) return true ; break ; default : break ; } return false ; } </s>

Recognize an RTL expression that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . Blackfin addressing modes are as follows : [ preg ] [ preg + imm16 ] B [ Preg + uimm15 ] W [ Preg + uimm16m2 ] [ Preg + uimm17m4 ] [ preg++ ] [ preg -- ] [ -- sp ]


<s> static rtx bfin_load_pic_reg ( rtx dest ) { struct cgraph_local_info * i = NULL ; rtx addr , insn ; if ( flag_unit_at_a_time ) i = cgraph_local_info ( current_function_decl ) ; if ( i && i -> local ) return pic_offset_table_rtx ; if ( bfin_lib_id_given ) addr = plus_constant ( pic_offset_table_rtx , - 4 - bfin_library_id * 4 ) ; else addr = gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_LIBRARY_OFFSET ) ) ; insn = emit_insn ( gen_movsi ( dest , gen_rtx_MEM ( Pmode , addr ) ) ) ; REG_NOTES ( insn ) = gen_rtx_EXPR_LIST ( REG_MAYBE_DEAD , const0_rtx , NULL ) ; return dest ; } </s>

Used while emitting the prologue to generate code to load the correct value into the PIC register , which is passed in DEST .


<s> int bfin_register_move_cost ( enum machine_mode mode ATTRIBUTE_UNUSED , enum reg_class class1 , enum reg_class class2 ) { if ( optimize_size ) return 2 ; if ( class1 == DREGS && class2 != DREGS ) return 2 * 2 ; return 2 ; } </s>

Return the cost of moving data from a register in class CLASS1 to one in class CLASS2 . A cost of 2 is the default .


<s> int bfin_return_in_memory ( tree type ) { int size = int_size_in_bytes ( type ) ; return size > 2 * UNITS_PER_WORD || size == - 1 ; } </s>

Decide whether a type should be returned in memory ( true ) or in a register ( false ) . This is called by the macro RETURN_IN_MEMORY .


<s> static bool bfin_valid_add ( enum machine_mode mode , HOST_WIDE_INT value ) { unsigned HOST_WIDE_INT v = value > 0 ? value : - value ; int sz = GET_MODE_SIZE ( mode ) ; int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2 ; unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff ; return ( v & ~ ( mask << shift ) ) == 0 ; } </s>

Return true if the legitimate memory address for a memory operand of mode MODE . Return false if not .


<s> static bool bfin_vector_mode_supported_p ( enum machine_mode mode ) { return mode == V2HImode ; } </s>

Implements target hook vector_mode_supported_p .


<s> static int branch_dest ( rtx branch ) { rtx dest ; int dest_uid ; rtx pat = PATTERN ( branch ) ; if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; dest = SET_SRC ( pat ) ; if ( GET_CODE ( dest ) == IF_THEN_ELSE ) dest = XEXP ( dest , 1 ) ; dest = XEXP ( dest , 0 ) ; dest_uid = INSN_UID ( dest ) ; return INSN_ADDRESSES ( dest_uid ) ; } </s>

Return the destination address of BRANCH . We need to use this instead of get_attr_length , because the cbranch_with_nops pattern conservatively sets its length to 6 , and we still prefer to use shorter sequences .


<s> static int cbranch_predicted_taken_p ( rtx insn ) { rtx x = find_reg_note ( insn , REG_BR_PROB , 0 ) ; if ( x ) { int pred_val = INTVAL ( XEXP ( x , 0 ) ) ; return pred_val >= REG_BR_PROB_BASE / 2 ; } return 0 ; } </s>

Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates it 's a branch that 's predicted taken .


<s> void conditional_register_usage ( void ) { bfin_cc_rtx = gen_rtx_REG ( BImode , REG_CC ) ; bfin_rets_rtx = gen_rtx_REG ( Pmode , REG_RETS ) ; } </s>

Called early in the compilation to conditionally modify fixed_regs/call_used_regs .


<s> static void do_link ( rtx spreg , HOST_WIDE_INT frame_size , bool all ) { frame_size += arg_area_size ( ) ; if ( all || stack_frame_needed_p ( ) || ( must_save_fp_p ( ) && ! current_function_is_leaf ) ) emit_link_insn ( spreg , frame_size ) ; else { if ( ! current_function_is_leaf ) { rtx pat = gen_movsi ( gen_rtx_MEM ( Pmode , gen_rtx_PRE_DEC ( Pmode , spreg ) ) , bfin_rets_rtx ) ; rtx insn = emit_insn ( pat ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( must_save_fp_p ( ) ) { rtx pat = gen_movsi ( gen_rtx_MEM ( Pmode , gen_rtx_PRE_DEC ( Pmode , spreg ) ) , gen_rtx_REG ( Pmode , REG_FP ) ) ; rtx insn = emit_insn ( pat ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } add_to_sp ( spreg , - frame_size , 1 ) ; } } </s>

Save RETS and FP , and allocate a stack frame . ALL is true if the function must save all its registers ( true only for certain interrupt handlers ) .


<s> static void do_unlink ( rtx spreg , HOST_WIDE_INT frame_size , bool all ) { frame_size += arg_area_size ( ) ; if ( all || stack_frame_needed_p ( ) ) emit_insn ( gen_unlink ( ) ) ; else { rtx postinc = gen_rtx_MEM ( Pmode , gen_rtx_POST_INC ( Pmode , spreg ) ) ; add_to_sp ( spreg , frame_size , 0 ) ; if ( must_save_fp_p ( ) ) { rtx fpreg = gen_rtx_REG ( Pmode , REG_FP ) ; emit_move_insn ( fpreg , postinc ) ; emit_insn ( gen_rtx_USE ( VOIDmode , fpreg ) ) ; } if ( ! current_function_is_leaf ) { emit_move_insn ( bfin_rets_rtx , postinc ) ; emit_insn ( gen_rtx_USE ( VOIDmode , bfin_rets_rtx ) ) ; } } } </s>

Like do_link , but used for epilogues to deallocate the stack frame .


<s> int effective_address_32bit_p ( rtx op , enum machine_mode mode ) { HOST_WIDE_INT offset ; mode = GET_MODE ( op ) ; op = XEXP ( op , 0 ) ; if ( GET_CODE ( op ) != PLUS ) { gcc_assert ( REG_P ( op ) || GET_CODE ( op ) == POST_INC || GET_CODE ( op ) == PRE_DEC || GET_CODE ( op ) == POST_DEC ) ; return 0 ; } offset = INTVAL ( XEXP ( op , 1 ) ) ; if ( GET_MODE_SIZE ( mode ) == 1 ) return 1 ; if ( GET_MODE_SIZE ( mode ) == 4 ) { if ( XEXP ( op , 0 ) == frame_pointer_rtx ) return offset < - 128 || offset > 60 ; return offset < 0 || offset > 60 ; } return offset < 0 || offset > 30 ; } </s>

This predicate is used to compute the length of a load/store insn . OP is a MEM rtx , we return nonzero if its addressing mode requires a 32 bit instruction .


<s> static void emit_link_insn ( rtx spreg , HOST_WIDE_INT frame_size ) { HOST_WIDE_INT link_size = frame_size ; rtx insn ; int i ; if ( link_size > 262140 ) link_size = 262140 ; insn = emit_insn ( gen_link ( GEN_INT ( - 8 - link_size ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; for ( i = 0 ; i < XVECLEN ( PATTERN ( insn ) , 0 ) ; i ++ ) { rtx set = XVECEXP ( PATTERN ( insn ) , 0 , i ) ; gcc_assert ( GET_CODE ( set ) == SET ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; } frame_size -= link_size ; if ( frame_size > 0 ) { rtx tmpreg = gen_rtx_REG ( Pmode , REG_P1 ) ; frame_related_constant_load ( tmpreg , - frame_size , TRUE ) ; insn = emit_insn ( gen_addsi3 ( spreg , spreg , tmpreg ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } } </s>

Generate a LINK insn for a frame sized FRAME_SIZE . If this constant is too large , generate a sequence of insns that has the same effect . SPREG contains ( reg : SI REG_SP ) .


<s> void emit_pic_move ( rtx * operands , enum machine_mode mode ATTRIBUTE_UNUSED ) { rtx temp = reload_in_progress ? operands [ 0 ] : gen_reg_rtx ( Pmode ) ; if ( GET_CODE ( operands [ 0 ] ) == MEM && SYMBOLIC_CONST ( operands [ 1 ] ) ) operands [ 1 ] = force_reg ( SImode , operands [ 1 ] ) ; else operands [ 1 ] = legitimize_pic_address ( operands [ 1 ] , temp , pic_offset_table_rtx ) ; } </s>

Emit insns to move operands [ 1 ] into operands [ 0 ] .


<s> static void expand_epilogue_reg_restore ( rtx spreg , bool saveall , bool is_inthandler ) { int ndregs = saveall ? 8 : n_dregs_to_save ( is_inthandler ) ; int npregs = saveall ? 6 : n_pregs_to_save ( is_inthandler ) ; int total = ndregs + npregs ; int i , regno ; rtx pat , insn ; if ( total == 0 ) return ; pat = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( total + 1 ) ) ; XVECEXP ( pat , 0 , 0 ) = gen_rtx_SET ( VOIDmode , spreg , gen_rtx_PLUS ( Pmode , spreg , GEN_INT ( total * 4 ) ) ) ; if ( npregs > 0 ) regno = REG_P5 + 1 ; else regno = REG_R7 + 1 ; for ( i = 0 ; i < total ; i ++ ) { rtx addr = ( i > 0 ? gen_rtx_PLUS ( Pmode , spreg , GEN_INT ( i * 4 ) ) : spreg ) ; rtx memref = gen_rtx_MEM ( word_mode , addr ) ; regno -- ; XVECEXP ( pat , 0 , i + 1 ) = gen_rtx_SET ( VOIDmode , gen_rtx_REG ( word_mode , regno ) , memref ) ; if ( npregs > 0 ) { if ( -- npregs == 0 ) regno = REG_R7 + 1 ; } } insn = emit_insn ( pat ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Emit code to restore registers in the epilogue . SAVEALL is nonzero if we must save all registers ; this is used for interrupt handlers . SPREG contains ( reg : SI REG_SP ) . IS_INTHANDLER is true if we 're doing this for an interrupt ( or exception ) handler .


<s> static void expand_interrupt_handler_epilogue ( rtx spreg , e_funkind fkind ) { int i ; rtx postinc1 = gen_rtx_POST_INC ( SImode , spreg ) ; rtx postinc = gen_rtx_MEM ( SImode , postinc1 ) ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = lookup_attribute ( "saveall" , attrs ) != NULL_TREE ; MEM_VOLATILE_P ( postinc ) = 1 ; do_unlink ( spreg , get_frame_size ( ) , all ) ; if ( lookup_attribute ( "nesting" , attrs ) ) { rtx srcreg = gen_rtx_REG ( Pmode , ( fkind == EXCPT_HANDLER ? REG_RETX : fkind == NMI_HANDLER ? REG_RETN : REG_RETI ) ) ; emit_move_insn ( srcreg , postinc ) ; } if ( ! current_function_is_leaf ) all = true ; for ( i = REG_CC - 1 ; i > REG_P7 ; i -- ) if ( all || regs_ever_live [ i ] || ( ! leaf_function_p ( ) && call_used_regs [ i ] ) ) { if ( i == REG_A0 || i == REG_A1 ) { rtx mem = gen_rtx_MEM ( PDImode , postinc1 ) ; MEM_VOLATILE_P ( mem ) = 1 ; emit_move_insn ( gen_rtx_REG ( PDImode , i ) , mem ) ; } else emit_move_insn ( gen_rtx_REG ( SImode , i ) , postinc ) ; } expand_epilogue_reg_restore ( spreg , all , true ) ; emit_move_insn ( gen_rtx_REG ( SImode , REG_ASTAT ) , postinc ) ; if ( fkind == EXCPT_HANDLER ) emit_insn ( gen_addsi3 ( spreg , spreg , GEN_INT ( 12 ) ) ) ; emit_jump_insn ( gen_return_internal ( GEN_INT ( fkind ) ) ) ; } </s>

Generate an epilogue suitable for a function of kind FKIND . This is called for interrupt and exception handler epilogues . SPREG contains ( reg : SI REG_SP ) .


<s> void expand_move ( rtx * operands , enum machine_mode mode ) { if ( flag_pic && SYMBOLIC_CONST ( operands [ 1 ] ) ) emit_pic_move ( operands , mode ) ; else if ( ( reload_in_progress | reload_completed ) == 0 && GET_CODE ( operands [ 0 ] ) == MEM && GET_CODE ( operands [ 1 ] ) != REG ) operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; } </s>

Expand a move operation in mode MODE . The operands are in OPERANDS .


<s> static void expand_prologue_reg_save ( rtx spreg , int saveall , bool is_inthandler ) { int ndregs = saveall ? 8 : n_dregs_to_save ( is_inthandler ) ; int npregs = saveall ? 6 : n_pregs_to_save ( is_inthandler ) ; int dregno = REG_R7 + 1 - ndregs ; int pregno = REG_P5 + 1 - npregs ; int total = ndregs + npregs ; int i ; rtx pat , insn , val ; if ( total == 0 ) return ; val = GEN_INT ( - total * 4 ) ; pat = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( total + 2 ) ) ; XVECEXP ( pat , 0 , 0 ) = gen_rtx_UNSPEC ( VOIDmode , gen_rtvec ( 1 , val ) , UNSPEC_PUSH_MULTIPLE ) ; XVECEXP ( pat , 0 , total + 1 ) = gen_rtx_SET ( VOIDmode , spreg , gen_rtx_PLUS ( Pmode , spreg , val ) ) ; RTX_FRAME_RELATED_P ( XVECEXP ( pat , 0 , total + 1 ) ) = 1 ; for ( i = 0 ; i < total ; i ++ ) { rtx memref = gen_rtx_MEM ( word_mode , gen_rtx_PLUS ( Pmode , spreg , GEN_INT ( - i * 4 - 4 ) ) ) ; rtx subpat ; if ( ndregs > 0 ) { subpat = gen_rtx_SET ( VOIDmode , memref , gen_rtx_REG ( word_mode , dregno ++ ) ) ; ndregs -- ; } else { subpat = gen_rtx_SET ( VOIDmode , memref , gen_rtx_REG ( word_mode , pregno ++ ) ) ; npregs ++ ; } XVECEXP ( pat , 0 , i + 1 ) = subpat ; RTX_FRAME_RELATED_P ( subpat ) = 1 ; } insn = emit_insn ( pat ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Emit code to save registers in the prologue . SAVEALL is nonzero if we must save all registers ; this is used for interrupt handlers . SPREG contains ( reg : SI REG_SP ) . IS_INTHANDLER is true if we 're doing this for an interrupt ( or exception ) handler .


<s> static void frame_related_constant_load ( rtx reg , HOST_WIDE_INT constant , bool related ) { rtx insn ; rtx cst = GEN_INT ( constant ) ; if ( constant >= - 32768 && constant < 65536 ) insn = emit_move_insn ( reg , cst ) ; else { insn = emit_insn ( gen_movsi_high ( reg , cst ) ) ; if ( related ) RTX_FRAME_RELATED_P ( insn ) = 1 ; insn = emit_insn ( gen_movsi_low ( reg , reg , cst ) ) ; } if ( related ) RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Emit code to load a constant CONSTANT into register REG ; setting RTX_FRAME_RELATED_P on all insns we generate if RELATED is true . Make sure that the insns we generate need not be split .


<s> struct rtx_def * function_arg ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int named ATTRIBUTE_UNUSED ) { int bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; if ( mode == VOIDmode ) return GEN_INT ( cum -> call_cookie ) ; if ( bytes == - 1 ) return NULL_RTX ; if ( cum -> nregs ) return gen_rtx_REG ( mode , * ( cum -> arg_regs ) ) ; return NULL_RTX ; } </s>

Return an RTL expression containing the register for the given mode , or 0 if the argument is to be passed on the stack . INCOMING_P is nonzero if this is an incoming argument to the current function .


<s> void function_arg_advance ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int named ATTRIBUTE_UNUSED ) { int count , bytes , words ; bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; cum -> words += words ; cum -> nregs -= words ; if ( cum -> nregs <= 0 ) { cum -> nregs = 0 ; cum -> arg_regs = NULL ; } else { for ( count = 1 ; count <= words ; count ++ ) cum -> arg_regs ++ ; } return ; } </s>

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


<s> static e_funkind funkind ( tree funtype ) { tree attrs = TYPE_ATTRIBUTES ( funtype ) ; if ( lookup_attribute ( "interrupt_handler" , attrs ) ) return INTERRUPT_HANDLER ; else if ( lookup_attribute ( "exception_handler" , attrs ) ) return EXCPT_HANDLER ; else if ( lookup_attribute ( "nmi_handler" , attrs ) ) return NMI_HANDLER ; else return SUBROUTINE ; } </s>

Examine machine-dependent attributes of function type FUNTYPE and return its type . See the definition of E_FUNKIND .


"%qs attribute only applies to functions"

"multiple function type attributes specified"

Handle interrupt_handler , exception_handler and nmi_handler function attributes ; arguments as in struct attribute_spec.handler .


<s> int hard_regno_mode_ok ( int regno , enum machine_mode mode ) { enum reg_class class = REGNO_REG_CLASS ( regno ) ; if ( mode == CCmode ) return 0 ; if ( mode == V2HImode ) return D_REGNO_P ( regno ) ; if ( class == CCREGS ) return mode == BImode ; if ( mode == PDImode ) return regno == REG_A0 || regno == REG_A1 ; if ( mode == SImode && TEST_HARD_REG_BIT ( reg_class_contents [ PROLOGUE_REGS ] , regno ) ) return 1 ; return TEST_HARD_REG_BIT ( reg_class_contents [ MOST_REGS ] , regno ) ; } </s>

Value is 1 if hard register REGNO can hold a value of machine-mode MODE .


<s> rtx legitimize_address ( rtx x ATTRIBUTE_UNUSED , rtx oldx ATTRIBUTE_UNUSED , enum machine_mode mode ATTRIBUTE_UNUSED ) { return NULL_RTX ; } </s>

Try machine-dependent ways of modifying an illegitimate address X to be legitimate . If we find one , return the new , valid address . OLDX is the address as it was before break_out_memory_refs was called . In some cases it is useful to look at this to decide what needs to be done . MODE is the mode of the operand pointed to by X .


<s> rtx legitimize_pic_address ( rtx orig , rtx reg , rtx picreg ) { rtx addr = orig ; rtx new = orig ; if ( GET_CODE ( addr ) == SYMBOL_REF || GET_CODE ( addr ) == LABEL_REF ) { if ( GET_CODE ( addr ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( addr ) ) reg = new = orig ; else { if ( reg == 0 ) { gcc_assert ( ! no_new_pseudos ) ; reg = gen_reg_rtx ( Pmode ) ; } if ( flag_pic == 2 ) { emit_insn ( gen_movsi_high_pic ( reg , addr ) ) ; emit_insn ( gen_movsi_low_pic ( reg , reg , addr ) ) ; emit_insn ( gen_addsi3 ( reg , reg , picreg ) ) ; new = gen_const_mem ( Pmode , reg ) ; } else { rtx tmp = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , addr ) , UNSPEC_MOVE_PIC ) ; new = gen_const_mem ( Pmode , gen_rtx_PLUS ( Pmode , picreg , tmp ) ) ; } emit_move_insn ( reg , new ) ; } if ( picreg == pic_offset_table_rtx ) current_function_uses_pic_offset_table = 1 ; return reg ; } else if ( GET_CODE ( addr ) == CONST || GET_CODE ( addr ) == PLUS ) { rtx base ; if ( GET_CODE ( addr ) == CONST ) { addr = XEXP ( addr , 0 ) ; gcc_assert ( GET_CODE ( addr ) == PLUS ) ; } if ( XEXP ( addr , 0 ) == picreg ) return orig ; if ( reg == 0 ) { gcc_assert ( ! no_new_pseudos ) ; reg = gen_reg_rtx ( Pmode ) ; } base = legitimize_pic_address ( XEXP ( addr , 0 ) , reg , picreg ) ; addr = legitimize_pic_address ( XEXP ( addr , 1 ) , base == reg ? NULL_RTX : reg , picreg ) ; if ( GET_CODE ( addr ) == CONST_INT ) { gcc_assert ( ! reload_in_progress && ! reload_completed ) ; addr = force_reg ( Pmode , addr ) ; } if ( GET_CODE ( addr ) == PLUS && CONSTANT_P ( XEXP ( addr , 1 ) ) ) { base = gen_rtx_PLUS ( Pmode , base , XEXP ( addr , 0 ) ) ; addr = XEXP ( addr , 1 ) ; } return gen_rtx_PLUS ( Pmode , base , addr ) ; } return new ; } </s>

Legitimize PIC addresses . If the address is already position-independent , we return ORIG . Newly generated position-independent addresses go into a reg . This is REG if nonzero , otherwise we allocate register ( s ) as necessary .


<s> static bool must_save_fp_p ( void ) { return frame_pointer_needed || regs_ever_live [ REG_FP ] ; } </s>

Determine if we are going to save the frame pointer in the prologue .


<s> static int n_dregs_to_save ( bool is_inthandler ) { unsigned i ; for ( i = REG_R0 ; i <= REG_R7 ; i ++ ) { if ( regs_ever_live [ i ] && ( is_inthandler || ! call_used_regs [ i ] ) ) return REG_R7 - i + 1 ; if ( current_function_calls_eh_return ) { unsigned j ; for ( j = 0 ; ; j ++ ) { unsigned test = EH_RETURN_DATA_REGNO ( j ) ; if ( test == INVALID_REGNUM ) break ; if ( test == i ) return REG_R7 - i + 1 ; } } } return 0 ; } </s>

Compute the number of DREGS to save with a push_multiple operation . This could include registers that are n't modified in the function , since push_multiple only takes a range of registers . If IS_INTHANDLER , then everything that is live must be saved , even if normally call-clobbered .


<s> static int n_pregs_to_save ( bool is_inthandler ) { unsigned i ; for ( i = REG_P0 ; i <= REG_P5 ; i ++ ) if ( ( regs_ever_live [ i ] && ( is_inthandler || ! call_used_regs [ i ] ) ) || ( i == PIC_OFFSET_TABLE_REGNUM && ( current_function_uses_pic_offset_table || ( TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf ) ) ) ) return REG_P5 - i + 1 ; return 0 ; } </s>

Like n_dregs_to_save , but compute number of PREGS to save .


<s> static int n_regs_saved_by_prologue ( void ) { e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; bool is_inthandler = fkind != SUBROUTINE ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = ( lookup_attribute ( "saveall" , attrs ) != NULL_TREE || ( is_inthandler && ! current_function_is_leaf ) ) ; int ndregs = all ? 8 : n_dregs_to_save ( is_inthandler ) ; int npregs = all ? 6 : n_pregs_to_save ( is_inthandler ) ; int n = ndregs + npregs ; if ( all || stack_frame_needed_p ( ) ) n += 2 ; else { if ( must_save_fp_p ( ) ) n ++ ; if ( ! current_function_is_leaf ) n ++ ; } if ( fkind != SUBROUTINE ) { int i ; n ++ ; if ( lookup_attribute ( "nesting" , attrs ) ) n ++ ; for ( i = REG_P7 + 1 ; i < REG_CC ; i ++ ) if ( all || regs_ever_live [ i ] || ( ! leaf_function_p ( ) && call_used_regs [ i ] ) ) n += i == REG_A0 || i == REG_A1 ? 2 : 1 ; } return n ; } </s>

Return the number of registers pushed during the prologue .


<s>
static
void
output_file_start
(
void
)
{
FILE
*
file
=
asm_out_file
;
int
i
;
fprintf
(
file
,
".file \"%s\";\n"
,
input_filename
)
;
for
(
i
=
0
;
arg_regs
[
i
]
>=
0
;
i
++
)
;
max_arg_registers
=
i
;
}
</s>

Output to FILE the start of the assembler file .


<s>
void
output_pop_multiple
(
rtx
insn
,
rtx
*
operands
)
{
char
buf
[
80
]
;
int
ok
;
ok
=
pop_multiple_operation
(
PATTERN
(
insn
)
,
VOIDmode
)
;
gcc_assert
(
ok
)
;
if
(
first_dreg_to_save
==
8
)
sprintf
(
buf
,
"( p5:%d ) = [sp++];\n"
,
first_preg_to_save
)
;
else
if
(
first_preg_to_save
==
6
)
sprintf
(
buf
,
"( r7:%d ) = [sp++];\n"
,
first_dreg_to_save
)
;
else
sprintf
(
buf
,
"( r7:%d, p5:%d ) = [sp++];\n"
,
first_dreg_to_save
,
first_preg_to_save
)
;
output_asm_insn
(
buf
,
operands
)
;
}
</s>

Emit assembly code for one multi-register pop described by INSN , with operands in OPERANDS .


<s>
void
output_push_multiple
(
rtx
insn
,
rtx
*
operands
)
{
char
buf
[
80
]
;
int
ok
;
ok
=
push_multiple_operation
(
PATTERN
(
insn
)
,
VOIDmode
)
;
gcc_assert
(
ok
)
;
if
(
first_dreg_to_save
==
8
)
sprintf
(
buf
,
"[--sp] = ( p5:%d );\n"
,
first_preg_to_save
)
;
else
if
(
first_preg_to_save
==
6
)
sprintf
(
buf
,
"[--sp] = ( r7:%d );\n"
,
first_dreg_to_save
)
;
else
sprintf
(
buf
,
"[--sp] = ( r7:%d, p5:%d );\n"
,
first_dreg_to_save
,
first_preg_to_save
)
;
output_asm_insn
(
buf
,
operands
)
;
}
</s>

Emit assembly code for one multi-register push described by INSN , with operands in OPERANDS .


"-mshared-library-id= specified without -mid-shared-library"

Set global variables as needed for the options enabled .


<s> void print_address_operand ( FILE * file , rtx x ) { switch ( GET_CODE ( x ) ) { case PLUS : output_address ( XEXP ( x , 0 ) ) ; fprintf ( file , "+" ) ; output_address ( XEXP ( x , 1 ) ) ; break ; case PRE_DEC : fprintf ( file , "--" ) ; output_address ( XEXP ( x , 0 ) ) ; break ; case POST_INC : output_address ( XEXP ( x , 0 ) ) ; fprintf ( file , "++" ) ; break ; case POST_DEC : output_address ( XEXP ( x , 0 ) ) ; fprintf ( file , "--" ) ; break ; default : gcc_assert ( GET_CODE ( x ) != MEM ) ; print_operand ( file , x , 0 ) ; break ; } } </s>

Subroutine of print_operand ; used to print a memory reference X to FILE .


<s> enum reg_class secondary_input_reload_class ( enum reg_class class , enum machine_mode mode , rtx x ) { enum reg_class default_class = GET_MODE_SIZE ( mode ) >= 4 ? DPREGS : DREGS ; enum reg_class x_class = NO_REGS ; enum rtx_code code = GET_CODE ( x ) ; if ( code == SUBREG ) x = SUBREG_REG ( x ) , code = GET_CODE ( x ) ; if ( REG_P ( x ) ) { int regno = REGNO ( x ) ; if ( regno >= FIRST_PSEUDO_REGISTER ) regno = reg_renumber [ regno ] ; if ( regno == - 1 ) code = MEM ; else x_class = REGNO_REG_CLASS ( regno ) ; } if ( fp_plus_const_operand ( x , mode ) ) { rtx op2 = XEXP ( x , 1 ) ; int large_constant_p = ! CONST_7BIT_IMM_P ( INTVAL ( op2 ) ) ; if ( class == PREGS || class == PREGS_CLOBBERED ) return NO_REGS ; if ( class == DREGS || class == DPREGS ) return large_constant_p ? PREGS : NO_REGS ; return PREGS ; } if ( x_class == AREGS ) return class == DREGS || class == AREGS ? NO_REGS : DREGS ; if ( class == AREGS ) { if ( x != const0_rtx && x_class != DREGS ) return DREGS ; else return NO_REGS ; } if ( class == CCREGS && x_class != DREGS ) return DREGS ; if ( x_class == CCREGS && class != DREGS ) return DREGS ; if ( code == MEM ) if ( ! reg_class_subset_p ( class , default_class ) ) return default_class ; return NO_REGS ; } </s>

Inform reload about cases where moving X with a mode MODE to a register in CLASS requires an extra scratch register . Return the class needed for the scratch register .


<s> enum reg_class secondary_output_reload_class ( enum reg_class class , enum machine_mode mode , rtx x ) { return secondary_input_reload_class ( class , mode , x ) ; } </s>

Like secondary_input_reload_class ; and all we do is call that function .


<s> static void setup_incoming_varargs ( CUMULATIVE_ARGS * cum , enum machine_mode mode ATTRIBUTE_UNUSED , tree type ATTRIBUTE_UNUSED , int * pretend_size , int no_rtl ) { rtx mem ; int i ; if ( no_rtl ) return ; for ( i = cum -> words + 1 ; i < max_arg_registers ; i ++ ) { mem = gen_rtx_MEM ( Pmode , plus_constant ( arg_pointer_rtx , ( i * UNITS_PER_WORD ) ) ) ; emit_move_insn ( mem , gen_rtx_REG ( Pmode , i ) ) ; } * pretend_size = 0 ; } </s>

Perform any needed actions needed for a function that is receiving a variable number of arguments . CUM is as above . MODE and TYPE are the mode and type of the current parameter . PRETEND_SIZE is a variable that should be set to the amount of stack that must be pushed by the prolog to pretend that our caller pushed it . Normally , this macro will push all remaining incoming registers on the stack and set PRETEND_SIZE to the length of the registers pushed .


<s> static void single_move_for_strmov ( rtx dst , rtx src , enum machine_mode mode , HOST_WIDE_INT offset ) { rtx scratch = gen_reg_rtx ( mode ) ; rtx srcmem , dstmem ; srcmem = adjust_address_nv ( src , mode , offset ) ; dstmem = adjust_address_nv ( dst , mode , offset ) ; emit_move_insn ( scratch , srcmem ) ; emit_move_insn ( dstmem , scratch ) ; } </s>

Adjust DST and SRC by OFFSET bytes , and generate one move in mode MODE .


<s> static void add_sched_insns_for_speculation ( void ) { rtx_insn * insn ; if ( ! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS && ! ENABLE_WA_INDIRECT_CALLS ) return ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx pat ; if ( NOTE_P ( insn ) || BARRIER_P ( insn ) || LABEL_P ( insn ) ) continue ; if ( JUMP_TABLE_DATA_P ( insn ) ) continue ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == USE || GET_CODE ( pat ) == CLOBBER || GET_CODE ( pat ) == ASM_INPUT || asm_noperands ( pat ) >= 0 ) continue ; if ( JUMP_P ( insn ) ) { if ( any_condjump_p ( insn ) && ! cbranch_predicted_taken_p ( insn ) ) { rtx n = next_real_insn ( insn ) ; emit_insn_before ( gen_stall ( GEN_INT ( 3 ) ) , n ) ; } } } for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) && any_condjump_p ( insn ) && ( cbranch_predicted_taken_p ( insn ) ) ) { rtx target = JUMP_LABEL ( insn ) ; rtx_insn * next = next_real_insn ( target ) ; if ( GET_CODE ( PATTERN ( next ) ) == UNSPEC_VOLATILE && get_attr_type ( next ) == TYPE_STALL ) continue ; emit_insn_before ( gen_stall ( GEN_INT ( 1 ) ) , next ) ; } } } </s>

Called just before the final scheduling pass . If we need to insert NOPs later on to work around speculative loads , insert special placeholder insns that cause loads to be delayed for as many cycles as necessary ( and possible ) . This reduces the number of NOPs we need to add . The dummy insns we generate are later removed by bfin_gen_bundles .


<s> static void add_to_reg ( rtx reg , HOST_WIDE_INT value , int frame , int epilogue_p ) { if ( value == 0 ) return ; if ( value > 120 || value < - 120 ) { rtx tmpreg ; rtx tmpreg2 ; rtx_insn * insn ; tmpreg2 = NULL_RTX ; if ( epilogue_p >= 0 ) tmpreg = gen_rtx_REG ( SImode , REG_P1 ) ; else { int i ; for ( i = REG_P0 ; i <= REG_P5 ; i ++ ) if ( ( df_regs_ever_live_p ( i ) && ! call_used_regs [ i ] ) || ( ! TARGET_FDPIC && i == PIC_OFFSET_TABLE_REGNUM && ( crtl -> uses_pic_offset_table || ( TARGET_ID_SHARED_LIBRARY && ! crtl -> is_leaf ) ) ) ) break ; if ( i <= REG_P5 ) tmpreg = gen_rtx_REG ( SImode , i ) ; else { tmpreg = gen_rtx_REG ( SImode , REG_P1 ) ; tmpreg2 = gen_rtx_REG ( SImode , REG_I0 ) ; emit_move_insn ( tmpreg2 , tmpreg ) ; } } if ( frame ) frame_related_constant_load ( tmpreg , value , TRUE ) ; else insn = emit_move_insn ( tmpreg , GEN_INT ( value ) ) ; insn = emit_insn ( gen_addsi3 ( reg , reg , tmpreg ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( tmpreg2 != NULL_RTX ) emit_move_insn ( tmpreg , tmpreg2 ) ; } else do { int size = value ; rtx_insn * insn ; if ( size > 60 ) size = 60 ; else if ( size < - 60 ) size = - 60 ; insn = emit_insn ( gen_addsi3 ( reg , reg , GEN_INT ( size ) ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; value -= size ; } while ( value != 0 ) ; } </s>

Generate efficient code to add a value to a P register . Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero . EPILOGUE_P is zero if this function is called for prologue , otherwise it 's nonzero . And it 's less than zero if this is for sibcall epilogue .


<s> static int bfin_arg_partial_bytes ( cumulative_args_t cum , machine_mode mode , tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { int bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; int bytes_left = get_cumulative_args ( cum ) -> nregs * UNITS_PER_WORD ; if ( bytes == - 1 ) return 0 ; if ( bytes_left == 0 ) return 0 ; if ( bytes > bytes_left ) return bytes_left ; return 0 ; } </s>

For an arg passed partly in registers and partly in memory , this is the number of bytes passed in registers . For args passed entirely in registers or entirely in memory , zero . Refer VDSP C Compiler manual , our ABI . First 3 words are in registers . So , if a an argument is larger than the registers available , it will span the register and stack .


<s> static bool bfin_can_use_doloop_p ( const widest_int & , const widest_int & iterations_max , unsigned int , bool ) { if ( ! flag_unsafe_loop_optimizations && wi :: geu_p ( iterations_max , 0xFFFFFFFF ) ) return false ; return true ; } </s>


<s> bool bfin_expand_movmem ( rtx dst , rtx src , rtx count_exp , rtx align_exp ) { rtx srcreg , destreg , countreg ; HOST_WIDE_INT align = 0 ; unsigned HOST_WIDE_INT count = 0 ; if ( GET_CODE ( align_exp ) == CONST_INT ) align = INTVAL ( align_exp ) ; if ( GET_CODE ( count_exp ) == CONST_INT ) { count = INTVAL ( count_exp ) ; if ( ! TARGET_INLINE_ALL_STRINGOPS && count > 64 ) return false ; } if ( optimize_size ) { if ( count == 2 && align < 2 ) return false ; if ( count == 4 && align < 4 ) return false ; if ( count != 1 && count != 2 && count != 4 ) return false ; } if ( align < 2 && count != 1 ) return false ; destreg = copy_to_mode_reg ( Pmode , XEXP ( dst , 0 ) ) ; if ( destreg != XEXP ( dst , 0 ) ) dst = replace_equiv_address_nv ( dst , destreg ) ; srcreg = copy_to_mode_reg ( Pmode , XEXP ( src , 0 ) ) ; if ( srcreg != XEXP ( src , 0 ) ) src = replace_equiv_address_nv ( src , srcreg ) ; if ( count != 0 && align >= 2 ) { unsigned HOST_WIDE_INT offset = 0 ; if ( align >= 4 ) { if ( ( count & ~ 3 ) == 4 ) { single_move_for_movmem ( dst , src , SImode , offset ) ; offset = 4 ; } else if ( count & ~ 3 ) { HOST_WIDE_INT new_count = ( ( count >> 2 ) & 0x3fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movsi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; cfun -> machine -> has_loopreg_clobber = true ; } if ( count & 2 ) { single_move_for_movmem ( dst , src , HImode , offset ) ; offset += 2 ; } } else { if ( ( count & ~ 1 ) == 2 ) { single_move_for_movmem ( dst , src , HImode , offset ) ; offset = 2 ; } else if ( count & ~ 1 ) { HOST_WIDE_INT new_count = ( ( count >> 1 ) & 0x7fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movhi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; cfun -> machine -> has_loopreg_clobber = true ; } } if ( count & 1 ) { single_move_for_movmem ( dst , src , QImode , offset ) ; } return true ; } return false ; } </s>

Expand a string move operation of COUNT_EXP bytes from SRC to DST , with alignment ALIGN_EXP . Return true if successful , false if we should fall back on a different method .


<s> void bfin_expand_prologue ( void ) { HOST_WIDE_INT frame_size = get_frame_size ( ) ; rtx spreg = gen_rtx_REG ( Pmode , REG_SP ) ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; rtx pic_reg_loaded = NULL_RTX ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = lookup_attribute ( "saveall" , attrs ) != NULL_TREE ; if ( fkind != SUBROUTINE ) { expand_interrupt_handler_prologue ( spreg , fkind , all ) ; return ; } if ( crtl -> limit_stack || ( TARGET_STACK_CHECK_L1 && ! DECL_NO_LIMIT_STACK ( current_function_decl ) ) ) { HOST_WIDE_INT offset = bfin_initial_elimination_offset ( ARG_POINTER_REGNUM , STACK_POINTER_REGNUM ) ; rtx lim = crtl -> limit_stack ? stack_limit_rtx : NULL_RTX ; rtx tmp = gen_rtx_REG ( Pmode , REG_R3 ) ; rtx p2reg = gen_rtx_REG ( Pmode , REG_P2 ) ; emit_move_insn ( tmp , p2reg ) ; if ( ! lim ) { emit_move_insn ( p2reg , gen_int_mode ( 0xFFB00000 , SImode ) ) ; emit_move_insn ( p2reg , gen_rtx_MEM ( Pmode , p2reg ) ) ; lim = p2reg ; } if ( GET_CODE ( lim ) == SYMBOL_REF ) { if ( TARGET_ID_SHARED_LIBRARY ) { rtx p1reg = gen_rtx_REG ( Pmode , REG_P1 ) ; rtx val ; pic_reg_loaded = bfin_load_pic_reg ( p2reg ) ; val = legitimize_pic_address ( stack_limit_rtx , p1reg , pic_reg_loaded ) ; emit_move_insn ( p1reg , val ) ; frame_related_constant_load ( p2reg , offset , FALSE ) ; emit_insn ( gen_addsi3 ( p2reg , p2reg , p1reg ) ) ; lim = p2reg ; } else { rtx limit = plus_constant ( Pmode , lim , offset ) ; emit_move_insn ( p2reg , limit ) ; lim = p2reg ; } } else { if ( lim != p2reg ) emit_move_insn ( p2reg , lim ) ; add_to_reg ( p2reg , offset , 0 , 0 ) ; lim = p2reg ; } emit_insn ( gen_compare_lt ( bfin_cc_rtx , spreg , lim ) ) ; emit_insn ( gen_trapifcc ( ) ) ; emit_move_insn ( p2reg , tmp ) ; } expand_prologue_reg_save ( spreg , all , false ) ; do_link ( spreg , frame_size , all ) ; if ( TARGET_ID_SHARED_LIBRARY && ! TARGET_SEP_DATA && ( crtl -> uses_pic_offset_table || ! crtl -> is_leaf ) ) bfin_load_pic_reg ( pic_offset_table_rtx ) ; } </s>

Generate RTL for the prologue of the current function .


<s> static rtx bfin_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; if ( mode == VOIDmode ) return GEN_INT ( cum -> call_cookie ) ; if ( bytes == - 1 ) return NULL_RTX ; if ( cum -> nregs ) return gen_rtx_REG ( mode , * ( cum -> arg_regs ) ) ; return NULL_RTX ; } </s>

Define where to put the arguments to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) .


<s> static void bfin_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int count , bytes , words ; bytes = ( mode == BLKmode ) ? int_size_in_bytes ( type ) : GET_MODE_SIZE ( mode ) ; words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; cum -> words += words ; cum -> nregs -= words ; if ( cum -> nregs <= 0 ) { cum -> nregs = 0 ; cum -> arg_regs = NULL ; } else { for ( count = 1 ; count <= words ; count ++ ) cum -> arg_regs ++ ; } return ; } </s>

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


<s> static bool bfin_function_ok_for_sibcall ( tree decl ATTRIBUTE_UNUSED , tree exp ATTRIBUTE_UNUSED ) { struct cgraph_local_info * this_func , * called_func ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; if ( fkind != SUBROUTINE ) return false ; if ( ! TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA ) return true ; if ( ! decl ) return false ; this_func = cgraph_node :: local_info ( current_function_decl ) ; called_func = cgraph_node :: local_info ( decl ) ; if ( ! called_func ) return false ; return ! called_func -> local || this_func -> local ; } </s>

Decide whether we can make a sibling call to a function . DECL is the declaration of the function being targeted by the call and EXP is the CALL_EXPR representing the call .


<s> static void bfin_gen_bundles ( void ) { basic_block bb ; FOR_EACH_BB_FN ( bb , cfun ) { rtx_insn * insn , * next ; rtx_insn * slot [ 3 ] ; int n_filled = 0 ; slot [ 0 ] = slot [ 1 ] = slot [ 2 ] = NULL ; for ( insn = BB_HEAD ( bb ) ; ; insn = next ) { int at_end ; rtx delete_this = NULL_RTX ; if ( NONDEBUG_INSN_P ( insn ) ) { enum attr_type type = get_attr_type ( insn ) ; if ( type == TYPE_STALL ) { gcc_assert ( n_filled == 0 ) ; delete_this = insn ; } else { if ( type == TYPE_DSP32 || type == TYPE_DSP32SHIFTIMM ) slot [ 0 ] = insn ; else if ( slot [ 1 ] == NULL_RTX ) slot [ 1 ] = insn ; else slot [ 2 ] = insn ; n_filled ++ ; } } next = NEXT_INSN ( insn ) ; while ( next && insn != BB_END ( bb ) && ! ( INSN_P ( next ) && GET_CODE ( PATTERN ( next ) ) != USE && GET_CODE ( PATTERN ( next ) ) != CLOBBER ) ) { insn = next ; next = NEXT_INSN ( insn ) ; } at_end = insn == BB_END ( bb ) ; if ( delete_this == NULL_RTX && ( at_end || GET_MODE ( next ) == TImode ) ) { if ( ( n_filled < 2 || ! gen_one_bundle ( slot ) ) && slot [ 0 ] != NULL_RTX ) { rtx pat = PATTERN ( slot [ 0 ] ) ; if ( GET_CODE ( pat ) == SET && GET_CODE ( SET_SRC ( pat ) ) == UNSPEC && XINT ( SET_SRC ( pat ) , 1 ) == UNSPEC_32BIT ) { SET_SRC ( pat ) = XVECEXP ( SET_SRC ( pat ) , 0 , 0 ) ; INSN_CODE ( slot [ 0 ] ) = - 1 ; df_insn_rescan ( slot [ 0 ] ) ; } } n_filled = 0 ; slot [ 0 ] = slot [ 1 ] = slot [ 2 ] = NULL ; } if ( delete_this != NULL_RTX ) delete_insn ( delete_this ) ; if ( at_end ) break ; } } } </s>

Go through all insns , and use the information generated during scheduling to generate SEQUENCEs to represent bundles of instructions issued simultaneously .


<s> rtx bfin_gen_compare ( rtx cmp , machine_mode mode ATTRIBUTE_UNUSED ) { enum rtx_code code1 , code2 ; rtx op0 = XEXP ( cmp , 0 ) , op1 = XEXP ( cmp , 1 ) ; rtx tem = bfin_cc_rtx ; enum rtx_code code = GET_CODE ( cmp ) ; if ( GET_MODE ( op0 ) == BImode ) { gcc_assert ( ( code == NE || code == EQ ) && op1 == const0_rtx ) ; tem = op0 , code2 = code ; } else { switch ( code ) { case EQ : case LT : case LE : case LEU : case LTU : code1 = code ; code2 = NE ; break ; default : code1 = reverse_condition ( code ) ; code2 = EQ ; break ; } emit_insn ( gen_rtx_SET ( VOIDmode , tem , gen_rtx_fmt_ee ( code1 , BImode , op0 , op1 ) ) ) ; } return gen_rtx_fmt_ee ( code2 , BImode , tem , CONST0_RTX ( BImode ) ) ; } </s>

Emit rtl for a comparison operation CMP in mode MODE . Operands have been stored in bfin_compare_op0 and bfin_compare_op1 already .


<s> static bool bfin_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { switch ( GET_CODE ( x ) ) { case REG : if ( bfin_valid_reg_p ( REGNO ( x ) , strict , mode , MEM ) ) return true ; break ; case PLUS : if ( REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , PLUS ) && ( ( GET_CODE ( XEXP ( x , 1 ) ) == UNSPEC && mode == SImode ) || ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && bfin_valid_add ( mode , INTVAL ( XEXP ( x , 1 ) ) ) ) ) ) return true ; break ; case POST_INC : case POST_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , POST_INC ) ) return true ; case PRE_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && XEXP ( x , 0 ) == stack_pointer_rtx && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , PRE_DEC ) ) return true ; break ; default : break ; } return false ; } </s>

Recognize an RTL expression that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . Blackfin addressing modes are as follows : [ preg ] [ preg + imm16 ] B [ Preg + uimm15 ] W [ Preg + uimm16m2 ] [ Preg + uimm17m4 ] [ preg++ ] [ preg -- ] [ -- sp ]


<s> static rtx bfin_load_pic_reg ( rtx dest ) { struct cgraph_local_info * i = NULL ; rtx addr ; i = cgraph_node :: local_info ( current_function_decl ) ; if ( i && i -> local ) return pic_offset_table_rtx ; if ( global_options_set . x_bfin_library_id ) addr = plus_constant ( Pmode , pic_offset_table_rtx , - 4 - bfin_library_id * 4 ) ; else addr = gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_LIBRARY_OFFSET ) ) ; emit_insn ( gen_movsi ( dest , gen_rtx_MEM ( Pmode , addr ) ) ) ; return dest ; } </s>

Used while emitting the prologue to generate code to load the correct value into the PIC register , which is passed in DEST .


<s> unsigned bfin_local_alignment ( tree type , unsigned align ) { if ( TYPE_SIZE ( type ) && TREE_CODE ( TYPE_SIZE ( type ) ) == INTEGER_CST && wi :: gtu_p ( TYPE_SIZE ( type ) , 8 ) && align < 32 ) return 32 ; return align ; } </s>

Compute the alignment for a local variable . TYPE is the data type , and ALIGN is the alignment that the object would ordinarily have . The value of this macro is used instead of that alignment to align the object .


"-mfdpic is not supported, please use a bfin-linux-uclibc target"

"-mshared-library-id= specified without -mid-shared-library"

"-fstack-limit- options are ignored with -mfdpic; use -mstack-check-l1"

"can%'t use multiple stack checking methods together"

"ID shared libraries and FD-PIC mode can%'t be used together"

"cannot specify both -msep-data and -mid-shared-library"

"-mmulticore can only be used with BF561"

"-mcorea should be used with -mmulticore"

"-mcoreb should be used with -mmulticore"

"-mcorea and -mcoreb can%'t be used together"

Implement the TARGET_OPTION_OVERRIDE hook .


<s> static bool bfin_pass_by_reference ( cumulative_args_t cum ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , const_tree type , bool named ATTRIBUTE_UNUSED ) { return type && TREE_CODE ( TYPE_SIZE ( type ) ) != INTEGER_CST ; } </s>

Variable sized types are passed by reference .


<s> static int cbranch_predicted_taken_p ( rtx insn ) { rtx x = find_reg_note ( insn , REG_BR_PROB , 0 ) ; if ( x ) { int pred_val = XINT ( x , 0 ) ; return pred_val >= REG_BR_PROB_BASE / 2 ; } return 0 ; } </s>

Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates it 's a branch that 's predicted taken .


<s> int hard_regno_mode_ok ( int regno , machine_mode mode ) { enum reg_class rclass = REGNO_REG_CLASS ( regno ) ; if ( mode == CCmode ) return 0 ; if ( mode == V2HImode ) return D_REGNO_P ( regno ) ; if ( rclass == CCREGS ) return mode == BImode ; if ( mode == PDImode || mode == V2PDImode ) return regno == REG_A0 || regno == REG_A1 ; if ( mode == DImode ) return regno < REG_M3 ; if ( mode == SImode && TEST_HARD_REG_BIT ( reg_class_contents [ PROLOGUE_REGS ] , regno ) ) return 1 ; return TEST_HARD_REG_BIT ( reg_class_contents [ MOST_REGS ] , regno ) ; } </s>

Value is 1 if hard register REGNO can hold a value of machine-mode MODE .


<s> static void hwloop_fail ( hwloop_info loop ) { rtx insn = loop -> loop_end ; if ( DPREG_P ( loop -> iter_reg ) ) { rtx insn , test ; emit_insn_before ( gen_addsi3 ( loop -> iter_reg , loop -> iter_reg , constm1_rtx ) , loop -> loop_end ) ; test = gen_rtx_NE ( VOIDmode , loop -> iter_reg , const0_rtx ) ; insn = emit_jump_insn_before ( gen_cbranchsi4 ( test , loop -> iter_reg , const0_rtx , loop -> start_label ) , loop -> loop_end ) ; JUMP_LABEL ( insn ) = loop -> start_label ; LABEL_NUSES ( loop -> start_label ) ++ ; delete_insn ( loop -> loop_end ) ; } else { splitting_loops = 1 ; try_split ( PATTERN ( insn ) , insn , 1 ) ; splitting_loops = 0 ; } } </s>

A callback for the hw-doloop pass . Called when a loop we have discovered turns out not to be optimizable ; we have to split the doloop_end pattern into a subtract and a test .


<s> static bool must_save_p ( bool is_inthandler , unsigned regno ) { if ( D_REGNO_P ( regno ) ) { bool is_eh_return_reg = false ; if ( crtl -> calls_eh_return ) { unsigned j ; for ( j = 0 ; ; j ++ ) { unsigned test = EH_RETURN_DATA_REGNO ( j ) ; if ( test == INVALID_REGNUM ) break ; if ( test == regno ) is_eh_return_reg = true ; } } return ( is_eh_return_reg || ( df_regs_ever_live_p ( regno ) && ! fixed_regs [ regno ] && ( is_inthandler || ! call_used_regs [ regno ] ) ) ) ; } else if ( P_REGNO_P ( regno ) ) { return ( ( df_regs_ever_live_p ( regno ) && ! fixed_regs [ regno ] && ( is_inthandler || ! call_used_regs [ regno ] ) ) || ( is_inthandler && ( ENABLE_WA_05000283 || ENABLE_WA_05000315 ) && regno == REG_P5 ) || ( ! TARGET_FDPIC && regno == PIC_OFFSET_TABLE_REGNUM && ( crtl -> uses_pic_offset_table || ( TARGET_ID_SHARED_LIBRARY && ! crtl -> is_leaf ) ) ) ) ; } else return ( ( is_inthandler || ! call_used_regs [ regno ] ) && ( df_regs_ever_live_p ( regno ) || ( ! leaf_function_p ( ) && call_used_regs [ regno ] ) ) ) ; } </s>

For a given REGNO , determine whether it must be saved in the function prologue . IS_INTHANDLER specifies whether we 're generating a normal prologue or an interrupt/exception one .


<s> static int n_regs_saved_by_prologue ( void ) { e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; bool is_inthandler = fkind != SUBROUTINE ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = ( lookup_attribute ( "saveall" , attrs ) != NULL_TREE || ( is_inthandler && ! crtl -> is_leaf ) ) ; int ndregs = all ? 8 : n_dregs_to_save ( is_inthandler , false ) ; int npregs = all ? 6 : n_pregs_to_save ( is_inthandler , false ) ; int n = ndregs + npregs ; int i ; if ( all || stack_frame_needed_p ( ) ) n += 2 ; else { if ( must_save_fp_p ( ) ) n ++ ; if ( must_save_rets_p ( ) ) n ++ ; } if ( fkind != SUBROUTINE || all ) { n ++ ; if ( ! crtl -> is_leaf || cfun -> machine -> has_hardware_loops || cfun -> machine -> has_loopreg_clobber ) { n += 6 ; } } if ( fkind != SUBROUTINE ) { if ( lookup_attribute ( "nesting" , attrs ) ) n ++ ; } for ( i = REG_P7 + 1 ; i < REG_CC ; i ++ ) if ( all || ( fkind != SUBROUTINE && ( df_regs_ever_live_p ( i ) || ( ! leaf_function_p ( ) && call_used_regs [ i ] ) ) ) ) n += i == REG_A0 || i == REG_A1 ? 2 : 1 ; return n ; } </s>

Return the number of registers pushed during the prologue .


<s> static void setup_incoming_varargs ( cumulative_args_t cum , machine_mode mode ATTRIBUTE_UNUSED , tree type ATTRIBUTE_UNUSED , int * pretend_size , int no_rtl ) { rtx mem ; int i ; if ( no_rtl ) return ; for ( i = get_cumulative_args ( cum ) -> words + 1 ; i < max_arg_registers ; i ++ ) { mem = gen_rtx_MEM ( Pmode , plus_constant ( Pmode , arg_pointer_rtx , ( i * UNITS_PER_WORD ) ) ) ; emit_move_insn ( mem , gen_rtx_REG ( Pmode , i ) ) ; } * pretend_size = 0 ; } </s>

Perform any needed actions needed for a function that is receiving a variable number of arguments . CUM is as above . MODE and TYPE are the mode and type of the current parameter . PRETEND_SIZE is a variable that should be set to the amount of stack that must be pushed by the prolog to pretend that our caller pushed it . Normally , this macro will push all remaining incoming registers on the stack and set PRETEND_SIZE to the length of the registers pushed .


<s> static void single_move_for_movmem ( rtx dst , rtx src , machine_mode mode , HOST_WIDE_INT offset ) { rtx scratch = gen_reg_rtx ( mode ) ; rtx srcmem , dstmem ; srcmem = adjust_address_nv ( src , mode , offset ) ; dstmem = adjust_address_nv ( dst , mode , offset ) ; emit_move_insn ( scratch , srcmem ) ; emit_move_insn ( dstmem , scratch ) ; } </s>

Adjust DST and SRC by OFFSET bytes , and generate one move in mode MODE .


<s> static void add_sched_insns_for_speculation ( void ) { rtx_insn * insn ; if ( ! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS && ! ENABLE_WA_INDIRECT_CALLS ) return ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx pat ; if ( NOTE_P ( insn ) || BARRIER_P ( insn ) || LABEL_P ( insn ) ) continue ; if ( JUMP_TABLE_DATA_P ( insn ) ) continue ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == USE || GET_CODE ( pat ) == CLOBBER || GET_CODE ( pat ) == ASM_INPUT || asm_noperands ( pat ) >= 0 ) continue ; if ( JUMP_P ( insn ) ) { if ( any_condjump_p ( insn ) && ! cbranch_predicted_taken_p ( insn ) ) { rtx_insn * n = next_real_insn ( insn ) ; emit_insn_before ( gen_stall ( GEN_INT ( 3 ) ) , n ) ; } } } for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) && any_condjump_p ( insn ) && ( cbranch_predicted_taken_p ( insn ) ) ) { rtx target = JUMP_LABEL ( insn ) ; rtx_insn * next = next_real_insn ( target ) ; if ( GET_CODE ( PATTERN ( next ) ) == UNSPEC_VOLATILE && get_attr_type ( next ) == TYPE_STALL ) continue ; emit_insn_before ( gen_stall ( GEN_INT ( 1 ) ) , next ) ; } } } </s>

Called just before the final scheduling pass . If we need to insert NOPs later on to work around speculative loads , insert special placeholder insns that cause loads to be delayed for as many cycles as necessary ( and possible ) . This reduces the number of NOPs we need to add . The dummy insns we generate are later removed by bfin_gen_bundles .


<s> initialize_trampoline ( TRAMP , FNADDR , CXT ) { { ARG_POINTER_REGNUM , STACK_POINTER_REGNUM } , \ { ARG_POINTER_REGNUM , FRAME_POINTER_REGNUM } , \ { FRAME_POINTER_REGNUM , STACK_POINTER_REGNUM } } </s>

Emit RTL insns to initialize the variable parts of a trampoline at TRAMP . FNADDR is an RTX for the address of the function 's pure code . CXT is an RTX for the static chain value for the function .


<s> static void add_sched_insns_for_speculation ( void ) { rtx_insn * insn ; if ( ! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS && ! ENABLE_WA_INDIRECT_CALLS ) return ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx pat ; if ( NOTE_P ( insn ) || BARRIER_P ( insn ) || LABEL_P ( insn ) ) continue ; if ( JUMP_TABLE_DATA_P ( insn ) ) continue ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == USE || GET_CODE ( pat ) == CLOBBER || GET_CODE ( pat ) == ASM_INPUT || asm_noperands ( pat ) >= 0 ) continue ; if ( JUMP_P ( insn ) ) { if ( any_condjump_p ( insn ) && ! cbranch_predicted_taken_p ( insn ) ) { rtx_insn * n = next_real_insn ( insn ) ; emit_insn_before ( gen_stall ( GEN_INT ( 3 ) ) , n ) ; } } } for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) && any_condjump_p ( insn ) && ( cbranch_predicted_taken_p ( insn ) ) ) { rtx_insn * target = JUMP_LABEL_AS_INSN ( insn ) ; rtx_insn * next = next_real_insn ( target ) ; if ( GET_CODE ( PATTERN ( next ) ) == UNSPEC_VOLATILE && get_attr_type ( next ) == TYPE_STALL ) continue ; emit_insn_before ( gen_stall ( GEN_INT ( 1 ) ) , next ) ; } } } </s>


<s> static void add_to_reg ( rtx reg , HOST_WIDE_INT value , int frame , int epilogue_p ) { if ( value == 0 ) return ; if ( value > 120 || value < - 120 ) { rtx tmpreg ; rtx tmpreg2 ; rtx_insn * insn ; tmpreg2 = NULL_RTX ; if ( epilogue_p >= 0 ) tmpreg = gen_rtx_REG ( SImode , REG_P1 ) ; else { int i ; for ( i = REG_P0 ; i <= REG_P5 ; i ++ ) if ( ( df_regs_ever_live_p ( i ) && ! call_used_or_fixed_reg_p ( i ) ) || ( ! TARGET_FDPIC && i == PIC_OFFSET_TABLE_REGNUM && ( crtl -> uses_pic_offset_table || ( TARGET_ID_SHARED_LIBRARY && ! crtl -> is_leaf ) ) ) ) break ; if ( i <= REG_P5 ) tmpreg = gen_rtx_REG ( SImode , i ) ; else { tmpreg = gen_rtx_REG ( SImode , REG_P1 ) ; tmpreg2 = gen_rtx_REG ( SImode , REG_I0 ) ; emit_move_insn ( tmpreg2 , tmpreg ) ; } } if ( frame ) frame_related_constant_load ( tmpreg , value , TRUE ) ; else insn = emit_move_insn ( tmpreg , GEN_INT ( value ) ) ; insn = emit_insn ( gen_addsi3 ( reg , reg , tmpreg ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( tmpreg2 != NULL_RTX ) emit_move_insn ( tmpreg , tmpreg2 ) ; } else do { int size = value ; rtx_insn * insn ; if ( size > 60 ) size = 60 ; else if ( size < - 60 ) size = - 60 ; insn = emit_insn ( gen_addsi3 ( reg , reg , GEN_INT ( size ) ) ) ; if ( frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; value -= size ; } while ( value != 0 ) ; } </s>

Generate efficient code to add a value to a P register . Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero . EPILOGUE_P is zero if this function is called for prologue , otherwise it 's nonzero . And it 's less than zero if this is for sibcall epilogue .


<s> static HOST_WIDE_INT arg_area_size ( void ) { if ( crtl -> outgoing_args_size ) { if ( crtl -> outgoing_args_size >= FIXED_STACK_AREA ) return crtl -> outgoing_args_size ; else return FIXED_STACK_AREA ; } return 0 ; } </s>

Return the number of bytes we must reserve for outgoing arguments in the current function 's stack frame .


<s> void asm_conditional_branch ( rtx_insn * insn , rtx * operands , int n_nops , int predict_taken ) { int offset = branch_dest ( insn ) - INSN_ADDRESSES ( INSN_UID ( insn ) ) ; int len = ( offset >= - 1024 && offset <= 1022 ? 0 : offset >= - 4094 && offset <= 4096 ? 1 : 2 ) ; int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p ( insn ) ; int idx = ( bp << 1 ) | ( GET_CODE ( operands [ 0 ] ) == EQ ? BRF : BRT ) ; output_asm_insn ( ccbranch_templates [ idx ] [ len ] , operands ) ; gcc_assert ( n_nops == 0 || ! bp ) ; if ( len == 0 ) while ( n_nops -- > 0 ) output_asm_insn ( "nop;" , NULL ) ; } </s>

Output INSN , which is a conditional branch instruction with operands OPERANDS . We deal with the various forms of conditional branches that can be generated by bfin_reorg to prevent the hardware from doing speculative loads , by - emitting a sufficient number of nops , if N_NOPS is nonzero , or - always emitting the branch as predicted taken , if PREDICT_TAKEN is true . Either of these is only necessary if the branch is short , otherwise the template we use ends in an unconditional jump which flushes the pipeline anyway .


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

Return cost of the memory address ADDR . All addressing modes are equally cheap on the Blackfin .


<s> static int bfin_arg_partial_bytes ( cumulative_args_t cum , const function_arg_info & arg ) { int bytes = arg . promoted_size_in_bytes ( ) ; int bytes_left = get_cumulative_args ( cum ) -> nregs * UNITS_PER_WORD ; if ( bytes == - 1 ) return 0 ; if ( bytes_left == 0 ) return 0 ; if ( bytes > bytes_left ) return bytes_left ; return 0 ; } </s>

For an arg passed partly in registers and partly in memory , this is the number of bytes passed in registers . For args passed entirely in registers or entirely in memory , zero . Refer VDSP C Compiler manual , our ABI . First 3 words are in registers . So , if a an argument is larger than the registers available , it will span the register and stack .


<s> static void bfin_asm_trampoline_template ( FILE * f ) { if ( TARGET_FDPIC ) { fprintf ( f , "\t.dd\t0x00000000\n" ) ; fprintf ( f , "\t.dd\t0x00000000\n" ) ; fprintf ( f , "\t.dd\t0x0000e109\n" ) ; fprintf ( f , "\t.dd\t0x0000e149\n" ) ; fprintf ( f , "\t.dd\t0x0000e10a\n" ) ; fprintf ( f , "\t.dd\t0x0000e14a\n" ) ; fprintf ( f , "\t.dw\t0xac4b\n" ) ; fprintf ( f , "\t.dw\t0x9149\n" ) ; fprintf ( f , "\t.dw\t0x0051\n" ) ; } else { fprintf ( f , "\t.dd\t0x0000e109\n" ) ; fprintf ( f , "\t.dd\t0x0000e149\n" ) ; fprintf ( f , "\t.dd\t0x0000e10a\n" ) ; fprintf ( f , "\t.dd\t0x0000e14a\n" ) ; fprintf ( f , "\t.dw\t0x0051\n" ) ; } } </s>

Write a template for a trampoline to F .


<s> static bool bfin_assemble_integer ( rtx value , unsigned int size , int aligned_p ) { if ( TARGET_FDPIC && size == UNITS_PER_WORD ) { if ( GET_CODE ( value ) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P ( value ) ) { fputs ( "\t.picptr\tfuncdesc(" , asm_out_file ) ; output_addr_const ( asm_out_file , value ) ; fputs ( ")\n" , asm_out_file ) ; return true ; } if ( ! aligned_p ) { assemble_integer_with_op ( "\t.4byte\t" , value ) ; return true ; } } return default_assemble_integer ( value , size , aligned_p ) ; } </s>

Implementation of TARGET_ASM_INTEGER . When using FD-PIC , we need to tell the assembler to generate pointers to function descriptors in some cases .


<s> static bool bfin_cannot_force_const_mem ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ATTRIBUTE_UNUSED ) { return true ; } </s>

Decide whether we can force certain constants to memory . If we decide we ca n't , the caller should be able to cope with it in another way .


<s> static bool bfin_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true ) ; } </s>

Given FROM and TO register numbers , say whether this elimination is allowed . Frame pointer elimination is automatically handled . All other eliminations are valid .


<s> static bool bfin_can_use_doloop_p ( const widest_int & , const widest_int & iterations_max , unsigned int , bool ) { return ( wi :: ltu_p ( iterations_max , 0xFFFFFFFF ) ) ; } </s>


<s> static bool bfin_class_likely_spilled_p ( reg_class_t rclass ) { switch ( rclass ) { case PREGS_CLOBBERED : case PROLOGUE_REGS : case P0REGS : case D0REGS : case D1REGS : case D2REGS : case CCREGS : return true ; default : break ; } return false ; } </s>


<s> static int bfin_comp_type_attributes ( const_tree type1 , const_tree type2 ) { e_funkind kind1 , kind2 ; if ( TREE_CODE ( type1 ) != FUNCTION_TYPE ) return 1 ; kind1 = funkind ( type1 ) ; kind2 = funkind ( type2 ) ; if ( kind1 != kind2 ) return 0 ; if ( ! lookup_attribute ( "nesting" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "nesting" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "saveall" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "saveall" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "kspisusp" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "kspisusp" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; if ( ! lookup_attribute ( "longcall" , TYPE_ATTRIBUTES ( type1 ) ) != ! lookup_attribute ( "longcall" , TYPE_ATTRIBUTES ( type2 ) ) ) return 0 ; return 1 ; } </s>

Return 0 if the attributes for two types are incompatible , 1 if they are compatible , and 2 if they are nearly compatible ( which causes a warning to be generated ) .


<s> bool bfin_dsp_memref_p ( rtx x ) { if ( ! MEM_P ( x ) ) return false ; x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == POST_INC || GET_CODE ( x ) == PRE_INC || GET_CODE ( x ) == POST_DEC || GET_CODE ( x ) == PRE_DEC ) x = XEXP ( x , 0 ) ; return IREG_P ( x ) ; } </s>

Returns true if X is a memory reference using an I register .


<s> static rtx bfin_expand_binop_builtin ( enum insn_code icode , tree exp , rtx target , int macflag ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; tree arg1 = CALL_EXPR_ARG ( exp , 1 ) ; rtx op0 = expand_normal ( arg0 ) ; rtx op1 = expand_normal ( arg1 ) ; machine_mode op0mode = GET_MODE ( op0 ) ; machine_mode op1mode = GET_MODE ( op1 ) ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; machine_mode mode1 = insn_data [ icode ] . operand [ 2 ] . mode ; if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( VECTOR_MODE_P ( mode1 ) ) op1 = safe_vector_operand ( op1 , mode1 ) ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; if ( ( op0mode == SImode || op0mode == VOIDmode ) && mode0 == HImode ) { op0mode = HImode ; op0 = gen_lowpart ( HImode , op0 ) ; } if ( ( op1mode == SImode || op1mode == VOIDmode ) && mode1 == HImode ) { op1mode = HImode ; op1 = gen_lowpart ( HImode , op1 ) ; } gcc_assert ( ( op0mode == mode0 || op0mode == VOIDmode ) && ( op1mode == mode1 || op1mode == VOIDmode ) ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 2 ] . predicate ) ( op1 , mode1 ) ) op1 = copy_to_mode_reg ( mode1 , op1 ) ; if ( macflag == - 1 ) pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( target , op0 , op1 , GEN_INT ( macflag ) ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>

Subroutine of bfin_expand_builtin to take care of binop insns . MACFLAG is -1 if this is a normal binary op , or one of the MACFLAG_xxx constants .


<s> bool bfin_expand_cpymem ( rtx dst , rtx src , rtx count_exp , rtx align_exp ) { rtx srcreg , destreg , countreg ; HOST_WIDE_INT align = 0 ; unsigned HOST_WIDE_INT count = 0 ; if ( GET_CODE ( align_exp ) == CONST_INT ) align = INTVAL ( align_exp ) ; if ( GET_CODE ( count_exp ) == CONST_INT ) { count = INTVAL ( count_exp ) ; if ( ! TARGET_INLINE_ALL_STRINGOPS && count > 64 ) return false ; } if ( optimize_size ) { if ( count == 2 && align < 2 ) return false ; if ( count == 4 && align < 4 ) return false ; if ( count != 1 && count != 2 && count != 4 ) return false ; } if ( align < 2 && count != 1 ) return false ; destreg = copy_to_mode_reg ( Pmode , XEXP ( dst , 0 ) ) ; if ( destreg != XEXP ( dst , 0 ) ) dst = replace_equiv_address_nv ( dst , destreg ) ; srcreg = copy_to_mode_reg ( Pmode , XEXP ( src , 0 ) ) ; if ( srcreg != XEXP ( src , 0 ) ) src = replace_equiv_address_nv ( src , srcreg ) ; if ( count != 0 && align >= 2 ) { unsigned HOST_WIDE_INT offset = 0 ; if ( align >= 4 ) { if ( ( count & ~ 3 ) == 4 ) { single_move_for_cpymem ( dst , src , SImode , offset ) ; offset = 4 ; } else if ( count & ~ 3 ) { HOST_WIDE_INT new_count = ( ( count >> 2 ) & 0x3fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movsi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; cfun -> machine -> has_loopreg_clobber = true ; } if ( count & 2 ) { single_move_for_cpymem ( dst , src , HImode , offset ) ; offset += 2 ; } } else { if ( ( count & ~ 1 ) == 2 ) { single_move_for_cpymem ( dst , src , HImode , offset ) ; offset = 2 ; } else if ( count & ~ 1 ) { HOST_WIDE_INT new_count = ( ( count >> 1 ) & 0x7fffffff ) - 1 ; countreg = copy_to_mode_reg ( Pmode , GEN_INT ( new_count ) ) ; emit_insn ( gen_rep_movhi ( destreg , srcreg , countreg , destreg , srcreg ) ) ; cfun -> machine -> has_loopreg_clobber = true ; } } if ( count & 1 ) { single_move_for_cpymem ( dst , src , QImode , offset ) ; } return true ; } return false ; } </s>

Expand a string move operation of COUNT_EXP bytes from SRC to DST , with alignment ALIGN_EXP . Return true if successful , false if we should fall back on a different method .


<s> void bfin_expand_epilogue ( int need_return , int eh_return , bool sibcall_p ) { rtx spreg = gen_rtx_REG ( Pmode , REG_SP ) ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; int e = sibcall_p ? - 1 : 1 ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = lookup_attribute ( "saveall" , attrs ) != NULL_TREE ; if ( fkind != SUBROUTINE ) { expand_interrupt_handler_epilogue ( spreg , fkind , all ) ; return ; } do_unlink ( spreg , get_frame_size ( ) , all , e ) ; expand_epilogue_reg_restore ( spreg , all , false ) ; if ( ! need_return ) return ; if ( eh_return ) emit_insn ( gen_addsi3 ( spreg , spreg , gen_rtx_REG ( Pmode , REG_P2 ) ) ) ; emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , REG_RETS ) ) ) ; } </s>

Generate RTL for the epilogue of the current function . NEED_RETURN is zero if this is for a sibcall . EH_RETURN is nonzero if we 're expanding an eh_return pattern .


<s> void bfin_expand_prologue ( void ) { HOST_WIDE_INT frame_size = get_frame_size ( ) ; rtx spreg = gen_rtx_REG ( Pmode , REG_SP ) ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; rtx pic_reg_loaded = NULL_RTX ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; bool all = lookup_attribute ( "saveall" , attrs ) != NULL_TREE ; if ( flag_stack_usage_info ) current_function_static_stack_size = frame_size ; if ( fkind != SUBROUTINE ) { expand_interrupt_handler_prologue ( spreg , fkind , all ) ; return ; } if ( crtl -> limit_stack || ( TARGET_STACK_CHECK_L1 && ! DECL_NO_LIMIT_STACK ( current_function_decl ) ) ) { HOST_WIDE_INT offset = bfin_initial_elimination_offset ( ARG_POINTER_REGNUM , STACK_POINTER_REGNUM ) ; rtx lim = crtl -> limit_stack ? stack_limit_rtx : NULL_RTX ; rtx tmp = gen_rtx_REG ( Pmode , REG_R3 ) ; rtx p2reg = gen_rtx_REG ( Pmode , REG_P2 ) ; emit_move_insn ( tmp , p2reg ) ; if ( ! lim ) { emit_move_insn ( p2reg , gen_int_mode ( 0xFFB00000 , SImode ) ) ; emit_move_insn ( p2reg , gen_rtx_MEM ( Pmode , p2reg ) ) ; lim = p2reg ; } if ( GET_CODE ( lim ) == SYMBOL_REF ) { if ( TARGET_ID_SHARED_LIBRARY ) { rtx p1reg = gen_rtx_REG ( Pmode , REG_P1 ) ; rtx val ; pic_reg_loaded = bfin_load_pic_reg ( p2reg ) ; val = legitimize_pic_address ( stack_limit_rtx , p1reg , pic_reg_loaded ) ; emit_move_insn ( p1reg , val ) ; frame_related_constant_load ( p2reg , offset , FALSE ) ; emit_insn ( gen_addsi3 ( p2reg , p2reg , p1reg ) ) ; lim = p2reg ; } else { rtx limit = plus_constant ( Pmode , lim , offset ) ; emit_move_insn ( p2reg , limit ) ; lim = p2reg ; } } else { if ( lim != p2reg ) emit_move_insn ( p2reg , lim ) ; add_to_reg ( p2reg , offset , 0 , 0 ) ; lim = p2reg ; } emit_insn ( gen_compare_lt ( bfin_cc_rtx , spreg , lim ) ) ; emit_insn ( gen_trapifcc ( ) ) ; emit_move_insn ( p2reg , tmp ) ; } expand_prologue_reg_save ( spreg , all , false ) ; do_link ( spreg , frame_size , all ) ; if ( TARGET_ID_SHARED_LIBRARY && ! TARGET_SEP_DATA && ( crtl -> uses_pic_offset_table || ! crtl -> is_leaf ) ) bfin_load_pic_reg ( pic_offset_table_rtx ) ; } </s>

Generate RTL for the prologue of the current function .


<s> static rtx bfin_expand_unop_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; rtx op0 = expand_normal ( arg0 ) ; machine_mode op0mode = GET_MODE ( op0 ) ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( op0mode == SImode && mode0 == HImode ) { op0mode = HImode ; op0 = gen_lowpart ( HImode , op0 ) ; } gcc_assert ( op0mode == mode0 || op0mode == VOIDmode ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; pat = GEN_FCN ( icode ) ( target , op0 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>

Subroutine of bfin_expand_builtin to take care of unop insns .


<s> static void bfin_extra_live_on_entry ( bitmap regs ) { if ( TARGET_FDPIC ) bitmap_set_bit ( regs , FDPIC_REGNO ) ; } </s>


<s> static bool bfin_frame_pointer_required ( void ) { e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; if ( fkind != SUBROUTINE ) return true ; if ( TARGET_OMIT_LEAF_FRAME_POINTER && ! crtl -> is_leaf ) return true ; return false ; } </s>

Value should be nonzero if functions must have frame pointers . Zero means the frame pointer need not be set up ( and parms may be accessed via the stack pointer ) in functions that seem suitable .


<s> static rtx bfin_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int bytes = arg . promoted_size_in_bytes ( ) ; if ( arg . end_marker_p ( ) ) return GEN_INT ( cum -> call_cookie ) ; if ( bytes == - 1 ) return NULL_RTX ; if ( cum -> nregs ) return gen_rtx_REG ( arg . mode , * ( cum -> arg_regs ) ) ; return NULL_RTX ; } </s>

Define where to put the arguments to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) .


<s> static void bfin_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int count , bytes , words ; bytes = arg . promoted_size_in_bytes ( ) ; words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; cum -> words += words ; cum -> nregs -= words ; if ( cum -> nregs <= 0 ) { cum -> nregs = 0 ; cum -> arg_regs = NULL ; } else { for ( count = 1 ; count <= words ; count ++ ) cum -> arg_regs ++ ; } return ; } </s>

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


<s> static bool bfin_function_ok_for_sibcall ( tree decl ATTRIBUTE_UNUSED , tree exp ATTRIBUTE_UNUSED ) { cgraph_node * this_func , * called_func ; e_funkind fkind = funkind ( TREE_TYPE ( current_function_decl ) ) ; if ( fkind != SUBROUTINE ) return false ; if ( ! TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA ) return true ; if ( ! decl ) return false ; this_func = cgraph_node :: local_info_node ( current_function_decl ) ; called_func = cgraph_node :: local_info_node ( decl ) ; if ( ! called_func ) return false ; return ! called_func -> local || this_func -> local ; } </s>

Decide whether we can make a sibling call to a function . DECL is the declaration of the function being targeted by the call and EXP is the CALL_EXPR representing the call .


<s> static void bfin_gen_bundles ( void ) { basic_block bb ; FOR_EACH_BB_FN ( bb , cfun ) { rtx_insn * insn , * next ; rtx_insn * slot [ 3 ] ; int n_filled = 0 ; slot [ 0 ] = slot [ 1 ] = slot [ 2 ] = NULL ; for ( insn = BB_HEAD ( bb ) ; ; insn = next ) { int at_end ; rtx_insn * delete_this = NULL ; if ( NONDEBUG_INSN_P ( insn ) ) { enum attr_type type = get_attr_type ( insn ) ; if ( type == TYPE_STALL ) { gcc_assert ( n_filled == 0 ) ; delete_this = insn ; } else { if ( type == TYPE_DSP32 || type == TYPE_DSP32SHIFTIMM ) slot [ 0 ] = insn ; else if ( slot [ 1 ] == NULL_RTX ) slot [ 1 ] = insn ; else slot [ 2 ] = insn ; n_filled ++ ; } } next = NEXT_INSN ( insn ) ; while ( next && insn != BB_END ( bb ) && ! ( INSN_P ( next ) && GET_CODE ( PATTERN ( next ) ) != USE && GET_CODE ( PATTERN ( next ) ) != CLOBBER ) ) { insn = next ; next = NEXT_INSN ( insn ) ; } at_end = insn == BB_END ( bb ) ; if ( delete_this == NULL_RTX && ( at_end || GET_MODE ( next ) == TImode ) ) { if ( ( n_filled < 2 || ! gen_one_bundle ( slot ) ) && slot [ 0 ] != NULL_RTX ) { rtx pat = PATTERN ( slot [ 0 ] ) ; if ( GET_CODE ( pat ) == SET && GET_CODE ( SET_SRC ( pat ) ) == UNSPEC && XINT ( SET_SRC ( pat ) , 1 ) == UNSPEC_32BIT ) { SET_SRC ( pat ) = XVECEXP ( SET_SRC ( pat ) , 0 , 0 ) ; INSN_CODE ( slot [ 0 ] ) = - 1 ; df_insn_rescan ( slot [ 0 ] ) ; } } n_filled = 0 ; slot [ 0 ] = slot [ 1 ] = slot [ 2 ] = NULL ; } if ( delete_this != NULL_RTX ) delete_insn ( delete_this ) ; if ( at_end ) break ; } } } </s>

Go through all insns , and use the information generated during scheduling to generate SEQUENCEs to represent bundles of instructions issued simultaneously .


<s> rtx bfin_gen_compare ( rtx cmp , machine_mode mode ATTRIBUTE_UNUSED ) { enum rtx_code code1 , code2 ; rtx op0 = XEXP ( cmp , 0 ) , op1 = XEXP ( cmp , 1 ) ; rtx tem = bfin_cc_rtx ; enum rtx_code code = GET_CODE ( cmp ) ; if ( GET_MODE ( op0 ) == BImode ) { gcc_assert ( ( code == NE || code == EQ ) && op1 == const0_rtx ) ; tem = op0 , code2 = code ; } else { switch ( code ) { case EQ : case LT : case LE : case LEU : case LTU : code1 = code ; code2 = NE ; break ; default : code1 = reverse_condition ( code ) ; code2 = EQ ; break ; } emit_insn ( gen_rtx_SET ( tem , gen_rtx_fmt_ee ( code1 , BImode , op0 , op1 ) ) ) ; } return gen_rtx_fmt_ee ( code2 , BImode , tem , CONST0_RTX ( BImode ) ) ; } </s>

Emit rtl for a comparison operation CMP in mode MODE . Operands have been stored in bfin_compare_op0 and bfin_compare_op1 already .


"%qE attribute only applies to variables"

"%qE attribute cannot be specified for local variables"

"section of %q+D conflicts with previous declaration"

Handle a `` l1_data '' , `` l1_data_A '' or `` l1_data_B '' attribute ; arguments as in struct attribute_spec.handler .


"%qE attribute only applies to functions"

Handle a `` l1_text '' attribute ; arguments as in struct attribute_spec.handler .


Handle a `` l2 '' attribute ; arguments as in struct attribute_spec.handler .


"cannot apply both %<longcall%> and %<shortcall%> attributes "

Handle a `` longcall '' or `` shortcall '' attribute ; arguments as in struct attribute_spec.handler .


<s> void bfin_hardware_loop ( void ) { cfun -> machine -> has_hardware_loops ++ ; } </s>

Increment the counter for the number of loop instructions in the current function .


<s> static bool bfin_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { enum reg_class rclass = REGNO_REG_CLASS ( regno ) ; if ( mode == CCmode ) return false ; if ( mode == V2HImode ) return D_REGNO_P ( regno ) ; if ( rclass == CCREGS ) return mode == BImode ; if ( mode == PDImode || mode == V2PDImode ) return regno == REG_A0 || regno == REG_A1 ; if ( mode == DImode ) return regno < REG_M3 ; if ( mode == SImode && TEST_HARD_REG_BIT ( reg_class_contents [ PROLOGUE_REGS ] , regno ) ) return true ; return TEST_HARD_REG_BIT ( reg_class_contents [ MOST_REGS ] , regno ) ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . Do not allow to store a value in REG_CC for any mode . Do not allow to store value in pregs if mode is not SI .


<s> static unsigned int bfin_hard_regno_nregs ( unsigned int regno , machine_mode mode ) { if ( mode == PDImode && ( regno == REG_A0 || regno == REG_A1 ) ) return 1 ; if ( mode == V2PDImode && ( regno == REG_A0 || regno == REG_A1 ) ) return 2 ; return CLASS_MAX_NREGS ( GENERAL_REGS , mode ) ; } </s>


<s> int bfin_hard_regno_rename_ok ( unsigned int old_reg ATTRIBUTE_UNUSED , unsigned int new_reg ) { if ( funkind ( TREE_TYPE ( current_function_decl ) ) != SUBROUTINE && ! df_regs_ever_live_p ( new_reg ) ) return 0 ; return 1 ; } </s>

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


<s> HOST_WIDE_INT bfin_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT offset = 0 ; if ( from == ARG_POINTER_REGNUM ) offset = n_regs_saved_by_prologue ( ) * 4 ; if ( to == STACK_POINTER_REGNUM ) { if ( crtl -> outgoing_args_size >= FIXED_STACK_AREA ) offset += crtl -> outgoing_args_size ; else if ( crtl -> outgoing_args_size ) offset += FIXED_STACK_AREA ; offset += get_frame_size ( ) ; } return offset ; } </s>

Return the offset between two registers , one to be eliminated , and the other its replacement , at the start of a routine .


<s> static int bfin_issue_rate ( void ) { return 3 ; } </s>


<s> static bool bfin_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { switch ( GET_CODE ( x ) ) { case REG : if ( bfin_valid_reg_p ( REGNO ( x ) , strict , mode , MEM ) ) return true ; break ; case PLUS : if ( REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , PLUS ) && ( ( GET_CODE ( XEXP ( x , 1 ) ) == UNSPEC && mode == SImode ) || ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && bfin_valid_add ( mode , INTVAL ( XEXP ( x , 1 ) ) ) ) ) ) return true ; break ; case POST_INC : case POST_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , POST_INC ) ) return true ; break ; case PRE_DEC : if ( LEGITIMATE_MODE_FOR_AUTOINC_P ( mode ) && XEXP ( x , 0 ) == stack_pointer_rtx && REG_P ( XEXP ( x , 0 ) ) && bfin_valid_reg_p ( REGNO ( XEXP ( x , 0 ) ) , strict , mode , PRE_DEC ) ) return true ; break ; default : break ; } return false ; } </s>

Recognize an RTL expression that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . Blackfin addressing modes are as follows : [ preg ] [ preg + imm16 ] B [ Preg + uimm15 ] W [ Preg + uimm16m2 ] [ Preg + uimm17m4 ] [ preg++ ] [ preg -- ] [ -- sp ]


<s> static bool bfin_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { rtx sym ; HOST_WIDE_INT offset ; if ( GET_CODE ( x ) != CONST ) return true ; x = XEXP ( x , 0 ) ; gcc_assert ( GET_CODE ( x ) == PLUS ) ; sym = XEXP ( x , 0 ) ; x = XEXP ( x , 1 ) ; if ( GET_CODE ( sym ) != SYMBOL_REF || GET_CODE ( x ) != CONST_INT ) return true ; offset = INTVAL ( x ) ; if ( SYMBOL_REF_DECL ( sym ) == 0 ) return true ; if ( offset < 0 || offset >= int_size_in_bytes ( TREE_TYPE ( SYMBOL_REF_DECL ( sym ) ) ) ) return false ; return true ; } </s>

Ensure that for any constant of the form symbol + offset , the offset remains within the object . Any other constants are ok . This ensures that flat binaries never have to deal with relocations crossing section boundaries .


<s> static rtx bfin_load_pic_reg ( rtx dest ) { rtx addr ; cgraph_node * local_info_node = cgraph_node :: local_info_node ( current_function_decl ) ; if ( local_info_node && local_info_node -> local ) return pic_offset_table_rtx ; if ( OPTION_SET_P ( bfin_library_id ) ) addr = plus_constant ( Pmode , pic_offset_table_rtx , - 4 - bfin_library_id * 4 ) ; else addr = gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_LIBRARY_OFFSET ) ) ; emit_insn ( gen_movsi ( dest , gen_rtx_MEM ( Pmode , addr ) ) ) ; return dest ; } </s>

Used while emitting the prologue to generate code to load the correct value into the PIC register , which is passed in DEST .


<s> unsigned bfin_local_alignment ( tree type , unsigned align ) { if ( TYPE_SIZE ( type ) && TREE_CODE ( TYPE_SIZE ( type ) ) == INTEGER_CST && wi :: gtu_p ( wi :: to_wide ( TYPE_SIZE ( type ) ) , 8 ) && align < 32 ) return 32 ; return align ; } </s>

Compute the alignment for a local variable . TYPE is the data type , and ALIGN is the alignment that the object would ordinarily have . The value of this macro is used instead of that alignment to align the object .


"%<-mfdpic%> is not supported, please use a bfin-linux-uclibc "

"%<-mshared-library-id=%> specified without "

"%<-fstack-limit-%> options are ignored with %<-mfdpic%>; "

"cannot use multiple stack checking methods together"

"ID shared libraries and FD-PIC mode cannot be used together"

"cannot specify both %<-msep-data%> and %<-mid-shared-library%>"

"%<-mmulticore%> can only be used with BF561"

"%<-mcorea%> should be used with %<-mmulticore%>"

"%<-mcoreb%> should be used with %<-mmulticore%>"

"%<-mcorea%> and %<-mcoreb%> cannot be used together"

Implement the TARGET_OPTION_OVERRIDE hook .


<s> static bool bfin_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { return arg . type && TREE_CODE ( TYPE_SIZE ( arg . type ) ) != INTEGER_CST ; } </s>

Variable sized types are passed by reference .


<s> static int bfin_register_move_cost ( machine_mode mode , reg_class_t class1 , reg_class_t class2 ) { if ( ( class1 == CCREGS && ! reg_class_subset_p ( class2 , DREGS ) ) || ( class2 == CCREGS && ! reg_class_subset_p ( class1 , DREGS ) ) ) return 4 ; if ( optimize_size ) return 2 ; if ( GET_MODE_CLASS ( mode ) == MODE_INT ) { if ( TEST_HARD_REG_BIT ( reg_class_contents [ class1 ] , REG_A0 ) || TEST_HARD_REG_BIT ( reg_class_contents [ class1 ] , REG_A1 ) || TEST_HARD_REG_BIT ( reg_class_contents [ class2 ] , REG_A0 ) || TEST_HARD_REG_BIT ( reg_class_contents [ class2 ] , REG_A1 ) ) return 20 ; } return 2 ; } </s>

Return the cost of moving data from a register in class CLASS1 to one in class CLASS2 . A cost of 2 is the default .


<s> static void bfin_reorg ( void ) { compute_bb_for_insn ( ) ; if ( flag_schedule_insns_after_reload ) { splitting_for_sched = 1 ; split_all_insns ( ) ; splitting_for_sched = 0 ; add_sched_insns_for_speculation ( ) ; timevar_push ( TV_SCHED2 ) ; if ( flag_selective_scheduling2 && ! maybe_skip_selective_scheduling ( ) ) run_selective_scheduling ( ) ; else schedule_insns ( ) ; timevar_pop ( TV_SCHED2 ) ; bfin_gen_bundles ( ) ; } df_analyze ( ) ; if ( cfun -> machine -> has_hardware_loops ) bfin_reorg_loops ( ) ; workaround_speculation ( ) ; if ( flag_var_tracking ) { timevar_push ( TV_VAR_TRACKING ) ; variable_tracking_main ( ) ; reorder_var_tracking_notes ( ) ; timevar_pop ( TV_VAR_TRACKING ) ; } df_finish_pass ( false ) ; workaround_rts_anomaly ( ) ; } </s>

We use the machine specific reorg pass for emitting CSYNC instructions after conditional branches as needed . The Blackfin is unusual in that a code sequence like if cc jump label r0 = ( p0 ) may speculatively perform the load even if the condition is n't true . This happens for a branch that is predicted not taken , because the pipeline is n't flushed or stalled , so the early stages of the following instructions , which perform the memory reference , are allowed to execute before the jump condition is evaluated . Therefore , we must insert additional instructions in all places where this could lead to incorrect behavior . The manual recommends CSYNC , while VDSP seems to use NOPs ( even though its corresponding compiler option is named CSYNC ) . When optimizing for speed , we emit NOPs , which seems faster than a CSYNC . When optimizing for size , we turn the branch into a predicted taken one . This may be slower due to mispredicts , but saves code size .


<s> static void bfin_reorg_loops ( void ) { reorg_loops ( true , & bfin_doloop_hooks ) ; } </s>

Run from machine_dependent_reorg , this pass looks for doloop_end insns and tries to rewrite the RTL of these loops so that proper Blackfin hardware loops are generated .


<s> rtx bfin_return_addr_rtx ( int count ) { if ( count != 0 ) return const0_rtx ; return get_hard_reg_initial_val ( Pmode , REG_RETS ) ; } </s>

Return the value of the return address for the frame COUNT steps up from the current frame , after the prologue . We punt for everything but the current frame by returning const0_rtx .


<s> static bool bfin_return_in_memory ( const_tree type , const_tree fntype ATTRIBUTE_UNUSED ) { int size = int_size_in_bytes ( type ) ; return size > 2 * UNITS_PER_WORD || size == - 1 ; } </s>

Decide whether a type should be returned in memory ( true ) or in a register ( false ) . This is called by the macro RETURN_IN_MEMORY .


<s> static reg_class_t bfin_secondary_reload ( bool in_p , rtx x , reg_class_t rclass_i , machine_mode mode , secondary_reload_info * sri ) { enum reg_class default_class = GET_MODE_SIZE ( mode ) >= 4 ? DPREGS : DREGS ; enum reg_class x_class = NO_REGS ; enum rtx_code code = GET_CODE ( x ) ; enum reg_class rclass = ( enum reg_class ) rclass_i ; if ( code == SUBREG ) x = SUBREG_REG ( x ) , code = GET_CODE ( x ) ; if ( REG_P ( x ) ) { int regno = REGNO ( x ) ; if ( regno >= FIRST_PSEUDO_REGISTER ) regno = reg_renumber [ regno ] ; if ( regno == - 1 ) code = MEM ; else x_class = REGNO_REG_CLASS ( regno ) ; } if ( fp_plus_const_operand ( x , mode ) ) { rtx op2 = XEXP ( x , 1 ) ; int large_constant_p = ! satisfies_constraint_Ks7 ( op2 ) ; if ( rclass == PREGS || rclass == PREGS_CLOBBERED ) return NO_REGS ; if ( ( rclass == DREGS || rclass == DPREGS ) && ! large_constant_p ) return NO_REGS ; sri -> icode = CODE_FOR_reload_insi ; return NO_REGS ; } if ( x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS ) return ( rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS ? NO_REGS : DREGS ) ; if ( rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS ) { if ( code == MEM ) { sri -> icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi ; return NO_REGS ; } if ( x != const0_rtx && x_class != DREGS ) { return DREGS ; } else return NO_REGS ; } if ( rclass == CCREGS && x_class != DREGS ) return DREGS ; if ( x_class == CCREGS && rclass != DREGS ) return DREGS ; if ( code == MEM ) if ( ! reg_class_subset_p ( rclass , default_class ) ) return default_class ; return NO_REGS ; } </s>

Inform reload about cases where moving X with a mode MODE to a register in RCLASS requires an extra scratch register . Return the class needed for the scratch register .


<s> static rtx bfin_struct_value_rtx ( tree fntype ATTRIBUTE_UNUSED , int incoming ATTRIBUTE_UNUSED ) { return gen_rtx_REG ( Pmode , REG_P0 ) ; } </s>

Register in which address to store a structure value is passed to a function .