<s> static void bfin_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx t1 = copy_to_reg ( XEXP ( DECL_RTL ( fndecl ) , 0 ) ) ; rtx t2 = copy_to_reg ( chain_value ) ; rtx mem ; int i = 0 ; emit_block_move ( m_tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; if ( TARGET_FDPIC ) { rtx a = force_reg ( Pmode , plus_constant ( Pmode , XEXP ( m_tramp , 0 ) , 8 ) ) ; mem = adjust_address ( m_tramp , Pmode , 0 ) ; emit_move_insn ( mem , a ) ; i = 8 ; } mem = adjust_address ( m_tramp , HImode , i + 2 ) ; emit_move_insn ( mem , gen_lowpart ( HImode , t1 ) ) ; emit_insn ( gen_ashrsi3 ( t1 , t1 , GEN_INT ( 16 ) ) ) ; mem = adjust_address ( m_tramp , HImode , i + 6 ) ; emit_move_insn ( mem , gen_lowpart ( HImode , t1 ) ) ; mem = adjust_address ( m_tramp , HImode , i + 10 ) ; emit_move_insn ( mem , gen_lowpart ( HImode , t2 ) ) ; emit_insn ( gen_ashrsi3 ( t2 , t2 , GEN_INT ( 16 ) ) ) ; mem = adjust_address ( m_tramp , HImode , i + 14 ) ; emit_move_insn ( mem , gen_lowpart ( HImode , t2 ) ) ; } </s>

Emit RTL insns to initialize the variable parts of a trampoline at M_TRAMP . FNDECL is the target function . CHAIN_VALUE is an RTX for the static chain value for the function .


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

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


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

Implements target hook vector_mode_supported_p .


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

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


<s> static int cbranch_predicted_taken_p ( rtx insn ) { rtx x = find_reg_note ( insn , REG_BR_PROB , 0 ) ; if ( x ) { return profile_probability :: from_reg_br_prob_note ( XINT ( x , 0 ) ) >= profile_probability :: even ( ) ; } return 0 ; } </s>

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


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

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


<s> static void do_unlink ( rtx spreg , HOST_WIDE_INT frame_size , bool all , int epilogue_p ) { frame_size += arg_area_size ( ) ; if ( stack_frame_needed_p ( ) ) emit_insn ( gen_unlink ( ) ) ; else { rtx postinc = gen_rtx_MEM ( Pmode , gen_rtx_POST_INC ( Pmode , spreg ) ) ; add_to_reg ( spreg , frame_size , 0 , epilogue_p ) ; if ( all || must_save_fp_p ( ) ) { rtx fpreg = gen_rtx_REG ( Pmode , REG_FP ) ; emit_move_insn ( fpreg , postinc ) ; emit_use ( fpreg ) ; } if ( all || must_save_rets_p ( ) ) { emit_move_insn ( bfin_rets_rtx , postinc ) ; emit_use ( bfin_rets_rtx ) ; } } } </s>

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


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

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


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

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


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

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


<s> static void expand_interrupt_handler_epilogue ( rtx spreg , e_funkind fkind , bool all ) { tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; rtx postinc1 = gen_rtx_POST_INC ( SImode , spreg ) ; rtx postinc = gen_rtx_MEM ( SImode , postinc1 ) ; MEM_VOLATILE_P ( postinc ) = 1 ; do_unlink ( spreg , get_frame_size ( ) , all , 1 ) ; if ( lookup_attribute ( "nesting" , attrs ) ) { rtx srcreg = gen_rtx_REG ( Pmode , ret_regs [ fkind ] ) ; emit_move_insn ( srcreg , postinc ) ; } if ( ! crtl -> is_leaf ) all = true ; expand_epilogue_reg_restore ( spreg , all , true ) ; if ( fkind == EXCPT_HANDLER ) emit_insn ( gen_addsi3 ( spreg , spreg , GEN_INT ( 12 ) ) ) ; emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , ret_regs [ fkind ] ) ) ) ; } </s>

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


<s> static void expand_interrupt_handler_prologue ( rtx spreg , e_funkind fkind , bool all ) { HOST_WIDE_INT frame_size = get_frame_size ( ) ; rtx predec1 = gen_rtx_PRE_DEC ( SImode , spreg ) ; rtx predec = gen_rtx_MEM ( SImode , predec1 ) ; rtx_insn * insn ; tree attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( current_function_decl ) ) ; tree kspisusp = lookup_attribute ( "kspisusp" , attrs ) ; if ( kspisusp ) { insn = emit_move_insn ( spreg , gen_rtx_REG ( Pmode , REG_USP ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( fkind == EXCPT_HANDLER ) { insn = emit_insn ( gen_addsi3 ( spreg , spreg , GEN_INT ( - 12 ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( ! crtl -> is_leaf ) all = true ; expand_prologue_reg_save ( spreg , all , true ) ; if ( ENABLE_WA_05000283 || ENABLE_WA_05000315 ) { rtx chipid = GEN_INT ( trunc_int_for_mode ( 0xFFC00014 , SImode ) ) ; rtx p5reg = gen_rtx_REG ( Pmode , REG_P5 ) ; emit_insn ( gen_movbi ( bfin_cc_rtx , const1_rtx ) ) ; emit_insn ( gen_movsi_high ( p5reg , chipid ) ) ; emit_insn ( gen_movsi_low ( p5reg , p5reg , chipid ) ) ; emit_insn ( gen_dummy_load ( p5reg , bfin_cc_rtx ) ) ; } if ( lookup_attribute ( "nesting" , attrs ) ) { rtx srcreg = gen_rtx_REG ( Pmode , ret_regs [ fkind ] ) ; insn = emit_move_insn ( predec , srcreg ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } do_link ( spreg , frame_size , all ) ; if ( fkind == EXCPT_HANDLER ) { rtx r0reg = gen_rtx_REG ( SImode , REG_R0 ) ; rtx r1reg = gen_rtx_REG ( SImode , REG_R1 ) ; rtx r2reg = gen_rtx_REG ( SImode , REG_R2 ) ; emit_move_insn ( r0reg , gen_rtx_REG ( SImode , REG_SEQSTAT ) ) ; emit_insn ( gen_ashrsi3 ( r0reg , r0reg , GEN_INT ( 26 ) ) ) ; emit_insn ( gen_ashlsi3 ( r0reg , r0reg , GEN_INT ( 26 ) ) ) ; emit_move_insn ( r1reg , spreg ) ; emit_move_insn ( r2reg , gen_rtx_REG ( Pmode , REG_FP ) ) ; emit_insn ( gen_addsi3 ( r2reg , r2reg , GEN_INT ( 8 ) ) ) ; } } </s>

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


<s> bool expand_move ( rtx * operands , machine_mode mode ) { rtx op = operands [ 1 ] ; if ( ( TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC ) && SYMBOLIC_CONST ( op ) ) emit_pic_move ( operands , mode ) ; else if ( mode == SImode && GET_CODE ( op ) == CONST && GET_CODE ( XEXP ( op , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( op , 0 ) , 0 ) ) == SYMBOL_REF && ! targetm . legitimate_constant_p ( mode , op ) ) { rtx dest = operands [ 0 ] ; rtx op0 , op1 ; gcc_assert ( ! reload_in_progress && ! reload_completed ) ; op = XEXP ( op , 0 ) ; op0 = force_reg ( mode , XEXP ( op , 0 ) ) ; op1 = XEXP ( op , 1 ) ; if ( ! insn_data [ CODE_FOR_addsi3 ] . operand [ 2 ] . predicate ( op1 , mode ) ) op1 = force_reg ( mode , op1 ) ; if ( GET_CODE ( dest ) == MEM ) dest = gen_reg_rtx ( mode ) ; emit_insn ( gen_addsi3 ( dest , op0 , op1 ) ) ; if ( dest == operands [ 0 ] ) return true ; operands [ 1 ] = dest ; } else if ( ( reload_in_progress | reload_completed ) == 0 && GET_CODE ( operands [ 0 ] ) == MEM && GET_CODE ( operands [ 1 ] ) != REG ) operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; return false ; } </s>

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


<s> static rtx_insn * find_load ( rtx_insn * insn ) { if ( ! NONDEBUG_INSN_P ( insn ) ) return NULL ; if ( get_attr_type ( insn ) == TYPE_MCLD ) return insn ; if ( GET_MODE ( insn ) != SImode ) return NULL ; do { insn = NEXT_INSN ( insn ) ; if ( ( GET_MODE ( insn ) == SImode || GET_MODE ( insn ) == QImode ) && get_attr_type ( insn ) == TYPE_MCLD ) return insn ; } while ( GET_MODE ( insn ) != QImode ) ; return NULL ; } </s>

Return INSN if it is of TYPE_MCLD . Alternatively , if INSN is the start of a three-insn bundle , see if one of them is a load and return that if so . Return NULL if the insn does not contain loads .


<s> static rtx_insn * find_next_insn_start ( rtx_insn * insn ) { if ( GET_MODE ( insn ) == SImode ) { while ( GET_MODE ( insn ) != QImode ) insn = NEXT_INSN ( insn ) ; } return NEXT_INSN ( insn ) ; } </s>

This function acts like NEXT_INSN , but is aware of three-insn bundles and skips all subsequent parallel instructions if INSN is the start of such a group .


<s> static rtx_insn * find_prev_insn_start ( rtx_insn * insn ) { insn = PREV_INSN ( insn ) ; gcc_assert ( GET_MODE ( insn ) != SImode ) ; if ( GET_MODE ( insn ) == QImode ) { while ( GET_MODE ( PREV_INSN ( insn ) ) == SImode ) insn = PREV_INSN ( insn ) ; } return insn ; } </s>

This function acts like PREV_INSN , but is aware of three-insn bundles and skips all subsequent parallel instructions if INSN is the start of such a group .


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

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


<s> bool function_arg_regno_p ( int n ) { int i ; for ( i = 0 ; arg_regs [ i ] != - 1 ; i ++ ) if ( n == arg_regs [ i ] ) return true ; return false ; } </s>

Return true when register may be used to pass function parameters .


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

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


<s> static bool gen_one_bundle ( rtx_insn * slot [ 3 ] ) { gcc_assert ( slot [ 1 ] != NULL_RTX ) ; if ( optimize_size && ( slot [ 0 ] == NULL_RTX || slot [ 2 ] == NULL_RTX ) ) return false ; if ( slot [ 0 ] ) { rtx_insn * t = NEXT_INSN ( slot [ 0 ] ) ; while ( t != slot [ 1 ] ) { if ( ! NOTE_P ( t ) || NOTE_KIND ( t ) != NOTE_INSN_DELETED ) return false ; t = NEXT_INSN ( t ) ; } } if ( slot [ 2 ] ) { rtx_insn * t = NEXT_INSN ( slot [ 1 ] ) ; while ( t != slot [ 2 ] ) { if ( ! NOTE_P ( t ) || NOTE_KIND ( t ) != NOTE_INSN_DELETED ) return false ; t = NEXT_INSN ( t ) ; } } if ( slot [ 0 ] == NULL_RTX ) { slot [ 0 ] = emit_insn_before ( gen_mnop ( ) , slot [ 1 ] ) ; df_insn_rescan ( slot [ 0 ] ) ; } if ( slot [ 2 ] == NULL_RTX ) { slot [ 2 ] = emit_insn_after ( gen_forced_nop ( ) , slot [ 1 ] ) ; df_insn_rescan ( slot [ 2 ] ) ; } if ( INSN_LOCATION ( slot [ 1 ] ) && INSN_LOCATION ( slot [ 1 ] ) != INSN_LOCATION ( slot [ 0 ] ) ) INSN_LOCATION ( slot [ 1 ] ) = INSN_LOCATION ( slot [ 0 ] ) ; if ( INSN_LOCATION ( slot [ 2 ] ) && INSN_LOCATION ( slot [ 2 ] ) != INSN_LOCATION ( slot [ 0 ] ) ) INSN_LOCATION ( slot [ 2 ] ) = INSN_LOCATION ( slot [ 0 ] ) ; PUT_MODE ( slot [ 0 ] , SImode ) ; PUT_MODE ( slot [ 1 ] , SImode ) ; PUT_MODE ( slot [ 2 ] , QImode ) ; return true ; } </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 .


"%qE attribute only applies to functions"

"multiple function type attributes specified"

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


<s> static bool harmless_null_pointer_p ( rtx mem , int np_reg ) { mem = XEXP ( mem , 0 ) ; if ( GET_CODE ( mem ) == POST_INC || GET_CODE ( mem ) == POST_DEC ) mem = XEXP ( mem , 0 ) ; if ( REG_P ( mem ) && ( int ) REGNO ( mem ) == np_reg ) return true ; if ( GET_CODE ( mem ) == PLUS && REG_P ( XEXP ( mem , 0 ) ) && ( int ) REGNO ( XEXP ( mem , 0 ) ) == np_reg ) { mem = XEXP ( mem , 1 ) ; if ( GET_CODE ( mem ) == CONST_INT && INTVAL ( mem ) > 0 ) return true ; } return false ; } </s>

Return true iff the address found in MEM is based on the register NP_REG and optionally has a positive offset .


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

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


<s> static rtx hwloop_pattern_reg ( rtx_insn * insn ) { rtx reg ; if ( ! JUMP_P ( insn ) || recog_memoized ( insn ) != CODE_FOR_loop_end ) return NULL_RTX ; reg = SET_DEST ( XVECEXP ( PATTERN ( insn ) , 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 bool indirect_call_p ( rtx pat ) { if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET ) pat = SET_SRC ( pat ) ; gcc_assert ( GET_CODE ( pat ) == CALL ) ; pat = XEXP ( pat , 0 ) ; gcc_assert ( GET_CODE ( pat ) == MEM ) ; pat = XEXP ( pat , 0 ) ; return REG_P ( pat ) ; } </s>

Determine whether PAT is an indirect call pattern .


<s> void init_cumulative_args ( CUMULATIVE_ARGS * cum , tree fntype , rtx libname ATTRIBUTE_UNUSED ) { static CUMULATIVE_ARGS zero_cum ; * cum = zero_cum ; cum -> nregs = max_arg_registers ; cum -> arg_regs = arg_regs ; cum -> call_cookie = CALL_NORMAL ; if ( fntype && lookup_attribute ( "shortcall" , TYPE_ATTRIBUTES ( fntype ) ) ) cum -> call_cookie |= CALL_SHORT ; else if ( fntype && lookup_attribute ( "longcall" , TYPE_ATTRIBUTES ( fntype ) ) ) cum -> call_cookie |= CALL_LONG ; return ; } </s>

Handle the INIT_CUMULATIVE_ARGS macro . Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE . For a library call , FNTYPE is 0 .


<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 ; rtx tmp ; if ( TARGET_ID_SHARED_LIBRARY ) unspec = UNSPEC_MOVE_PIC ; else if ( GET_CODE ( addr ) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P ( addr ) ) unspec = UNSPEC_FUNCDESC_GOT17M4 ; else unspec = UNSPEC_MOVE_FDPIC ; if ( reg == 0 ) { gcc_assert ( can_create_pseudo_p ( ) ) ; reg = gen_reg_rtx ( Pmode ) ; } 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 int length_for_loop ( rtx_insn * insn ) { int length = 0 ; if ( JUMP_P ( insn ) && any_condjump_p ( insn ) && ! optimize_size ) { if ( ENABLE_WA_SPECULATIVE_SYNCS ) length = 8 ; else if ( ENABLE_WA_SPECULATIVE_LOADS ) length = 6 ; } else if ( LABEL_P ( insn ) ) { if ( ENABLE_WA_SPECULATIVE_SYNCS ) length = 4 ; } if ( NONDEBUG_INSN_P ( insn ) ) length += get_attr_length ( insn ) ; return length ; } </s>

Estimate the length of INSN conservatively .


<s> int log2constp ( unsigned HOST_WIDE_INT c ) { c &= 0xFFFFFFFF ; return c != 0 && ( c & ( c - 1 ) ) == 0 ; } </s>

Return nonzero iff C has exactly one bit set if it is interpreted as a 32 bit constant .


<s> static bool must_save_fp_p ( void ) { return df_regs_ever_live_p ( REG_FP ) ; } </s>

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


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

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


<s> static bool must_save_rets_p ( void ) { return df_regs_ever_live_p ( REG_RETS ) ; } </s>

Determine if we are going to save the RETS register .


<s> static void note_np_check_stores ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data ATTRIBUTE_UNUSED ) { if ( REG_P ( x ) && ( REGNO ( x ) == REG_CC || ( int ) REGNO ( x ) == np_check_regno ) ) np_check_regno = - 1 ; } </s>

Subroutine of workaround_speculation , called through note_stores .


<s> static int n_dregs_to_save ( bool is_inthandler , bool consecutive ) { int count = 0 ; unsigned i ; for ( i = REG_R7 + 1 ; i -- != REG_R0 ; ) { if ( must_save_p ( is_inthandler , i ) ) count ++ ; else if ( consecutive ) return count ; } return count ; } </s>

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


<s> static int n_pregs_to_save ( bool is_inthandler , bool consecutive ) { int count = 0 ; unsigned i ; for ( i = REG_P5 + 1 ; i -- != REG_P0 ; ) if ( must_save_p ( is_inthandler , i ) ) count ++ ; else if ( consecutive ) return count ; return count ; } </s>

Like n_dregs_to_save , but compute number of PREGS to save .


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

Return the number of registers pushed during the prologue .


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

Output to FILE the start of the assembler file .


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

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


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

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


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

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


<s> static void reorder_var_tracking_notes ( void ) { basic_block bb ; FOR_EACH_BB_FN ( bb , cfun ) { rtx_insn * insn , * next ; rtx_insn * queue = NULL ; bool in_bundle = false ; for ( insn = BB_HEAD ( bb ) ; insn != BB_END ( bb ) ; insn = next ) { next = NEXT_INSN ( insn ) ; if ( INSN_P ( insn ) ) { if ( GET_MODE ( insn ) == QImode ) { while ( queue ) { rtx_insn * next_queue = PREV_INSN ( queue ) ; SET_PREV_INSN ( NEXT_INSN ( insn ) ) = queue ; SET_NEXT_INSN ( queue ) = NEXT_INSN ( insn ) ; SET_NEXT_INSN ( insn ) = queue ; SET_PREV_INSN ( queue ) = insn ; queue = next_queue ; } in_bundle = false ; } else if ( GET_MODE ( insn ) == SImode ) in_bundle = true ; } else if ( NOTE_P ( insn ) && NOTE_KIND ( insn ) == NOTE_INSN_VAR_LOCATION ) { if ( in_bundle ) { rtx_insn * prev = PREV_INSN ( insn ) ; SET_PREV_INSN ( next ) = prev ; SET_NEXT_INSN ( prev ) = next ; SET_PREV_INSN ( insn ) = queue ; queue = insn ; } } } } } </s>

Ensure that no var tracking notes are emitted in the middle of a three-instruction bundle .


<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 void setup_incoming_varargs ( cumulative_args_t cum , const function_arg_info & , int * pretend_size , int no_rtl ) { rtx mem ; int i ; if ( no_rtl ) return ; for ( i = get_cumulative_args ( cum ) -> words + 1 ; i < max_arg_registers ; i ++ ) { mem = gen_rtx_MEM ( Pmode , plus_constant ( Pmode , arg_pointer_rtx , ( i * UNITS_PER_WORD ) ) ) ; emit_move_insn ( mem , gen_rtx_REG ( Pmode , i ) ) ; } * pretend_size = 0 ; } </s>

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


<s> static int shiftr_zero ( HOST_WIDE_INT * v ) { unsigned HOST_WIDE_INT tmp = * v ; unsigned HOST_WIDE_INT sgn ; int n = 0 ; if ( tmp == 0 ) return 0 ; sgn = tmp & ( ( unsigned HOST_WIDE_INT ) 1 << ( HOST_BITS_PER_WIDE_INT - 1 ) ) ; while ( ( tmp & 0x1 ) == 0 && n <= 32 ) { tmp = ( tmp >> 1 ) | sgn ; n ++ ; } * v = tmp ; return n ; } </s>

Returns the number of consecutive least significant zeros in the binary representation of * V. We modify * V to contain the original value arithmetically shifted right by the number of zeroes .


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

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


<s> void split_di ( rtx operands [ ] , int num , rtx lo_half [ ] , rtx hi_half [ ] ) { while ( num -- ) { rtx op = operands [ num ] ; if ( GET_CODE ( op ) == MEM ) { lo_half [ num ] = adjust_address ( op , SImode , 0 ) ; hi_half [ num ] = adjust_address ( op , SImode , 4 ) ; } else { lo_half [ num ] = simplify_gen_subreg ( SImode , op , GET_MODE ( op ) == VOIDmode ? DImode : GET_MODE ( op ) , 0 ) ; hi_half [ num ] = simplify_gen_subreg ( SImode , op , GET_MODE ( op ) == VOIDmode ? DImode : GET_MODE ( op ) , 4 ) ; } } } </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> int symbolic_reference_mentioned_p ( rtx op ) { const char * fmt ; int i ; if ( GET_CODE ( op ) == SYMBOL_REF || GET_CODE ( op ) == LABEL_REF ) return 1 ; fmt = GET_RTX_FORMAT ( GET_CODE ( op ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( op ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( op , i ) - 1 ; j >= 0 ; j -- ) if ( symbolic_reference_mentioned_p ( XVECEXP ( op , i , j ) ) ) return 1 ; } else if ( fmt [ i ] == 'e' && symbolic_reference_mentioned_p ( XEXP ( op , i ) ) ) return 1 ; } return 0 ; } </s>

Return true if OP contains a symbol reference


<s> static bool trapping_loads_p ( rtx_insn * insn , int np_reg , bool after_np_branch ) { rtx mem = SET_SRC ( single_set ( insn ) ) ; if ( ! after_np_branch ) np_reg = - 1 ; return ( ( np_reg == - 1 || ! harmless_null_pointer_p ( mem , np_reg ) ) && may_trap_p ( mem ) ) ; } </s>

Return nonzero if INSN contains any loads that may trap .


<s> static enum attr_type type_for_anomaly ( rtx_insn * insn ) { rtx pat = PATTERN ( insn ) ; if ( rtx_sequence * seq = dyn_cast < rtx_sequence * > ( pat ) ) { enum attr_type t ; t = get_attr_type ( seq -> insn ( 1 ) ) ; if ( t == TYPE_MCLD ) return t ; t = get_attr_type ( seq -> insn ( 2 ) ) ; if ( t == TYPE_MCLD ) return t ; return TYPE_MCST ; } else return get_attr_type ( insn ) ; } </s>

Return an insn type for INSN that can be used by the caller for anomaly workarounds . This differs from plain get_attr_type in that it handles SEQUENCEs .


<s> static void workaround_rts_anomaly ( void ) { rtx_insn * insn , * first_insn = NULL ; int cycles = 4 ; if ( ! ENABLE_WA_RETS ) return ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx pat ; if ( BARRIER_P ( insn ) ) return ; if ( NOTE_P ( insn ) || LABEL_P ( insn ) ) continue ; if ( JUMP_TABLE_DATA_P ( insn ) ) continue ; if ( first_insn == NULL_RTX ) first_insn = insn ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == USE || GET_CODE ( pat ) == CLOBBER || GET_CODE ( pat ) == ASM_INPUT || asm_noperands ( pat ) >= 0 ) continue ; if ( CALL_P ( insn ) ) return ; if ( JUMP_P ( insn ) ) { if ( recog_memoized ( insn ) == CODE_FOR_return_internal ) break ; if ( ! any_condjump_p ( insn ) ) return ; if ( cycles <= 1 ) return ; cycles -- ; } else if ( INSN_P ( insn ) ) { rtx pat = PATTERN ( insn ) ; int this_cycles = 1 ; if ( GET_CODE ( pat ) == PARALLEL ) { if ( analyze_push_multiple_operation ( pat ) || analyze_pop_multiple_operation ( pat ) ) this_cycles = n_regs_to_save ; } else { int icode = recog_memoized ( insn ) ; if ( icode == CODE_FOR_link ) this_cycles = 4 ; else if ( icode == CODE_FOR_unlink ) this_cycles = 3 ; else if ( icode == CODE_FOR_mulsi3 ) this_cycles = 5 ; } if ( this_cycles >= cycles ) return ; cycles -= this_cycles ; } } while ( cycles > 0 ) { emit_insn_before ( gen_nop ( ) , first_insn ) ; cycles -- ; } } </s>

On some silicon revisions , functions shorter than a certain number of cycles can cause unpredictable behaviour . Work around this by adding NOPs as needed .