<s> static void reorg_emit_nops ( rtx_code_label * * 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 reshuffle_units ( basic_block loop ) { rtx_insn * head = BB_HEAD ( loop ) ; rtx_insn * tail = BB_END ( loop ) ; rtx_insn * insn ; unit_req_table reqs ; edge e ; edge_iterator ei ; bitmap_head bbs ; count_unit_reqs ( reqs , head , PREV_INSN ( tail ) ) ; merge_unit_reqs ( reqs ) ; regrename_init ( true ) ; bitmap_initialize ( & bbs , & bitmap_default_obstack ) ; FOR_EACH_EDGE ( e , ei , loop -> preds ) bitmap_set_bit ( & bbs , e -> src -> index ) ; bitmap_set_bit ( & bbs , loop -> index ) ; regrename_analyze ( & bbs ) ; for ( insn = head ; insn != NEXT_INSN ( tail ) ; insn = NEXT_INSN ( insn ) ) { enum attr_units units ; int count , side1 , side2 , req1 , req2 ; unsigned int mask1 , mask2 ; insn_rr_info * info ; if ( ! NONDEBUG_INSN_P ( insn ) ) continue ; count = get_unit_reqs ( insn , & req1 , & side1 , & req2 , & side2 ) ; if ( count == 0 ) continue ; if ( ! get_unit_operand_masks ( insn , & mask1 , & mask2 ) ) continue ; info = & insn_rr [ INSN_UID ( insn ) ] ; if ( info -> op_info == NULL ) continue ; if ( reqs [ side1 ] [ req1 ] > 1 && reqs [ side1 ] [ req1 ] > 2 * reqs [ side1 ^ 1 ] [ req1 ] ) { try_rename_operands ( head , tail , reqs , insn , info , mask1 , side1 ) ; } units = get_attr_units ( insn ) ; if ( units == UNITS_D_ADDR ) { gcc_assert ( count == 2 ) ; if ( reqs [ side2 ] [ req2 ] > 1 && reqs [ side2 ] [ req2 ] > 2 * reqs [ side2 ^ 1 ] [ req2 ] ) { try_rename_operands ( head , tail , reqs , insn , info , mask2 , side2 ) ; } } } regrename_finish ( ) ; } </s>

Find insns in LOOP which would , if shifted to the other side of the machine , reduce an imbalance in the unit reservations .


<s> static int res_mii ( unit_req_table reqs ) { int side , req ; int worst = 1 ; for ( side = 0 ; side < 2 ; side ++ ) for ( req = 0 ; req < UNIT_REQ_MAX ; req ++ ) { int factor = unit_req_factor ( ( enum unitreqs ) req ) ; worst = MAX ( ( reqs [ side ] [ UNIT_REQ_D ] + factor - 1 ) / factor , worst ) ; } return worst ; } </s>

Return the resource-constrained minimum iteration interval given the data in the REQS table . This must have been processed with merge_unit_reqs already .


<s> static bool returning_call_p ( rtx_insn * insn ) { if ( CALL_P ( insn ) ) return ( ! SIBLING_CALL_P ( insn ) && get_attr_type ( insn ) != TYPE_CALLP && get_attr_type ( insn ) != TYPE_SHADOW ) ; if ( recog_memoized ( insn ) < 0 ) return false ; if ( get_attr_type ( insn ) == TYPE_CALL ) return true ; return false ; } </s>

Determine whether INSN is a call that needs to have a return label placed .


<s> static rtx safe_vector_operand ( rtx x , machine_mode mode ) { if ( x != const0_rtx ) return x ; x = gen_reg_rtx ( SImode ) ; emit_insn ( gen_movsi ( x , CONST0_RTX ( SImode ) ) ) ; return gen_lowpart ( mode , x ) ; } </s>

Errors in the source file can cause expand_expr to return const0_rtx where we expect a vector . To avoid crashing , use one of the vector clear instructions .


<s> static bool shadow_or_blockage_p ( rtx_insn * insn ) { enum attr_type type ; if ( ! NONDEBUG_INSN_P ( insn ) || recog_memoized ( insn ) < 0 ) return false ; type = get_attr_type ( insn ) ; return shadow_type_p ( type ) || type == TYPE_BLOCKAGE ; } </s>

Return true iff INSN is a shadow or blockage pattern .


<s> static bool shadow_p ( rtx_insn * insn ) { if ( ! NONDEBUG_INSN_P ( insn ) || recog_memoized ( insn ) < 0 ) return false ; return shadow_type_p ( get_attr_type ( insn ) ) ; } </s>

Return true iff INSN is a shadow pattern .


<s> static bool shadow_type_p ( enum attr_type type ) { return ( type == TYPE_SHADOW || type == TYPE_LOAD_SHADOW || type == TYPE_MULT_SHADOW ) ; } </s>

Return true iff TYPE is one of the shadow types .


<s> static bool shift_p ( rtx x , enum rtx_code code , int amount ) { return ( GET_CODE ( x ) == code && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && INTVAL ( XEXP ( x , 1 ) ) == amount ) ; } </s>

Determine whether X is a shift with code CODE and an integer amount AMOUNT .


<s> static void split_delayed_branch ( rtx_insn * insn ) { int code = recog_memoized ( insn ) ; rtx_insn * i1 ; rtx newpat ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == COND_EXEC ) pat = COND_EXEC_CODE ( pat ) ; if ( CALL_P ( insn ) ) { rtx src = pat , dest = NULL_RTX ; rtx callee ; if ( GET_CODE ( pat ) == SET ) { dest = SET_DEST ( pat ) ; src = SET_SRC ( pat ) ; } callee = XEXP ( XEXP ( src , 0 ) , 0 ) ; if ( SIBLING_CALL_P ( insn ) ) { if ( REG_P ( callee ) ) newpat = gen_indirect_sibcall_shadow ( ) ; else newpat = gen_sibcall_shadow ( callee ) ; pat = gen_real_jump ( callee ) ; } else if ( dest != NULL_RTX ) { if ( REG_P ( callee ) ) newpat = gen_indirect_call_value_shadow ( dest ) ; else newpat = gen_call_value_shadow ( dest , callee ) ; pat = gen_real_call ( callee ) ; } else { if ( REG_P ( callee ) ) newpat = gen_indirect_call_shadow ( ) ; else newpat = gen_call_shadow ( callee ) ; pat = gen_real_call ( callee ) ; } pat = duplicate_cond ( pat , insn ) ; newpat = duplicate_cond ( newpat , insn ) ; } else { rtx src , op ; if ( GET_CODE ( pat ) == PARALLEL && GET_CODE ( XVECEXP ( pat , 0 , 0 ) ) == RETURN ) { newpat = gen_return_shadow ( ) ; pat = gen_real_ret ( XEXP ( XVECEXP ( pat , 0 , 1 ) , 0 ) ) ; newpat = duplicate_cond ( newpat , insn ) ; } else switch ( code ) { case CODE_FOR_br_true : case CODE_FOR_br_false : src = SET_SRC ( pat ) ; op = XEXP ( src , code == CODE_FOR_br_true ? 1 : 2 ) ; newpat = gen_condjump_shadow ( op ) ; pat = gen_real_jump ( op ) ; if ( code == CODE_FOR_br_true ) pat = gen_rtx_COND_EXEC ( VOIDmode , XEXP ( src , 0 ) , pat ) ; else pat = gen_rtx_COND_EXEC ( VOIDmode , reversed_comparison ( XEXP ( src , 0 ) , VOIDmode ) , pat ) ; break ; case CODE_FOR_jump : op = SET_SRC ( pat ) ; newpat = gen_jump_shadow ( op ) ; break ; case CODE_FOR_indirect_jump : newpat = gen_indirect_jump_shadow ( ) ; break ; case CODE_FOR_return_internal : newpat = gen_return_shadow ( ) ; pat = gen_real_ret ( XEXP ( XVECEXP ( pat , 0 , 1 ) , 0 ) ) ; break ; default : return ; } } i1 = emit_insn_before ( pat , insn ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; record_delay_slot_pair ( i1 , insn , 5 , 0 ) ; } </s>

If possible , split INSN , which we know is either a jump or a call , into a real insn and its shadow .


<s> static void split_delayed_insns ( void ) { rtx_insn * insn ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) || CALL_P ( insn ) ) split_delayed_branch ( insn ) ; } } </s>

Split every insn ( i.e . jumps and calls ) which can have delay slots into two parts : the first one is scheduled normally and emits the instruction , while the second one is a shadow insn which shows the side effect taking place . The second one is placed in the right cycle by the scheduler , but not emitted as an assembly instruction .


<s> static bool split_delayed_nonbranch ( rtx_insn * insn ) { int code = recog_memoized ( insn ) ; enum attr_type type ; rtx_insn * i1 ; rtx newpat , src , dest ; rtx pat = PATTERN ( insn ) ; rtvec rtv ; int delay ; if ( GET_CODE ( pat ) == COND_EXEC ) pat = COND_EXEC_CODE ( pat ) ; if ( code < 0 || GET_CODE ( pat ) != SET ) return false ; src = SET_SRC ( pat ) ; dest = SET_DEST ( pat ) ; if ( ! REG_P ( dest ) ) return false ; type = get_attr_type ( insn ) ; if ( code >= 0 && ( type == TYPE_LOAD || type == TYPE_LOADN ) ) { if ( ! MEM_P ( src ) && ( GET_CODE ( src ) != ZERO_EXTEND || ! MEM_P ( XEXP ( src , 0 ) ) ) ) return false ; if ( GET_MODE_SIZE ( GET_MODE ( dest ) ) > 4 && ( GET_MODE_SIZE ( GET_MODE ( dest ) ) != 8 || ! TARGET_LDDW ) ) return false ; rtv = gen_rtvec ( 2 , GEN_INT ( REGNO ( SET_DEST ( pat ) ) ) , SET_SRC ( pat ) ) ; newpat = gen_load_shadow ( SET_DEST ( pat ) ) ; pat = gen_rtx_UNSPEC ( VOIDmode , rtv , UNSPEC_REAL_LOAD ) ; delay = 4 ; } else if ( code >= 0 && ( type == TYPE_MPY2 || type == TYPE_MPY4 ) ) { if ( GET_MODE ( dest ) == SFmode ) return false ; rtv = gen_rtvec ( 2 , GEN_INT ( REGNO ( SET_DEST ( pat ) ) ) , SET_SRC ( pat ) ) ; newpat = gen_mult_shadow ( SET_DEST ( pat ) ) ; pat = gen_rtx_UNSPEC ( VOIDmode , rtv , UNSPEC_REAL_MULT ) ; delay = type == TYPE_MPY2 ? 1 : 3 ; } else return false ; pat = duplicate_cond ( pat , insn ) ; newpat = duplicate_cond ( newpat , insn ) ; i1 = emit_insn_before ( pat , insn ) ; PATTERN ( insn ) = newpat ; INSN_CODE ( insn ) = - 1 ; recog_memoized ( insn ) ; recog_memoized ( i1 ) ; record_delay_slot_pair ( i1 , insn , delay , 0 ) ; return true ; } </s>

If INSN is a multi-cycle insn that should be handled properly in modulo-scheduling , split it into a real insn and a shadow . Return true if we made a change . It is valid for us to fail to split an insn ; the caller has to deal with the possibility . Currently we handle loads and most mpy2 and mpy4 insns .


<s> void split_di ( rtx operands [ ] , int num , rtx lo_half [ ] , rtx hi_half [ ] ) { while ( num -- ) { rtx op = operands [ num ] ; lo_half [ num ] = c6x_subword ( op , false ) ; hi_half [ num ] = c6x_subword ( op , true ) ; } } </s>

Split one or more DImode RTL references into pairs of SImode references . The RTL can be REG , offsettable MEM , integer constant , or CONST_DOUBLE . `` operands '' is a pointer to an array of DImode RTL to split and `` num '' is its length . lo_half and hi_half are output arrays that parallel `` operands '' .


<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 ( 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 int unit_req_factor ( enum unitreqs r ) { switch ( r ) { case UNIT_REQ_D : case UNIT_REQ_L : case UNIT_REQ_S : case UNIT_REQ_M : case UNIT_REQ_X : case UNIT_REQ_T : return 1 ; case UNIT_REQ_DL : case UNIT_REQ_LS : case UNIT_REQ_DS : return 2 ; case UNIT_REQ_DLS : return 3 ; default : gcc_unreachable ( ) ; } } </s>

Return a factor by which to weight unit imbalances for a reservation R .


<s> static int unit_req_imbalance ( unit_req_table reqs ) { int val = 0 ; int i ; for ( i = 0 ; i < UNIT_REQ_MAX ; i ++ ) { int factor = unit_req_factor ( ( enum unitreqs ) i ) ; int diff = abs ( reqs [ 0 ] [ i ] - reqs [ 1 ] [ i ] ) ; val += ( diff + factor - 1 ) / factor / 2 ; } return val ; } </s>

Examine the table REQS and return a measure of unit imbalance by comparing the two sides of the machine . If , for example , D1 is used twice and D2 used not at all , the return value should be 1 in the absence of other imbalances .


<s> static bool use_push_rts_p ( int nregs ) { if ( TARGET_INSNS_64PLUS && optimize_function_for_size_p ( cfun ) && ! cfun -> machine -> contains_sibcall && ! cfun -> returns_struct && ! TARGET_LONG_CALLS && nregs >= 6 && ! frame_pointer_needed ) return true ; return false ; } </s>

Examine the number of regs NREGS we 've determined we must save . Return true if we should use __c6xabi_push_rts/__c6xabi_pop_rts for prologue and epilogue .