<s> static tree arc_builtin_decl ( unsigned id , bool initialize_p ATTRIBUTE_UNUSED ) { if ( id < ARC_BUILTIN_COUNT ) return arc_bdesc [ id ] . fndecl ; return error_mark_node ; } </s>


<s> static rtx arc_call_tls_get_addr ( rtx ti ) { rtx arg = gen_rtx_REG ( Pmode , R0_REG ) ; rtx ret = gen_rtx_REG ( Pmode , R0_REG ) ; rtx fn ; rtx_insn * insn ; if ( ! arc_tls_symbol ) arc_tls_symbol = init_one_libfunc ( "__tls_get_addr" ) ; emit_move_insn ( arg , ti ) ; fn = gen_rtx_MEM ( SImode , arc_tls_symbol ) ; insn = emit_call_insn ( gen_call_value ( ret , fn , const0_rtx ) ) ; RTL_CONST_CALL_P ( insn ) = 1 ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , ret ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , arg ) ; return ret ; } </s>

Emit a call to __tls_get_addr . TI is the argument to this function . RET is an RTX for the return value location . The entire insn sequence is returned .


<s> static bool arc_cannot_force_const_mem ( machine_mode mode , rtx x ) { return ! arc_legitimate_constant_p ( mode , x ) ; } </s>

Determine if it 's legal to put X into the constant pool .


<s> static bool arc_cannot_substitute_mem_equiv_p ( rtx ) { return true ; } </s>

Return true if SUBST ca n't safely replace its equivalent during RA .


<s> static bool arc_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( ( to == HARD_FRAME_POINTER_REGNUM ) || ( to == STACK_POINTER_REGNUM ) ) ; } </s>

Given FROM and TO register numbers , say whether this elimination is allowed . Frame pointer elimination is automatically handled . All eliminations are permissible . If we need a frame pointer , we must eliminate ARG_POINTER_REGNUM into FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM .


<s> static bool arc_can_follow_jump ( const rtx_insn * follower , const rtx_insn * followee ) { union { const rtx_insn * c ; rtx_insn * r ; } u ; u . c = follower ; if ( CROSSING_JUMP_P ( followee ) ) switch ( get_attr_type ( u . r ) ) { case TYPE_BRANCH : if ( get_attr_length ( u . r ) != 2 ) break ; case TYPE_BRCC : case TYPE_BRCC_NO_DELAY_SLOT : return false ; default : return true ; } return true ; } </s>

Without this , gcc.dg/tree-prof/bb-reorg.c fails to assemble when compiling with -O2 -freorder-blocks-and-partition -fprofile-use -D_PROFILE_USE ; delay branch scheduling then follows a crossing jump to redirect two breqs .


<s> static bool arc_can_use_doloop_p ( const widest_int & , const widest_int & iterations_max , unsigned int loop_depth , bool entered_at_top ) { if ( loop_depth > 1 || ! entered_at_top ) return false ; if ( arc_lpcwidth != 32 && ( wi :: gtu_p ( iterations_max , ( ( 1 << arc_lpcwidth ) - 1 ) ) || wi :: eq_p ( iterations_max , 0 ) ) ) return false ; return true ; } </s>


<s> bool arc_can_use_return_insn ( void ) { return ( reload_completed && cfun -> machine -> frame_info . total_size == 0 && ! ARC_INTERRUPT_P ( arc_compute_function_type ( cfun ) ) ) ; } </s>

Return nonzero if this function is known to have a null epilogue . This allows the optimizer to omit jumps to jumps if no stack was created .


<s> static void arc_ccfsm_at_label ( const char * prefix , int num , struct arc_ccfsm * state ) { if ( state -> state == 3 && state -> target_label == num && ! strcmp ( prefix , "L" ) ) { state -> state = 0 ; state -> target_insn = NULL ; } } </s>

Record that we are currently outputting label NUM with prefix PREFIX . It it 's the label we 're looking for , reset the ccfsm machinery . Called from ( * targetm.asm_out.internal_label ) .


<s> bool arc_ccfsm_branch_deleted_p ( void ) { return ARC_CCFSM_BRANCH_DELETED_P ( & arc_ccfsm_current ) ; } </s>

See if the current insn , which is a conditional branch , is to be deleted .


<s> bool arc_ccfsm_cond_exec_p ( void ) { return ( cfun -> machine -> prescan_initialized && ARC_CCFSM_COND_EXEC_P ( & arc_ccfsm_current ) ) ; } </s>

During insn output , indicate if the current insn is predicated .


<s> static void arc_ccfsm_post_advance ( rtx_insn * insn , struct arc_ccfsm * state ) { enum attr_type type ; if ( LABEL_P ( insn ) ) arc_ccfsm_at_label ( "L" , CODE_LABEL_NUMBER ( insn ) , state ) ; else if ( JUMP_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) != ADDR_VEC && GET_CODE ( PATTERN ( insn ) ) != ADDR_DIFF_VEC && ( ( type = get_attr_type ( insn ) ) == TYPE_BRANCH || ( ( type == TYPE_UNCOND_BRANCH || type == TYPE_RETURN ) && ARC_CCFSM_BRANCH_DELETED_P ( state ) ) ) ) { if ( ARC_CCFSM_BRANCH_DELETED_P ( state ) ) ARC_CCFSM_RECORD_BRANCH_DELETED ( state ) ; else { rtx src = SET_SRC ( PATTERN ( insn ) ) ; arc_ccfsm_record_condition ( XEXP ( src , 0 ) , XEXP ( src , 1 ) == pc_rtx , insn , state ) ; } } else if ( arc_ccfsm_current . state == 5 ) arc_ccfsm_current . state = 0 ; } </s>

Update * STATE as we would when we emit INSN .


<s> void arc_ccfsm_record_branch_deleted ( void ) { ARC_CCFSM_RECORD_BRANCH_DELETED ( & arc_ccfsm_current ) ; } </s>

Record a branch is n't output because subsequent insns can be conditionalized .


<s> void arc_ccfsm_record_condition ( rtx cond , bool reverse , rtx_insn * jump , struct arc_ccfsm * state ) { rtx_insn * seq_insn = NEXT_INSN ( PREV_INSN ( jump ) ) ; if ( ! state ) state = & arc_ccfsm_current ; gcc_assert ( state -> state == 0 ) ; if ( seq_insn != jump ) { rtx insn = XVECEXP ( PATTERN ( seq_insn ) , 0 , 1 ) ; if ( ! as_a < rtx_insn * > ( insn ) -> deleted ( ) && INSN_ANNULLED_BRANCH_P ( jump ) && ( TARGET_AT_DBR_CONDEXEC || INSN_FROM_TARGET_P ( insn ) ) ) { state -> cond = cond ; state -> cc = get_arc_condition_code ( cond ) ; if ( ! reverse ) arc_ccfsm_current . cc = ARC_INVERSE_CONDITION_CODE ( state -> cc ) ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == COND_EXEC ) gcc_assert ( ( INSN_FROM_TARGET_P ( insn ) ? ARC_INVERSE_CONDITION_CODE ( state -> cc ) : state -> cc ) == get_arc_condition_code ( XEXP ( pat , 0 ) ) ) ; else state -> state = 5 ; } } } </s>

We are considering a conditional branch with the condition COND . Check if we want to conditionalize a delay slot insn , and if so modify the ccfsm state accordingly . REVERSE says branch will branch when the condition is false .


<s> bool arc_check_ior_const ( HOST_WIDE_INT ival ) { unsigned int mask = ( unsigned int ) ( ival & 0xffffffff ) ; if ( UNSIGNED_INT6 ( ival ) || IS_POWEROF2_P ( mask ) ) return false ; if ( __builtin_popcount ( mask ) <= 3 ) return true ; if ( __builtin_popcount ( mask & ~ 0x3f ) <= 1 ) return true ; return false ; } </s>


<s> int arc_check_millicode ( rtx op , int offset , int load_p ) { int len = XVECLEN ( op , 0 ) - offset ; int i ; if ( load_p == 2 ) { if ( len < 2 || len > 13 ) return 0 ; load_p = 1 ; } else { rtx elt = XVECEXP ( op , 0 , -- len ) ; if ( GET_CODE ( elt ) != CLOBBER || ! REG_P ( XEXP ( elt , 0 ) ) || REGNO ( XEXP ( elt , 0 ) ) != RETURN_ADDR_REGNUM || len < 3 || len > 13 ) return 0 ; } for ( i = 1 ; i < len ; i ++ ) { rtx elt = XVECEXP ( op , 0 , i + offset ) ; rtx reg , mem , addr ; if ( GET_CODE ( elt ) != SET ) return 0 ; mem = XEXP ( elt , load_p ) ; reg = XEXP ( elt , 1 - load_p ) ; if ( ! REG_P ( reg ) || REGNO ( reg ) != 13U + i || ! MEM_P ( mem ) ) return 0 ; addr = XEXP ( mem , 0 ) ; if ( GET_CODE ( addr ) != PLUS || ! rtx_equal_p ( stack_pointer_rtx , XEXP ( addr , 0 ) ) || ! CONST_INT_P ( XEXP ( addr , 1 ) ) || INTVAL ( XEXP ( addr , 1 ) ) != i * 4 ) return 0 ; } return 1 ; } </s>

Check if OP is a proper parallel of a millicode call pattern . OFFSET indicates a number of elements to ignore - that allows to have a sibcall pattern that starts with ( return ) . LOAD_P is zero for store multiple ( for prologues ) , and one for load multiples ( for epilogues ) , and two for load multiples where no final clobber of blink is required . We also skip the first load / store element since this is supposed to be checked in the instruction pattern .


<s> bool arc_check_mov_const ( HOST_WIDE_INT ival ) { ival = ival & 0xffffffff ; if ( SIGNED_INT12 ( ival ) ) return false ; if ( ( ival & ~ 0x8000001f ) == 0 ) return true ; if ( IS_POWEROF2_P ( ival + 1 ) ) return true ; if ( ! TARGET_BARREL_SHIFTER ) return false ; if ( ( ( ival >> ( __builtin_ffs ( ival ) - 1 ) ) & 0xffffff00 ) == 0 ) return true ; if ( ( ival & ~ 0x3f00 ) == 0 ) return true ; if ( ( ival & ~ 0x3f0000 ) == 0 ) return true ; if ( ( ival & ~ 0x3f000000 ) == 0 ) return true ; return false ; } </s>


<s> bool arc_check_multi ( rtx op , bool push_p ) { HOST_WIDE_INT len = XVECLEN ( op , 0 ) ; unsigned int regno , i , start ; unsigned int memp = push_p ? 0 : 1 ; rtx elt ; if ( len <= 1 ) return false ; start = 1 ; elt = XVECEXP ( op , 0 , 0 ) ; if ( ! push_p && GET_CODE ( elt ) == RETURN ) start = 2 ; for ( i = start , regno = ENTER_LEAVE_START_REG ; i < len ; i ++ , regno ++ ) { rtx elt = XVECEXP ( op , 0 , i ) ; rtx reg , mem , addr ; if ( GET_CODE ( elt ) != SET ) return false ; mem = XEXP ( elt , memp ) ; reg = XEXP ( elt , 1 - memp ) ; if ( ! REG_P ( reg ) || ! MEM_P ( mem ) ) return false ; if ( REGNO ( reg ) == RETURN_ADDR_REGNUM && i == start ) regno = 12 ; else if ( REGNO ( reg ) == HARD_FRAME_POINTER_REGNUM ) ++ i ; else if ( REGNO ( reg ) != regno ) return false ; addr = XEXP ( mem , 0 ) ; if ( GET_CODE ( addr ) == PLUS ) { if ( ! rtx_equal_p ( stack_pointer_rtx , XEXP ( addr , 0 ) ) || ! CONST_INT_P ( XEXP ( addr , 1 ) ) ) return false ; } else { if ( ! rtx_equal_p ( stack_pointer_rtx , addr ) ) return false ; } } return true ; } </s>

Helper for { push/pop } _multi_operand : check if rtx OP is a suitable construct to match either enter or leave instruction . Which one which is selected by PUSH_P argument .


<s> void arc_clear_unalign ( void ) { if ( cfun ) cfun -> machine -> unalign = 0 ; } </s>

Accessor functions for cfun- > machine- > unalign .


<s> static unsigned int arc_compute_frame_size ( void ) { int regno ; unsigned int total_size , var_size , args_size , pretend_size , extra_size ; unsigned int reg_size ; uint64_t gmask ; struct arc_frame_info * frame_info ; int size ; unsigned int extra_plus_reg_size ; unsigned int extra_plus_reg_size_aligned ; unsigned int fn_type = arc_compute_function_type ( cfun ) ; if ( cfun -> machine -> frame_info . initialized ) return cfun -> machine -> frame_info . total_size ; frame_info = & cfun -> machine -> frame_info ; size = ARC_STACK_ALIGN ( get_frame_size ( ) ) ; var_size = size ; args_size = crtl -> outgoing_args_size ; reg_size = 0 ; gmask = 0 ; for ( regno = 0 ; regno <= ( GMASK_LEN - 4 ) ; regno ++ ) { if ( arc_must_save_register ( regno , cfun , false ) ) { reg_size += UNITS_PER_WORD ; gmask |= 1ULL << regno ; } } if ( crtl -> calls_eh_return ) for ( regno = 0 ; EH_RETURN_DATA_REGNO ( regno ) != INVALID_REGNUM ; regno ++ ) { reg_size += UNITS_PER_WORD ; gmask |= 1ULL << regno ; } frame_info -> save_return_addr = ( ! crtl -> is_leaf || df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) || crtl -> calls_eh_return ) ; if ( TARGET_MILLICODE_THUNK_SET && ! ARC_INTERRUPT_P ( fn_type ) && ! crtl -> calls_eh_return ) { if ( arc_compute_millicode_save_restore_regs ( gmask , frame_info ) ) frame_info -> save_return_addr = true ; } if ( arc_lpcwidth != 0 && arc_must_save_register ( LP_COUNT , cfun , true ) ) reg_size += UNITS_PER_WORD * 3 ; if ( arc_must_save_register ( TARGET_BIG_ENDIAN ? R41_REG : R40_REG , cfun , TARGET_DPFP ) ) reg_size += UNITS_PER_WORD * 2 ; if ( arc_must_save_register ( TARGET_BIG_ENDIAN ? R43_REG : R42_REG , cfun , TARGET_DPFP ) ) reg_size += UNITS_PER_WORD * 2 ; if ( arc_must_save_register ( R58_REG , cfun , true ) ) reg_size += UNITS_PER_WORD * 2 ; extra_size = 0 ; if ( arc_must_save_return_addr ( cfun ) ) extra_size = 4 ; if ( arc_frame_pointer_needed ( ) && ! ARC_AUTOFP_IRQ_P ( fn_type ) ) extra_size += 4 ; pretend_size = crtl -> args . pretend_args_size ; extra_plus_reg_size = extra_size + reg_size ; extra_plus_reg_size_aligned = ARC_STACK_ALIGN ( extra_plus_reg_size ) ; reg_size = extra_plus_reg_size_aligned - extra_size ; total_size = var_size + args_size + extra_size + pretend_size + reg_size ; gcc_assert ( total_size == ARC_STACK_ALIGN ( total_size ) ) ; frame_info -> total_size = total_size ; frame_info -> extra_size = extra_size ; frame_info -> pretend_size = pretend_size ; frame_info -> var_size = var_size ; frame_info -> args_size = args_size ; frame_info -> reg_size = reg_size ; frame_info -> gmask = gmask ; frame_info -> initialized = reload_completed ; return total_size ; } </s>

Return the bytes needed to compute the frame pointer from the current stack pointer . SIZE is the size needed for local variables .


<s> static unsigned int arc_compute_function_type ( struct function * fun ) { tree attr , decl = fun -> decl ; unsigned int fn_type = fun -> machine -> fn_type ; if ( fn_type != ARC_FUNCTION_UNKNOWN ) return fn_type ; if ( lookup_attribute ( "naked" , DECL_ATTRIBUTES ( decl ) ) != NULL_TREE ) fn_type |= ARC_FUNCTION_NAKED ; else fn_type |= ARC_FUNCTION_NORMAL ; attr = lookup_attribute ( "interrupt" , DECL_ATTRIBUTES ( decl ) ) ; if ( attr != NULL_TREE ) { tree value , args = TREE_VALUE ( attr ) ; gcc_assert ( list_length ( args ) == 1 ) ; value = TREE_VALUE ( args ) ; gcc_assert ( TREE_CODE ( value ) == STRING_CST ) ; if ( ! strcmp ( TREE_STRING_POINTER ( value ) , "ilink1" ) || ! strcmp ( TREE_STRING_POINTER ( value ) , "ilink" ) ) fn_type |= ARC_FUNCTION_ILINK1 ; else if ( ! strcmp ( TREE_STRING_POINTER ( value ) , "ilink2" ) ) fn_type |= ARC_FUNCTION_ILINK2 ; else if ( ! strcmp ( TREE_STRING_POINTER ( value ) , "firq" ) ) fn_type |= ARC_FUNCTION_FIRQ ; else gcc_unreachable ( ) ; } return fun -> machine -> fn_type = fn_type ; } </s>

Type of function DECL . The result is cached . To reset the cache at the end of a function , call with DECL = NULL_TREE .


<s> static int arc_compute_millicode_save_restore_regs ( uint64_t gmask , struct arc_frame_info * frame ) { int regno ; int start_reg = 13 , end_reg = 25 ; for ( regno = start_reg ; regno <= end_reg && ( gmask & ( 1ULL << regno ) ) ; ) regno ++ ; end_reg = regno - 1 ; if ( regno - start_reg >= 3 - ( crtl -> is_leaf == 0 ) ) { frame -> millicode_start_reg = 13 ; frame -> millicode_end_reg = regno - 1 ; return 1 ; } return 0 ; } </s>

Return non-zero if there are registers to be saved or loaded using millicode thunks . We can only use consecutive sequences starting with r13 , and not going beyond r25 . GMASK is a bitmask of registers to save . This function sets FRAME- > millicod_start_reg .. FRAME- > millicode_end_reg to the range of registers to be saved / restored with a millicode call .


Return zero if TYPE1 and TYPE are incompatible , one if they are compatible , and two if they are nearly compatible ( which causes a warning to be generated ) .


<s> bool arc_double_limm_p ( rtx value ) { HOST_WIDE_INT low , high ; gcc_assert ( GET_CODE ( value ) == CONST_DOUBLE ) ; if ( TARGET_DPFP ) return true ; low = CONST_DOUBLE_LOW ( value ) ; high = CONST_DOUBLE_HIGH ( value ) ; if ( low & 0x80000000 ) { return ( ( ( unsigned HOST_WIDE_INT ) low <= 0xffffffff && high == 0 ) || ( ( ( low & - ( unsigned HOST_WIDE_INT ) 0x80000000 ) == - ( unsigned HOST_WIDE_INT ) 0x80000000 ) && high == - 1 ) ) ; } else { return ( unsigned HOST_WIDE_INT ) low <= 0x7fffffff && high == 0 ; } } </s>

Return 1 if VALUE , a const_double , will fit in a limm ( 4 byte number ) . We assume the value can be either signed or unsigned .


<s> static void arc_dwarf_emit_irq_save_regs ( void ) { rtx tmp , par , insn , reg ; int i , offset , j ; par = gen_rtx_SEQUENCE ( VOIDmode , rtvec_alloc ( irq_ctrl_saved . irq_save_last_reg + 1 + irq_ctrl_saved . irq_save_blink + irq_ctrl_saved . irq_save_lpcount + 1 ) ) ; j = 0 ; offset = UNITS_PER_WORD * ( irq_ctrl_saved . irq_save_last_reg + 1 + irq_ctrl_saved . irq_save_blink + irq_ctrl_saved . irq_save_lpcount ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , - 1 * offset ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , tmp ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j ++ ) = tmp ; offset -= UNITS_PER_WORD ; if ( irq_ctrl_saved . irq_save_lpcount ) { reg = gen_rtx_REG ( SImode , 60 ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , offset ) ; tmp = gen_frame_mem ( SImode , tmp ) ; tmp = gen_rtx_SET ( tmp , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j ++ ) = tmp ; offset -= UNITS_PER_WORD ; } if ( irq_ctrl_saved . irq_save_blink ) { reg = gen_rtx_REG ( SImode , 31 ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , offset ) ; tmp = gen_frame_mem ( SImode , tmp ) ; tmp = gen_rtx_SET ( tmp , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j ++ ) = tmp ; offset -= UNITS_PER_WORD ; } for ( i = irq_ctrl_saved . irq_save_last_reg ; i >= 0 ; i -- ) { reg = gen_rtx_REG ( SImode , i ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , offset ) ; tmp = gen_frame_mem ( SImode , tmp ) ; tmp = gen_rtx_SET ( tmp , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j ++ ) = tmp ; offset -= UNITS_PER_WORD ; } insn = emit_insn ( gen_stack_irq_dwarf ( ) ) ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , par ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Build dwarf information when the context is saved via AUX_IRQ_CTRL mechanism .


<s> static rtx arc_dwarf_register_span ( rtx rtl ) { machine_mode mode = GET_MODE ( rtl ) ; unsigned regno ; rtx p ; if ( GET_MODE_SIZE ( mode ) != 8 ) return NULL_RTX ; p = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( 2 ) ) ; regno = REGNO ( rtl ) ; XVECEXP ( p , 0 , 0 ) = gen_rtx_REG ( SImode , regno ) ; XVECEXP ( p , 0 , 1 ) = gen_rtx_REG ( SImode , regno + 1 ) ; return p ; } </s>

Return a parallel of registers to represent where to find the register pieces if required , otherwise NULL_RTX .


<s> void arc_eh_return_address_location ( rtx source ) { rtx mem ; int offset ; struct arc_frame_info * afi ; arc_compute_frame_size ( ) ; afi = & cfun -> machine -> frame_info ; gcc_assert ( crtl -> calls_eh_return ) ; gcc_assert ( afi -> save_return_addr ) ; gcc_assert ( afi -> extra_size >= 4 ) ; offset = afi -> reg_size + afi -> extra_size - 4 ; mem = gen_frame_mem ( Pmode , plus_constant ( Pmode , hard_frame_pointer_rtx , offset ) ) ; MEM_VOLATILE_P ( mem ) = true ; emit_move_insn ( mem , source ) ; } </s>

Return rtx for the location of the return address on the stack , suitable for use in __builtin_eh_return . The new return address will be written to this location in order to redirect the return to the exception handler .


<s> bool arc_eh_uses ( int regno ) { if ( regno == arc_tp_regno ) return true ; return false ; } </s>


<s> static void arc_encode_section_info ( tree decl , rtx rtl , int first ) { default_encode_section_info ( decl , rtl , first ) ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { rtx symbol = XEXP ( rtl , 0 ) ; int flags = SYMBOL_REF_FLAGS ( symbol ) ; tree attr = ( TREE_TYPE ( decl ) != error_mark_node ? TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) : NULL_TREE ) ; tree long_call_attr = lookup_attribute ( "long_call" , attr ) ; tree medium_call_attr = lookup_attribute ( "medium_call" , attr ) ; tree short_call_attr = lookup_attribute ( "short_call" , attr ) ; if ( long_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_LONG_CALL ; else if ( medium_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_MEDIUM_CALL ; else if ( short_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_SHORT_CALL ; SYMBOL_REF_FLAGS ( symbol ) = flags ; } else if ( TREE_CODE ( decl ) == VAR_DECL ) { rtx symbol = XEXP ( rtl , 0 ) ; tree attr = ( TREE_TYPE ( decl ) != error_mark_node ? DECL_ATTRIBUTES ( decl ) : NULL_TREE ) ; tree sec_attr = lookup_attribute ( "section" , attr ) ; if ( sec_attr ) { const char * sec_name = TREE_STRING_POINTER ( TREE_VALUE ( TREE_VALUE ( sec_attr ) ) ) ; if ( strcmp ( sec_name , ".cmem" ) == 0 || strcmp ( sec_name , ".cmem_shared" ) == 0 || strcmp ( sec_name , ".cmem_private" ) == 0 ) SYMBOL_REF_FLAGS ( symbol ) |= SYMBOL_FLAG_CMEM ; } } } </s>

Implement TARGET_ENCODE_SECTION_INFO hook .


<s> static bool arc_enter_leave_p ( uint64_t gmask ) { int regno ; unsigned int rmask = 0 ; if ( ! gmask ) return false ; for ( regno = ENTER_LEAVE_START_REG ; regno <= ENTER_LEAVE_END_REG && ( gmask & ( 1ULL << regno ) ) ; regno ++ ) rmask |= 1ULL << regno ; if ( rmask ^ gmask ) return false ; return true ; } </s>

Check if we have a continous range to be save/restored with the help of enter/leave instructions . A vaild register range starts from $ r13 and is up to ( including ) $ r26 .


<s> bool arc_epilogue_uses ( int regno ) { unsigned int fn_type ; fn_type = arc_compute_function_type ( cfun ) ; if ( regno == arc_tp_regno ) return true ; if ( regno == RETURN_ADDR_REGNUM ) return true ; if ( regno == arc_return_address_register ( fn_type ) ) return true ; if ( epilogue_completed && ARC_INTERRUPT_P ( fn_type ) ) { if ( df_regs_ever_live_p ( regno ) || call_used_or_fixed_reg_p ( regno ) ) return true ; } return false ; } </s>

Implement EPILOGUE__USES . Return true if REGNO should be added to the deemed uses of the epilogue . We use the return address arc_return_address_regs [ arc_compute_function_type ( cfun ) ] . But also , we have to make sure all the register restore instructions are known to be live in interrupt functions , plus the blink register if it is clobbered by the isr .


<s> void arc_expand_atomic_op ( enum rtx_code code , rtx mem , rtx val , rtx orig_before , rtx orig_after , rtx model_rtx ) { enum memmodel model = ( enum memmodel ) INTVAL ( model_rtx ) ; machine_mode mode = GET_MODE ( mem ) ; rtx label , x , cond ; rtx before = orig_before , after = orig_after ; gcc_assert ( mode == SImode ) ; arc_pre_atomic_barrier ( model ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; label = gen_rtx_LABEL_REF ( VOIDmode , label ) ; if ( before == NULL_RTX ) before = gen_reg_rtx ( mode ) ; if ( after == NULL_RTX ) after = gen_reg_rtx ( mode ) ; emit_insn ( gen_arc_load_exclusivesi ( before , mem ) ) ; switch ( code ) { case NOT : x = gen_rtx_AND ( mode , before , val ) ; emit_insn ( gen_rtx_SET ( after , x ) ) ; x = gen_rtx_NOT ( mode , after ) ; emit_insn ( gen_rtx_SET ( after , x ) ) ; break ; case MINUS : if ( CONST_INT_P ( val ) ) { val = GEN_INT ( - INTVAL ( val ) ) ; code = PLUS ; } default : x = gen_rtx_fmt_ee ( code , mode , before , val ) ; emit_insn ( gen_rtx_SET ( after , x ) ) ; break ; } emit_insn ( gen_arc_store_exclusivesi ( mem , after ) ) ; cond = gen_rtx_REG ( CC_Zmode , CC_REG ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , label , pc_rtx ) ; emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; arc_post_atomic_barrier ( model ) ; } </s>

Expand an atomic fetch-and-operate pattern . CODE is the binary operation to perform . MEM is the memory on which to operate . VAL is the second operand of the binary operator . BEFORE and AFTER are optional locations to return the value of MEM either before of after the operation . MODEL_RTX is a CONST_INT containing the memory model to use .


"%<__builtin_arc_aligned%> with non-constant alignment"

"invalid alignment value for %<__builtin_arc_aligned%>"

Helper to expand __builtin_arc_aligned ( void * val , int alignval ) .


<s> void arc_expand_compare_and_swap ( rtx operands [ ] ) { rtx bval , rval , mem , oldval , newval , is_weak , mod_s , mod_f , x ; machine_mode mode ; bval = operands [ 0 ] ; rval = operands [ 1 ] ; mem = operands [ 2 ] ; oldval = operands [ 3 ] ; newval = operands [ 4 ] ; is_weak = operands [ 5 ] ; mod_s = operands [ 6 ] ; mod_f = operands [ 7 ] ; mode = GET_MODE ( mem ) ; if ( reg_overlap_mentioned_p ( rval , oldval ) ) oldval = copy_to_reg ( oldval ) ; if ( mode == SImode ) { emit_insn ( gen_atomic_compare_and_swapsi_1 ( rval , mem , oldval , newval , is_weak , mod_s , mod_f ) ) ; x = gen_rtx_REG ( CC_Zmode , CC_REG ) ; x = gen_rtx_EQ ( SImode , x , const0_rtx ) ; emit_insn ( gen_rtx_SET ( bval , x ) ) ; } else { arc_expand_compare_and_swap_qh ( bval , rval , mem , oldval , newval , is_weak , mod_s , mod_f ) ; } } </s>

Helper function used by `` atomic_compare_and_swap '' expand pattern .


Set the cpu type and print out other fancy things , at the top of the file .


<s>
void
arc_final_prescan_insn
(
rtx_insn
*
insn
,
rtx
*
opvec
ATTRIBUTE_UNUSED
,
int
noperands
ATTRIBUTE_UNUSED
)
{
if
(
TARGET_DUMPISIZE
)
fprintf
(
asm_out_file
,
"\n; at %04x\n"
,
INSN_ADDRESSES
(
INSN_UID
(
insn
)
)
)
;
if
(
!
cfun
->
machine
->
prescan_initialized
)
{
memset
(
&
arc_ccfsm_current
,
0
,
sizeof
arc_ccfsm_current
)
;
cfun
->
machine
->
prescan_initialized
=
1
;
}
arc_ccfsm_advance
(
insn
,
&
arc_ccfsm_current
)
;
}
</s>

The state of the fsm controlling condition codes are : 0 : normal , do nothing special 1 : do n't output this insn 2 : do n't output this insn 3 : make insns conditional 4 : make insns conditional State transitions ( state- > state by whom , under what condition ) : 0 - > 1 final_prescan_insn , if insn is conditional branch 0 - > 2 final_prescan_insn , if the ` target ' is an unconditional branch 1 - > 3 branch patterns , after having not output the conditional branch 2 - > 4 branch patterns , after having not output the conditional branch 3 - > 0 ( * targetm.asm_out.internal_label ) , if the ` target ' label is reached ( the target label has CODE_LABEL_NUMBER equal to arc_ccfsm_target_label ) . 4 - > 0 final_prescan_insn , if ` target ' unconditional branch is reached If the jump clobbers the conditions then we use states 2 and 4 . A similar thing can be done with conditional return insns . We also handle separating branches from sets of the condition code . This is done here because knowledge of the ccfsm state is required , we may not be outputting the branch .


<s> static rtx arc_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int arg_num = * cum ; rtx ret ; const char * debstr ATTRIBUTE_UNUSED ; arg_num = ROUND_ADVANCE_CUM ( arg_num , arg . mode , arg . type ) ; if ( arg . end_marker_p ( ) ) { ret = const0_rtx ; debstr = "<0>" ; } else if ( GPR_REST_ARG_REGS ( arg_num ) > 0 ) { ret = gen_rtx_REG ( arg . mode , arg_num ) ; debstr = reg_names [ arg_num ] ; } else { ret = NULL_RTX ; debstr = "memory" ; } return ret ; } </s>

On the ARC the first MAX_ARC_PARM_REGS args are normally in registers and the rest are pushed .


<s> static void arc_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int bytes = arg . promoted_size_in_bytes ( ) ; int words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; int i ; if ( words ) * cum = ROUND_ADVANCE_CUM ( * cum , arg . mode , arg . type ) ; for ( i = 0 ; i < words ; i ++ ) * cum = ARC_NEXT_ARG_REG ( * cum ) ; } </s>

For the ARC : the cum set here is passed on to function_arg where we look at its value and say which reg to use . Strategy : advance the regnumber here till we run out of arg regs , then set * cum to last reg . In function_arg , since * cum > last arg reg we would return 0 and thus the arg will end up on the stack . For straddling args of course function_arg_partial_nregs will come into play .


<s> static bool arc_function_ok_for_sibcall ( tree decl , tree exp ATTRIBUTE_UNUSED ) { tree attrs = NULL_TREE ; if ( ARC_INTERRUPT_P ( arc_compute_function_type ( cfun ) ) ) return false ; if ( decl ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "jli_always" , attrs ) ) return false ; if ( lookup_attribute ( "jli_fixed" , attrs ) ) return false ; if ( lookup_attribute ( "secure_call" , attrs ) ) return false ; } return true ; } </s>

Return true if it is ok to make a tail-call to DECL .


<s> static rtx arc_function_value ( const_tree valtype , const_tree fn_decl_or_type ATTRIBUTE_UNUSED , bool outgoing ATTRIBUTE_UNUSED ) { machine_mode mode = TYPE_MODE ( valtype ) ; int unsignedp ATTRIBUTE_UNUSED ; unsignedp = TYPE_UNSIGNED ( valtype ) ; if ( INTEGRAL_TYPE_P ( valtype ) || TREE_CODE ( valtype ) == OFFSET_TYPE ) PROMOTE_MODE ( mode , unsignedp , valtype ) ; return gen_rtx_REG ( mode , 0 ) ; } </s>

Define how to find the value returned by a function . VALTYPE is the data type of the value ( as a tree ) . If the precise function being called is known , FN_DECL_OR_TYPE is its FUNCTION_DECL ; otherwise , FN_DECL_OR_TYPE is its type .


<s> static rtx arc_get_ccfsm_cond ( struct arc_ccfsm * statep , bool reverse ) { rtx cond = statep -> cond ; int raw_cc = get_arc_condition_code ( cond ) ; if ( reverse ) raw_cc = ARC_INVERSE_CONDITION_CODE ( raw_cc ) ; if ( statep -> cc == raw_cc ) return copy_rtx ( cond ) ; gcc_assert ( ARC_INVERSE_CONDITION_CODE ( raw_cc ) == statep -> cc ) ; machine_mode ccm = GET_MODE ( XEXP ( cond , 0 ) ) ; enum rtx_code code = reverse_condition ( GET_CODE ( cond ) ) ; if ( code == UNKNOWN || ccm == CC_FP_GTmode || ccm == CC_FP_GEmode ) code = reverse_condition_maybe_unordered ( GET_CODE ( cond ) ) ; return gen_rtx_fmt_ee ( code , GET_MODE ( cond ) , copy_rtx ( XEXP ( cond , 0 ) ) , copy_rtx ( XEXP ( cond , 1 ) ) ) ; } </s>

Return a copy of COND from * STATEP , inverted if that is indicated by the CC field of * STATEP .


"%qE attribute only applies to variables"

Handle aux attribute . The auxiliary registers are addressed using special instructions lr and sr . The attribute 'aux ' indicates if a variable refers to the aux-regs and what is the register number desired .


"argument of %qE attribute is not a string constant"

"argument of %qE attribute is not \"ilink1\" or \"ilink2\""

"argument of %qE attribute is not \"ilink\" or \"firq\""

Handle an `` interrupt '' attribute ; arguments as in struct attribute_spec.handler .


<s>
static
tree
arc_handle_uncached_attribute
(
tree
*
node
,
tree
name
,
tree
args
,
int
flags
ATTRIBUTE_UNUSED
,
bool
*
no_add_attrs
)
{
if
(
DECL_P
(
*
node
)
&&
TREE_CODE
(
*
node
)
!=
TYPE_DECL
)
{
error
(
"%qE attribute only applies to types"
,
name
)
;
*
no_add_attrs
=
true
;
}
else
if
(
args
)
{
warning
(
OPT_Wattributes
,
"argument of %qE attribute ignored"
,
name
)
;
}
return
NULL_TREE
;
}
</s>

arc
"%qE attribute only applies to types"
"argument of %qE attribute ignored"


<s> static bool arc_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { return ( arc_hard_regno_modes [ regno ] & arc_mode_class [ mode ] ) != 0 ; } </s>


<s> static unsigned int arc_hard_regno_nregs ( unsigned int regno , machine_mode mode ) { if ( GET_MODE_SIZE ( mode ) == 16 && regno >= ARC_FIRST_SIMD_VR_REG && regno <= ARC_LAST_SIMD_VR_REG ) return 1 ; return CEIL ( GET_MODE_SIZE ( mode ) , UNITS_PER_WORD ) ; } </s>


<s> int arc_hazard ( rtx_insn * pred , rtx_insn * succ ) { if ( ! pred || ! INSN_P ( pred ) || ! succ || ! INSN_P ( succ ) ) return 0 ; if ( TARGET_ARC600 ) return arc600_corereg_hazard ( pred , succ ) ; return 0 ; } </s>

For ARC600 : A write to a core reg greater or equal to 32 must not be immediately followed by a use . Anticipate the length requirement to insert a nop between PRED and SUCC to prevent a hazard .


"%<-mno-mpy%> supported only for ARC700 or ARCv2"

"%<-mno-dpfp-lrsr%> supported only with %<-mdpfp%>"

"FPX fast and compact options cannot be specified together"

"%<-mspfp_fast%> not available on ARC600 or ARC601"

Called by OVERRIDE_OPTIONS to initialize various things .


<s> static void arc_initialize_trampoline ( rtx tramp , tree fndecl , rtx cxt ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; emit_block_move ( tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; emit_move_insn ( adjust_address ( tramp , SImode , 8 ) , fnaddr ) ; emit_move_insn ( adjust_address ( tramp , SImode , 12 ) , cxt ) ; maybe_emit_call_builtin___clear_cache ( XEXP ( tramp , 0 ) , plus_constant ( Pmode , XEXP ( tramp , 0 ) , TRAMPOLINE_SIZE ) ) ; } </s>

With potentially multiple shared objects loaded , and multiple stacks present for multiple thereds where trampolines might reside , a simple range check will likely not suffice for the profiler to tell if a callee is a trampoline . We a speedier check by making the trampoline start at an address that is not 4-byte aligned . A trampoline looks like this : nop_s 0x78e0entry : ld_s r12 , [ pcl,12 ] 0xd403 ld r11 , [ pcl,12 ] 0x170c 700b j_s [ r12 ] 0x7c00 nop_s 0x78e0 The fastest trampoline to execute for trampolines within +-8KB of CTX would be : add2 r11 , pcl , s12 j [ limm ] 0x20200f80 limm and that would also be faster to write to the stack by computing the offset from CTX to TRAMP at compile time . However , it would really be better to get rid of the high cost of cache invalidation when generating trampolines , which requires that the code part of trampolines stays constant , and additionally either - making sure that no executable code but trampolines is on the stack , no icache entries linger for the area of the stack from when before the stack was allocated , and allocating trampolines in trampoline-only cache lines or - allocate trampolines fram a special pool of pre-allocated trampolines .


<s> int arc_initial_elimination_offset ( int from , int to ) { if ( ! cfun -> machine -> frame_info . initialized ) arc_compute_frame_size ( ) ; if ( from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM ) { return ( cfun -> machine -> frame_info . extra_size + cfun -> machine -> frame_info . reg_size ) ; } if ( from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) { return ( cfun -> machine -> frame_info . total_size - cfun -> machine -> frame_info . pretend_size ) ; } if ( ( from == FRAME_POINTER_REGNUM ) && ( to == STACK_POINTER_REGNUM ) ) { return ( cfun -> machine -> frame_info . total_size - ( cfun -> machine -> frame_info . pretend_size + cfun -> machine -> frame_info . extra_size + cfun -> machine -> frame_info . reg_size ) ) ; } if ( ( from == FRAME_POINTER_REGNUM ) && ( to == HARD_FRAME_POINTER_REGNUM ) ) return 0 ; gcc_unreachable ( ) ; } </s>

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


<s> void arc_init_expanders ( void ) { init_machine_status = arc_init_machine_status ; } </s>

Implements INIT_EXPANDERS . We just set up to call the above function .


<s> static struct machine_function * arc_init_machine_status ( void ) { struct machine_function * machine ; machine = ggc_cleared_alloc < machine_function > ( ) ; machine -> fn_type = ARC_FUNCTION_UNKNOWN ; return machine ; } </s>

The usual ; we set up our machine_function data .


<s> static void arc_init_reg_tables ( void ) { int i ; for ( i = 0 ; i < NUM_MACHINE_MODES ; i ++ ) { machine_mode m = ( machine_mode ) i ; switch ( GET_MODE_CLASS ( m ) ) { case MODE_INT : case MODE_PARTIAL_INT : case MODE_COMPLEX_INT : if ( GET_MODE_SIZE ( m ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) S_MODE ; else if ( GET_MODE_SIZE ( m ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) D_MODE ; else if ( GET_MODE_SIZE ( m ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) T_MODE ; else if ( GET_MODE_SIZE ( m ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) O_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_FLOAT : case MODE_COMPLEX_FLOAT : if ( GET_MODE_SIZE ( m ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) SF_MODE ; else if ( GET_MODE_SIZE ( m ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) DF_MODE ; else if ( GET_MODE_SIZE ( m ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) TF_MODE ; else if ( GET_MODE_SIZE ( m ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) OF_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_VECTOR_INT : if ( GET_MODE_SIZE ( m ) == 4 ) arc_mode_class [ i ] = ( 1 << ( int ) S_MODE ) ; else if ( GET_MODE_SIZE ( m ) == 8 ) arc_mode_class [ i ] = ( 1 << ( int ) D_MODE ) ; else arc_mode_class [ i ] = ( 1 << ( int ) V_MODE ) ; break ; case MODE_CC : default : if ( i == ( int ) CCmode || i == ( int ) CC_ZNmode || i == ( int ) CC_Zmode || i == ( int ) CC_Cmode || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode || i == CC_FPUmode || i == CC_FPUEmode || i == CC_FPU_UNEQmode ) arc_mode_class [ i ] = 1 << ( int ) C_MODE ; else arc_mode_class [ i ] = 0 ; break ; } } } </s>


<s> static int arc_insn_cost ( rtx_insn * insn , bool speed ) { int cost ; if ( recog_memoized ( insn ) < 0 ) return 0 ; if ( ! speed ) return get_attr_length ( insn ) ; cost = get_attr_cost ( insn ) ; if ( cost > 0 ) return cost ; enum attr_type type = get_attr_type ( insn ) ; switch ( type ) { case TYPE_LOAD : case TYPE_STORE : cost = COSTS_N_INSNS ( 2 ) ; break ; default : cost = COSTS_N_INSNS ( 1 ) ; break ; } return cost ; } </s>

Helper for INSN_COST . Per Segher Boessenkool : rtx_costs computes the cost for any rtx ( an insn , a set , a set source , any random piece of one ) . set_src_cost , set_rtx_cost , etc . are helper functions that use that . Those functions do not work for parallels . Also , costs are not additive like this simplified model assumes . Also , more complex backends tend to miss many cases in their rtx_costs function . Many passes that want costs want to know the cost of a full insn . Like combine . That 's why I created insn_cost : it solves all of the above problems .


<s> static void arc_internal_label ( FILE * stream , const char * prefix , unsigned long labelno ) { if ( cfun ) arc_ccfsm_at_label ( prefix , labelno , & arc_ccfsm_current ) ; default_internal_label ( stream , prefix , labelno ) ; } </s>

This is how to output a definition of an internal numbered label where PREFIX is the class of label and NUM is the number within the class .


<s>
static
const
char
*
arc_invalid_within_doloop
(
const
rtx_insn
*
insn
)
{
if
(
CALL_P
(
insn
)
)
return
"Function call in the loop."
;
return
;
}
</s>

NULL if INSN insn is valid within a low-overhead loop . Otherwise return why doloop can not be applied .


<s> static bool arc_in_small_data_p ( const_tree decl ) { HOST_WIDE_INT size ; tree attr ; if ( TREE_CODE ( decl ) != VAR_DECL ) return false ; if ( TARGET_NO_SDATA_SET ) return false ; if ( DECL_WEAK ( decl ) ) return false ; if ( TREE_READONLY ( decl ) ) return false ; if ( ! TARGET_VOLATILE_CACHE_SET && TREE_THIS_VOLATILE ( decl ) ) return false ; attr = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "uncached" , attr ) ) return false ; attr = DECL_ATTRIBUTES ( decl ) ; if ( lookup_attribute ( "aux" , attr ) ) return false ; if ( DECL_SECTION_NAME ( decl ) != 0 ) { const char * name = DECL_SECTION_NAME ( decl ) ; if ( strcmp ( name , ".sdata" ) == 0 || strcmp ( name , ".sbss" ) == 0 ) return true ; } else if ( TREE_PUBLIC ( decl ) ) { size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; return ( size > 0 && size <= g_switch_value ) ; } return false ; } </s>

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


<s> static bool arc_is_aux_reg_p ( rtx pat ) { tree attrs = NULL_TREE ; tree addr ; if ( ! MEM_P ( pat ) ) return false ; addr = MEM_EXPR ( pat ) ; if ( ! addr ) return false ; if ( TREE_CODE ( addr ) == VAR_DECL ) attrs = DECL_ATTRIBUTES ( addr ) ; else if ( TREE_CODE ( addr ) == MEM_REF ) attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 0 ) ) ) ; else return false ; if ( lookup_attribute ( "aux" , attrs ) ) return true ; return false ; } </s>

Return TRUE if PAT is accessing an aux-reg .


<s> bool arc_is_jli_call_p ( rtx pat ) { tree attrs ; tree decl = SYMBOL_REF_DECL ( pat ) ; if ( ! decl || ! SYMBOL_REF_FUNCTION_P ( pat ) || ! TREE_PUBLIC ( decl ) ) return false ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "jli_always" , attrs ) ) return true ; if ( lookup_attribute ( "jli_fixed" , attrs ) ) return true ; return TARGET_JLI_ALWAYS ; } </s>

Return nonzero if a jli call should be generated for a call from the current function to DECL .


<s> bool arc_is_longcall_p ( rtx sym_ref ) { if ( GET_CODE ( sym_ref ) != SYMBOL_REF ) return false ; return ( SYMBOL_REF_LONG_CALL_P ( sym_ref ) || ( TARGET_LONG_CALLS_SET && ! SYMBOL_REF_SHORT_CALL_P ( sym_ref ) && ! SYMBOL_REF_MEDIUM_CALL_P ( sym_ref ) ) ) ; } </s>

Return true if a 32 bit `` long_call '' should be generated for this calling SYM_REF . We generate a long_call if the function : a. has an __attribute__ ( ( long call ) ) or b. the -mlong-calls command line switch has been specified However we do not generate a long call if the function has an __attribute__ ( ( short_call ) ) or __attribute__ ( ( medium_call ) ) This function will be called by C fragments contained in the machine description file .


<s> bool arc_is_secure_call_p ( rtx pat ) { tree attrs ; tree decl = SYMBOL_REF_DECL ( pat ) ; if ( ! decl ) return false ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "secure_call" , attrs ) ) return true ; return false ; } </s>

Return nonzero if the symbol is a secure function .


<s> bool arc_is_shortcall_p ( rtx sym_ref ) { if ( GET_CODE ( sym_ref ) != SYMBOL_REF ) return false ; return ( SYMBOL_REF_SHORT_CALL_P ( sym_ref ) || ( ! TARGET_LONG_CALLS_SET && ! TARGET_MEDIUM_CALLS && ! SYMBOL_REF_LONG_CALL_P ( sym_ref ) && ! SYMBOL_REF_MEDIUM_CALL_P ( sym_ref ) ) ) ; } </s>


<s> bool arc_is_uncached_mem_p ( rtx pat ) { tree attrs = NULL_TREE ; tree addr ; if ( ! MEM_P ( pat ) ) return false ; addr = MEM_EXPR ( pat ) ; if ( ! addr ) return false ; if ( TREE_CODE ( addr ) == MEM_REF || TREE_CODE ( addr ) == VAR_DECL ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( addr ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; } if ( TREE_CODE ( addr ) == MEM_REF ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 0 ) ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 1 ) ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; } while ( handled_component_p ( addr ) ) { if ( TREE_CODE ( addr ) == COMPONENT_REF ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( addr ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 0 ) ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 1 ) ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; } addr = TREE_OPERAND ( addr , 0 ) ; } return false ; } </s>

Return TRUE if PAT is a memory addressing an uncached data .


<s> int arc_label_align ( rtx_insn * label ) { if ( align_labels . levels [ 0 ] . log < 1 ) { rtx_insn * next = next_nonnote_nondebug_insn ( label ) ; if ( INSN_P ( next ) && recog_memoized ( next ) >= 0 ) return 1 ; } return align_labels . levels [ 0 ] . log ; } </s>

Oddly enough , sometimes we get a zero overhead loop that branch shortening does n't think is a loop - observed with compile/pr24883.c -O3 -fomit-frame-pointer -funroll-loops . Make sure to include the alignment visible for branch shortening ( we actually align the loop insn before it , but that is equivalent since the loop insn is 4 byte long . )


<s>
bool
arc_legitimate_constant_p
(
machine_mode
mode
,
rtx
x
)
{
switch
(
GET_CODE
(
x
)
)
{
case
CONST
:
if
(
flag_pic
)
{
if
(
arc_legitimate_pic_addr_p
(
x
)
)
return
true
;
}
return
arc_legitimate_constant_p
(
mode
,
XEXP
(
x
,
0
)
)
;
case
SYMBOL_REF
:
if
(
SYMBOL_REF_TLS_MODEL
(
x
)
)
return
false
;
case
LABEL_REF
:
if
(
flag_pic
)
return
false
;
case
CONST_INT
:
case
CONST_DOUBLE
:
return
true
;
case
NEG
:
return
arc_legitimate_constant_p
(
mode
,
XEXP
(
x
,
0
)
)
;
case
PLUS
:
case
MINUS
:
{
bool
t1
=
arc_legitimate_constant_p
(
mode
,
XEXP
(
x
,
0
)
)
;
bool
t2
=
arc_legitimate_constant_p
(
mode
,
XEXP
(
x
,
1
)
)
;
return
(
t1
&&
t2
)
;
}
case
CONST_VECTOR
:
switch
(
mode
)
{
case
E_V2HImode
:
return
TARGET_PLUS_DMPY
;
case
E_V2SImode
:
case
E_V4HImode
:
return
TARGET_PLUS_QMACW
;
default
:
return
false
;
}
case
UNSPEC
:
switch
(
XINT
(
x
,
1
)
)
{
case
UNSPEC_TLS_GD
:
case
UNSPEC_TLS_OFF
:
case
UNSPEC_TLS_IE
:
return
true
;
default
:
return
false
;
}
default
:
fatal_insn
(
"unrecognized supposed constant"
,
x
)
;
}
gcc_unreachable
(
)
;
}
</s>

Determine if a given RTX is a valid constant . We already know this satisfies CONSTANT_P .


<s> bool arc_legitimate_pic_addr_p ( rtx addr ) { if ( GET_CODE ( addr ) != CONST ) return false ; addr = XEXP ( addr , 0 ) ; if ( GET_CODE ( addr ) == PLUS ) { if ( GET_CODE ( XEXP ( addr , 1 ) ) != CONST_INT ) return false ; addr = XEXP ( addr , 0 ) ; } if ( GET_CODE ( addr ) != UNSPEC || XVECLEN ( addr , 0 ) != 1 ) return false ; if ( XINT ( addr , 1 ) != ARC_UNSPEC_GOT && XINT ( addr , 1 ) != ARC_UNSPEC_GOTOFF && XINT ( addr , 1 ) != ARC_UNSPEC_GOTOFFPC && XINT ( addr , 1 ) != UNSPEC_TLS_GD && XINT ( addr , 1 ) != UNSPEC_TLS_IE ) return false ; if ( GET_CODE ( XVECEXP ( addr , 0 , 0 ) ) != SYMBOL_REF && GET_CODE ( XVECEXP ( addr , 0 , 0 ) ) != LABEL_REF ) return false ; return true ; } </s>

Return true if ADDR is a valid pic address . A valid pic address on arc should look like const ( unspec ( SYMBOL_REF/LABEL ) ( ARC_UNSPEC_GOTOFF/ARC_UNSPEC_GOT ) )


<s> static rtx arc_legitimize_address_0 ( rtx x , rtx oldx ATTRIBUTE_UNUSED , machine_mode mode ) { rtx addr , inner ; addr = x ; if ( GET_CODE ( addr ) == CONST ) addr = XEXP ( addr , 0 ) ; if ( GET_CODE ( addr ) == PLUS && CONST_INT_P ( XEXP ( addr , 1 ) ) && ( ( GET_CODE ( XEXP ( addr , 0 ) ) == SYMBOL_REF && ! SYMBOL_REF_FUNCTION_P ( XEXP ( addr , 0 ) ) ) || ( REG_P ( XEXP ( addr , 0 ) ) && ( INTVAL ( XEXP ( addr , 1 ) ) & 252 ) ) ) ) { HOST_WIDE_INT offs , upper ; int size = GET_MODE_SIZE ( mode ) ; offs = INTVAL ( XEXP ( addr , 1 ) ) ; upper = ( offs + 256 * size ) & ~ 511 * size ; inner = plus_constant ( Pmode , XEXP ( addr , 0 ) , upper ) ; if ( GET_CODE ( x ) == CONST ) inner = gen_rtx_CONST ( Pmode , inner ) ; addr = plus_constant ( Pmode , force_reg ( Pmode , inner ) , offs - upper ) ; x = addr ; } else if ( GET_CODE ( addr ) == SYMBOL_REF && ! SYMBOL_REF_FUNCTION_P ( addr ) ) x = force_reg ( Pmode , x ) ; if ( memory_address_p ( ( machine_mode ) mode , x ) ) return x ; return NULL_RTX ; } </s>

This is like the hook , but returns NULL when it ca n't / wo n't generate a legitimate address .


<s> static rtx arc_legitimize_pic_address ( rtx addr ) { if ( ! flag_pic ) return addr ; switch ( GET_CODE ( addr ) ) { case UNSPEC : switch ( XINT ( addr , 1 ) ) { case ARC_UNSPEC_GOT : case ARC_UNSPEC_GOTOFFPC : addr = XVECEXP ( addr , 0 , 0 ) ; break ; default : return addr ; } case SYMBOL_REF : if ( SYMBOL_REF_TLS_MODEL ( addr ) ) return addr ; if ( ! arc_symbol_binds_local_p ( addr ) ) return gen_const_mem ( Pmode , arc_unspec_offset ( addr , ARC_UNSPEC_GOT ) ) ; case LABEL_REF : return arc_unspec_offset ( addr , ARC_UNSPEC_GOTOFFPC ) ; default : break ; } return addr ; } </s>

Legitimize a pic address reference in ORIG . The return value is the legitimated address . If OLDX is non-zero , it is the target to assign the address to first .


<s> static rtx arc_legitimize_tls_address ( rtx addr , enum tls_model model ) { rtx tmp ; if ( ! flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC ) model = TLS_MODEL_LOCAL_EXEC ; gcc_assert ( arc_tp_regno != - 1 ) ; switch ( model ) { case TLS_MODEL_GLOBAL_DYNAMIC : tmp = gen_reg_rtx ( Pmode ) ; emit_move_insn ( tmp , arc_unspec_offset ( addr , UNSPEC_TLS_GD ) ) ; return arc_call_tls_get_addr ( tmp ) ; case TLS_MODEL_LOCAL_DYNAMIC : rtx base ; tree decl ; const char * base_name ; decl = SYMBOL_REF_DECL ( addr ) ; base_name = DTPOFF_ZERO_SYM ; if ( decl && bss_initializer_p ( decl ) ) base_name = ".tbss" ; base = gen_rtx_SYMBOL_REF ( Pmode , base_name ) ; tmp = gen_reg_rtx ( Pmode ) ; emit_move_insn ( tmp , arc_unspec_offset ( base , UNSPEC_TLS_GD ) ) ; base = arc_call_tls_get_addr ( tmp ) ; return gen_rtx_PLUS ( Pmode , force_reg ( Pmode , base ) , arc_unspec_offset ( addr , UNSPEC_TLS_OFF ) ) ; case TLS_MODEL_INITIAL_EXEC : addr = arc_unspec_offset ( addr , UNSPEC_TLS_IE ) ; addr = copy_to_mode_reg ( Pmode , gen_const_mem ( Pmode , addr ) ) ; return gen_rtx_PLUS ( Pmode , gen_rtx_REG ( Pmode , arc_tp_regno ) , addr ) ; case TLS_MODEL_LOCAL_EXEC : addr = arc_unspec_offset ( addr , UNSPEC_TLS_OFF ) ; return gen_rtx_PLUS ( Pmode , gen_rtx_REG ( Pmode , arc_tp_regno ) , addr ) ; default : gcc_unreachable ( ) ; } } </s>

Return a legitimized address for ADDR , which is a SYMBOL_REF with tls_model MODEL .


<s> bool arc_lra_p ( void ) { return arc_lra_flag ; } </s>

Return true if we use LRA instead of reload pass .


<s> static int arc_memory_move_cost ( machine_mode mode , reg_class_t rclass ATTRIBUTE_UNUSED , bool in ATTRIBUTE_UNUSED ) { if ( ( GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD ) || ( ( GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD * 2 ) && TARGET_LL64 ) ) return 6 ; return ( 2 * GET_MODE_SIZE ( mode ) ) ; } </s>


Implement TARGET_MODES_TIEABLE_P . Tie QI/HI/SI modes together .


<s> static bool arc_mode_dependent_address_p ( const_rtx addr , addr_space_t ) { if ( GET_CODE ( addr ) == PLUS && GET_CODE ( XEXP ( ( addr ) , 0 ) ) == MULT ) return true ; return false ; } </s>

Return true iff ADDR ( a legitimate address expression ) has an effect that depends on the machine mode it is used for .


<s> static bool arc_must_save_register ( int regno , struct function * func , bool special_p ) { unsigned int fn_type = arc_compute_function_type ( func ) ; bool irq_auto_save_p = ( ( irq_ctrl_saved . irq_save_last_reg >= regno ) && ARC_AUTO_IRQ_P ( fn_type ) ) ; bool firq_auto_save_p = ARC_FAST_INTERRUPT_P ( fn_type ) ; switch ( rgf_banked_register_count ) { case 4 : firq_auto_save_p &= ( regno < 4 ) ; break ; case 8 : firq_auto_save_p &= ( ( regno < 4 ) || ( ( regno > 11 ) && ( regno < 16 ) ) ) ; break ; case 16 : firq_auto_save_p &= ( ( regno < 4 ) || ( ( regno > 9 ) && ( regno < 16 ) ) || ( ( regno > 25 ) && ( regno < 29 ) ) || ( ( regno > 29 ) && ( regno < 32 ) ) ) ; break ; case 32 : firq_auto_save_p &= ( regno != 29 ) && ( regno < 32 ) ; break ; default : firq_auto_save_p = false ; break ; } switch ( regno ) { case ILINK1_REG : case RETURN_ADDR_REGNUM : case STACK_POINTER_REGNUM : return false ; case R30_REG : if ( ! TARGET_V2 ) return false ; break ; case R40_REG : case R41_REG : case R42_REG : case R43_REG : case R44_REG : if ( TARGET_DPFP && ! special_p ) return false ; case R32_REG : case R33_REG : case R34_REG : case R35_REG : case R36_REG : case R37_REG : case R38_REG : case R39_REG : case R45_REG : case R46_REG : case R47_REG : case R48_REG : case R49_REG : case R50_REG : case R51_REG : case R52_REG : case R53_REG : case R54_REG : case R55_REG : case R56_REG : case R57_REG : if ( ARC_INTERRUPT_P ( fn_type ) && ( df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) || df_regs_ever_live_p ( regno ) ) && ! fixed_regs [ regno ] ) return true ; return false ; case R58_REG : case R59_REG : if ( ARC_INTERRUPT_P ( fn_type ) && ( df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) || df_regs_ever_live_p ( regno ) ) && ( ( ! fixed_regs [ regno ] && ! special_p ) || ( TARGET_MUL64_SET && special_p ) ) ) return true ; return false ; case 61 : case 62 : case 63 : return false ; case HARD_FRAME_POINTER_REGNUM : if ( arc_frame_pointer_needed ( ) ) return false ; break ; default : break ; } if ( ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( ARC_INTERRUPT_P ( fn_type ) && ( df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) || df_regs_ever_live_p ( regno ) ) ) ) && ! irq_auto_save_p && ! firq_auto_save_p ) return true ; return false ; } </s>

Tell prologue and epilogue if register REGNO should be saved / restored . The return address , stack pointer and frame pointer are treated separately . Do n't consider them here . Addition for pic : The gp register needs to be saved if the current function changes it to access gotoff variables . FIXME : This will not be needed if we used some arbitrary register instead of r26 .


<s> static bool arc_must_save_return_addr ( struct function * func ) { if ( func -> machine -> frame_info . save_return_addr ) return true ; return false ; } </s>

Return true if the return address must be saved in the current function , otherwise return false .


<s> bool arc_need_delay ( rtx_insn * insn ) { rtx_insn * next ; if ( ! flag_delayed_branch ) return false ; if ( NONJUMP_INSN_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) == USE && ( ! ( next = next_active_insn ( insn ) ) || ( ( ! NONJUMP_INSN_P ( next ) || GET_CODE ( PATTERN ( next ) ) != SEQUENCE ) && arc_attr_type ( next ) == TYPE_RETURN ) ) && ( ! TARGET_PAD_RETURN || ( prev_active_insn ( insn ) && prev_active_insn ( prev_active_insn ( insn ) ) && prev_active_insn ( prev_active_insn ( prev_active_insn ( insn ) ) ) ) ) ) return true ; if ( NONJUMP_INSN_P ( insn ) ? ( GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || GET_CODE ( PATTERN ( insn ) ) == SEQUENCE ) : JUMP_P ( insn ) ? ( GET_CODE ( PATTERN ( insn ) ) == ADDR_VEC || GET_CODE ( PATTERN ( insn ) ) == ADDR_DIFF_VEC ) : ! CALL_P ( insn ) ) return false ; return num_delay_slots ( insn ) != 0 ; } </s>

Return true if INSN is an instruction with a delay slot we may want to fill .


<s> static bool arc_no_speculation_in_delay_slots_p ( ) { return true ; } </s>


<s> int arc_output_addsi ( rtx * operands , bool cond_p , bool output_p ) { char format [ 35 ] ; int match = operands_match_p ( operands [ 0 ] , operands [ 1 ] ) ; int match2 = operands_match_p ( operands [ 0 ] , operands [ 2 ] ) ; int intval = ( REG_P ( operands [ 2 ] ) ? 1 : CONST_INT_P ( operands [ 2 ] ) ? INTVAL ( operands [ 2 ] ) : 0xbadc057 ) ; int neg_intval = - intval ; int short_0 = satisfies_constraint_Rcq ( operands [ 0 ] ) ; int short_p = ( ! cond_p && short_0 && satisfies_constraint_Rcq ( operands [ 1 ] ) ) ; int ret = 0 ; && REGNO ( OP ) != 30 ) \ || ! TARGET_V2 ) ) if ( output_p ) \ output_asm_insn ( FORMAT , operands ) ; \ return ret ; \ } </s>

Emit code for an addsi3 instruction with OPERANDS . COND_P indicates if this will use conditional execution . Return the length of the instruction . If OUTPUT_P is false , do n't actually output the instruction , just return its length .


<s>
const
char
*
arc_output_libcall
(
const
char
*
fname
)
{
unsigned
len
=
strlen
(
fname
)
;
static
char
buf
[
64
]
;
gcc_assert
(
len
<
sizeof
buf
35
)
;
if
(
TARGET_LONG_CALLS_SET
||
(
TARGET_MEDIUM_CALLS
&&
arc_ccfsm_cond_exec_p
(
)
)
)
{
if
(
flag_pic
)
sprintf
(
buf
,
"add r12,pcl,@%s@pcl\n\tjl%%!%%* [r12]"
,
fname
)
;
else
sprintf
(
buf
,
"jl%%! @%s"
,
fname
)
;
}
else
sprintf
(
buf
,
"bl%%!%%* @%s"
,
fname
)
;
return
buf
;
}
</s>

Output a library call to a function called FNAME that has been arranged to be local to any dso .


<s>
static
void
arc_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
fnname
=
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
thunk
)
)
;
int
mi_delta
=
delta
;
const
char
*
const
mi_op
=
mi_delta
<
0
"sub"
:
"add"
;
int
shift
=
0
;
int
this_regno
=
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
1
:
0
;
rtx
fnaddr
;
assemble_start_function
(
thunk
,
fnname
)
;
if
(
mi_delta
<
0
)
mi_delta
=
mi_delta
;
while
(
mi_delta
!=
0
)
{
if
(
(
mi_delta
&
(
3
<<
shift
)
)
==
0
)
shift
+=
2
;
else
{
asm_fprintf
(
file
,
"\t%s\t%s, %s, %d\n"
,
mi_op
,
reg_names
[
this_regno
]
,
reg_names
[
this_regno
]
,
mi_delta
&
(
0xff
<<
shift
)
)
;
mi_delta
&=
~
(
0xff
<<
shift
)
;
shift
+=
8
;
}
}
if
(
vcall_offset
!=
0
)
{
asm_fprintf
(
file
,
"\tld\t%s, [%s]\n"
,
ARC_TEMP_SCRATCH_REG
,
reg_names
[
this_regno
]
)
;
asm_fprintf
(
file
,
"\tadd\t%s, %s, "
HOST_WIDE_INT_PRINT_DEC
"\n"
,
ARC_TEMP_SCRATCH_REG
,
ARC_TEMP_SCRATCH_REG
,
vcall_offset
)
;
asm_fprintf
(
file
,
"\tld\t%s, [%s]\n"
,
ARC_TEMP_SCRATCH_REG
,
ARC_TEMP_SCRATCH_REG
)
;
asm_fprintf
(
file
,
"\tadd\t%s, %s, %s\n"
,
reg_names
[
this_regno
]
,
reg_names
[
this_regno
]
,
ARC_TEMP_SCRATCH_REG
)
;
}
fnaddr
=
XEXP
(
DECL_RTL
(
function
)
,
0
)
;
if
(
arc_is_longcall_p
(
fnaddr
)
)
{
if
(
flag_pic
)
{
asm_fprintf
(
file
,
"\tld\t%s, [pcl, @"
,
ARC_TEMP_SCRATCH_REG
)
;
assemble_name
(
file
,
XSTR
(
fnaddr
,
0
)
)
;
fputs
(
"@gotpc]\n"
,
file
)
;
asm_fprintf
(
file
,
"\tj\t[%s]"
,
ARC_TEMP_SCRATCH_REG
)
;
}
else
{
fputs
(
"\tj\t@"
,
file
)
;
assemble_name
(
file
,
XSTR
(
fnaddr
,
0
)
)
;
}
}
else
{
fputs
(
"\tb\t@"
,
file
)
;
assemble_name
(
file
,
XSTR
(
fnaddr
,
0
)
)
;
if
(
flag_pic
)
fputs
(
"@plt\n"
,
file
)
;
}
fputc
(
'\n'
,
file
)
;
assemble_end_function
(
thunk
,
fnname
)
;
}
</s>

Output code to add DELTA to the first argument , and then jump to FUNCTION . Used for C++ multiple inheritance .


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

For ARC , All aggregates and arguments greater than 8 bytes are passed by reference .


<s> static void arc_post_atomic_barrier ( enum memmodel model ) { if ( need_atomic_barrier_p ( model , false ) ) emit_insn ( gen_memory_barrier ( ) ) ; } </s>

Emit a ( post ) memory barrier around an atomic sequence according to MODEL .


<s> static unsigned arc_predicate_delay_insns ( void ) { for ( rtx_insn * insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx pat , jump , dlay , src , cond , * patp ; int reverse ; if ( ! NONJUMP_INSN_P ( insn ) || GET_CODE ( pat = PATTERN ( insn ) ) != SEQUENCE ) continue ; jump = XVECEXP ( pat , 0 , 0 ) ; dlay = XVECEXP ( pat , 0 , 1 ) ; if ( ! JUMP_P ( jump ) || ! INSN_ANNULLED_BRANCH_P ( jump ) ) continue ; if ( ! TARGET_AT_DBR_CONDEXEC && ! INSN_FROM_TARGET_P ( dlay ) ) continue ; gcc_assert ( GET_CODE ( PATTERN ( jump ) ) == SET ) ; gcc_assert ( SET_DEST ( PATTERN ( jump ) ) == pc_rtx ) ; src = SET_SRC ( PATTERN ( jump ) ) ; gcc_assert ( GET_CODE ( src ) == IF_THEN_ELSE ) ; cond = XEXP ( src , 0 ) ; if ( XEXP ( src , 2 ) == pc_rtx ) reverse = 0 ; else if ( XEXP ( src , 1 ) == pc_rtx ) reverse = 1 ; else gcc_unreachable ( ) ; if ( reverse != ! INSN_FROM_TARGET_P ( dlay ) ) { machine_mode ccm = GET_MODE ( XEXP ( cond , 0 ) ) ; enum rtx_code code = reverse_condition ( GET_CODE ( cond ) ) ; if ( code == UNKNOWN || ccm == CC_FP_GTmode || ccm == CC_FP_GEmode ) code = reverse_condition_maybe_unordered ( GET_CODE ( cond ) ) ; cond = gen_rtx_fmt_ee ( code , GET_MODE ( cond ) , copy_rtx ( XEXP ( cond , 0 ) ) , copy_rtx ( XEXP ( cond , 1 ) ) ) ; } else cond = copy_rtx ( cond ) ; patp = & PATTERN ( dlay ) ; pat = * patp ; pat = conditionalize_nonjump ( pat , cond , dlay , true ) ; validate_change ( dlay , patp , pat , 1 ) ; if ( ! apply_change_group ( ) ) gcc_unreachable ( ) ; } return 0 ; } </s>

Find annulled delay insns and convert them to use the appropriate predicate . This allows branch shortening to size up these insns properly .


<s> static machine_mode arc_preferred_simd_mode ( scalar_mode mode ) { switch ( mode ) { case E_HImode : return TARGET_PLUS_QMACW ? V4HImode : V2HImode ; case E_SImode : return V2SImode ; default : return word_mode ; } } </s>

Implements target hook TARGET_VECTORIZE_PREFERRED_SIMD_MODE .


<s> static void arc_pre_atomic_barrier ( enum memmodel model ) { if ( need_atomic_barrier_p ( model , true ) ) emit_insn ( gen_memory_barrier ( ) ) ; } </s>

Emit a ( pre ) memory barrier around an atomic sequence according to MODEL .


<s> void arc_print_operand_address ( FILE * file , rtx addr ) { rtx base , index = 0 ; switch ( GET_CODE ( addr ) ) { case REG : fputs ( reg_names [ REGNO ( addr ) ] , file ) ; break ; case SYMBOL_REF : if ( output_sdata ) fputs ( "gp," , file ) ; output_addr_const ( file , addr ) ; if ( output_sdata ) fputs ( "@sda" , file ) ; output_sdata = 0 ; break ; case PLUS : if ( GET_CODE ( XEXP ( addr , 0 ) ) == MULT ) index = XEXP ( XEXP ( addr , 0 ) , 0 ) , base = XEXP ( addr , 1 ) ; else if ( CONST_INT_P ( XEXP ( addr , 0 ) ) ) index = XEXP ( addr , 0 ) , base = XEXP ( addr , 1 ) ; else base = XEXP ( addr , 0 ) , index = XEXP ( addr , 1 ) ; gcc_assert ( OBJECT_P ( base ) ) ; arc_print_operand_address ( file , base ) ; if ( CONSTANT_P ( base ) && CONST_INT_P ( index ) ) fputc ( '+' , file ) ; else fputc ( ',' , file ) ; gcc_assert ( OBJECT_P ( index ) ) ; arc_print_operand_address ( file , index ) ; break ; case CONST : { rtx c = XEXP ( addr , 0 ) ; if ( ( GET_CODE ( c ) == UNSPEC && ( XINT ( c , 1 ) == UNSPEC_TLS_OFF || XINT ( c , 1 ) == UNSPEC_TLS_IE ) ) || ( GET_CODE ( c ) == PLUS && GET_CODE ( XEXP ( c , 0 ) ) == UNSPEC && ( XINT ( XEXP ( c , 0 ) , 1 ) == UNSPEC_TLS_OFF || XINT ( XEXP ( c , 0 ) , 1 ) == ARC_UNSPEC_GOTOFFPC ) ) ) { arc_output_pic_addr_const ( file , c , 0 ) ; break ; } gcc_assert ( GET_CODE ( c ) == PLUS ) ; gcc_assert ( GET_CODE ( XEXP ( c , 0 ) ) == SYMBOL_REF ) ; gcc_assert ( GET_CODE ( XEXP ( c , 1 ) ) == CONST_INT ) ; output_address ( VOIDmode , XEXP ( addr , 0 ) ) ; break ; } case PRE_INC : case PRE_DEC : gcc_unreachable ( ) ; break ; default : if ( flag_pic ) arc_output_pic_addr_const ( file , addr , 0 ) ; else output_addr_const ( file , addr ) ; break ; } } </s>

Print a memory address as an operand to reference that memory location .


<s> static bool arc_process_double_reg_moves ( rtx * operands ) { enum usesDxState { none , srcDx , destDx , maxDx } ; enum usesDxState state = none ; rtx dest = operands [ 0 ] ; rtx src = operands [ 1 ] ; if ( refers_to_regno_p ( 40 , 44 , src , 0 ) ) { state = srcDx ; gcc_assert ( REG_P ( dest ) ) ; } if ( refers_to_regno_p ( 40 , 44 , dest , 0 ) ) { gcc_assert ( REG_P ( src ) ) ; gcc_assert ( state == none ) ; state = destDx ; } if ( state == none ) return false ; if ( state == srcDx ) { if ( TARGET_DPFP_DISABLE_LRSR ) { rtx set = gen_rtx_SET ( dest , src ) ; rtx use1 = gen_rtx_USE ( VOIDmode , const1_rtx ) ; emit_insn ( gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , set , use1 ) ) ) ; } else { rtx destHigh = simplify_gen_subreg ( SImode , dest , DFmode , TARGET_BIG_ENDIAN ? 0 : 4 ) ; rtx destLow = simplify_gen_subreg ( SImode , dest , DFmode , TARGET_BIG_ENDIAN ? 4 : 0 ) ; emit_insn ( gen_rtx_SET ( destHigh , gen_rtx_UNSPEC_VOLATILE ( Pmode , gen_rtvec ( 1 , src ) , VUNSPEC_ARC_LR_HIGH ) ) ) ; emit_insn ( gen_rtx_SET ( destLow , gen_rtx_UNSPEC_VOLATILE ( Pmode , gen_rtvec ( 1 , src ) , VUNSPEC_ARC_LR ) ) ) ; } } else if ( state == destDx ) { rtx srcHigh = simplify_gen_subreg ( SImode , src , DFmode , TARGET_BIG_ENDIAN ? 0 : 4 ) ; rtx srcLow = simplify_gen_subreg ( SImode , src , DFmode , TARGET_BIG_ENDIAN ? 4 : 0 ) ; emit_insn ( gen_dexcl_2op ( dest , srcHigh , srcLow ) ) ; } else gcc_unreachable ( ) ; return true ; } </s>

Handle DOUBLE_REGS uses . Operand 0 : destination register Operand 1 : source register


<s> bool arc_raw_symbolic_reference_mentioned_p ( rtx op , bool skip_local ) { const char * fmt ; int i ; if ( GET_CODE ( op ) == UNSPEC ) return false ; if ( GET_CODE ( op ) == SYMBOL_REF ) { if ( SYMBOL_REF_TLS_MODEL ( op ) ) return true ; if ( ! flag_pic ) return false ; tree decl = SYMBOL_REF_DECL ( op ) ; return ! skip_local || ! decl || ! default_binds_local_p ( decl ) ; } 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 ( arc_raw_symbolic_reference_mentioned_p ( XVECEXP ( op , i , j ) , skip_local ) ) return true ; } else if ( fmt [ i ] == 'e' && arc_raw_symbolic_reference_mentioned_p ( XEXP ( op , i ) , skip_local ) ) return true ; } return false ; } </s>

Return true if OP contains a SYMBOL_REF that is not wrapped in an unspec . If SKIP_LOCAL is true , skip symbols that bind locally . This is used further down in this file , and , without SKIP_LOCAL , in the addsi3 / subsi3 expanders when generating PIC code .


<s> rtx arc_regno_use_in ( unsigned int regno , rtx x ) { const char * fmt ; int i , j ; rtx tem ; if ( REG_P ( x ) && refers_to_regno_p ( regno , x ) ) return x ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'e' ) { if ( ( tem = regno_use_in ( regno , XEXP ( x , i ) ) ) ) return tem ; } else if ( fmt [ i ] == 'E' ) for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( ( tem = regno_use_in ( regno , XVECEXP ( x , i , j ) ) ) ) return tem ; } return NULL_RTX ; } </s>

Searches X for any reference to REGNO , returning the rtx of the reference found if any . Otherwise , returns NULL_RTX .


<s> static void arc_reorg_loops ( void ) { reorg_loops ( true , & arc_doloop_hooks ) ; } </s>

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


<s> static int arc_restore_callee_saves ( uint64_t gmask , bool restore_blink , bool restore_fp , HOST_WIDE_INT offset , HOST_WIDE_INT allocated ) { rtx reg ; int frame_deallocated = 0 ; HOST_WIDE_INT offs = cfun -> machine -> frame_info . reg_size ; unsigned int fn_type = arc_compute_function_type ( cfun ) ; bool early_blink_restore ; int i ; if ( arc_frame_pointer_needed ( ) && offset ) { frame_move ( stack_pointer_rtx , hard_frame_pointer_rtx ) ; frame_deallocated += offset ; offset = 0 ; } if ( restore_fp ) { gcc_assert ( offset == 0 ) ; frame_deallocated += frame_restore_reg ( hard_frame_pointer_rtx , 0 ) ; } if ( offset ) { frame_stack_add ( offset ) ; frame_deallocated += offset ; offset = 0 ; } early_blink_restore = restore_blink && ! optimize_size && offs && ! ARC_INTERRUPT_P ( fn_type ) ; if ( early_blink_restore ) { rtx addr = plus_constant ( Pmode , stack_pointer_rtx , offs ) ; reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; rtx insn = frame_move_inc ( reg , gen_frame_mem ( Pmode , addr ) , stack_pointer_rtx , NULL_RTX ) ; add_reg_note ( insn , REG_CFA_RESTORE , reg ) ; restore_blink = false ; } if ( gmask ) for ( i = 0 ; i <= GMASK_LEN ; i ++ ) { machine_mode restore_mode = SImode ; if ( TARGET_LL64 && ( ( i % 2 ) == 0 ) && ( ( gmask & ( 1ULL << i ) ) != 0 ) && ( ( gmask & ( 1ULL << ( i + 1 ) ) ) != 0 ) ) restore_mode = DImode ; else if ( ( gmask & ( 1ULL << i ) ) == 0 ) continue ; reg = gen_rtx_REG ( restore_mode , i ) ; offs = 0 ; switch ( restore_mode ) { case E_DImode : if ( ( GMASK_LEN - __builtin_clzll ( gmask ) ) == ( i + 1 ) && early_blink_restore ) offs = 4 ; break ; case E_SImode : if ( ( GMASK_LEN - __builtin_clzll ( gmask ) ) == i && early_blink_restore ) offs = 4 ; break ; default : offs = 0 ; } frame_deallocated += frame_restore_reg ( reg , offs ) ; offset = 0 ; if ( restore_mode == DImode ) i ++ ; } if ( restore_blink ) { reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; frame_deallocated += frame_restore_reg ( reg , allocated - frame_deallocated - UNITS_PER_WORD ) ; } return frame_deallocated ; } </s>

ARC 's epilogue , restore any required call-saved regs ( and call-used if it is for an interrupt handler ) using LD/LDD instructions .


<s> static int arc_return_address_register ( unsigned int fn_type ) { int regno = 0 ; if ( ARC_INTERRUPT_P ( fn_type ) ) { if ( ( fn_type & ( ARC_FUNCTION_ILINK1 | ARC_FUNCTION_FIRQ ) ) != 0 ) regno = ILINK1_REG ; else if ( ( fn_type & ARC_FUNCTION_ILINK2 ) != 0 ) regno = ILINK2_REG ; else gcc_unreachable ( ) ; } else if ( ARC_NORMAL_P ( fn_type ) || ARC_NAKED_P ( fn_type ) ) regno = RETURN_ADDR_REGNUM ; gcc_assert ( regno != 0 ) ; return regno ; } </s>

Return the register number of the register holding the return address for a function of type TYPE .


<s> rtx arc_return_addr_rtx ( int count , ATTRIBUTE_UNUSED rtx frame ) { if ( count != 0 ) return const0_rtx ; return get_hard_reg_initial_val ( Pmode , RETURN_ADDR_REGNUM ) ; } </s>

Returns the return address that is used by builtin_return_address .


<s> static bool arc_return_in_memory ( const_tree type , const_tree fntype ATTRIBUTE_UNUSED ) { if ( AGGREGATE_TYPE_P ( type ) || TREE_ADDRESSABLE ( type ) ) return true ; else { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; return ( size == - 1 || size > ( TARGET_V2 ? 16 : 8 ) ) ; } } </s>

Worker function for TARGET_RETURN_IN_MEMORY .


<s> static int arc_save_callee_enter ( uint64_t gmask , bool save_blink , bool save_fp , HOST_WIDE_INT offset ) { int start_reg = ENTER_LEAVE_START_REG ; int end_reg = ENTER_LEAVE_END_REG ; int regno , indx , off , nregs ; rtx insn , reg , mem ; int frame_allocated = 0 ; for ( regno = start_reg ; regno <= end_reg && ( gmask & ( 1ULL << regno ) ) ; ) regno ++ ; end_reg = regno - 1 ; nregs = end_reg - start_reg + 1 ; nregs += save_blink ? 1 : 0 ; nregs += save_fp ? 1 : 0 ; if ( offset ) frame_stack_add ( offset ) ; insn = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( nregs + ( save_fp ? 1 : 0 ) + 1 ) ) ; indx = 0 ; reg = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - nregs * UNITS_PER_WORD ) ) ; RTX_FRAME_RELATED_P ( reg ) = 1 ; XVECEXP ( insn , 0 , indx ++ ) = reg ; off = nregs * UNITS_PER_WORD ; if ( save_blink ) { reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; mem = gen_frame_mem ( Pmode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; XVECEXP ( insn , 0 , indx ) = gen_rtx_SET ( mem , reg ) ; RTX_FRAME_RELATED_P ( XVECEXP ( insn , 0 , indx ++ ) ) = 1 ; off -= UNITS_PER_WORD ; save_blink = false ; } for ( regno = start_reg ; regno <= end_reg ; regno ++ , indx ++ , off -= UNITS_PER_WORD ) { reg = gen_rtx_REG ( SImode , regno ) ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; XVECEXP ( insn , 0 , indx ) = gen_rtx_SET ( mem , reg ) ; RTX_FRAME_RELATED_P ( XVECEXP ( insn , 0 , indx ) ) = 1 ; gmask = gmask & ~ ( 1ULL << regno ) ; } if ( save_fp ) { mem = gen_frame_mem ( Pmode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; XVECEXP ( insn , 0 , indx ) = gen_rtx_SET ( mem , hard_frame_pointer_rtx ) ; RTX_FRAME_RELATED_P ( XVECEXP ( insn , 0 , indx ++ ) ) = 1 ; off -= UNITS_PER_WORD ; XVECEXP ( insn , 0 , indx ) = gen_rtx_SET ( hard_frame_pointer_rtx , stack_pointer_rtx ) ; RTX_FRAME_RELATED_P ( XVECEXP ( insn , 0 , indx ++ ) ) = 1 ; save_fp = false ; } gcc_assert ( off == 0 ) ; insn = frame_insn ( insn ) ; add_reg_note ( insn , REG_INC , stack_pointer_rtx ) ; frame_allocated = nregs * UNITS_PER_WORD ; return frame_allocated - offset ; } </s>

ARC prologue , save the registers using enter instruction . Leave instruction can also save $ blink ( SAVE_BLINK ) and $ fp ( SAVE_FP ) register .


<s> static int arc_save_callee_milli ( uint64_t gmask , bool save_blink , bool save_fp , HOST_WIDE_INT offset , HOST_WIDE_INT reg_size ) { int start_reg = 13 ; int end_reg = 25 ; int regno , indx , off , nregs ; rtx insn , reg , mem ; int frame_allocated = 0 ; for ( regno = start_reg ; regno <= end_reg && ( gmask & ( 1ULL << regno ) ) ; ) regno ++ ; end_reg = regno - 1 ; nregs = end_reg - start_reg + 1 ; gcc_assert ( end_reg > 14 ) ; if ( save_blink ) { reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; frame_allocated += frame_save_reg ( reg , offset ) ; offset = 0 ; } if ( reg_size || offset ) { frame_stack_add ( offset - reg_size ) ; frame_allocated += nregs * UNITS_PER_WORD - offset ; offset = 0 ; } insn = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( nregs + 1 ) ) ; indx = 0 ; XVECEXP ( insn , 0 , nregs ) = gen_rtx_CLOBBER ( VOIDmode , gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ) ; for ( regno = start_reg , indx = 0 , off = 0 ; regno <= end_reg ; regno ++ , indx ++ , off += UNITS_PER_WORD ) { reg = gen_rtx_REG ( SImode , regno ) ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; XVECEXP ( insn , 0 , indx ) = gen_rtx_SET ( mem , reg ) ; RTX_FRAME_RELATED_P ( XVECEXP ( insn , 0 , indx ) ) = 1 ; gmask = gmask & ~ ( 1ULL << regno ) ; } insn = frame_insn ( insn ) ; for ( regno = start_reg , off = 0 ; regno <= end_reg ; regno ++ , off += UNITS_PER_WORD ) { reg = gen_rtx_REG ( SImode , regno ) ; mem = gen_rtx_MEM ( SImode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; add_reg_note ( insn , REG_CFA_OFFSET , gen_rtx_SET ( mem , reg ) ) ; } if ( arc_must_save_return_addr ( cfun ) ) { emit_insn ( gen_rtx_SET ( gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) , gen_rtx_MEM ( Pmode , plus_constant ( Pmode , stack_pointer_rtx , reg_size ) ) ) ) ; } for ( regno = 0 ; regno <= GMASK_LEN ; regno ++ ) { if ( ( gmask & ( 1ULL << regno ) ) == 0 ) continue ; reg = gen_rtx_REG ( SImode , regno ) ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , off ) ) ; frame_move_inc ( mem , reg , stack_pointer_rtx , 0 ) ; frame_allocated += UNITS_PER_WORD ; off += UNITS_PER_WORD ; } if ( save_fp ) frame_allocated += frame_save_reg ( hard_frame_pointer_rtx , offset ) ; if ( arc_frame_pointer_needed ( ) ) frame_move ( hard_frame_pointer_rtx , stack_pointer_rtx ) ; return frame_allocated ; } </s>

Millicode thunks implementation : Generates calls to millicodes for registers starting from r13 to r25 Present Limitations : - Only one range supported . The remaining regs will have the ordinary st and ld instructions for store and loads . Hence a gmask asking to store r13-14 , r16-r25 will only generate calls to store and load r13 to r14 while store and load insns will be generated for r16 to r25 in the prologue and epilogue respectively . - Presently library only supports register ranges starting from r13 .


<s> static int arc_save_callee_saves ( uint64_t gmask , bool save_blink , bool save_fp , HOST_WIDE_INT offset , bool emit_move ) { rtx reg ; int frame_allocated = 0 ; int i ; if ( save_blink ) { reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; frame_allocated += frame_save_reg ( reg , offset ) ; offset = 0 ; } if ( gmask ) for ( i = GMASK_LEN ; i >= 0 ; i -- ) { machine_mode save_mode = SImode ; if ( TARGET_LL64 && ( ( i - 1 ) % 2 == 0 ) && ( ( gmask & ( 1ULL << i ) ) != 0 ) && ( ( gmask & ( 1ULL << ( i - 1 ) ) ) != 0 ) ) { save_mode = DImode ; -- i ; } else if ( ( gmask & ( 1ULL << i ) ) == 0 ) continue ; reg = gen_rtx_REG ( save_mode , i ) ; frame_allocated += frame_save_reg ( reg , offset ) ; offset = 0 ; } if ( save_fp ) { frame_allocated += frame_save_reg ( hard_frame_pointer_rtx , offset ) ; offset = 0 ; } if ( emit_move ) frame_move ( hard_frame_pointer_rtx , stack_pointer_rtx ) ; return frame_allocated ; } </s>

ARC 's prologue , save any needed call-saved regs ( and call-used if this is an interrupt handler ) for ARCompact ISA , using ST/STD instructions .


<s> bool arc_scheduling_not_expected ( void ) { return cfun -> machine -> arc_reorg_started ; } </s>

Return true if the scheduling pass ( es ) has/have already run , i.e . where possible , we should try to mitigate high latencies by different instruction selection .


<s> static int arc_sched_adjust_priority ( rtx_insn * insn , int priority ) { rtx set = single_set ( insn ) ; if ( set && GET_MODE ( SET_SRC ( set ) ) == DFmode && GET_CODE ( SET_SRC ( set ) ) == REG ) { return priority + 20 ; } return priority ; } </s>

Try to keep the ( mov : DF _ , reg ) as early as possible so that the d < add/sub/mul > h-lr insns appear together and can use the peephole2 pattern .


<s> static int arc_sched_issue_rate ( void ) { switch ( arc_tune ) { case TUNE_ARCHS4X : case TUNE_ARCHS4XD : return 3 ; default : break ; } return 1 ; } </s>

Implements target hook TARGET_SCHED_ISSUE_RATE .


<s> static reg_class_t arc_secondary_reload ( bool in_p , rtx x , reg_class_t cl , machine_mode mode , secondary_reload_info * sri ) { enum rtx_code code = GET_CODE ( x ) ; if ( cl == DOUBLE_REGS ) return GENERAL_REGS ; if ( code == SUBREG ) { rtx addr = NULL_RTX ; x = SUBREG_REG ( x ) ; if ( REG_P ( x ) ) { int regno = REGNO ( x ) ; if ( regno >= FIRST_PSEUDO_REGISTER ) regno = reg_renumber [ regno ] ; if ( regno != - 1 ) return NO_REGS ; if ( ! lra_in_progress && reg_equiv_mem ( REGNO ( x ) ) ) { rtx mem = reg_equiv_mem ( REGNO ( x ) ) ; addr = find_replacement ( & XEXP ( mem , 0 ) ) ; } } else { gcc_assert ( MEM_P ( x ) ) ; addr = XEXP ( x , 0 ) ; addr = simplify_rtx ( addr ) ; } if ( addr && GET_CODE ( addr ) == PLUS && CONST_INT_P ( XEXP ( addr , 1 ) ) && ( ! RTX_OK_FOR_OFFSET_P ( mode , XEXP ( addr , 1 ) ) ) ) { switch ( mode ) { case E_QImode : sri -> icode = in_p ? CODE_FOR_reload_qi_load : CODE_FOR_reload_qi_store ; break ; case E_HImode : sri -> icode = in_p ? CODE_FOR_reload_hi_load : CODE_FOR_reload_hi_store ; break ; default : break ; } } } return NO_REGS ; } </s>

For ARC base register + offset addressing , the validity of the address is mode-dependent for most of the offset range , as the offset can be scaled by the access size . We do n't expose these as mode-dependent addresses in the mode_dependent_address_p target hook , because that would disable lots of optimizations , and most uses of these addresses are for 32 or 64 bit accesses anyways , which are fine . However , that leaves some addresses for 8 / 16 bit values not properly reloaded by the generic code , which is why we have to schedule secondary reloads for these .


<s> void arc_secondary_reload_conv ( rtx reg , rtx mem , rtx scratch , bool store_p ) { rtx addr ; gcc_assert ( GET_CODE ( mem ) == MEM ) ; addr = XEXP ( mem , 0 ) ; emit_move_insn ( scratch , addr ) ; mem = replace_equiv_address_nv ( mem , scratch ) ; if ( store_p ) emit_insn ( gen_rtx_SET ( mem , reg ) ) ; else emit_insn ( gen_rtx_SET ( reg , mem ) ) ; return ; } </s>

Convert reloads using offsets that are too large to use indirect addressing .


<s> bool arc_sets_cc_p ( rtx_insn * insn ) { if ( NONJUMP_INSN_P ( insn ) ) if ( rtx_sequence * seq = dyn_cast < rtx_sequence * > ( PATTERN ( insn ) ) ) insn = seq -> insn ( seq -> len ( ) - 1 ) ; return arc_attr_type ( insn ) == TYPE_COMPARE ; } </s>

Return true if insn sets the condition codes .


<s> static void arc_setup_incoming_varargs ( cumulative_args_t args_so_far , const function_arg_info & arg , int * pretend_size , int no_rtl ) { int first_anon_arg ; CUMULATIVE_ARGS next_cum ; next_cum = * get_cumulative_args ( args_so_far ) ; arc_function_arg_advance ( pack_cumulative_args ( & next_cum ) , arg ) ; first_anon_arg = next_cum ; if ( FUNCTION_ARG_REGNO_P ( first_anon_arg ) ) { int first_reg_offset = first_anon_arg ; if ( ! no_rtl ) { rtx regblock = gen_rtx_MEM ( BLKmode , plus_constant ( Pmode , arg_pointer_rtx , FIRST_PARM_OFFSET ( 0 ) ) ) ; move_block_from_reg ( first_reg_offset , regblock , MAX_ARC_PARM_REGS - first_reg_offset ) ; } * pretend_size = ( ( MAX_ARC_PARM_REGS - first_reg_offset ) * UNITS_PER_WORD ) ; } } </s>

Do any needed setup for a variadic function . For the ARC , we must create a register parameter block , and then copy any anonymous arguments in registers to memory . CUM has not been updated for the last named argument which has type TYPE and mode MODE , and we rely on this fact .


<s> bool arc_short_comparison_p ( rtx comparison , int offset ) { gcc_assert ( ARC_CC_NC == ARC_CC_HS ) ; gcc_assert ( ARC_CC_C == ARC_CC_LO ) ; switch ( get_arc_condition_code ( comparison ) ) { case ARC_CC_EQ : case ARC_CC_NE : return offset >= - 512 && offset <= 506 ; case ARC_CC_GT : case ARC_CC_LE : case ARC_CC_GE : case ARC_CC_LT : case ARC_CC_HI : case ARC_CC_LS : case ARC_CC_LO : case ARC_CC_HS : return offset >= - 64 && offset <= 58 ; default : return false ; } } </s>

Return true if COMPARISON has a short form that can accomodate OFFSET .


<s> const char * arc_short_long ( rtx_insn * insn , const char * s_tmpl , const char * l_tmpl ) { int is_short = arc_verify_short ( insn , cfun -> machine -> unalign , - 1 ) ; extract_constrain_insn_cached ( insn ) ; return is_short ? s_tmpl : l_tmpl ; } </s>

Select between the instruction output templates s_tmpl ( for short INSNs ) and l_tmpl ( for long INSNs ) .


<s> void arc_split_compare_and_swap ( rtx operands [ ] ) { rtx rval , mem , oldval , newval ; machine_mode mode ; enum memmodel mod_s , mod_f ; bool is_weak ; rtx label1 , label2 , x , cond ; rval = operands [ 0 ] ; mem = operands [ 1 ] ; oldval = operands [ 2 ] ; newval = operands [ 3 ] ; is_weak = ( operands [ 4 ] != const0_rtx ) ; mod_s = ( enum memmodel ) INTVAL ( operands [ 5 ] ) ; mod_f = ( enum memmodel ) INTVAL ( operands [ 6 ] ) ; mode = GET_MODE ( mem ) ; gcc_assert ( mode == SImode ) ; arc_pre_atomic_barrier ( mod_s ) ; label1 = NULL_RTX ; if ( ! is_weak ) { label1 = gen_label_rtx ( ) ; emit_label ( label1 ) ; } label2 = gen_label_rtx ( ) ; emit_insn ( gen_arc_load_exclusivesi ( rval , mem ) ) ; mode = SELECT_CC_MODE ( NE , rval , oldval ) ; cond = gen_rtx_REG ( mode , CC_REG ) ; emit_insn ( gen_rtx_SET ( cond , gen_rtx_COMPARE ( mode , rval , oldval ) ) ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label2 ) , pc_rtx ) ; emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; emit_insn ( gen_arc_store_exclusivesi ( mem , newval ) ) ; if ( ! is_weak ) { cond = gen_rtx_REG ( CC_Zmode , CC_REG ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label1 ) , pc_rtx ) ; emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; } if ( mod_f != MEMMODEL_RELAXED ) emit_label ( label2 ) ; arc_post_atomic_barrier ( mod_s ) ; if ( mod_f == MEMMODEL_RELAXED ) emit_label ( label2 ) ; } </s>

Helper function used by the `` atomic_compare_and_swapsi_1 '' pattern .


<s> void arc_split_ior ( rtx * operands ) { unsigned HOST_WIDE_INT mask , maskx ; rtx op1 = operands [ 1 ] ; gcc_assert ( CONST_INT_P ( operands [ 2 ] ) ) ; mask = INTVAL ( operands [ 2 ] ) & 0xffffffff ; if ( __builtin_popcount ( mask ) > 3 || ( mask & 0x3f ) ) { maskx = mask & 0x3f ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , op1 , GEN_INT ( maskx ) ) ) ) ; op1 = operands [ 0 ] ; mask &= ~ maskx ; } switch ( __builtin_popcount ( mask ) ) { case 3 : maskx = 1 << ( __builtin_ffs ( mask ) - 1 ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , op1 , GEN_INT ( maskx ) ) ) ) ; mask &= ~ maskx ; op1 = operands [ 0 ] ; case 2 : maskx = 1 << ( __builtin_ffs ( mask ) - 1 ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , op1 , GEN_INT ( maskx ) ) ) ) ; mask &= ~ maskx ; op1 = operands [ 0 ] ; case 1 : maskx = 1 << ( __builtin_ffs ( mask ) - 1 ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , op1 , GEN_INT ( maskx ) ) ) ) ; break ; case 0 : break ; default : gcc_unreachable ( ) ; } } </s>

Split an OR instruction into multiple BSET/OR instructions in a attempt to avoid long immediate constants . The next strategies are employed when destination is ' q ' reg . 1. if there are up to three bits set in the mask , a succession of three bset instruction will be emitted : OR rA , rB , mask - > BSET ( _S ) rA , rB , mask1/BSET_S rA , rA , mask2/BSET_S rA , rA , mask3 2. if the lower 6 bits of the mask is set and there is only one bit set in the upper remaining bits then we will emit one bset and one OR instruction : OR rA , rB , mask - > OR rA , rB , mask1/BSET_S rA , mask2 3. otherwise an OR with limm will be emmitted .


<s> bool arc_split_move_p ( rtx * operands ) { machine_mode mode = GET_MODE ( operands [ 0 ] ) ; if ( TARGET_LL64 && ( ( memory_operand ( operands [ 0 ] , mode ) && ( even_register_operand ( operands [ 1 ] , mode ) || satisfies_constraint_Cm3 ( operands [ 1 ] ) ) ) || ( memory_operand ( operands [ 1 ] , mode ) && even_register_operand ( operands [ 0 ] , mode ) ) ) ) return false ; if ( TARGET_PLUS_QMACW && even_register_operand ( operands [ 0 ] , mode ) && even_register_operand ( operands [ 1 ] , mode ) ) return false ; return true ; } </s>

Check if we need to split a 64bit move . We do not need to split it if we can use vadd2 or ldd/std instructions .


<s> bool arc_split_mov_const ( rtx * operands ) { unsigned HOST_WIDE_INT ival ; HOST_WIDE_INT shimm ; machine_mode mode = GET_MODE ( operands [ 0 ] ) ; gcc_assert ( CONST_INT_P ( operands [ 1 ] ) ) ; ival = INTVAL ( operands [ 1 ] ) & 0xffffffff ; if ( TARGET_BARREL_SHIFTER && TARGET_V2 && ( ( ival & ~ 0x3f000000 ) == 0 ) ) { shimm = ( ival >> 24 ) & 0x3f ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_ROTATERT ( mode , GEN_INT ( shimm ) , GEN_INT ( 8 ) ) ) ) ; return true ; } if ( TARGET_BARREL_SHIFTER && TARGET_V2 && ( ( ival & ~ 0x3f00 ) == 0 ) ) { shimm = ( ival >> 8 ) & 0x3f ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_ASHIFT ( mode , GEN_INT ( shimm ) , GEN_INT ( 8 ) ) ) ) ; return true ; } if ( TARGET_BARREL_SHIFTER && TARGET_V2 && ( ( ival & ~ 0x3f0000 ) == 0 ) ) { shimm = ( ival >> 16 ) & 0x3f ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_ASHIFT ( mode , GEN_INT ( shimm ) , GEN_INT ( 16 ) ) ) ) ; return true ; } if ( ( ( ival >> ( __builtin_ffs ( ival ) - 1 ) ) & 0xffffff00 ) == 0 && TARGET_BARREL_SHIFTER ) { HOST_WIDE_INT shift = __builtin_ffs ( ival ) ; shimm = ( ival >> ( shift - 1 ) ) & 0xff ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , GEN_INT ( shimm ) ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_ASHIFT ( mode , operands [ 0 ] , GEN_INT ( shift - 1 ) ) ) ) ; return true ; } if ( ( ival & ~ 0x8000001f ) == 0 ) { shimm = ( ival * 2 + 1 ) & 0x3f ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_ROTATERT ( mode , GEN_INT ( shimm ) , const1_rtx ) ) ) ; return true ; } if ( IS_POWEROF2_P ( ival + 1 ) ) { emit_insn ( gen_rtx_SET ( operands [ 0 ] , constm1_rtx ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_AND ( mode , operands [ 0 ] , GEN_INT ( ival ) ) ) ) ; return true ; } gcc_unreachable ( ) ; } </s>

Split a mov with long immediate instruction into smaller , size friendly instructions .


<s> static bool arc_store_addr_hazard_internal_p ( rtx_insn * producer , rtx_insn * consumer ) { rtx in_set , out_set ; rtx out_addr , in_addr ; if ( ! producer ) return false ; if ( ! consumer ) return false ; out_set = single_set ( producer ) ; if ( out_set ) { out_addr = SET_DEST ( out_set ) ; if ( ! out_addr ) return false ; if ( GET_CODE ( out_addr ) == ZERO_EXTEND || GET_CODE ( out_addr ) == SIGN_EXTEND ) out_addr = XEXP ( out_addr , 0 ) ; if ( ! MEM_P ( out_addr ) ) return false ; in_set = single_set ( consumer ) ; if ( in_set ) { in_addr = SET_SRC ( in_set ) ; if ( ! in_addr ) return false ; if ( GET_CODE ( in_addr ) == ZERO_EXTEND || GET_CODE ( in_addr ) == SIGN_EXTEND ) in_addr = XEXP ( in_addr , 0 ) ; if ( ! MEM_P ( in_addr ) ) return false ; in_addr = XEXP ( in_addr , 0 ) ; out_addr = XEXP ( out_addr , 0 ) ; return exp_equiv_p ( in_addr , out_addr , 0 , true ) ; } } return false ; } </s>

Return true if a load instruction ( CONSUMER ) uses the same address as a store instruction ( PRODUCER ) . This function is used to avoid st/ld address hazard in ARC700 cores .


<s> bool arc_store_addr_hazard_p ( rtx_insn * producer , rtx_insn * consumer ) { if ( TARGET_ARC700 && ( arc_tune != ARC_TUNE_ARC7XX ) ) return true ; return arc_store_addr_hazard_internal_p ( producer , consumer ) ; } </s>


<s> static bool arc_symbol_binds_local_p ( const_rtx x ) { return ( SYMBOL_REF_DECL ( x ) ? targetm . binds_local_p ( SYMBOL_REF_DECL ( x ) ) : SYMBOL_REF_LOCAL_P ( x ) ) ; } </s>

Return true if SYMBOL_REF X binds locally .


<s> bool arc_text_label ( rtx_insn * label ) { rtx_insn * next ; gcc_assert ( GET_CODE ( label ) == CODE_LABEL || ( GET_CODE ( label ) == NOTE && NOTE_KIND ( label ) == NOTE_INSN_DELETED_LABEL ) ) ; next = next_nonnote_insn ( label ) ; if ( next ) return ( ! JUMP_TABLE_DATA_P ( next ) || GET_CODE ( PATTERN ( next ) ) != ADDR_VEC ) ; else if ( ! PREV_INSN ( label ) ) return true ; return false ; } </s>

Return true if LABEL is in executable code .


<s> static char * arc_tolower ( char * lo , const char * up ) { char * lo0 = lo ; for ( ; * up ; up ++ , lo ++ ) * lo = TOLOWER ( * up ) ; * lo = '\0' ; return lo0 ; } </s>

Transform UP into lowercase and write the result to LO . You must provide enough space for LO . Return LO .


<s> int arc_unalign_branch_p ( rtx branch ) { rtx note ; if ( ! TARGET_UNALIGN_BRANCH ) return 0 ; if ( get_attr_delay_slot_filled ( branch ) == DELAY_SLOT_FILLED_YES && ! NEXT_INSN ( branch ) -> deleted ( ) ) return 0 ; note = find_reg_note ( branch , REG_BR_PROB , 0 ) ; return ( ! note || ( arc_unalign_prob_threshold && ! br_prob_note_reliable_p ( note ) ) || INTVAL ( XEXP ( note , 0 ) ) < arc_unalign_prob_threshold ) ; } </s>

Return nonzero iff BRANCH should be unaligned if possible by upsizing a previous instruction .


<s> static rtx arc_unspec_offset ( rtx loc , int unspec ) { return gen_rtx_CONST ( Pmode , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , loc ) , unspec ) ) ; } </s>


<s> static bool arc_use_anchors_for_symbol_p ( const_rtx symbol ) { if ( SYMBOL_REF_TLS_MODEL ( symbol ) ) return false ; if ( flag_pic ) return false ; if ( SYMBOL_REF_SMALL_P ( symbol ) ) return false ; return default_use_anchors_for_symbol_p ( symbol ) ; } </s>

Implement TARGET_USE_ANCHORS_FOR_SYMBOL_P . We do n't want to use anchors for small data : the GP register acts as an anchor in that case . We also do n't want to use them for PC-relative accesses , where the PC acts as an anchor . Prohibit also TLS symbols to use anchors .


<s> static bool arc_use_by_pieces_infrastructure_p ( unsigned HOST_WIDE_INT size , unsigned int align , enum by_pieces_operation op , bool speed_p ) { if ( op == MOVE_BY_PIECES ) return false ; return default_use_by_pieces_infrastructure_p ( size , align , op , speed_p ) ; } </s>


<s> static bool arc_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case E_V2HImode : return TARGET_PLUS_DMPY ; case E_V4HImode : case E_V2SImode : return TARGET_PLUS_QMACW ; case E_V4SImode : case E_V8HImode : return TARGET_SIMD_SET ; default : return false ; } } </s>

Implements target hook vector_mode_supported_p .


<s> static int arc_verify_short ( rtx_insn * insn , int , int check_attr ) { enum attr_iscompact iscompact ; if ( check_attr > 0 ) { iscompact = get_attr_iscompact ( insn ) ; if ( iscompact == ISCOMPACT_FALSE ) return 0 ; } return ( get_attr_length ( insn ) & 2 ) != 0 ; } </s>

Return non-zero if INSN should be output as a short insn . UNALIGN is zero if the current insn is aligned to a 4-byte-boundary , two otherwise . If CHECK_ATTR is greater than 0 , check the iscompact attribute first .


<s> static bool arc_warn_func_return ( tree decl ) { struct function * func = DECL_STRUCT_FUNCTION ( decl ) ; unsigned int fn_type = arc_compute_function_type ( func ) ; return ! ARC_NAKED_P ( fn_type ) ; } </s>


<s> int arc_write_ext_corereg ( rtx insn ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , PATTERN ( insn ) , NONCONST ) { const_rtx x = * iter ; switch ( GET_CODE ( x ) ) { case SET : case POST_INC : case POST_DEC : case PRE_INC : case PRE_DEC : break ; default : continue ; } const_rtx dest = XEXP ( x , 0 ) ; if ( REG_P ( dest ) && REGNO ( dest ) >= 32 && REGNO ( dest ) < 61 ) return 1 ; } return 0 ; } </s>

Return nonzreo iff INSN writes to an extension core register .


<s> static int branch_dest ( rtx branch ) { rtx pat = PATTERN ( branch ) ; rtx dest = ( GET_CODE ( pat ) == PARALLEL ? SET_SRC ( XVECEXP ( pat , 0 , 0 ) ) : SET_SRC ( pat ) ) ; int dest_uid ; if ( GET_CODE ( dest ) == IF_THEN_ELSE ) dest = XEXP ( dest , XEXP ( dest , 1 ) == pc_rtx ? 2 : 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 .


"register number must be a compile-time constant.  "

Returns true if the operands [ opno ] is a valid compile-time constant to be used as register number in the code for builtins . Else it flags an error and returns false .


<s> static void check_store_cacheline_hazard ( void ) { rtx_insn * insn , * succ0 , * insn1 ; bool found = false ; for ( insn = get_insns ( ) ; insn ; insn = arc_active_insn ( insn ) ) { succ0 = arc_active_insn ( insn ) ; if ( ! succ0 ) return ; if ( ! single_set ( insn ) ) continue ; if ( ( get_attr_type ( insn ) != TYPE_STORE ) ) continue ; for ( insn1 = succ0 ; insn1 ; insn1 = arc_active_insn ( insn1 ) ) if ( ! single_set ( insn1 ) || get_attr_type ( insn1 ) != TYPE_STORE ) break ; succ0 = insn1 ; if ( insn1 && single_set ( insn1 ) && ( get_attr_type ( insn1 ) == TYPE_LOAD ) ) { found = true ; emit_insn_before ( gen_nopv ( ) , insn1 ) ; emit_insn_before ( gen_nopv ( ) , insn1 ) ; } else { if ( insn1 && ( get_attr_type ( insn1 ) == TYPE_COMPARE ) ) { add_reg_note ( insn1 , REG_SAVE_NOTE , GEN_INT ( 3 ) ) ; } insn1 = arc_active_insn ( insn1 ) ; if ( insn1 && single_set ( insn1 ) && ( get_attr_type ( insn1 ) == TYPE_LOAD ) ) { found = true ; emit_insn_before ( gen_nopv ( ) , insn1 ) ; } } if ( found ) { insn = insn1 ; found = false ; } else insn = succ0 ; } } </s>

Search for a sequence made out of two stores and a given number of loads , insert a nop if required .


<s> bool compact_sda_memory_operand ( rtx op , machine_mode mode , bool short_p ) { rtx addr ; int size ; int align = 0 ; int mask = 0 ; if ( GET_CODE ( op ) != MEM ) return false ; if ( mode == VOIDmode ) mode = GET_MODE ( op ) ; size = GET_MODE_SIZE ( mode ) ; if ( size > UNITS_PER_WORD ) return false ; addr = XEXP ( op , 0 ) ; if ( ! legitimate_small_data_address_p ( addr , mode ) ) return false ; if ( ! short_p || size == 1 ) return true ; align = get_symbol_alignment ( addr ) ; switch ( mode ) { case E_HImode : mask = 1 ; break ; default : mask = 3 ; break ; } if ( align && ( ( align & mask ) == 0 ) ) return true ; return false ; } </s>

volatile cache option still to be handled .


<s> static rtx conditionalize_nonjump ( rtx pat , rtx cond , rtx insn , bool annulled ) { if ( GET_CODE ( pat ) == SET ) { rtx src = SET_SRC ( pat ) ; if ( COMMUTATIVE_P ( src ) ) { rtx src0 = XEXP ( src , 0 ) ; rtx src1 = XEXP ( src , 1 ) ; rtx dst = SET_DEST ( pat ) ; if ( rtx_equal_p ( src1 , dst ) && ! rtx_equal_p ( src0 , dst ) && REG_P ( src0 ) ) pat = gen_rtx_SET ( dst , gen_rtx_fmt_ee ( GET_CODE ( src ) , GET_MODE ( src ) , src1 , src0 ) ) ; } } if ( RTX_FRAME_RELATED_P ( insn ) ) { gcc_assert ( annulled ) ; rtx note = alloc_reg_note ( REG_FRAME_RELATED_EXPR , pat , REG_NOTES ( insn ) ) ; validate_change ( insn , & REG_NOTES ( insn ) , note , 1 ) ; } pat = gen_rtx_COND_EXEC ( VOIDmode , cond , pat ) ; return pat ; } </s>

Return version of PAT conditionalized with COND , which is part of INSN . ANNULLED indicates if INSN is an annulled delay-slot insn . Register further changes if necessary .


<s> rtx disi_highpart ( rtx in ) { return simplify_gen_subreg ( SImode , in , DImode , TARGET_BIG_ENDIAN ? 0 : 4 ) ; } </s>

Return the SImode highpart of the DImode value IN .


<s> void emit_shift ( enum rtx_code code , rtx op0 , rtx op1 , rtx op2 ) { rtx shift = gen_rtx_fmt_ee ( code , SImode , op1 , op2 ) ; rtx pat = ( ( shift4_operator ( shift , SImode ) ? gen_shift_si3 : gen_shift_si3_loop ) ( op0 , op1 , op2 , shift ) ) ; emit_insn ( pat ) ; } </s>

Emit a shift insn to set OP0 to OP1 shifted by OP2 ; CODE specifies what kind of shift .


<s> static void emit_unlikely_jump ( rtx insn ) { rtx_insn * jump = emit_jump_insn ( insn ) ; add_reg_br_prob_note ( jump , profile_probability :: very_unlikely ( ) ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> virtual unsigned int execute ( function * ) { return arc_predicate_delay_insns ( ) ; } </s>


<s> static rtx frame_add ( rtx reg , HOST_WIDE_INT offset ) { gcc_assert ( ( offset & 0x3 ) == 0 ) ; if ( ! offset ) return NULL_RTX ; return frame_move ( reg , plus_constant ( Pmode , reg , offset ) ) ; } </s>

Emit a frame insn which adjusts a frame address register REG by OFFSET .


<s> static rtx frame_insn ( rtx x ) { x = emit_insn ( x ) ; RTX_FRAME_RELATED_P ( x ) = 1 ; return x ; } </s>

Emit the specified insn and mark it as frame related . FIXME : Rename this to emit_frame_insn .


<s> static rtx frame_move ( rtx dst , rtx src ) { rtx tmp = gen_rtx_SET ( dst , src ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; return frame_insn ( tmp ) ; } </s>


<s> static rtx frame_move_inc ( rtx dst , rtx src , rtx reg , rtx addr ) { rtx insn = frame_move ( dst , src ) ; if ( ! addr || GET_CODE ( addr ) == PRE_DEC || GET_CODE ( addr ) == POST_INC || GET_CODE ( addr ) == PRE_MODIFY || GET_CODE ( addr ) == POST_MODIFY ) add_reg_note ( insn , REG_INC , reg ) ; return insn ; } </s>

Like frame_move , but add a REG_INC note for REG if ADDR contains an auto increment address , or is zero .


<s> static int frame_restore_reg ( rtx reg , HOST_WIDE_INT offset ) { rtx addr , insn ; if ( offset ) { rtx tmp = plus_constant ( Pmode , stack_pointer_rtx , offset + GET_MODE_SIZE ( GET_MODE ( reg ) ) ) ; addr = gen_frame_mem ( GET_MODE ( reg ) , gen_rtx_POST_MODIFY ( Pmode , stack_pointer_rtx , tmp ) ) ; } else addr = gen_frame_mem ( GET_MODE ( reg ) , gen_rtx_POST_INC ( Pmode , stack_pointer_rtx ) ) ; insn = frame_move_inc ( reg , addr , stack_pointer_rtx , 0 ) ; add_reg_note ( insn , REG_CFA_RESTORE , reg ) ; if ( reg == hard_frame_pointer_rtx ) add_reg_note ( insn , REG_CFA_DEF_CFA , plus_constant ( Pmode , stack_pointer_rtx , GET_MODE_SIZE ( GET_MODE ( reg ) ) + offset ) ) ; else add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , GET_MODE_SIZE ( GET_MODE ( reg ) ) + offset ) ) ) ; return GET_MODE_SIZE ( GET_MODE ( reg ) ) + offset ; } </s>

Helper for epilogue : emit frame load with post_modify or post_inc to restore register REG from stack . The initial offset is passed via OFFSET .


<s> static int frame_save_reg ( rtx reg , HOST_WIDE_INT offset ) { rtx addr ; if ( offset ) { rtx tmp = plus_constant ( Pmode , stack_pointer_rtx , offset - GET_MODE_SIZE ( GET_MODE ( reg ) ) ) ; addr = gen_frame_mem ( GET_MODE ( reg ) , gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , tmp ) ) ; } else addr = gen_frame_mem ( GET_MODE ( reg ) , gen_rtx_PRE_DEC ( Pmode , stack_pointer_rtx ) ) ; frame_move_inc ( addr , reg , stack_pointer_rtx , 0 ) ; return GET_MODE_SIZE ( GET_MODE ( reg ) ) - offset ; } </s>

Helper for prologue : emit frame store with pre_modify or pre_dec to save register REG on stack . An initial offset OFFSET can be passed to the function .


<s> static rtx frame_stack_add ( HOST_WIDE_INT offset ) { return frame_add ( stack_pointer_rtx , offset ) ; } </s>

Emit a frame insn which adjusts stack pointer by OFFSET .


<s> rtx gen_acc1 ( void ) { return gen_rtx_REG ( SImode , TARGET_BIG_ENDIAN ? 56 : 57 ) ; } </s>

Return a REG rtx for acc1 . N.B . the gcc-internal representation may differ from the hardware register number in order to allow the generic code to correctly split the concatenation of acc1 and acc2 .


<s> rtx gen_acc2 ( void ) { return gen_rtx_REG ( SImode , TARGET_BIG_ENDIAN ? 57 : 56 ) ; } </s>

Return a REG rtx for acc2 . N.B . the gcc-internal representation may differ from the hardware register number in order to allow the generic code to correctly split the concatenation of acc1 and acc2 .