<s> static int c6x_adjust_cost ( rtx_insn * insn , rtx link , rtx_insn * dep_insn , int cost ) { enum attr_type insn_type = TYPE_UNKNOWN , dep_insn_type = TYPE_UNKNOWN ; int dep_insn_code_number , insn_code_number ; int shadow_bonus = 0 ; enum reg_note kind ; dep_insn_code_number = recog_memoized ( dep_insn ) ; insn_code_number = recog_memoized ( insn ) ; if ( dep_insn_code_number >= 0 ) dep_insn_type = get_attr_type ( dep_insn ) ; if ( insn_code_number >= 0 ) insn_type = get_attr_type ( insn ) ; kind = REG_NOTE_KIND ( link ) ; if ( kind == 0 ) { if ( dep_insn_type == TYPE_LOAD ) { rtx set = PATTERN ( dep_insn ) ; if ( GET_CODE ( set ) == COND_EXEC ) set = COND_EXEC_CODE ( set ) ; if ( GET_CODE ( set ) == UNSPEC ) cost = 1 ; else { gcc_assert ( GET_CODE ( set ) == SET ) ; if ( ! reg_overlap_mentioned_p ( SET_DEST ( set ) , PATTERN ( insn ) ) ) cost = 1 ; } } } if ( shadow_type_p ( insn_type ) ) shadow_bonus = 1 ; if ( kind != 0 ) { if ( kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW ) kind = REG_DEP_OUTPUT ; switch ( dep_insn_type ) { case TYPE_CALLP : return 1 ; case TYPE_BRANCH : case TYPE_CALL : if ( get_attr_has_shadow ( dep_insn ) == HAS_SHADOW_Y ) return 0 ; return 6 ; case TYPE_LOAD : case TYPE_LOADN : case TYPE_INTDP : if ( kind == REG_DEP_OUTPUT ) return 5 - shadow_bonus ; return 0 ; case TYPE_MPY4 : case TYPE_FP4 : if ( kind == REG_DEP_OUTPUT ) return 4 - shadow_bonus ; return 0 ; case TYPE_MPY2 : if ( kind == REG_DEP_OUTPUT ) return 2 - shadow_bonus ; return 0 ; case TYPE_CMPDP : if ( kind == REG_DEP_OUTPUT ) return 2 - shadow_bonus ; return 2 ; case TYPE_ADDDP : case TYPE_MPYSPDP : if ( kind == REG_DEP_OUTPUT ) return 7 - shadow_bonus ; return 2 ; case TYPE_MPYSP2DP : if ( kind == REG_DEP_OUTPUT ) return 5 - shadow_bonus ; return 2 ; case TYPE_MPYI : if ( kind == REG_DEP_OUTPUT ) return 9 - shadow_bonus ; return 4 ; case TYPE_MPYID : case TYPE_MPYDP : if ( kind == REG_DEP_OUTPUT ) return 10 - shadow_bonus ; return 4 ; default : if ( insn_type == TYPE_SPKERNEL ) return 0 ; if ( kind == REG_DEP_OUTPUT ) return 1 - shadow_bonus ; return 0 ; } } return cost - shadow_bonus ; } </s>

Implement the TARGET_SCHED_ADJUST_COST hook . We need special handling for anti- and output dependencies .


<s> static bool c6x_callee_copies ( cumulative_args_t cum_v ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { return true ; } </s>


<s> static bool c6x_call_saved_register_used ( tree call_expr ) { CUMULATIVE_ARGS cum_v ; cumulative_args_t cum ; HARD_REG_SET call_saved_regset ; tree parameter ; machine_mode mode ; tree type ; rtx parm_rtx ; int i ; INIT_CUMULATIVE_ARGS ( cum_v , NULL , NULL , 0 , 0 ) ; cum = pack_cumulative_args ( & cum_v ) ; COMPL_HARD_REG_SET ( call_saved_regset , call_used_reg_set ) ; for ( i = 0 ; i < call_expr_nargs ( call_expr ) ; i ++ ) { parameter = CALL_EXPR_ARG ( call_expr , i ) ; gcc_assert ( parameter ) ; if ( TREE_CODE ( parameter ) == ERROR_MARK ) return true ; type = TREE_TYPE ( parameter ) ; gcc_assert ( type ) ; mode = TYPE_MODE ( type ) ; gcc_assert ( mode ) ; if ( pass_by_reference ( & cum_v , mode , type , true ) ) { mode = Pmode ; type = build_pointer_type ( type ) ; } parm_rtx = c6x_function_arg ( cum , mode , type , 0 ) ; c6x_function_arg_advance ( cum , mode , type , 0 ) ; if ( ! parm_rtx ) continue ; if ( REG_P ( parm_rtx ) && overlaps_hard_reg_set_p ( call_saved_regset , GET_MODE ( parm_rtx ) , REGNO ( parm_rtx ) ) ) return true ; if ( GET_CODE ( parm_rtx ) == PARALLEL ) { int n = XVECLEN ( parm_rtx , 0 ) ; while ( n -- > 0 ) { rtx x = XEXP ( XVECEXP ( parm_rtx , 0 , n ) , 0 ) ; if ( REG_P ( x ) && overlaps_hard_reg_set_p ( call_saved_regset , GET_MODE ( x ) , REGNO ( x ) ) ) return true ; } } } return false ; } </s>

Checks whether the given CALL_EXPR would use a caller saved register . This is used to decide whether sibling call optimization could be performed on the respective function call .


<s> static rtx c6x_dwarf_register_span ( rtx rtl ) { unsigned regno ; unsigned real_regno ; int nregs ; int i ; rtx p ; regno = REGNO ( rtl ) ; nregs = HARD_REGNO_NREGS ( regno , GET_MODE ( rtl ) ) ; if ( nregs == 1 ) return NULL_RTX ; p = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( nregs ) ) ; for ( i = 0 ; i < nregs ; i ++ ) { if ( TARGET_BIG_ENDIAN ) real_regno = regno + nregs - ( i + 1 ) ; else real_regno = regno + i ; XVECEXP ( p , 0 , i ) = gen_rtx_REG ( SImode , real_regno ) ; } return p ; } </s>

We save pairs of registers using a DImode store . Describe the component registers for DWARF generation code .


<s> static rtx c6x_expand_builtin ( tree exp , rtx target ATTRIBUTE_UNUSED , rtx subtarget ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , int ignore ATTRIBUTE_UNUSED ) { size_t i ; const struct builtin_description * d ; tree fndecl = TREE_OPERAND ( CALL_EXPR_FN ( exp ) , 0 ) ; unsigned int fcode = DECL_FUNCTION_CODE ( fndecl ) ; for ( i = 0 , d = bdesc_2arg ; i < ARRAY_SIZE ( bdesc_2arg ) ; i ++ , d ++ ) if ( d -> code == fcode ) return c6x_expand_binop_builtin ( d -> icode , exp , target , fcode == C6X_BUILTIN_CLRR ) ; for ( i = 0 , d = bdesc_1arg ; i < ARRAY_SIZE ( bdesc_1arg ) ; i ++ , d ++ ) if ( d -> code == fcode ) return c6x_expand_unop_builtin ( d -> icode , exp , target ) ; 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 c6x_expand_call ( rtx retval , rtx address , bool sibcall ) { rtx callee = XEXP ( address , 0 ) ; rtx call_insn ; if ( ! c6x_call_operand ( callee , Pmode ) ) { callee = force_reg ( Pmode , callee ) ; address = change_address ( address , Pmode , callee ) ; } call_insn = gen_rtx_CALL ( VOIDmode , address , const0_rtx ) ; if ( sibcall ) { call_insn = emit_call_insn ( call_insn ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( call_insn ) , gen_rtx_REG ( Pmode , REG_B3 ) ) ; } else { if ( retval == NULL_RTX ) call_insn = emit_call_insn ( call_insn ) ; else call_insn = emit_call_insn ( gen_rtx_SET ( GET_MODE ( retval ) , retval , call_insn ) ) ; } if ( flag_pic ) use_reg ( & CALL_INSN_FUNCTION_USAGE ( call_insn ) , pic_offset_table_rtx ) ; } </s>


<s> static rtx c6x_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 ) ; if ( cum -> count >= cum -> nregs ) return NULL_RTX ; if ( type ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P ( type ) ) { if ( size > 4 ) { rtx reg1 = gen_rtx_REG ( SImode , argument_registers [ cum -> count ] + 1 ) ; rtx reg2 = gen_rtx_REG ( SImode , argument_registers [ cum -> count ] ) ; rtvec vec = gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , reg1 , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , reg2 , GEN_INT ( 4 ) ) ) ; return gen_rtx_PARALLEL ( mode , vec ) ; } } } return gen_rtx_REG ( mode , argument_registers [ cum -> count ] ) ; } </s>

Implements the macro FUNCTION_ARG defined in c6x.h .


<s> static bool c6x_function_ok_for_sibcall ( tree decl , tree exp ) { if ( c6x_call_saved_register_used ( exp ) ) return false ; if ( ! flag_pic ) return true ; if ( TARGET_DSBT ) { struct cgraph_local_info * this_func ; if ( ! decl ) return false ; this_func = cgraph_node :: local_info ( current_function_decl ) ; return this_func -> local ; } return true ; } </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 c6x_gen_bundles ( void ) { basic_block bb ; rtx_insn * insn , * next , * last_call ; FOR_EACH_BB_FN ( bb , cfun ) { rtx_insn * insn , * next ; rtx_insn * slot [ 15 ] ; int n_filled = 0 ; int first_slot = 0 ; for ( insn = BB_HEAD ( bb ) ; ; insn = next ) { int at_end ; rtx delete_this = NULL_RTX ; if ( NONDEBUG_INSN_P ( insn ) ) { if ( CALL_P ( insn ) ) { first_slot ++ ; if ( n_filled ) { memmove ( & slot [ 1 ] , & slot [ 0 ] , n_filled * sizeof ( slot [ 0 ] ) ) ; } if ( ! shadow_p ( insn ) ) { PUT_MODE ( insn , TImode ) ; if ( n_filled ) PUT_MODE ( slot [ 1 ] , VOIDmode ) ; } n_filled ++ ; slot [ 0 ] = insn ; } else { slot [ n_filled ++ ] = insn ; } } next = NEXT_INSN ( insn ) ; while ( next && insn != BB_END ( bb ) && ! ( NONDEBUG_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 && ! ( shadow_p ( next ) && CALL_P ( next ) ) ) ) ) { if ( n_filled >= 2 ) gen_one_bundle ( slot , n_filled , first_slot ) ; n_filled = 0 ; first_slot = 0 ; } if ( at_end ) break ; } } last_call = NULL ; for ( insn = get_insns ( ) ; insn ; insn = next ) { next = NEXT_INSN ( insn ) ; if ( CALL_P ( insn ) || ( INSN_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) == SEQUENCE && CALL_P ( XVECEXP ( PATTERN ( insn ) , 0 , 0 ) ) ) ) last_call = insn ; if ( ! NOTE_P ( insn ) || NOTE_KIND ( insn ) != NOTE_INSN_CALL_ARG_LOCATION ) continue ; if ( NEXT_INSN ( last_call ) == insn ) continue ; SET_NEXT_INSN ( PREV_INSN ( insn ) ) = NEXT_INSN ( insn ) ; SET_PREV_INSN ( NEXT_INSN ( insn ) ) = PREV_INSN ( insn ) ; SET_PREV_INSN ( insn ) = last_call ; SET_NEXT_INSN ( insn ) = NEXT_INSN ( last_call ) ; SET_PREV_INSN ( NEXT_INSN ( insn ) ) = insn ; SET_NEXT_INSN ( PREV_INSN ( insn ) ) = insn ; last_call = insn ; } } </s>

Move all parallel instructions into SEQUENCEs , so that no subsequent passes try to insert labels in the middle .


<s> char c6x_get_unit_specifier ( rtx_insn * insn ) { enum attr_units units ; if ( insn_info . exists ( ) ) { int unit = INSN_INFO_ENTRY ( INSN_UID ( insn ) ) . reservation ; return c6x_unit_names [ unit ] [ 0 ] ; } units = get_attr_units ( insn ) ; switch ( units ) { case UNITS_D : case UNITS_DL : case UNITS_DS : case UNITS_DLS : case UNITS_D_ADDR : return 'd' ; break ; case UNITS_L : case UNITS_LS : return 'l' ; break ; case UNITS_S : return 's' ; break ; case UNITS_M : return 'm' ; break ; default : gcc_unreachable ( ) ; } } </s>

Return a single character , which is either ' l ' , 's ' , 'd ' or 'm ' , which specifies the functional unit used by INSN .


<s> static void c6x_initialize_trampoline ( rtx tramp , tree fndecl , rtx cxt ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx t1 = copy_to_reg ( fnaddr ) ; rtx t2 = copy_to_reg ( cxt ) ; rtx mask = gen_reg_rtx ( SImode ) ; int i ; emit_block_move ( tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; emit_move_insn ( mask , GEN_INT ( 0xffff << 7 ) ) ; for ( i = 0 ; i < 4 ; i ++ ) { rtx mem = adjust_address ( tramp , SImode , i * 4 ) ; rtx t = ( i & 1 ) ? t2 : t1 ; rtx v1 = gen_reg_rtx ( SImode ) ; rtx v2 = gen_reg_rtx ( SImode ) ; emit_move_insn ( v1 , mem ) ; if ( i < 2 ) emit_insn ( gen_ashlsi3 ( v2 , t , GEN_INT ( 7 ) ) ) ; else emit_insn ( gen_lshrsi3 ( v2 , t , GEN_INT ( 9 ) ) ) ; emit_insn ( gen_andsi3 ( v2 , v2 , mask ) ) ; emit_insn ( gen_iorsi3 ( v2 , v2 , v1 ) ) ; emit_move_insn ( mem , v2 ) ; } tramp = XEXP ( tramp , 0 ) ; emit_library_call ( gen_rtx_SYMBOL_REF ( Pmode , "__gnu_clear_cache" ) , LCT_NORMAL , VOIDmode , 2 , tramp , Pmode , plus_constant ( Pmode , tramp , TRAMPOLINE_SIZE ) , Pmode ) ; } </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 c6x_mark_reg_read ( rtx reg , bool cross ) { unsigned regno = REGNO ( reg ) ; unsigned nregs = hard_regno_nregs [ regno ] [ GET_MODE ( reg ) ] ; while ( nregs -- > 0 ) c6x_mark_regno_read ( regno + nregs , cross ) ; } </s>

Note that REG is read in the insn being examined . If CROSS , it means the access is through a cross path . Update the temporary reg access arrays , and set REG_ACCESS_STALL if the insn ca n't be issued in the current cycle .


<s> static void c6x_mark_reg_written ( rtx reg , int cycles ) { unsigned regno = REGNO ( reg ) ; unsigned nregs = hard_regno_nregs [ regno ] [ GET_MODE ( reg ) ] ; while ( nregs -- > 0 ) ss . reg_set_in_cycle [ regno + nregs ] = cycles ; } </s>

Note that register REG is written in cycle CYCLES .


"-fpic and -fPIC not supported without -mdsbt on this target"


<s> static bool c6x_pass_by_reference ( cumulative_args_t cum_v ATTRIBUTE_UNUSED , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { int size = - 1 ; if ( type ) size = int_size_in_bytes ( type ) ; else if ( mode != VOIDmode ) size = GET_MODE_SIZE ( mode ) ; return size > 2 * UNITS_PER_WORD || size == - 1 ; } </s>

Types larger than 64 bit , and variable sized types , are passed by reference . The callee must copy them ; see c6x_callee_copies .


<s> static machine_mode c6x_preferred_simd_mode ( machine_mode mode ) { switch ( mode ) { case HImode : return V2HImode ; case QImode : return V4QImode ; default : return word_mode ; } } </s>


<s> static void c6x_print_operand_address ( FILE * file , rtx addr ) { c6x_print_address_operand ( file , addr , VOIDmode ) ; } </s>

Output assembly language output for the address ADDR to FILE .


<s> static void c6x_reorg ( void ) { basic_block bb ; rtx * call_labels ; bool do_selsched = ( c6x_flag_schedule_insns2 && flag_selective_scheduling2 && ! maybe_skip_selective_scheduling ( ) ) ; compute_bb_for_insn ( ) ; df_clear_flags ( DF_LR_RUN_DCE ) ; df_note_add_problem ( ) ; if ( optimize == 0 ) split_all_insns ( ) ; df_analyze ( ) ; if ( c6x_flag_schedule_insns2 ) { int sz = get_max_uid ( ) * 3 / 2 + 1 ; insn_info . create ( sz ) ; } sched_no_dce = true ; c6x_hwloops ( ) ; if ( c6x_flag_schedule_insns2 ) { split_delayed_insns ( ) ; timevar_push ( TV_SCHED2 ) ; if ( do_selsched ) run_selective_scheduling ( ) ; else schedule_ebbs ( ) ; conditionalize_after_sched ( ) ; timevar_pop ( TV_SCHED2 ) ; free_delay_pairs ( ) ; } sched_no_dce = false ; call_labels = XCNEWVEC ( rtx , get_max_uid ( ) + 1 ) ; reorg_split_calls ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { FOR_EACH_BB_FN ( bb , cfun ) if ( ( bb -> flags & BB_DISABLE_SCHEDULE ) == 0 ) assign_reservations ( BB_HEAD ( bb ) , BB_END ( bb ) ) ; } if ( c6x_flag_var_tracking ) { timevar_push ( TV_VAR_TRACKING ) ; variable_tracking_main ( ) ; timevar_pop ( TV_VAR_TRACKING ) ; } reorg_emit_nops ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { free_delay_pairs ( ) ; c6x_gen_bundles ( ) ; } df_finish_pass ( false ) ; } </s>

Implement the TARGET_MACHINE_DEPENDENT_REORG pass . We split call insns here into a sequence that loads the return register and performs the call , and emit the return label . If scheduling after reload is requested , it happens here .


<s> static int c6x_save_reg ( unsigned int regno ) { return ( ( df_regs_ever_live_p ( regno ) && ! call_used_regs [ regno ] && ! fixed_regs [ regno ] ) || ( regno == RETURN_ADDR_REGNO && ( df_regs_ever_live_p ( regno ) || ! crtl -> is_leaf ) ) || ( regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ( ) ) ) ; } </s>


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


<s> static bool c6x_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case V2HImode : case V4QImode : case V2SImode : case V4HImode : case V8QImode : return true ; default : return false ; } } </s>

Implements target hook vector_mode_supported_p .


<s> static void emit_add_sp_const ( HOST_WIDE_INT offset , bool frame_related_p ) { rtx to_add = GEN_INT ( offset ) ; rtx orig_to_add = to_add ; rtx_insn * insn ; if ( offset == 0 ) return ; if ( offset < - 32768 || offset > 32767 ) { rtx reg = gen_rtx_REG ( SImode , REG_A0 ) ; rtx low = GEN_INT ( trunc_int_for_mode ( offset , HImode ) ) ; insn = emit_insn ( gen_movsi_high ( reg , low ) ) ; if ( frame_related_p ) RTX_FRAME_RELATED_P ( insn ) = 1 ; insn = emit_insn ( gen_movsi_lo_sum ( reg , reg , to_add ) ) ; if ( frame_related_p ) RTX_FRAME_RELATED_P ( insn ) = 1 ; to_add = reg ; } insn = emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , to_add ) ) ; if ( frame_related_p ) { if ( REG_P ( to_add ) ) add_reg_note ( insn , REG_FRAME_RELATED_EXPR , gen_rtx_SET ( VOIDmode , stack_pointer_rtx , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , orig_to_add ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } } </s>

Emit insns to increment the stack pointer by OFFSET . If FRAME_RELATED_P , set the RTX_FRAME_RELATED_P flag on the insns . Does nothing if the offset is zero .


<s> static rtx_insn * emit_nop_after ( int cycles , rtx after ) { rtx_insn * insn ; if ( cycles == 10 ) cycles -- ; gcc_assert ( cycles < 10 ) ; insn = emit_insn_after ( gen_nop_count ( GEN_INT ( cycles ) ) , after ) ; PUT_MODE ( insn , TImode ) ; return insn ; } </s>

Emit a NOP instruction for CYCLES cycles after insn AFTER . Return it .


<s> static rtx find_last_same_clock ( rtx insn ) { rtx retval = insn ; rtx_insn * t = next_real_insn ( insn ) ; while ( t && GET_MODE ( t ) != TImode ) { if ( ! DEBUG_INSN_P ( t ) && recog_memoized ( t ) >= 0 ) retval = t ; t = next_real_insn ( t ) ; } return retval ; } </s>

Walk forward from INSN to find the last insn that issues in the same clock cycle .


<s> static rtx find_next_cycle_insn ( rtx insn , int clock ) { rtx t = insn ; if ( GET_MODE ( t ) == TImode ) t = next_real_insn ( t ) ; while ( t && GET_MODE ( t ) != TImode ) t = next_real_insn ( t ) ; if ( t && insn_get_clock ( t ) == clock ) return t ; return NULL_RTX ; } </s>

Scan forwards from INSN until we find the next insn that has mode TImode ( indicating it starts a new cycle ) , and occurs in cycle CLOCK . Return it if we find such an insn , NULL_RTX otherwise .


<s> static void maybe_clobber_cond ( rtx insn , int clock_var ) { int n , idx ; idx = ss . jump_cycle_index ; for ( n = 0 ; n < 12 ; n ++ , idx ++ ) { rtx cond , link ; int cycle ; if ( idx >= 12 ) idx -= 12 ; cycle = ss . jump_cycles [ idx ] ; if ( cycle <= clock_var ) return ; cond = ss . jump_cond [ idx ] ; if ( cond == NULL_RTX ) continue ; if ( CALL_P ( insn ) ) { ss . jump_cond [ idx ] = NULL_RTX ; continue ; } note_stores ( PATTERN ( insn ) , clobber_cond_1 , ss . jump_cond + idx ) ; for ( link = REG_NOTES ( insn ) ; link ; link = XEXP ( link , 1 ) ) if ( REG_NOTE_KIND ( link ) == REG_INC ) clobber_cond_1 ( XEXP ( link , 0 ) , NULL_RTX , ss . jump_cond + idx ) ; } } </s>

Examine INSN , and if it destroys the conditions have recorded for any of the jumps in flight , clear that condition so that we do n't predicate any more insns . CLOCK_VAR helps us limit the search to only those jumps which are still in flight .


<s> static bool must_reload_pic_reg_p ( void ) { struct cgraph_local_info * i = NULL ; if ( ! TARGET_DSBT ) return false ; i = cgraph_node :: local_info ( current_function_decl ) ; if ( ( crtl -> uses_pic_offset_table || ! crtl -> is_leaf ) && ! i -> local ) return true ; return false ; } </s>

Return true if we need to save and modify the PIC register in the prologue .


<s> static bool predicate_insn ( rtx_insn * insn , rtx cond , bool doit ) { int icode ; if ( cond == NULL_RTX ) { gcc_assert ( ! doit ) ; return false ; } if ( get_attr_predicable ( insn ) == PREDICABLE_YES && GET_CODE ( PATTERN ( insn ) ) != COND_EXEC ) { if ( doit ) { rtx newpat = gen_rtx_COND_EXEC ( VOIDmode , cond , PATTERN ( insn ) ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; } return true ; } if ( GET_CODE ( PATTERN ( insn ) ) == COND_EXEC && rtx_equal_p ( COND_EXEC_TEST ( PATTERN ( insn ) ) , cond ) ) return true ; icode = INSN_CODE ( insn ) ; if ( icode == CODE_FOR_real_jump || icode == CODE_FOR_jump || icode == CODE_FOR_indirect_jump ) { rtx pat = PATTERN ( insn ) ; rtx dest = ( icode == CODE_FOR_real_jump ? XVECEXP ( pat , 0 , 0 ) : icode == CODE_FOR_jump ? XEXP ( SET_SRC ( pat ) , 0 ) : SET_SRC ( pat ) ) ; if ( doit ) { rtx newpat ; if ( REG_P ( dest ) ) newpat = gen_rtx_COND_EXEC ( VOIDmode , cond , PATTERN ( insn ) ) ; else newpat = gen_br_true ( cond , XEXP ( cond , 0 ) , dest ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; } return true ; } if ( INSN_CODE ( insn ) == CODE_FOR_br_true ) { rtx br_cond = XEXP ( SET_SRC ( PATTERN ( insn ) ) , 0 ) ; return rtx_equal_p ( br_cond , cond ) ; } if ( INSN_CODE ( insn ) == CODE_FOR_br_false ) { rtx br_cond = XEXP ( SET_SRC ( PATTERN ( insn ) ) , 0 ) ; return conditions_opposite_p ( br_cond , cond ) ; } return false ; } </s>

Return true if we can add a predicate COND to INSN , or if INSN already has that predicate . If DOIT is true , also perform the modification .


<s> static void print_address_offset ( FILE * file , rtx off , machine_mode mem_mode ) { rtx pat ; if ( c6x_current_insn != NULL_RTX ) { pat = PATTERN ( c6x_current_insn ) ; if ( GET_CODE ( pat ) == COND_EXEC ) pat = COND_EXEC_CODE ( pat ) ; if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET && GET_CODE ( SET_SRC ( pat ) ) == UNSPEC && XINT ( SET_SRC ( pat ) , 1 ) == UNSPEC_MISALIGNED_ACCESS ) { gcc_assert ( CONST_INT_P ( off ) && ( INTVAL ( off ) & ( GET_MODE_SIZE ( mem_mode ) - 1 ) ) == 0 ) ; fprintf ( file , "[" HOST_WIDE_INT_PRINT_DEC "]" , INTVAL ( off ) / GET_MODE_SIZE ( mem_mode ) ) ; return ; } } fputs ( "(" , file ) ; output_address ( off ) ; fputs ( ")" , file ) ; } </s>

Subroutine of print_address_operand , print a single address offset OFF for a memory access of mode MEM_MODE , choosing between normal form and scaled form depending on the type of the insn . Misaligned memory references must use the scaled form .


<s> static void reorg_emit_nops ( rtx * call_labels ) { bool first ; rtx last_call ; rtx_insn * prev ; int prev_clock , earliest_bb_end ; int prev_implicit_nops ; rtx_insn * insn = get_insns ( ) ; insn = next_real_insn ( insn ) ; last_call = prev = NULL ; prev_clock = - 1 ; earliest_bb_end = 0 ; prev_implicit_nops = 0 ; first = true ; while ( insn ) { int this_clock = - 1 ; rtx_insn * next ; int max_cycles = 0 ; next = next_real_insn ( insn ) ; if ( DEBUG_INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || shadow_or_blockage_p ( insn ) || JUMP_TABLE_DATA_P ( insn ) ) goto next_insn ; if ( ! c6x_flag_schedule_insns2 ) PUT_MODE ( insn , TImode ) ; else { int cycles ; this_clock = insn_get_clock ( insn ) ; if ( this_clock != prev_clock ) { PUT_MODE ( insn , TImode ) ; if ( ! first ) { cycles = this_clock - prev_clock ; cycles -= prev_implicit_nops ; if ( cycles > 1 ) { rtx nop = emit_nop_after ( cycles - 1 , prev ) ; insn_set_clock ( nop , prev_clock + prev_implicit_nops + 1 ) ; } } prev_clock = this_clock ; if ( last_call && insn_get_clock ( last_call ) + 6 <= this_clock ) { emit_label_before ( call_labels [ INSN_UID ( last_call ) ] , insn ) ; last_call = NULL_RTX ; } prev_implicit_nops = 0 ; } } if ( recog_memoized ( insn ) >= 0 && ( c6x_flag_schedule_insns2 || ! returning_call_p ( insn ) ) ) { max_cycles = get_attr_cycles ( insn ) ; if ( get_attr_type ( insn ) == TYPE_CALLP ) prev_implicit_nops = 5 ; } else max_cycles = 1 ; if ( returning_call_p ( insn ) ) last_call = insn ; if ( c6x_flag_schedule_insns2 ) { gcc_assert ( this_clock >= 0 ) ; if ( earliest_bb_end < this_clock + max_cycles ) earliest_bb_end = this_clock + max_cycles ; } else if ( max_cycles > 1 ) emit_nop_after ( max_cycles - 1 , insn ) ; prev = insn ; first = false ; next_insn : if ( c6x_flag_schedule_insns2 && ( next == NULL_RTX || ( GET_MODE ( next ) == TImode && INSN_INFO_ENTRY ( INSN_UID ( next ) ) . ebb_start ) ) && earliest_bb_end > 0 ) { int cycles = earliest_bb_end - prev_clock ; if ( cycles > 1 ) { prev = emit_nop_after ( cycles - 1 , prev ) ; insn_set_clock ( prev , prev_clock + prev_implicit_nops + 1 ) ; } earliest_bb_end = 0 ; prev_clock = - 1 ; first = true ; if ( last_call ) emit_label_after ( call_labels [ INSN_UID ( last_call ) ] , prev ) ; last_call = NULL_RTX ; } insn = next ; } } </s>

Called as part of c6x_reorg . This function emits multi-cycle NOP insns as required for correctness . CALL_LABELS is the array that holds the return labels for call insns ; we emit these here if scheduling was run earlier .


<s> static void undo_split_delayed_nonbranch ( rtx_insn * insn ) { int icode = recog_memoized ( insn ) ; enum attr_type type ; rtx prev_pat , insn_pat ; rtx_insn * prev ; if ( icode < 0 ) return ; type = get_attr_type ( insn ) ; if ( type != TYPE_LOAD_SHADOW && type != TYPE_MULT_SHADOW ) return ; prev = PREV_INSN ( insn ) ; prev_pat = PATTERN ( prev ) ; insn_pat = PATTERN ( insn ) ; if ( GET_CODE ( prev_pat ) == COND_EXEC ) { prev_pat = COND_EXEC_CODE ( prev_pat ) ; insn_pat = COND_EXEC_CODE ( insn_pat ) ; } gcc_assert ( GET_CODE ( prev_pat ) == UNSPEC && ( ( XINT ( prev_pat , 1 ) == UNSPEC_REAL_LOAD && type == TYPE_LOAD_SHADOW ) || ( XINT ( prev_pat , 1 ) == UNSPEC_REAL_MULT && type == TYPE_MULT_SHADOW ) ) ) ; insn_pat = gen_rtx_SET ( VOIDmode , SET_DEST ( insn_pat ) , XVECEXP ( prev_pat , 0 , 1 ) ) ; insn_pat = duplicate_cond ( insn_pat , prev ) ; PATTERN ( insn ) = insn_pat ; INSN_CODE ( insn ) = - 1 ; delete_insn ( prev ) ; } </s>

Examine if INSN is the result of splitting a load into a real load and a shadow , and if so , undo the transformation .


<s> static void c6x_reorg ( void ) { basic_block bb ; bool do_selsched = ( c6x_flag_schedule_insns2 && flag_selective_scheduling2 && ! maybe_skip_selective_scheduling ( ) ) ; compute_bb_for_insn ( ) ; df_clear_flags ( DF_LR_RUN_DCE ) ; df_note_add_problem ( ) ; if ( optimize == 0 ) split_all_insns ( ) ; df_analyze ( ) ; if ( c6x_flag_schedule_insns2 ) { int sz = get_max_uid ( ) * 3 / 2 + 1 ; insn_info . create ( sz ) ; } sched_no_dce = true ; c6x_hwloops ( ) ; if ( c6x_flag_schedule_insns2 ) { split_delayed_insns ( ) ; timevar_push ( TV_SCHED2 ) ; if ( do_selsched ) run_selective_scheduling ( ) ; else schedule_ebbs ( ) ; conditionalize_after_sched ( ) ; timevar_pop ( TV_SCHED2 ) ; free_delay_pairs ( ) ; } sched_no_dce = false ; rtx_insn * * call_labels = XCNEWVEC ( rtx_insn * , get_max_uid ( ) + 1 ) ; reorg_split_calls ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { FOR_EACH_BB_FN ( bb , cfun ) if ( ( bb -> flags & BB_DISABLE_SCHEDULE ) == 0 ) assign_reservations ( BB_HEAD ( bb ) , BB_END ( bb ) ) ; } if ( c6x_flag_var_tracking ) { timevar_push ( TV_VAR_TRACKING ) ; variable_tracking_main ( ) ; timevar_pop ( TV_VAR_TRACKING ) ; } reorg_emit_nops ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { free_delay_pairs ( ) ; c6x_gen_bundles ( ) ; } df_finish_pass ( false ) ; } </s>


<s> static void reorg_emit_nops ( rtx_insn * * call_labels ) { bool first ; rtx last_call ; rtx_insn * prev ; int prev_clock , earliest_bb_end ; int prev_implicit_nops ; rtx_insn * insn = get_insns ( ) ; insn = next_real_insn ( insn ) ; last_call = prev = NULL ; prev_clock = - 1 ; earliest_bb_end = 0 ; prev_implicit_nops = 0 ; first = true ; while ( insn ) { int this_clock = - 1 ; rtx_insn * next ; int max_cycles = 0 ; next = next_real_insn ( insn ) ; if ( DEBUG_INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || shadow_or_blockage_p ( insn ) || JUMP_TABLE_DATA_P ( insn ) ) goto next_insn ; if ( ! c6x_flag_schedule_insns2 ) PUT_MODE ( insn , TImode ) ; else { int cycles ; this_clock = insn_get_clock ( insn ) ; if ( this_clock != prev_clock ) { PUT_MODE ( insn , TImode ) ; if ( ! first ) { cycles = this_clock - prev_clock ; cycles -= prev_implicit_nops ; if ( cycles > 1 ) { rtx nop = emit_nop_after ( cycles - 1 , prev ) ; insn_set_clock ( nop , prev_clock + prev_implicit_nops + 1 ) ; } } prev_clock = this_clock ; if ( last_call && insn_get_clock ( last_call ) + 6 <= this_clock ) { emit_label_before ( call_labels [ INSN_UID ( last_call ) ] , insn ) ; last_call = NULL_RTX ; } prev_implicit_nops = 0 ; } } if ( recog_memoized ( insn ) >= 0 && ( c6x_flag_schedule_insns2 || ! returning_call_p ( insn ) ) ) { max_cycles = get_attr_cycles ( insn ) ; if ( get_attr_type ( insn ) == TYPE_CALLP ) prev_implicit_nops = 5 ; } else max_cycles = 1 ; if ( returning_call_p ( insn ) ) last_call = insn ; if ( c6x_flag_schedule_insns2 ) { gcc_assert ( this_clock >= 0 ) ; if ( earliest_bb_end < this_clock + max_cycles ) earliest_bb_end = this_clock + max_cycles ; } else if ( max_cycles > 1 ) emit_nop_after ( max_cycles - 1 , insn ) ; prev = insn ; first = false ; next_insn : if ( c6x_flag_schedule_insns2 && ( next == NULL_RTX || ( GET_MODE ( next ) == TImode && INSN_INFO_ENTRY ( INSN_UID ( next ) ) . ebb_start ) ) && earliest_bb_end > 0 ) { int cycles = earliest_bb_end - prev_clock ; if ( cycles > 1 ) { prev = emit_nop_after ( cycles - 1 , prev ) ; insn_set_clock ( prev , prev_clock + prev_implicit_nops + 1 ) ; } earliest_bb_end = 0 ; prev_clock = - 1 ; first = true ; if ( last_call ) emit_label_after ( call_labels [ INSN_UID ( last_call ) ] , prev ) ; last_call = NULL_RTX ; } insn = next ; } } </s>


<s> static int bb_earliest_end_cycle ( basic_block bb , rtx ignore ) { int earliest = 0 ; rtx_insn * insn ; FOR_BB_INSNS ( bb , insn ) { int cycles , this_clock ; if ( LABEL_P ( insn ) || NOTE_P ( insn ) || DEBUG_INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || insn == ignore ) continue ; this_clock = insn_get_clock ( insn ) ; cycles = get_attr_cycles ( insn ) ; if ( earliest < this_clock + cycles ) earliest = this_clock + cycles ; } return earliest ; } </s>

Return the number of cycles taken by BB , as computed by scheduling , including the latencies of all insns with delay slots . IGNORE is an insn we should ignore in the calculation , usually the final branch .


<s> static int c6x_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep_insn , int cost , unsigned int ) { enum attr_type insn_type = TYPE_UNKNOWN , dep_insn_type = TYPE_UNKNOWN ; int dep_insn_code_number , insn_code_number ; int shadow_bonus = 0 ; enum reg_note kind ; dep_insn_code_number = recog_memoized ( dep_insn ) ; insn_code_number = recog_memoized ( insn ) ; if ( dep_insn_code_number >= 0 ) dep_insn_type = get_attr_type ( dep_insn ) ; if ( insn_code_number >= 0 ) insn_type = get_attr_type ( insn ) ; kind = ( reg_note ) dep_type ; if ( kind == 0 ) { if ( dep_insn_type == TYPE_LOAD ) { rtx set = PATTERN ( dep_insn ) ; if ( GET_CODE ( set ) == COND_EXEC ) set = COND_EXEC_CODE ( set ) ; if ( GET_CODE ( set ) == UNSPEC ) cost = 1 ; else { gcc_assert ( GET_CODE ( set ) == SET ) ; if ( ! reg_overlap_mentioned_p ( SET_DEST ( set ) , PATTERN ( insn ) ) ) cost = 1 ; } } } if ( shadow_type_p ( insn_type ) ) shadow_bonus = 1 ; if ( kind != 0 ) { if ( kind == REG_DEP_ANTI && insn_type == TYPE_SHADOW ) kind = REG_DEP_OUTPUT ; switch ( dep_insn_type ) { case TYPE_CALLP : return 1 ; case TYPE_BRANCH : case TYPE_CALL : if ( get_attr_has_shadow ( dep_insn ) == HAS_SHADOW_Y ) return 0 ; return 6 ; case TYPE_LOAD : case TYPE_LOADN : case TYPE_INTDP : if ( kind == REG_DEP_OUTPUT ) return 5 - shadow_bonus ; return 0 ; case TYPE_MPY4 : case TYPE_FP4 : if ( kind == REG_DEP_OUTPUT ) return 4 - shadow_bonus ; return 0 ; case TYPE_MPY2 : if ( kind == REG_DEP_OUTPUT ) return 2 - shadow_bonus ; return 0 ; case TYPE_CMPDP : if ( kind == REG_DEP_OUTPUT ) return 2 - shadow_bonus ; return 2 ; case TYPE_ADDDP : case TYPE_MPYSPDP : if ( kind == REG_DEP_OUTPUT ) return 7 - shadow_bonus ; return 2 ; case TYPE_MPYSP2DP : if ( kind == REG_DEP_OUTPUT ) return 5 - shadow_bonus ; return 2 ; case TYPE_MPYI : if ( kind == REG_DEP_OUTPUT ) return 9 - shadow_bonus ; return 4 ; case TYPE_MPYID : case TYPE_MPYDP : if ( kind == REG_DEP_OUTPUT ) return 10 - shadow_bonus ; return 4 ; default : if ( insn_type == TYPE_SPKERNEL ) return 0 ; if ( kind == REG_DEP_OUTPUT ) return 1 - shadow_bonus ; return 0 ; } } return cost - shadow_bonus ; } </s>

Implement the TARGET_SCHED_ADJUST_COST hook . We need special handling for anti- and output dependencies .


<s> static void * c6x_alloc_sched_context ( void ) { return xmalloc ( sizeof ( struct c6x_sched_context ) ) ; } </s>

Allocate store for new scheduling context .


<s> static void c6x_asm_emit_except_personality ( rtx personality ) { fputs ( "\t.personality\t" , asm_out_file ) ; output_addr_const ( asm_out_file , personality ) ; fputc ( '\n' , asm_out_file ) ; } </s>


<s> static void c6x_asm_init_sections ( void ) { exception_section = get_unnamed_section ( 0 , output_section_asm_op , "\t.handlerdata" ) ; } </s>

Use a special assembly directive rather than a regular setion for unwind table data .


<s> bool c6x_block_reg_pad_upward ( machine_mode mode ATTRIBUTE_UNUSED , const_tree type , bool first ) { HOST_WIDE_INT size ; if ( ! TARGET_BIG_ENDIAN ) return true ; if ( ! first ) return true ; if ( ! type ) return true ; size = int_size_in_bytes ( type ) ; return size == 3 ; } </s>

Return true if BLOCK_REG_PADDING ( MODE , TYPE , FIRST ) should return upward rather than downward .


<s> static tree c6x_build_builtin_va_list ( void ) { return build_pointer_type ( char_type_node ) ; } </s>

Return the type to use as __builtin_va_list .


<s> static tree c6x_builtin_decl ( unsigned code , bool initialize_p ATTRIBUTE_UNUSED ) { if ( code >= C6X_BUILTIN_MAX ) return error_mark_node ; return c6x_builtin_decls [ code ] ; } </s>


<s> static bool c6x_call_saved_register_used ( tree call_expr ) { CUMULATIVE_ARGS cum_v ; cumulative_args_t cum ; HARD_REG_SET call_saved_regset ; tree parameter ; rtx parm_rtx ; int i ; INIT_CUMULATIVE_ARGS ( cum_v , NULL , NULL , 0 , 0 ) ; cum = pack_cumulative_args ( & cum_v ) ; call_saved_regset = ~ call_used_or_fixed_regs ; for ( i = 0 ; i < call_expr_nargs ( call_expr ) ; i ++ ) { parameter = CALL_EXPR_ARG ( call_expr , i ) ; gcc_assert ( parameter ) ; if ( TREE_CODE ( parameter ) == ERROR_MARK ) return true ; function_arg_info arg ( TREE_TYPE ( parameter ) , true ) ; apply_pass_by_reference_rules ( & cum_v , arg ) ; parm_rtx = c6x_function_arg ( cum , arg ) ; c6x_function_arg_advance ( cum , arg ) ; if ( ! parm_rtx ) continue ; if ( REG_P ( parm_rtx ) && overlaps_hard_reg_set_p ( call_saved_regset , GET_MODE ( parm_rtx ) , REGNO ( parm_rtx ) ) ) return true ; if ( GET_CODE ( parm_rtx ) == PARALLEL ) { int n = XVECLEN ( parm_rtx , 0 ) ; while ( n -- > 0 ) { rtx x = XEXP ( XVECEXP ( parm_rtx , 0 , n ) , 0 ) ; if ( REG_P ( x ) && overlaps_hard_reg_set_p ( call_saved_regset , GET_MODE ( x ) , REGNO ( x ) ) ) return true ; } } } return false ; } </s>

Checks whether the given CALL_EXPR would use a caller saved register . This is used to decide whether sibling call optimization could be performed on the respective function call .


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

Given FROM and TO register numbers , say whether this elimination is allowed . Frame pointer elimination is automatically handled .


Determine whether c6x_output_mi_thunk can succeed .


<s> static void c6x_clear_sched_context ( void * _sc ) { c6x_sched_context_t sc = ( c6x_sched_context_t ) _sc ; gcc_assert ( _sc != NULL ) ; free ( sc -> prev_cycle_state_ctx ) ; } </s>


<s> static void c6x_compute_frame_layout ( struct c6x_frame * frame ) { HOST_WIDE_INT size = get_frame_size ( ) ; HOST_WIDE_INT offset ; int nregs ; offset = - 4 ; frame -> padding0 = 0 ; nregs = c6x_nsaved_regs ( ) ; frame -> push_rts = false ; frame -> b3_offset = 0 ; if ( use_push_rts_p ( nregs ) ) { frame -> push_rts = true ; frame -> b3_offset = ( TARGET_BIG_ENDIAN ? - 12 : - 13 ) * 4 ; nregs = 14 ; } else if ( c6x_save_reg ( REG_B3 ) ) { int idx ; for ( idx = N_SAVE_ORDER - 1 ; reg_save_order [ idx ] != REG_B3 ; idx -- ) { if ( c6x_save_reg ( reg_save_order [ idx ] ) ) frame -> b3_offset -= 4 ; } } frame -> nregs = nregs ; if ( size == 0 && nregs == 0 ) { frame -> padding0 = 4 ; frame -> padding1 = frame -> padding2 = 0 ; frame -> frame_pointer_offset = frame -> to_allocate = 0 ; frame -> outgoing_arguments_size = 0 ; return ; } if ( ! frame -> push_rts ) offset += frame -> nregs * 4 ; if ( offset == 0 && size == 0 && crtl -> outgoing_args_size == 0 && ! crtl -> is_leaf ) frame -> padding0 = frame -> padding1 = 4 ; else if ( offset & 4 ) frame -> padding1 = 4 ; else frame -> padding1 = 0 ; offset += frame -> padding0 + frame -> padding1 ; frame -> frame_pointer_offset = offset ; offset += size ; frame -> outgoing_arguments_size = crtl -> outgoing_args_size ; offset += frame -> outgoing_arguments_size ; if ( ( offset & 4 ) == 0 ) frame -> padding2 = 8 ; else frame -> padding2 = 4 ; frame -> to_allocate = offset + frame -> padding2 ; } </s>

Compute the layout of the stack frame and store it in FRAME .


<s> static void c6x_conditional_register_usage ( void ) { int i ; if ( c6x_arch == C6X_CPU_C62X || c6x_arch == C6X_CPU_C67X ) for ( i = 16 ; i < 32 ; i ++ ) { fixed_regs [ i ] = 1 ; fixed_regs [ 32 + i ] = 1 ; } if ( TARGET_INSNS_64 ) { SET_HARD_REG_BIT ( reg_class_contents [ ( int ) PREDICATE_A_REGS ] , REG_A0 ) ; SET_HARD_REG_BIT ( reg_class_contents [ ( int ) PREDICATE_REGS ] , REG_A0 ) ; CLEAR_HARD_REG_BIT ( reg_class_contents [ ( int ) NONPREDICATE_A_REGS ] , REG_A0 ) ; CLEAR_HARD_REG_BIT ( reg_class_contents [ ( int ) NONPREDICATE_REGS ] , REG_A0 ) ; } } </s>

Implement the TARGET_CONDITIONAL_REGISTER_USAGE hook .


<s> static enum unwind_info_type c6x_debug_unwind_info ( void ) { if ( flag_unwind_tables || flag_exceptions ) return UI_DWARF2 ; return default_debug_unwind_info ( ) ; } </s>

Target unwind frame info is generated from dwarf CFI directives , so always output dwarf2 unwind info .


<s> static rtx c6x_dwarf_register_span ( rtx rtl ) { unsigned regno ; unsigned real_regno ; int nregs ; int i ; rtx p ; regno = REGNO ( rtl ) ; nregs = REG_NREGS ( rtl ) ; if ( nregs == 1 ) return NULL_RTX ; p = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( nregs ) ) ; for ( i = 0 ; i < nregs ; i ++ ) { if ( TARGET_BIG_ENDIAN ) real_regno = regno + nregs - ( i + 1 ) ; else real_regno = regno + i ; XVECEXP ( p , 0 , i ) = gen_rtx_REG ( SImode , real_regno ) ; } return p ; } </s>

We save pairs of registers using a DImode store . Describe the component registers for DWARF generation code .


<s> static void ATTRIBUTE_UNUSED c6x_elf_unique_section ( tree decl , int reloc ) { const char * prefix = NULL ; bool one_only = DECL_COMDAT_GROUP ( decl ) && ! HAVE_COMDAT_GROUP ; if ( c6x_in_small_data_p ( decl ) ) { switch ( categorize_decl_for_section ( decl , reloc ) ) { case SECCAT_SDATA : prefix = one_only ? ".s" : ".neardata" ; break ; case SECCAT_SBSS : prefix = one_only ? ".sb" : ".bss" ; break ; case SECCAT_SRODATA : prefix = one_only ? ".s2" : ".rodata" ; break ; case SECCAT_RODATA_MERGE_STR : case SECCAT_RODATA_MERGE_STR_INIT : case SECCAT_RODATA_MERGE_CONST : case SECCAT_RODATA : case SECCAT_DATA : case SECCAT_DATA_REL : case SECCAT_DATA_REL_LOCAL : case SECCAT_DATA_REL_RO : case SECCAT_DATA_REL_RO_LOCAL : gcc_unreachable ( ) ; default : break ; } } else { switch ( categorize_decl_for_section ( decl , reloc ) ) { case SECCAT_DATA : case SECCAT_DATA_REL : case SECCAT_DATA_REL_LOCAL : case SECCAT_DATA_REL_RO : case SECCAT_DATA_REL_RO_LOCAL : prefix = one_only ? ".fd" : ".fardata" ; break ; case SECCAT_BSS : prefix = one_only ? ".fb" : ".far" ; break ; case SECCAT_RODATA : case SECCAT_RODATA_MERGE_STR : case SECCAT_RODATA_MERGE_STR_INIT : case SECCAT_RODATA_MERGE_CONST : prefix = one_only ? ".fr" : ".const" ; break ; case SECCAT_SRODATA : case SECCAT_SDATA : case SECCAT_SBSS : gcc_unreachable ( ) ; default : break ; } } if ( prefix ) { const char * name , * linkonce ; char * string ; name = IDENTIFIER_POINTER ( DECL_ASSEMBLER_NAME ( decl ) ) ; name = targetm . strip_name_encoding ( name ) ; linkonce = one_only ? ".gnu.linkonce" : "" ; string = ACONCAT ( ( linkonce , prefix , "." , name , NULL ) ) ; set_decl_section_name ( decl , string ) ; return ; } default_unique_section ( decl , reloc ) ; } </s>

Build up a unique section name , expressed as a STRING_CST node , and assign it to DECL_SECTION_NAME ( decl ) . RELOC indicates whether the initial value of EXP requires link-time relocations .


<s> static rtx c6x_expand_binop_builtin ( enum insn_code icode , tree exp , rtx target , bool match_op ) { int offs = match_op ? 1 : 0 ; rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; tree arg1 = CALL_EXPR_ARG ( exp , 1 ) ; rtx op0 = expand_expr ( arg0 , NULL_RTX , VOIDmode , EXPAND_NORMAL ) ; rtx op1 = expand_expr ( arg1 , NULL_RTX , VOIDmode , EXPAND_NORMAL ) ; 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 + offs ] . mode ; machine_mode mode1 = insn_data [ icode ] . operand [ 2 + offs ] . mode ; rtx ret = target ; 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 ) ) { if ( tmode == SQmode || tmode == V2SQmode ) { ret = gen_reg_rtx ( tmode == SQmode ? SImode : V2SImode ) ; target = gen_lowpart ( tmode , ret ) ; } else target = gen_reg_rtx ( tmode ) ; } if ( ( op0mode == V2HImode || op0mode == SImode || op0mode == VOIDmode ) && ( mode0 == V2HQmode || mode0 == HQmode || mode0 == SQmode ) ) { op0mode = mode0 ; op0 = gen_lowpart ( mode0 , op0 ) ; } if ( ( op1mode == V2HImode || op1mode == SImode || op1mode == VOIDmode ) && ( mode1 == V2HQmode || mode1 == HQmode || mode1 == SQmode ) ) { op1mode = mode1 ; op1 = gen_lowpart ( mode1 , op1 ) ; } gcc_assert ( ( op0mode == mode0 || op0mode == VOIDmode ) && ( op1mode == mode1 || op1mode == VOIDmode ) ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 + offs ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 2 + offs ] . predicate ) ( op1 , mode1 ) ) op1 = copy_to_mode_reg ( mode1 , op1 ) ; if ( match_op ) pat = GEN_FCN ( icode ) ( target , target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return ret ; } </s>

Subroutine of c6x_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> static rtx c6x_expand_builtin ( tree exp , rtx target ATTRIBUTE_UNUSED , rtx subtarget ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , int ignore ATTRIBUTE_UNUSED ) { size_t i ; const struct builtin_description * d ; tree fndecl = TREE_OPERAND ( CALL_EXPR_FN ( exp ) , 0 ) ; unsigned int fcode = DECL_MD_FUNCTION_CODE ( fndecl ) ; for ( i = 0 , d = bdesc_2arg ; i < ARRAY_SIZE ( bdesc_2arg ) ; i ++ , d ++ ) if ( d -> code == fcode ) return c6x_expand_binop_builtin ( d -> icode , exp , target , fcode == C6X_BUILTIN_CLRR ) ; for ( i = 0 , d = bdesc_1arg ; i < ARRAY_SIZE ( bdesc_1arg ) ; i ++ , d ++ ) if ( d -> code == fcode ) return c6x_expand_unop_builtin ( d -> icode , exp , target ) ; 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 c6x_expand_call ( rtx retval , rtx address , bool sibcall ) { rtx callee = XEXP ( address , 0 ) ; rtx call_insn ; if ( ! c6x_call_operand ( callee , Pmode ) ) { callee = force_reg ( Pmode , callee ) ; address = change_address ( address , Pmode , callee ) ; } call_insn = gen_rtx_CALL ( VOIDmode , address , const0_rtx ) ; if ( sibcall ) { call_insn = emit_call_insn ( call_insn ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( call_insn ) , gen_rtx_REG ( Pmode , REG_B3 ) ) ; } else { if ( retval == NULL_RTX ) call_insn = emit_call_insn ( call_insn ) ; else call_insn = emit_call_insn ( gen_rtx_SET ( retval , call_insn ) ) ; } if ( flag_pic ) use_reg ( & CALL_INSN_FUNCTION_USAGE ( call_insn ) , pic_offset_table_rtx ) ; } </s>


<s> static rtx c6x_expand_unop_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; rtx op0 = expand_expr ( arg0 , NULL_RTX , VOIDmode , EXPAND_NORMAL ) ; 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 c6x_expand_builtin to take care of unop insns .


<s> void c6x_final_prescan_insn ( rtx_insn * insn , rtx * opvec ATTRIBUTE_UNUSED , int noperands ATTRIBUTE_UNUSED ) { c6x_current_insn = insn ; } </s>


<s> bool c6x_force_op_for_comparison_p ( enum rtx_code code , rtx op ) { if ( ! CONST_INT_P ( op ) || satisfies_constraint_Iu4 ( op ) ) return false ; if ( ( code == EQ || code == LT || code == GT ) && ! satisfies_constraint_Is5 ( op ) ) return true ; if ( ( code == GTU || code == LTU ) && ( ! TARGET_INSNS_64 || ! satisfies_constraint_Iu5 ( op ) ) ) return true ; return false ; } </s>

This function is called when we 're about to expand an integer compare operation which performs COMPARISON . It examines the second operand , and if it is an integer constant that can not be used directly on the current machine in a comparison insn , it returns true .


<s> static void c6x_free_sched_context ( void * _sc ) { free ( _sc ) ; } </s>


<s> static rtx c6x_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; if ( cum -> count >= cum -> nregs ) return NULL_RTX ; if ( tree type = arg . type ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P ( type ) ) { if ( size > 4 ) { rtx reg1 = gen_rtx_REG ( SImode , argument_registers [ cum -> count ] + 1 ) ; rtx reg2 = gen_rtx_REG ( SImode , argument_registers [ cum -> count ] ) ; rtvec vec = gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , reg1 , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , reg2 , GEN_INT ( 4 ) ) ) ; return gen_rtx_PARALLEL ( arg . mode , vec ) ; } } } return gen_rtx_REG ( arg . mode , argument_registers [ cum -> count ] ) ; } </s>

Implements the macro FUNCTION_ARG defined in c6x.h .


<s> static unsigned int c6x_function_arg_boundary ( machine_mode mode , const_tree type ) { unsigned int boundary = type ? TYPE_ALIGN ( type ) : GET_MODE_BITSIZE ( mode ) ; if ( boundary > BITS_PER_WORD ) return 2 * BITS_PER_WORD ; if ( mode == BLKmode ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( size > 4 ) return 2 * BITS_PER_WORD ; if ( boundary < BITS_PER_WORD ) { if ( size >= 3 ) return BITS_PER_WORD ; if ( size >= 2 ) return 2 * BITS_PER_UNIT ; } } return boundary ; } </s>


<s> static unsigned int c6x_function_arg_round_boundary ( machine_mode mode , const_tree type ) { return c6x_function_arg_boundary ( mode , type ) ; } </s>


<s> void c6x_function_end ( FILE * file , const char * fname ) { c6x_output_fn_unwind ( file ) ; insn_info . release ( ) ; if ( ! flag_inhibit_size_directive ) ASM_OUTPUT_MEASURED_SIZE ( file , fname ) ; } </s>

Called when a function has been assembled . It should perform all the tasks of ASM_DECLARE_FUNCTION_SIZE in elfos.h , plus target-specific tasks . We free the reservation ( and other scheduling ) information here now that all insns have been output .


<s> static bool c6x_function_in_section_p ( tree decl , section * section ) { if ( ! TREE_STATIC ( decl ) ) return false ; if ( ! targetm . binds_local_p ( decl ) ) return false ; if ( ! DECL_SECTION_NAME ( decl ) ) { if ( flag_function_sections || DECL_COMDAT_GROUP ( decl ) ) return false ; } return function_section ( decl ) == section ; } </s>

Return true if DECL is known to be linked into section SECTION .


<s> static bool c6x_function_ok_for_sibcall ( tree decl , tree exp ) { if ( c6x_call_saved_register_used ( exp ) ) return false ; if ( ! flag_pic ) return true ; if ( TARGET_DSBT ) { if ( ! decl ) return false ; cgraph_node * this_func = cgraph_node :: local_info_node ( current_function_decl ) ; return this_func -> local ; } return true ; } </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 rtx c6x_function_value ( const_tree type , const_tree func ATTRIBUTE_UNUSED , bool outgoing ATTRIBUTE_UNUSED ) { if ( TARGET_BIG_ENDIAN && type && AGGREGATE_TYPE_P ( type ) ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( size > 4 ) { rtx reg1 = gen_rtx_REG ( SImode , REG_A4 + 1 ) ; rtx reg2 = gen_rtx_REG ( SImode , REG_A4 ) ; rtvec vec = gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , reg1 , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , reg2 , GEN_INT ( 4 ) ) ) ; return gen_rtx_PARALLEL ( TYPE_MODE ( type ) , vec ) ; } } return gen_rtx_REG ( TYPE_MODE ( type ) , REG_A4 ) ; } </s>

TARGET_FUNCTION_VALUE implementation . Returns an RTX representing the place where function FUNC returns or receives a value of data type TYPE .


<s> static bool c6x_function_value_regno_p ( const unsigned int regno ) { return regno == REG_A4 ; } </s>


<s> static void c6x_gen_bundles ( void ) { basic_block bb ; FOR_EACH_BB_FN ( bb , cfun ) { rtx_insn * insn , * next ; rtx_insn * slot [ 15 ] ; int n_filled = 0 ; int first_slot = 0 ; for ( insn = BB_HEAD ( bb ) ; ; insn = next ) { int at_end ; rtx delete_this = NULL_RTX ; if ( NONDEBUG_INSN_P ( insn ) ) { if ( CALL_P ( insn ) ) { first_slot ++ ; if ( n_filled ) { memmove ( & slot [ 1 ] , & slot [ 0 ] , n_filled * sizeof ( slot [ 0 ] ) ) ; } if ( ! shadow_p ( insn ) ) { PUT_MODE ( insn , TImode ) ; if ( n_filled ) PUT_MODE ( slot [ 1 ] , VOIDmode ) ; } n_filled ++ ; slot [ 0 ] = insn ; } else { slot [ n_filled ++ ] = insn ; } } next = NEXT_INSN ( insn ) ; while ( next && insn != BB_END ( bb ) && ! ( NONDEBUG_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 && ! ( shadow_p ( next ) && CALL_P ( next ) ) ) ) ) { if ( n_filled >= 2 ) gen_one_bundle ( slot , n_filled , first_slot ) ; n_filled = 0 ; first_slot = 0 ; } if ( at_end ) break ; } } } </s>

Move all parallel instructions into SEQUENCEs , so that no subsequent passes try to insert labels in the middle .


<s> char c6x_get_unit_specifier ( rtx_insn * insn ) { enum attr_units units ; if ( insn_info . exists ( ) ) { int unit = INSN_INFO_ENTRY ( INSN_UID ( insn ) ) . reservation ; return c6x_unit_names [ unit ] [ 0 ] ; } units = get_attr_units ( insn ) ; switch ( units ) { case UNITS_D : case UNITS_DL : case UNITS_DS : case UNITS_DLS : case UNITS_D_ADDR : return 'd' ; case UNITS_L : case UNITS_LS : return 'l' ; case UNITS_S : return 's' ; case UNITS_M : return 'm' ; default : gcc_unreachable ( ) ; } } </s>

Return a single character , which is either ' l ' , 's ' , 'd ' or 'm ' , which specifies the functional unit used by INSN .


<s> static bool c6x_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { return GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD || ( regno & 1 ) == 0 ; } </s>


<s> static void c6x_hwloops ( void ) { if ( optimize ) reorg_loops ( true , & c6x_doloop_hooks ) ; } </s>

Run the hw-doloop pass to modulo-schedule hardware loops , or split the doloop_end patterns where such optimizations are impossible .


<s> static void c6x_initialize_trampoline ( rtx tramp , tree fndecl , rtx cxt ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx t1 = copy_to_reg ( fnaddr ) ; rtx t2 = copy_to_reg ( cxt ) ; rtx mask = gen_reg_rtx ( SImode ) ; int i ; emit_block_move ( tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; emit_move_insn ( mask , GEN_INT ( 0xffff << 7 ) ) ; for ( i = 0 ; i < 4 ; i ++ ) { rtx mem = adjust_address ( tramp , SImode , i * 4 ) ; rtx t = ( i & 1 ) ? t2 : t1 ; rtx v1 = gen_reg_rtx ( SImode ) ; rtx v2 = gen_reg_rtx ( SImode ) ; emit_move_insn ( v1 , mem ) ; if ( i < 2 ) emit_insn ( gen_ashlsi3 ( v2 , t , GEN_INT ( 7 ) ) ) ; else emit_insn ( gen_lshrsi3 ( v2 , t , GEN_INT ( 9 ) ) ) ; emit_insn ( gen_andsi3 ( v2 , v2 , mask ) ) ; emit_insn ( gen_iorsi3 ( v2 , v2 , v1 ) ) ; emit_move_insn ( mem , v2 ) ; } tramp = XEXP ( tramp , 0 ) ; maybe_emit_call_builtin___clear_cache ( tramp , plus_constant ( Pmode , tramp , TRAMPOLINE_SIZE ) ) ; } </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> HOST_WIDE_INT c6x_initial_elimination_offset ( int from , int to ) { struct c6x_frame frame ; c6x_compute_frame_layout ( & frame ) ; if ( from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM ) return 0 ; else if ( from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM ) return - frame . frame_pointer_offset ; else { gcc_assert ( to == STACK_POINTER_REGNUM ) ; if ( from == ARG_POINTER_REGNUM ) return frame . to_allocate + ( frame . push_rts ? 56 : 0 ) ; gcc_assert ( from == FRAME_POINTER_REGNUM ) ; return frame . to_allocate - frame . frame_pointer_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> void c6x_init_cumulative_args ( CUMULATIVE_ARGS * cum , const_tree fntype , rtx libname , int n_named_args ATTRIBUTE_UNUSED ) { cum -> count = 0 ; cum -> nregs = 10 ; if ( ! libname && fntype ) { if ( stdarg_p ( fntype ) ) cum -> nregs = type_num_arguments ( fntype ) - 1 ; if ( cum -> nregs > 10 ) cum -> nregs = 10 ; } } </s>

Implements the macro INIT_CUMULATIVE_ARGS defined in c6x.h .


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

Allocate a new , cleared machine_function structure .


<s> static void c6x_init_sched_context ( void * _sc , bool clean_p ) { c6x_sched_context_t sc = ( c6x_sched_context_t ) _sc ; if ( clean_p ) { init_sched_state ( sc ) ; } else { * sc = ss ; sc -> prev_cycle_state_ctx = xmalloc ( dfa_state_size ) ; memcpy ( sc -> prev_cycle_state_ctx , prev_cycle_state , dfa_state_size ) ; } } </s>

If CLEAN_P is true then initializes _SC with clean data , and from the global context otherwise .


<s> static bool c6x_in_small_data_p ( const_tree exp ) { if ( TREE_CODE ( exp ) == STRING_CST ) return false ; if ( TREE_CODE ( exp ) == FUNCTION_DECL ) return false ; if ( TREE_CODE ( exp ) == VAR_DECL && DECL_WEAK ( exp ) ) return false ; if ( TREE_CODE ( exp ) == VAR_DECL && DECL_SECTION_NAME ( exp ) ) { const char * section = DECL_SECTION_NAME ( exp ) ; if ( strcmp ( section , ".neardata" ) == 0 || startswith ( section , ".neardata." ) || startswith ( section , ".gnu.linkonce.s." ) || strcmp ( section , ".bss" ) == 0 || startswith ( section , ".bss." ) || startswith ( section , ".gnu.linkonce.sb." ) || strcmp ( section , ".rodata" ) == 0 || startswith ( section , ".rodata." ) || startswith ( section , ".gnu.linkonce.s2." ) ) return true ; } else return PLACE_IN_SDATA_P ( exp ) ; return false ; } </s>

Return true if EXP goes in small data/bss .


<s> static int c6x_issue_rate ( void ) { return 8 ; } </s>

Implement the TARGET_SCHED_ISSUE_RATE hook .


<s> static rtx c6x_libcall_value ( machine_mode mode , const_rtx fun ATTRIBUTE_UNUSED ) { return gen_rtx_REG ( mode , REG_A4 ) ; } </s>


<s> bool c6x_long_call_p ( rtx op ) { tree decl ; if ( ! TARGET_LONG_CALLS ) return false ; decl = SYMBOL_REF_DECL ( op ) ; if ( decl != NULL_TREE && ! flag_reorder_blocks_and_partition && TREE_CODE ( decl ) == FUNCTION_DECL && c6x_function_in_section_p ( decl , current_function_section ( ) ) ) return false ; return true ; } </s>

Return true if a call to OP , which is a SYMBOL_REF , must be expanded as a long call .


<s> static void c6x_mark_reg_read ( rtx reg , bool cross ) { unsigned regno = REGNO ( reg ) ; unsigned nregs = REG_NREGS ( reg ) ; while ( nregs -- > 0 ) c6x_mark_regno_read ( regno + nregs , cross ) ; } </s>

Note that REG is read in the insn being examined . If CROSS , it means the access is through a cross path . Update the temporary reg access arrays , and set REG_ACCESS_STALL if the insn ca n't be issued in the current cycle .


<s> static void c6x_mark_reg_written ( rtx reg , int cycles ) { unsigned regno = REGNO ( reg ) ; unsigned nregs = REG_NREGS ( reg ) ; while ( nregs -- > 0 ) ss . reg_set_in_cycle [ regno + nregs ] = cycles ; } </s>

Note that register REG is written in cycle CYCLES .


<s> bool c6x_mem_operand ( rtx op , enum reg_class c , bool small_offset ) { machine_mode mode = GET_MODE ( op ) ; rtx base = XEXP ( op , 0 ) ; switch ( GET_CODE ( base ) ) { case REG : break ; case PLUS : if ( small_offset && ( XEXP ( base , 0 ) == stack_pointer_rtx || XEXP ( base , 0 ) == pic_offset_table_rtx ) ) { if ( ! c6x_legitimate_address_p_1 ( mode , base , true , true ) ) return false ; } case PRE_INC : case PRE_DEC : case PRE_MODIFY : case POST_INC : case POST_DEC : case POST_MODIFY : base = XEXP ( base , 0 ) ; break ; case CONST : case LABEL_REF : case SYMBOL_REF : gcc_assert ( sdata_symbolic_operand ( base , Pmode ) ) ; return ! small_offset && c == B_REGS ; default : return false ; } return TEST_HARD_REG_BIT ( reg_class_contents [ ( int ) ( c ) ] , REGNO ( base ) ) ; } </s>

Return TRUE if OP is a valid memory address with a base register of class C. If SMALL_OFFSET is true , we disallow memory references which would require a long offset with B14/B15 .


<s> int c6x_nsaved_regs ( void ) { int nregs = 0 ; int regno ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) if ( c6x_save_reg ( regno ) ) nregs ++ ; return nregs ; } </s>

Return number of saved general prupose registers .


"%<-fpic%> and %<-fPIC%> not supported without %<-mdsbt%> "


The LTO frontend only enables exceptions when it sees a function that uses it . This changes the return value of dwarf2out_do_frame , so we have to check before every function .


<s> static void c6x_output_fn_unwind ( FILE * f ) { if ( ! ( flag_unwind_tables || flag_exceptions ) ) return ; if ( ! ( flag_unwind_tables || crtl -> uses_eh_lsda ) && ( TREE_NOTHROW ( current_function_decl ) || crtl -> all_throwers_are_sibcalls ) ) fputs ( "\t.cantunwind\n" , f ) ; fputs ( "\t.endp\n" , f ) ; } </s>

Output unwind directives at the end of a function .


<s> static bool c6x_output_ttype ( rtx x ) { if ( GET_CODE ( x ) != CONST_INT ) fputs ( "\t.ehtype\t" , asm_out_file ) ; else fputs ( "\t.word\t" , asm_out_file ) ; output_addr_const ( asm_out_file , x ) ; fputc ( '\n' , asm_out_file ) ; return TRUE ; } </s>

Output a reference from a function exception table to the type_info object X . Output these via a special assembly directive .


<s> static bool c6x_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { int size = - 1 ; if ( arg . type ) size = int_size_in_bytes ( arg . type ) ; else if ( arg . mode != VOIDmode ) size = GET_MODE_SIZE ( arg . mode ) ; return size > 2 * UNITS_PER_WORD || size == - 1 ; } </s>

Types larger than 64 bit , and variable sized types , are passed by reference . The callee must copy them ; see c6x_callee_copies .


<s> static reg_class_t c6x_preferred_rename_class ( reg_class_t cl ) { if ( cl == A_REGS ) return NONPREDICATE_A_REGS ; if ( cl == B_REGS ) return NONPREDICATE_B_REGS ; if ( cl == ALL_REGS || cl == GENERAL_REGS ) return NONPREDICATE_REGS ; return NO_REGS ; } </s>


<s> static machine_mode c6x_preferred_simd_mode ( scalar_mode mode ) { switch ( mode ) { case E_HImode : return V2HImode ; case E_QImode : return V4QImode ; default : return word_mode ; } } </s>


<s> static void c6x_print_operand_address ( FILE * file , machine_mode mode , rtx addr ) { c6x_print_address_operand ( file , addr , mode ) ; } </s>

Output assembly language output for the address ADDR to FILE .


<s> static void c6x_print_unit_specifier_field ( FILE * file , rtx_insn * insn ) { enum attr_units units = get_attr_units ( insn ) ; enum attr_cross cross = get_attr_cross ( insn ) ; enum attr_dest_regfile rf = get_attr_dest_regfile ( insn ) ; int half ; char unitspec ; if ( units == UNITS_D_ADDR ) { enum attr_addr_regfile arf = get_attr_addr_regfile ( insn ) ; int t_half ; gcc_assert ( arf != ADDR_REGFILE_UNKNOWN ) ; half = arf == ADDR_REGFILE_A ? 1 : 2 ; t_half = rf == DEST_REGFILE_A ? 1 : 2 ; fprintf ( file , ".d%dt%d" , half , t_half ) ; return ; } if ( insn_info . exists ( ) ) { int unit = INSN_INFO_ENTRY ( INSN_UID ( insn ) ) . reservation ; fputs ( "." , file ) ; fputs ( c6x_unit_names [ unit ] , file ) ; if ( cross == CROSS_Y ) fputs ( "x" , file ) ; return ; } gcc_assert ( rf != DEST_REGFILE_UNKNOWN ) ; unitspec = c6x_get_unit_specifier ( insn ) ; half = rf == DEST_REGFILE_A ? 1 : 2 ; fprintf ( file , ".%c%d%s" , unitspec , half , cross == CROSS_Y ? "x" : "" ) ; } </s>


<s> static bool c6x_registers_update ( rtx_insn * insn ) { enum attr_cross cross ; enum attr_dest_regfile destrf ; int i , nops ; rtx x ; if ( ! reload_completed || recog_memoized ( insn ) < 0 ) return false ; reg_access_stall = false ; memcpy ( ss . tmp_reg_n_accesses , ss . reg_n_accesses , sizeof ss . tmp_reg_n_accesses ) ; memcpy ( ss . tmp_reg_n_xaccesses , ss . reg_n_xaccesses , sizeof ss . tmp_reg_n_xaccesses ) ; extract_insn ( insn ) ; cross = get_attr_cross ( insn ) ; destrf = get_attr_dest_regfile ( insn ) ; nops = recog_data . n_operands ; x = PATTERN ( insn ) ; if ( GET_CODE ( x ) == COND_EXEC ) { c6x_mark_reg_read ( XEXP ( XEXP ( x , 0 ) , 0 ) , false ) ; nops -= 2 ; } for ( i = 0 ; i < nops ; i ++ ) { rtx op = recog_data . operand [ i ] ; if ( recog_data . operand_type [ i ] == OP_OUT ) continue ; if ( REG_P ( op ) ) { bool this_cross = cross ; if ( destrf == DEST_REGFILE_A && A_REGNO_P ( REGNO ( op ) ) ) this_cross = false ; if ( destrf == DEST_REGFILE_B && B_REGNO_P ( REGNO ( op ) ) ) this_cross = false ; c6x_mark_reg_read ( op , this_cross ) ; } else if ( MEM_P ( op ) ) { op = XEXP ( op , 0 ) ; switch ( GET_CODE ( op ) ) { case POST_INC : case PRE_INC : case POST_DEC : case PRE_DEC : op = XEXP ( op , 0 ) ; case REG : c6x_mark_reg_read ( op , false ) ; break ; case POST_MODIFY : case PRE_MODIFY : op = XEXP ( op , 1 ) ; gcc_assert ( GET_CODE ( op ) == PLUS ) ; case PLUS : c6x_mark_reg_read ( XEXP ( op , 0 ) , false ) ; if ( REG_P ( XEXP ( op , 1 ) ) ) c6x_mark_reg_read ( XEXP ( op , 1 ) , false ) ; break ; case SYMBOL_REF : case LABEL_REF : case CONST : c6x_mark_regno_read ( REG_B14 , false ) ; break ; default : gcc_unreachable ( ) ; } } else if ( ! CONSTANT_P ( op ) && strlen ( recog_data . constraints [ i ] ) > 0 ) gcc_unreachable ( ) ; } return reg_access_stall ; } </s>

Update the register state information for an instruction whose body is X . Return true if the instruction has to be delayed until the next cycle .


<s> enum reg_class c6x_regno_reg_class ( int reg ) { if ( reg >= REG_A1 && reg <= REG_A2 ) return PREDICATE_A_REGS ; if ( reg == REG_A0 && TARGET_INSNS_64 ) return PREDICATE_A_REGS ; if ( reg >= REG_B0 && reg <= REG_B2 ) return PREDICATE_B_REGS ; if ( A_REGNO_P ( reg ) ) return NONPREDICATE_A_REGS ; if ( call_used_or_fixed_reg_p ( reg ) ) return CALL_USED_B_REGS ; return B_REGS ; } </s>


<s> static void c6x_reorg ( void ) { basic_block bb ; bool do_selsched = ( c6x_flag_schedule_insns2 && flag_selective_scheduling2 && ! maybe_skip_selective_scheduling ( ) ) ; compute_bb_for_insn ( ) ; df_clear_flags ( DF_LR_RUN_DCE ) ; df_note_add_problem ( ) ; if ( optimize == 0 ) split_all_insns ( ) ; df_analyze ( ) ; if ( c6x_flag_schedule_insns2 ) { int sz = get_max_uid ( ) * 3 / 2 + 1 ; insn_info . create ( sz ) ; } sched_no_dce = true ; c6x_hwloops ( ) ; if ( c6x_flag_schedule_insns2 ) { split_delayed_insns ( ) ; timevar_push ( TV_SCHED2 ) ; if ( do_selsched ) run_selective_scheduling ( ) ; else schedule_ebbs ( ) ; conditionalize_after_sched ( ) ; timevar_pop ( TV_SCHED2 ) ; free_delay_pairs ( ) ; } sched_no_dce = false ; rtx_code_label * * call_labels = XCNEWVEC ( rtx_code_label * , get_max_uid ( ) + 1 ) ; reorg_split_calls ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { FOR_EACH_BB_FN ( bb , cfun ) if ( ( bb -> flags & BB_DISABLE_SCHEDULE ) == 0 ) assign_reservations ( BB_HEAD ( bb ) , BB_END ( bb ) ) ; } if ( c6x_flag_var_tracking ) { timevar_push ( TV_VAR_TRACKING ) ; variable_tracking_main ( ) ; timevar_pop ( TV_VAR_TRACKING ) ; } reorg_emit_nops ( call_labels ) ; if ( c6x_flag_schedule_insns2 ) { free_delay_pairs ( ) ; c6x_gen_bundles ( ) ; } df_finish_pass ( false ) ; } </s>

Implement the TARGET_MACHINE_DEPENDENT_REORG pass . We split call insns here into a sequence that loads the return register and performs the call , and emit the return label . If scheduling after reload is requested , it happens here .


<s> rtx c6x_return_addr_rtx ( int count ) { if ( count != 0 ) return const0_rtx ; return get_hard_reg_initial_val ( Pmode , RETURN_ADDR_REGNO ) ; } </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 c6x_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 TARGET_RETURN_IN_MEMORY .


<s> static bool c6x_return_in_msb ( const_tree valtype ) { HOST_WIDE_INT size = int_size_in_bytes ( valtype ) ; return TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P ( valtype ) && size == 3 ; } </s>

Values which must be returned in the most-significant end of the return register .


<s> static int c6x_save_reg ( unsigned int regno ) { return ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( regno == RETURN_ADDR_REGNO && ( df_regs_ever_live_p ( regno ) || ! crtl -> is_leaf ) ) || ( regno == PIC_OFFSET_TABLE_REGNUM && must_reload_pic_reg_p ( ) ) ) ; } </s>


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


<s> static rtx c6x_sched_dfa_pre_cycle_insn ( void ) { return const0_rtx ; } </s>

Used together with the collapse_ndfa option , this ensures that we reach a deterministic automaton state before trying to advance a cycle . With collapse_ndfa , genautomata creates advance cycle arcs only for such deterministic states .


<s> static int c6x_sched_reorder_1 ( rtx_insn * * ready , int * pn_ready , int clock_var ) { int n_ready = * pn_ready ; rtx_insn * * e_ready = ready + n_ready ; rtx_insn * * insnp ; int first_jump ; for ( insnp = ready ; insnp < e_ready ; insnp ++ ) { rtx_insn * insn = * insnp ; int icode = recog_memoized ( insn ) ; bool is_asm = ( icode < 0 && ( GET_CODE ( PATTERN ( insn ) ) == ASM_INPUT || asm_noperands ( PATTERN ( insn ) ) >= 0 ) ) ; bool no_parallel = ( is_asm || icode == CODE_FOR_sploop || ( icode >= 0 && get_attr_type ( insn ) == TYPE_ATOMIC ) ) ; if ( ( no_parallel && ( ss . issued_this_cycle > 0 || clock_var < ss . delays_finished_at ) ) || c6x_registers_update ( insn ) || ( ss . issued_this_cycle > 0 && icode == CODE_FOR_sploop ) ) { memmove ( ready + 1 , ready , ( insnp - ready ) * sizeof ( rtx ) ) ; * ready = insn ; n_ready -- ; ready ++ ; } else if ( shadow_p ( insn ) ) { memmove ( ready + 1 , ready , ( insnp - ready ) * sizeof ( rtx ) ) ; * ready = insn ; } } first_jump = first_jump_index ( clock_var ) ; if ( first_jump != - 1 ) { int first_cycle = get_jump_cycle ( first_jump ) ; rtx first_cond = get_jump_cond ( first_jump ) ; int second_cycle = 0 ; if ( first_jump > 0 ) second_cycle = get_jump_cycle ( first_jump - 1 ) ; for ( insnp = ready ; insnp < e_ready ; insnp ++ ) { rtx_insn * insn = * insnp ; int icode = recog_memoized ( insn ) ; bool is_asm = ( icode < 0 && ( GET_CODE ( PATTERN ( insn ) ) == ASM_INPUT || asm_noperands ( PATTERN ( insn ) ) >= 0 ) ) ; int this_cycles , rsrv_cycles ; enum attr_type type ; gcc_assert ( ! is_asm ) ; if ( icode < 0 ) continue ; this_cycles = get_attr_cycles ( insn ) ; rsrv_cycles = get_attr_reserve_cycles ( insn ) ; type = get_attr_type ( insn ) ; if ( type == TYPE_BRANCH || type == TYPE_CALL ) this_cycles ++ ; if ( clock_var + this_cycles <= first_cycle ) continue ; if ( ( first_jump > 0 && clock_var + this_cycles > second_cycle ) || clock_var + rsrv_cycles > first_cycle || ! predicate_insn ( insn , first_cond , false ) ) { memmove ( ready + 1 , ready , ( insnp - ready ) * sizeof ( rtx ) ) ; * ready = insn ; n_ready -- ; ready ++ ; } } } return n_ready ; } </s>

Helper function for the TARGET_SCHED_REORDER and TARGET_SCHED_REORDER2 hooks . If scheduling an insn would be unsafe in the current cycle , move it down in the ready list and return the number of non-unsafe insns .


<s> static section * c6x_select_rtx_section ( machine_mode mode , rtx x , unsigned HOST_WIDE_INT align ) { if ( c6x_sdata_mode == C6X_SDATA_ALL || ( c6x_sdata_mode != C6X_SDATA_NONE && GET_MODE_SIZE ( mode ) <= 8 ) ) return sdata_section ; else return default_elf_select_rtx_section ( mode , x , align ) ; } </s>

Return a section for X . The only special thing we do here is to honor small data . We do n't have a tree type , so we ca n't use the PLACE_IN_SDATA_P macro we use everywhere else ; we choose to place everything sized 8 bytes or smaller into small data .


<s> void c6x_set_return_address ( rtx source , rtx scratch ) { struct c6x_frame frame ; rtx addr ; HOST_WIDE_INT offset ; c6x_compute_frame_layout ( & frame ) ; if ( ! c6x_save_reg ( RETURN_ADDR_REGNO ) ) emit_move_insn ( gen_rtx_REG ( Pmode , RETURN_ADDR_REGNO ) , source ) ; else { if ( frame_pointer_needed ) { addr = hard_frame_pointer_rtx ; offset = frame . b3_offset ; } else { addr = stack_pointer_rtx ; offset = frame . to_allocate - frame . b3_offset ; } if ( offset ) { HOST_WIDE_INT low = trunc_int_for_mode ( offset , HImode ) ; emit_insn ( gen_movsi_high ( scratch , GEN_INT ( low ) ) ) ; if ( low != offset ) emit_insn ( gen_movsi_lo_sum ( scratch , scratch , GEN_INT ( offset ) ) ) ; emit_insn ( gen_addsi3 ( scratch , addr , scratch ) ) ; addr = scratch ; } emit_move_insn ( gen_frame_mem ( Pmode , addr ) , source ) ; } } </s>

Modify the return address of the current function .


<s> static void c6x_set_sched_context ( void * _sc ) { c6x_sched_context_t sc = ( c6x_sched_context_t ) _sc ; gcc_assert ( sc != NULL ) ; ss = * sc ; memcpy ( prev_cycle_state , sc -> prev_cycle_state_ctx , dfa_state_size ) ; } </s>

Sets the global scheduling context to the one pointed to by _SC .


<s> static void c6x_set_sched_flags ( spec_info_t spec_info ) { unsigned int * flags = & ( current_sched_info -> flags ) ; if ( * flags & SCHED_EBB ) { * flags |= DO_BACKTRACKING | DO_PREDICATION ; } if ( in_hwloop ) * flags |= DONT_BREAK_DEPENDENCIES ; spec_info -> mask = 0 ; } </s>

Provide information about speculation capabilities , and set the DO_BACKTRACKING flag .


<s> static rtx c6x_struct_value_rtx ( tree type ATTRIBUTE_UNUSED , int incoming ATTRIBUTE_UNUSED ) { return gen_rtx_REG ( Pmode , REG_A3 ) ; } </s>


<s> rtx c6x_subword ( rtx op , bool high_p ) { unsigned int byte ; machine_mode mode ; mode = GET_MODE ( op ) ; if ( mode == VOIDmode ) mode = DImode ; if ( TARGET_BIG_ENDIAN ? ! high_p : high_p ) byte = UNITS_PER_WORD ; else byte = 0 ; if ( MEM_P ( op ) ) { rtx addr = XEXP ( op , 0 ) ; if ( GET_CODE ( addr ) == PLUS || REG_P ( addr ) ) return adjust_address ( op , word_mode , byte ) ; gcc_unreachable ( ) ; } return simplify_gen_subreg ( word_mode , op , mode , byte ) ; } </s>

Return one word of double-word value OP . HIGH_P is true to select the high part , false to select the low part . When encountering auto-increment addressing , we make the assumption that the low part is going to be accessed first .


<s> bool c6x_valid_mask_p ( HOST_WIDE_INT val ) { int i ; for ( i = 0 ; i < 32 ; i ++ ) if ( ! ( val & ( ( unsigned HOST_WIDE_INT ) 1 << i ) ) ) break ; for ( ; i < 32 ; i ++ ) if ( val & ( ( unsigned HOST_WIDE_INT ) 1 << i ) ) break ; for ( ; i < 32 ; i ++ ) if ( ! ( val & ( ( unsigned HOST_WIDE_INT ) 1 << i ) ) ) return false ; return true ; } </s>

Return true if VAL is a mask valid for a clr instruction .


<s> static bool c6x_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case E_V2HImode : case E_V4QImode : case E_V2SImode : case E_V4HImode : case E_V8QImode : return true ; default : return false ; } } </s>

Implements target hook vector_mode_supported_p .


<s> static bool can_use_callp ( rtx_insn * insn ) { int icode = recog_memoized ( insn ) ; if ( ! TARGET_INSNS_64PLUS || icode < 0 || GET_CODE ( PATTERN ( insn ) ) == COND_EXEC ) return false ; return ( ( icode == CODE_FOR_real_call || icode == CODE_FOR_call_internal || icode == CODE_FOR_call_value_internal ) && get_attr_dest_regfile ( insn ) == DEST_REGFILE_ANY ) ; } </s>

Determine whether INSN 's pattern can be converted to use callp .


<s> static void clobber_cond_1 ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data1 ) { rtx * cond = ( rtx * ) data1 ; if ( * cond != NULL_RTX && reg_overlap_mentioned_p ( x , * cond ) ) * cond = NULL_RTX ; } </s>

Subroutine of maybe_clobber_cond , called through note_stores .


<s>
static
void
conditionalize_after_sched
(
void
)
{
basic_block
bb
;
rtx_insn
*
insn
;
FOR_EACH_BB_FN
(
bb
,
cfun
)
FOR_BB_INSNS
(
bb
,
insn
)
{
unsigned
uid
=
INSN_UID
(
insn
)
;
rtx
cond
;
if
(
!
NONDEBUG_INSN_P
(
insn
)
||
uid
>=
INSN_INFO_LENGTH
)
continue
;
cond
=
INSN_INFO_ENTRY
(
uid
)
.
new_cond
;
if
(
cond
==
NULL_RTX
)
continue
;
if
(
dump_file
)
fprintf
(
dump_file
,
"Conditionalizing insn %d\n"
,
uid
)
;
predicate_insn
(
insn
,
cond
,
true
)
;
}
}
</s>

For every insn that has an entry in the new_conditions vector , give it the appropriate predicate .


<s> static bool conditions_opposite_p ( rtx cond1 , rtx cond2 ) { return ( rtx_equal_p ( XEXP ( cond1 , 0 ) , XEXP ( cond2 , 0 ) ) && rtx_equal_p ( XEXP ( cond1 , 1 ) , XEXP ( cond2 , 1 ) ) && GET_CODE ( cond1 ) == reverse_condition ( GET_CODE ( cond2 ) ) ) ; } </s>

Return true iff COND1 and COND2 are exactly opposite conditions one of them NE and the other EQ .


<s> static rtx condjump_opposite_condition ( rtx insn ) { rtx pat = PATTERN ( insn ) ; int icode = INSN_CODE ( insn ) ; rtx x = NULL ; if ( icode == CODE_FOR_br_true || icode == CODE_FOR_br_false ) { x = XEXP ( SET_SRC ( pat ) , 0 ) ; if ( icode == CODE_FOR_br_false ) return x ; } if ( GET_CODE ( pat ) == COND_EXEC ) { rtx t = COND_EXEC_CODE ( pat ) ; if ( ( GET_CODE ( t ) == PARALLEL && GET_CODE ( XVECEXP ( t , 0 , 0 ) ) == RETURN ) || ( GET_CODE ( t ) == UNSPEC && XINT ( t , 1 ) == UNSPEC_REAL_JUMP ) || ( GET_CODE ( t ) == SET && SET_DEST ( t ) == pc_rtx ) ) x = COND_EXEC_TEST ( pat ) ; } if ( x != NULL_RTX ) { enum rtx_code code = GET_CODE ( x ) ; x = gen_rtx_fmt_ee ( code == EQ ? NE : EQ , GET_MODE ( x ) , XEXP ( x , 0 ) , XEXP ( x , 1 ) ) ; } return x ; } </s>

Examine INSN , and if it is a conditional jump of any kind , return the opposite of the condition in which it branches . Otherwise , return NULL_RTX .


<s> static void convert_to_callp ( rtx_insn * insn ) { rtx lab ; extract_insn ( insn ) ; if ( GET_CODE ( PATTERN ( insn ) ) == SET ) { rtx dest = recog_data . operand [ 0 ] ; lab = recog_data . operand [ 1 ] ; PATTERN ( insn ) = gen_callp_value ( dest , lab ) ; INSN_CODE ( insn ) = CODE_FOR_callp_value ; } else { lab = recog_data . operand [ 0 ] ; PATTERN ( insn ) = gen_callp ( lab ) ; INSN_CODE ( insn ) = CODE_FOR_callp ; } } </s>

Convert the pattern of INSN , which must be a CALL_INSN , into a callp .


<s> static void count_unit_reqs ( unit_req_table reqs , rtx_insn * head , rtx_insn * tail ) { rtx_insn * insn ; memset ( reqs , 0 , sizeof ( unit_req_table ) ) ; for ( insn = head ; insn != NEXT_INSN ( tail ) ; insn = NEXT_INSN ( insn ) ) { int side1 , side2 , req1 , req2 ; switch ( get_unit_reqs ( insn , & req1 , & side1 , & req2 , & side2 ) ) { case 2 : reqs [ side2 ] [ req2 ] ++ ; case 1 : reqs [ side1 ] [ req1 ] ++ ; break ; } } } </s>

Walk the insns between and including HEAD and TAIL , and mark the resource requirements in the unit_reqs table .


<s> static rtx duplicate_cond ( rtx pat , rtx cond_insn ) { rtx cond_pat = PATTERN ( cond_insn ) ; if ( GET_CODE ( cond_pat ) == COND_EXEC ) pat = gen_rtx_COND_EXEC ( VOIDmode , copy_rtx ( COND_EXEC_TEST ( cond_pat ) ) , pat ) ; return pat ; } </s>

If COND_INSN has a COND_EXEC condition , wrap the same condition around PAT . Return PAT either unchanged or modified in this way .


<s> static void emit_add_sp_const ( HOST_WIDE_INT offset , bool frame_related_p ) { rtx to_add = GEN_INT ( offset ) ; rtx orig_to_add = to_add ; rtx_insn * insn ; if ( offset == 0 ) return ; if ( offset < - 32768 || offset > 32767 ) { rtx reg = gen_rtx_REG ( SImode , REG_A0 ) ; rtx low = GEN_INT ( trunc_int_for_mode ( offset , HImode ) ) ; insn = emit_insn ( gen_movsi_high ( reg , low ) ) ; if ( frame_related_p ) RTX_FRAME_RELATED_P ( insn ) = 1 ; insn = emit_insn ( gen_movsi_lo_sum ( reg , reg , to_add ) ) ; if ( frame_related_p ) RTX_FRAME_RELATED_P ( insn ) = 1 ; to_add = reg ; } insn = emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , to_add ) ) ; if ( frame_related_p ) { if ( REG_P ( to_add ) ) add_reg_note ( insn , REG_FRAME_RELATED_EXPR , gen_rtx_SET ( stack_pointer_rtx , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , orig_to_add ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } } </s>

Emit insns to increment the stack pointer by OFFSET . If FRAME_RELATED_P , set the RTX_FRAME_RELATED_P flag on the insns . Does nothing if the offset is zero .


<s> static rtx_insn * emit_nop_after ( int cycles , rtx_insn * after ) { rtx_insn * insn ; if ( cycles == 10 ) cycles -- ; gcc_assert ( cycles < 10 ) ; insn = emit_insn_after ( gen_nop_count ( GEN_INT ( cycles ) ) , after ) ; PUT_MODE ( insn , TImode ) ; return insn ; } </s>

Emit a NOP instruction for CYCLES cycles after insn AFTER . Return it .


<s> bool expand_move ( rtx * operands , machine_mode mode ) { rtx dest = operands [ 0 ] ; rtx op = operands [ 1 ] ; if ( ( reload_in_progress | reload_completed ) == 0 && GET_CODE ( dest ) == MEM && GET_CODE ( op ) != REG ) operands [ 1 ] = force_reg ( mode , op ) ; else if ( mode == SImode && symbolic_operand ( op , SImode ) ) { if ( flag_pic ) { if ( sdata_symbolic_operand ( op , SImode ) ) { emit_insn ( gen_load_sdata_pic ( dest , pic_offset_table_rtx , op ) ) ; crtl -> uses_pic_offset_table = 1 ; return true ; } else { rtx temp = ( reload_completed || reload_in_progress ? dest : gen_reg_rtx ( Pmode ) ) ; operands [ 1 ] = legitimize_pic_address ( op , temp , pic_offset_table_rtx ) ; } } else if ( reload_completed && ! sdata_symbolic_operand ( op , SImode ) ) { emit_insn ( gen_movsi_high ( dest , op ) ) ; emit_insn ( gen_movsi_lo_sum ( dest , dest , op ) ) ; return true ; } } return false ; } </s>

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


<s> static void filter_insns_above ( basic_block bb , int max_uid ) { rtx_insn * insn , * next ; bool prev_ti = false ; int prev_cycle = - 1 ; FOR_BB_INSNS_SAFE ( bb , insn , next ) { int this_cycle ; if ( ! NONDEBUG_INSN_P ( insn ) ) continue ; if ( insn == BB_END ( bb ) ) return ; this_cycle = insn_get_clock ( insn ) ; if ( prev_ti && this_cycle == prev_cycle ) { gcc_assert ( GET_MODE ( insn ) != TImode ) ; PUT_MODE ( insn , TImode ) ; } prev_ti = false ; if ( INSN_UID ( insn ) >= max_uid ) { if ( GET_MODE ( insn ) == TImode ) { prev_ti = true ; prev_cycle = this_cycle ; } delete_insn ( insn ) ; } } } </s>

Examine the insns in BB and remove all which have a uid greater or equal to MAX_UID .


<s> static rtx_insn * find_last_same_clock ( rtx_insn * insn ) { rtx_insn * retval = insn ; rtx_insn * t = next_real_insn ( insn ) ; while ( t && GET_MODE ( t ) != TImode ) { if ( ! DEBUG_INSN_P ( t ) && recog_memoized ( t ) >= 0 ) retval = t ; t = next_real_insn ( t ) ; } return retval ; } </s>

Walk forward from INSN to find the last insn that issues in the same clock cycle .


<s> static rtx_insn * find_next_cycle_insn ( rtx_insn * insn , int clock ) { rtx_insn * t = insn ; if ( GET_MODE ( t ) == TImode ) t = next_real_insn ( t ) ; while ( t && GET_MODE ( t ) != TImode ) t = next_real_insn ( t ) ; if ( t && insn_get_clock ( t ) == clock ) return t ; return NULL ; } </s>

Scan forwards from INSN until we find the next insn that has mode TImode ( indicating it starts a new cycle ) , and occurs in cycle CLOCK . Return it if we find such an insn , NULL_RTX otherwise .


<s> static int first_jump_index ( int clock_var ) { int retval = - 1 ; int n = 0 ; for ( ; ; ) { int t = get_jump_cycle ( n ) ; if ( t <= clock_var ) break ; retval = n ; n ++ ; } return retval ; } </s>

Return the index of the first jump that occurs after CLOCK_VAR . If no jump has delay slots beyond CLOCK_VAR , return -1 .


<s> static void gen_one_bundle ( rtx_insn * * slot , int n_filled , int real_first ) { rtx seq ; rtx_insn * bundle ; rtx_insn * t ; int i ; seq = gen_rtx_SEQUENCE ( VOIDmode , gen_rtvec_v ( n_filled , slot ) ) ; bundle = make_insn_raw ( seq ) ; BLOCK_FOR_INSN ( bundle ) = BLOCK_FOR_INSN ( slot [ 0 ] ) ; INSN_LOCATION ( bundle ) = INSN_LOCATION ( slot [ 0 ] ) ; SET_PREV_INSN ( bundle ) = SET_PREV_INSN ( slot [ real_first ] ) ; t = NULL ; for ( i = 0 ; i < n_filled ; i ++ ) { rtx_insn * insn = slot [ i ] ; remove_insn ( insn ) ; SET_PREV_INSN ( insn ) = t ? t : PREV_INSN ( bundle ) ; if ( t != NULL_RTX ) SET_NEXT_INSN ( t ) = insn ; t = insn ; if ( i > 0 ) INSN_LOCATION ( slot [ i ] ) = INSN_LOCATION ( bundle ) ; } SET_NEXT_INSN ( bundle ) = NEXT_INSN ( PREV_INSN ( bundle ) ) ; SET_NEXT_INSN ( t ) = NEXT_INSN ( bundle ) ; SET_NEXT_INSN ( PREV_INSN ( bundle ) ) = bundle ; SET_PREV_INSN ( NEXT_INSN ( bundle ) ) = bundle ; } </s>

Create a SEQUENCE rtx to replace the instructions in SLOT , of which there are N_FILLED . REAL_FIRST identifies the slot if the insn that appears first in the original stream .


<s> static int get_insn_side ( rtx_insn * insn , enum attr_units units ) { if ( units == UNITS_D_ADDR ) return ( get_attr_addr_regfile ( insn ) == ADDR_REGFILE_A ? 0 : 1 ) ; else { enum attr_dest_regfile rf = get_attr_dest_regfile ( insn ) ; if ( rf == DEST_REGFILE_ANY ) return get_attr_type ( insn ) == TYPE_BRANCH ? 0 : 1 ; else return rf == DEST_REGFILE_A ? 0 : 1 ; } } </s>

Compute the side of the machine used by INSN , which reserves UNITS . This must match the reservations in the scheduling description .


<s> static rtx get_jump_cond ( int n ) { if ( n >= 12 ) return NULL_RTX ; n += ss . jump_cycle_index ; if ( n >= 12 ) n -= 12 ; return ss . jump_cond [ n ] ; } </s>

Look up the jump condition with index N .


<s> static int get_jump_cycle ( int n ) { if ( n >= 12 ) return 0 ; n += ss . jump_cycle_index ; if ( n >= 12 ) n -= 12 ; return ss . jump_cycles [ n ] ; } </s>

Look up the jump cycle with index N. For an out-of-bounds N , we return 0 , so the caller does not specifically have to test for it .


<s> static int get_reservation_flags ( enum attr_units units ) { switch ( units ) { case UNITS_D : case UNITS_D_ADDR : return RESERVATION_FLAG_D ; case UNITS_L : return RESERVATION_FLAG_L ; case UNITS_S : return RESERVATION_FLAG_S ; case UNITS_M : return RESERVATION_FLAG_M ; case UNITS_LS : return RESERVATION_FLAG_LS ; case UNITS_DL : return RESERVATION_FLAG_DL ; case UNITS_DS : return RESERVATION_FLAG_DS ; case UNITS_DLS : return RESERVATION_FLAG_DLS ; default : return 0 ; } } </s>

Translate UNITS into a bitmask of units we can reserve for this insn .


<s> static bool get_unit_operand_masks ( rtx_insn * insn , unsigned int * pmask1 , unsigned int * pmask2 ) { enum attr_op_pattern op_pat ; if ( recog_memoized ( insn ) < 0 ) return 0 ; if ( GET_CODE ( PATTERN ( insn ) ) == COND_EXEC ) return false ; extract_insn ( insn ) ; op_pat = get_attr_op_pattern ( insn ) ; if ( op_pat == OP_PATTERN_DT ) { gcc_assert ( recog_data . n_operands == 2 ) ; * pmask1 = 1 << 0 ; * pmask2 = 1 << 1 ; return true ; } else if ( op_pat == OP_PATTERN_TD ) { gcc_assert ( recog_data . n_operands == 2 ) ; * pmask1 = 1 << 1 ; * pmask2 = 1 << 0 ; return true ; } else if ( op_pat == OP_PATTERN_SXS ) { gcc_assert ( recog_data . n_operands == 3 ) ; * pmask1 = ( 1 << 0 ) | ( 1 << 2 ) ; * pmask2 = 1 << 1 ; return true ; } else if ( op_pat == OP_PATTERN_SX ) { gcc_assert ( recog_data . n_operands == 2 ) ; * pmask1 = 1 << 0 ; * pmask2 = 1 << 1 ; return true ; } else if ( op_pat == OP_PATTERN_SSX ) { gcc_assert ( recog_data . n_operands == 3 ) ; * pmask1 = ( 1 << 0 ) | ( 1 << 1 ) ; * pmask2 = 1 << 2 ; return true ; } return false ; } </s>

Examine INSN , and store in PMASK1 and PMASK2 bitmasks that represent the operands that are involved in the ( up to ) two reservations , as found by get_unit_reqs . Return true if we did this successfully , false if we could n't identify what to do with INSN .


<s> static int get_unit_reqs ( rtx_insn * insn , int * req1 , int * side1 , int * req2 , int * side2 ) { enum attr_units units ; enum attr_cross cross ; int side , req ; if ( ! NONDEBUG_INSN_P ( insn ) || recog_memoized ( insn ) < 0 ) return 0 ; units = get_attr_units ( insn ) ; if ( units == UNITS_UNKNOWN ) return 0 ; side = get_insn_side ( insn , units ) ; cross = get_attr_cross ( insn ) ; req = ( units == UNITS_D ? UNIT_REQ_D : units == UNITS_D_ADDR ? UNIT_REQ_D : units == UNITS_DL ? UNIT_REQ_DL : units == UNITS_DS ? UNIT_REQ_DS : units == UNITS_L ? UNIT_REQ_L : units == UNITS_LS ? UNIT_REQ_LS : units == UNITS_S ? UNIT_REQ_S : units == UNITS_M ? UNIT_REQ_M : units == UNITS_DLS ? UNIT_REQ_DLS : - 1 ) ; gcc_assert ( req != - 1 ) ; * req1 = req ; * side1 = side ; if ( units == UNITS_D_ADDR ) { * req2 = UNIT_REQ_T ; * side2 = side ^ ( cross == CROSS_Y ? 1 : 0 ) ; return 2 ; } else if ( cross == CROSS_Y ) { * req2 = UNIT_REQ_X ; * side2 = side ; return 2 ; } return 1 ; } </s>

Examine INSN , and store in REQ1/SIDE1 and REQ2/SIDE2 the unit requirements . Returns zero if INSN ca n't be handled , otherwise either one or two to show how many of the two pairs are in use . REQ1 is always used , it holds what is normally thought of as the instructions reservation , e.g . UNIT_REQ_DL . REQ2 is used to either describe a cross path , or for loads/stores , the T unit .


<s>
static
void
hwloop_fail
(
hwloop_info
loop
)
{
rtx
insn
,
test
,
testreg
;
if
(
dump_file
)
fprintf
(
dump_file
,
"splitting doloop insn %d\n"
,
INSN_UID
(
loop
->
loop_end
)
)
;
insn
=
gen_addsi3
(
loop
->
iter_reg
,
loop
->
iter_reg
,
constm1_rtx
)
;
if
(
loop
->
head
==
||
loop
->
iter_reg_used_outside
||
loop
->
iter_reg_used
||
TEST_HARD_REG_BIT
(
loop
->
regs_set_in_loop
,
REGNO
(
loop
->
iter_reg
)
)
||
loop
->
incoming_dest
!=
loop
->
head
||
EDGE_COUNT
(
loop
->
head
->
preds
)
!=
2
)
emit_insn_before
(
insn
,
loop
->
loop_end
)
;
else
{
rtx_insn
*
t
=
loop
->
start_label
;
while
(
!
NOTE_P
(
t
)
||
NOTE_KIND
(
t
)
!=
NOTE_INSN_BASIC_BLOCK
)
t
=
NEXT_INSN
(
t
)
;
emit_insn_after
(
insn
,
t
)
;
}
testreg
=
SET_DEST
(
XVECEXP
(
PATTERN
(
loop
->
loop_end
)
,
0
,
2
)
)
;
if
(
GET_CODE
(
testreg
)
==
SCRATCH
)
testreg
=
loop
->
iter_reg
;
else
emit_insn_before
(
gen_movsi
(
testreg
,
loop
->
iter_reg
)
,
loop
->
loop_end
)
;
test
=
gen_rtx_NE
(
VOIDmode
,
testreg
,
const0_rtx
)
;
insn
=
emit_jump_insn_before
(
gen_cbranchsi4
(
test
,
testreg
,
const0_rtx
,
loop
->
start_label
)
,
loop
->
loop_end
)
;
JUMP_LABEL
(
insn
)
=
loop
->
start_label
;
LABEL_NUSES
(
loop
->
start_label
)
++
;
delete_insn
(
loop
->
loop_end
)
;
}
</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 rtx hwloop_pattern_reg ( rtx_insn * insn ) { rtx pat , reg ; if ( ! JUMP_P ( insn ) || recog_memoized ( insn ) != CODE_FOR_loop_end ) return NULL_RTX ; pat = PATTERN ( insn ) ; reg = SET_DEST ( XVECEXP ( pat , 0 , 1 ) ) ; if ( ! REG_P ( reg ) ) return NULL_RTX ; return reg ; } </s>

A callback for the hw-doloop pass . This function examines INSN ; if it is a doloop_end pattern we recognize , return the reg rtx for the loop counter . Otherwise , return NULL_RTX .


<s> static void init_sched_state ( c6x_sched_context_t sc ) { sc -> last_scheduled_insn = NULL ; sc -> last_scheduled_iter0 = NULL ; sc -> issued_this_cycle = 0 ; memset ( sc -> jump_cycles , 0 , sizeof sc -> jump_cycles ) ; memset ( sc -> jump_cond , 0 , sizeof sc -> jump_cond ) ; sc -> jump_cycle_index = 0 ; sc -> delays_finished_at = 0 ; sc -> curr_sched_clock = 0 ; sc -> prev_cycle_state_ctx = xmalloc ( dfa_state_size ) ; memset ( sc -> reg_n_accesses , 0 , sizeof sc -> reg_n_accesses ) ; memset ( sc -> reg_n_xaccesses , 0 , sizeof sc -> reg_n_xaccesses ) ; memset ( sc -> reg_set_in_cycle , 0 , sizeof sc -> reg_set_in_cycle ) ; state_reset ( sc -> prev_cycle_state_ctx ) ; } </s>

Initialize SC . Used by c6x_init_sched_context and c6x_sched_init .


<s> static int insn_get_clock ( rtx insn ) { return insn_uid_get_clock ( INSN_UID ( insn ) ) ; } </s>

Return the clock cycle we set for INSN .


<s> static void insn_set_clock ( rtx insn , int cycle ) { unsigned uid = INSN_UID ( insn ) ; if ( uid >= INSN_INFO_LENGTH ) insn_info . safe_grow ( uid * 5 / 4 + 10 , true ) ; INSN_INFO_ENTRY ( uid ) . clock = cycle ; INSN_INFO_ENTRY ( uid ) . new_cond = NULL ; INSN_INFO_ENTRY ( uid ) . reservation = 0 ; INSN_INFO_ENTRY ( uid ) . ebb_start = false ; } </s>

Set the clock cycle of INSN to CYCLE . Also clears the insn 's entry in new_conditions .


<s> static int insn_uid_get_clock ( int uid ) { return INSN_INFO_ENTRY ( uid ) . clock ; } </s>

Return the clock cycle we set for the insn with uid UID .


<s> static rtx legitimize_pic_address ( rtx orig , rtx reg , rtx picreg ) { rtx addr = orig ; rtx new_rtx = orig ; if ( GET_CODE ( addr ) == SYMBOL_REF || GET_CODE ( addr ) == LABEL_REF ) { int unspec = UNSPEC_LOAD_GOT ; rtx tmp ; if ( reg == 0 ) { gcc_assert ( can_create_pseudo_p ( ) ) ; reg = gen_reg_rtx ( Pmode ) ; } if ( flag_pic == 2 ) { if ( can_create_pseudo_p ( ) ) tmp = gen_reg_rtx ( Pmode ) ; else tmp = reg ; emit_insn ( gen_movsi_gotoff_high ( tmp , addr ) ) ; emit_insn ( gen_movsi_gotoff_lo_sum ( tmp , tmp , addr ) ) ; emit_insn ( gen_load_got_gotoff ( reg , picreg , tmp ) ) ; } else { tmp = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , addr ) , unspec ) ; new_rtx = gen_const_mem ( Pmode , gen_rtx_PLUS ( Pmode , picreg , tmp ) ) ; emit_move_insn ( reg , new_rtx ) ; } if ( picreg == pic_offset_table_rtx ) crtl -> 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 ( can_create_pseudo_p ( ) ) ; 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_rtx ; } </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 void maybe_clobber_cond ( rtx_insn * insn , int clock_var ) { int n , idx ; idx = ss . jump_cycle_index ; for ( n = 0 ; n < 12 ; n ++ , idx ++ ) { rtx cond , link ; int cycle ; if ( idx >= 12 ) idx -= 12 ; cycle = ss . jump_cycles [ idx ] ; if ( cycle <= clock_var ) return ; cond = ss . jump_cond [ idx ] ; if ( cond == NULL_RTX ) continue ; if ( CALL_P ( insn ) ) { ss . jump_cond [ idx ] = NULL_RTX ; continue ; } note_stores ( insn , clobber_cond_1 , ss . jump_cond + idx ) ; for ( link = REG_NOTES ( insn ) ; link ; link = XEXP ( link , 1 ) ) if ( REG_NOTE_KIND ( link ) == REG_INC ) clobber_cond_1 ( XEXP ( link , 0 ) , NULL_RTX , ss . jump_cond + idx ) ; } } </s>

Examine INSN , and if it destroys the conditions have recorded for any of the jumps in flight , clear that condition so that we do n't predicate any more insns . CLOCK_VAR helps us limit the search to only those jumps which are still in flight .


<s> static void merge_unit_reqs ( unit_req_table reqs ) { int side ; for ( side = 0 ; side < 2 ; side ++ ) { int d = reqs [ side ] [ UNIT_REQ_D ] ; int l = reqs [ side ] [ UNIT_REQ_L ] ; int s = reqs [ side ] [ UNIT_REQ_S ] ; int dl = reqs [ side ] [ UNIT_REQ_DL ] ; int ls = reqs [ side ] [ UNIT_REQ_LS ] ; int ds = reqs [ side ] [ UNIT_REQ_DS ] ; reqs [ side ] [ UNIT_REQ_DL ] += d ; reqs [ side ] [ UNIT_REQ_DL ] += l ; reqs [ side ] [ UNIT_REQ_DS ] += d ; reqs [ side ] [ UNIT_REQ_DS ] += s ; reqs [ side ] [ UNIT_REQ_LS ] += l ; reqs [ side ] [ UNIT_REQ_LS ] += s ; reqs [ side ] [ UNIT_REQ_DLS ] += ds + dl + ls + d + l + s ; } } </s>

Update the table REQS by merging more specific unit reservations into more general ones , i.e . counting ( for example ) UNIT_REQ_D also in UNIT_REQ_DL , DS , and DLS .


<s> static bool must_reload_pic_reg_p ( void ) { if ( ! TARGET_DSBT ) return false ; cgraph_node * local_info_node = cgraph_node :: local_info_node ( current_function_decl ) ; if ( ( crtl -> uses_pic_offset_table || ! crtl -> is_leaf ) && ! local_info_node -> local ) return true ; return false ; } </s>

Return true if we need to save and modify the PIC register in the prologue .


<s> static bool predicate_insn ( rtx_insn * insn , rtx cond , bool doit ) { int icode ; if ( cond == NULL_RTX ) { gcc_assert ( ! doit ) ; return false ; } if ( get_attr_predicable ( insn ) == PREDICABLE_YES && GET_CODE ( PATTERN ( insn ) ) != COND_EXEC ) { if ( doit ) { cond = copy_rtx ( cond ) ; rtx newpat = gen_rtx_COND_EXEC ( VOIDmode , cond , PATTERN ( insn ) ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; } return true ; } if ( GET_CODE ( PATTERN ( insn ) ) == COND_EXEC && rtx_equal_p ( COND_EXEC_TEST ( PATTERN ( insn ) ) , cond ) ) return true ; icode = INSN_CODE ( insn ) ; if ( icode == CODE_FOR_real_jump || icode == CODE_FOR_jump || icode == CODE_FOR_indirect_jump ) { rtx pat = PATTERN ( insn ) ; rtx dest = ( icode == CODE_FOR_real_jump ? XVECEXP ( pat , 0 , 0 ) : icode == CODE_FOR_jump ? XEXP ( SET_SRC ( pat ) , 0 ) : SET_SRC ( pat ) ) ; if ( doit ) { rtx newpat ; if ( REG_P ( dest ) ) newpat = gen_rtx_COND_EXEC ( VOIDmode , cond , PATTERN ( insn ) ) ; else newpat = gen_br_true ( cond , XEXP ( cond , 0 ) , dest ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; } return true ; } if ( INSN_CODE ( insn ) == CODE_FOR_br_true ) { rtx br_cond = XEXP ( SET_SRC ( PATTERN ( insn ) ) , 0 ) ; return rtx_equal_p ( br_cond , cond ) ; } if ( INSN_CODE ( insn ) == CODE_FOR_br_false ) { rtx br_cond = XEXP ( SET_SRC ( PATTERN ( insn ) ) , 0 ) ; return conditions_opposite_p ( br_cond , cond ) ; } return false ; } </s>

Return true if we can add a predicate COND to INSN , or if INSN already has that predicate . If DOIT is true , also perform the modification .


<s> static void print_address_offset ( FILE * file , rtx off , machine_mode mem_mode ) { rtx pat ; if ( c6x_current_insn != NULL_RTX ) { pat = PATTERN ( c6x_current_insn ) ; if ( GET_CODE ( pat ) == COND_EXEC ) pat = COND_EXEC_CODE ( pat ) ; if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET && GET_CODE ( SET_SRC ( pat ) ) == UNSPEC && XINT ( SET_SRC ( pat ) , 1 ) == UNSPEC_MISALIGNED_ACCESS ) { gcc_assert ( CONST_INT_P ( off ) && ( INTVAL ( off ) & ( GET_MODE_SIZE ( mem_mode ) - 1 ) ) == 0 ) ; fprintf ( file , "[" HOST_WIDE_INT_PRINT_DEC "]" , INTVAL ( off ) / GET_MODE_SIZE ( mem_mode ) ) ; return ; } } fputs ( "(" , file ) ; output_address ( mem_mode , off ) ; fputs ( ")" , file ) ; } </s>

Subroutine of print_address_operand , print a single address offset OFF for a memory access of mode MEM_MODE , choosing between normal form and scaled form depending on the type of the insn . Misaligned memory references must use the scaled form .


<s> static void record_jump ( int cycle , rtx cond ) { if ( ss . jump_cycle_index == 0 ) ss . jump_cycle_index = 11 ; else ss . jump_cycle_index -- ; ss . jump_cycles [ ss . jump_cycle_index ] = cycle ; ss . jump_cond [ ss . jump_cycle_index ] = cond ; } </s>

Add a new entry in our scheduling state for a jump that occurs in CYCLE and has the opposite condition of COND .