<s> bool prepare_move_operands ( rtx * operands , machine_mode mode ) { if ( 1 ) { if ( ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 0 ] , Pmode ) ) operands [ 0 ] = arc_rewrite_small_data ( operands [ 0 ] ) ; else if ( mode == SImode && flag_pic && SYMBOLIC_CONST ( operands [ 1 ] ) ) { emit_pic_move ( operands , SImode ) ; } else if ( GET_CODE ( operands [ 0 ] ) != MEM && ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 1 ] , Pmode ) ) { operands [ 1 ] = arc_rewrite_small_data ( operands [ 1 ] ) ; emit_insn ( gen_rtx_SET ( mode , operands [ 0 ] , operands [ 1 ] ) ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , operands [ 1 ] ) ; emit_move_insn ( operands [ 0 ] , operands [ 0 ] ) ; return true ; } } if ( MEM_P ( operands [ 0 ] ) && ! ( reload_in_progress || reload_completed ) ) { operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; if ( ! move_dest_operand ( operands [ 0 ] , mode ) ) { rtx addr = copy_to_mode_reg ( Pmode , XEXP ( operands [ 0 ] , 0 ) ) ; rtx pat = change_address ( operands [ 0 ] , mode , addr ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } if ( ! cse_not_expected ) { rtx pat = XEXP ( operands [ 0 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 0 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } } } if ( MEM_P ( operands [ 1 ] ) && ! cse_not_expected ) { rtx pat = XEXP ( operands [ 1 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 1 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 1 ] ) ; operands [ 1 ] = pat ; } } return false ; } </s>

Prepare operands for a move define_expand in MODE .


<s> bool small_data_pattern ( rtx op , machine_mode ) { if ( GET_CODE ( op ) == SEQUENCE ) return false ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , op , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == PLUS && rtx_equal_p ( XEXP ( x , 0 ) , pic_offset_table_rtx ) ) iter . skip_subrtxes ( ) ; else if ( arc_rewrite_small_data_p ( x ) ) return true ; } return false ; } </s>

Return true if OP refers to small data symbols directly , not through a PLUS .


<s> static hashval_t unspec_prof_hash ( const void * x ) { const_rtx u = ( const_rtx ) x ; const_rtx s1 = XVECEXP ( u , 0 , 1 ) ; return ( htab_hash_string ( XSTR ( XVECEXP ( u , 0 , 0 ) , 0 ) ) ^ ( s1 -> code == SYMBOL_REF ? htab_hash_string ( XSTR ( s1 , 0 ) ) : 0 ) ) ; } </s>

Hash function for UNSPEC_PROF htab . Use both the caller 's name and the callee 's name ( if known ) .


<s> static int unspec_prof_htab_eq ( const void * x , const void * y ) { const_rtx u0 = ( const_rtx ) x ; const_rtx u1 = ( const_rtx ) y ; const_rtx s01 = XVECEXP ( u0 , 0 , 1 ) ; const_rtx s11 = XVECEXP ( u1 , 0 , 1 ) ; return ( ! strcmp ( XSTR ( XVECEXP ( u0 , 0 , 0 ) , 0 ) , XSTR ( XVECEXP ( u1 , 0 , 0 ) , 0 ) ) && rtx_equal_p ( s01 , s11 ) ) ; } </s>

Equality function for UNSPEC_PROF htab . Two pieces of UNSPEC_PROF rtl shall refer to the same counter if both caller name and callee rtl are identical .


Called via walk_stores . DATA points to a hash table we can use to establish a unique SYMBOL_REF for each counter , which corresponds to a caller-callee pair . X is a store which we want to examine for an UNSPEC_PROF , which would be an address loaded into a register , or directly used in a MEM . If we found an UNSPEC_PROF , if we encounter a new counter the first time , write out a description and a data allocation for a 32 bit counter . Also , fill in the appropriate symbol_ref into each UNSPEC_PROF instance .


<s> enum arc_function_type arc_compute_function_type ( struct function * fun ) { tree decl = fun -> decl ; tree a ; enum arc_function_type fn_type = fun -> machine -> fn_type ; if ( fn_type != ARC_FUNCTION_UNKNOWN ) return fn_type ; fn_type = ARC_FUNCTION_NORMAL ; for ( a = DECL_ATTRIBUTES ( decl ) ; a ; a = TREE_CHAIN ( a ) ) { tree name = TREE_PURPOSE ( a ) , args = TREE_VALUE ( a ) ; if ( name == get_identifier ( "interrupt" ) && list_length ( args ) == 1 && TREE_CODE ( TREE_VALUE ( args ) ) == STRING_CST ) { tree value = TREE_VALUE ( args ) ; 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 gcc_unreachable ( ) ; break ; } } 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 rtx arc_dwarf_register_span ( rtx rtl ) { enum 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 .


"__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> bool arc_expand_movmem ( rtx * operands ) { rtx dst = operands [ 0 ] ; rtx src = operands [ 1 ] ; rtx dst_addr , src_addr ; HOST_WIDE_INT size ; int align = INTVAL ( operands [ 3 ] ) ; unsigned n_pieces ; int piece = align ; rtx store [ 2 ] ; rtx tmpx [ 2 ] ; int i ; if ( ! CONST_INT_P ( operands [ 2 ] ) ) return false ; size = INTVAL ( operands [ 2 ] ) ; if ( align >= 4 ) { if ( TARGET_LL64 ) n_pieces = ( size + 4 ) / 8U + ( ( size >> 1 ) & 1 ) + ( size & 1 ) ; else n_pieces = ( size + 2 ) / 4U + ( size & 1 ) ; } else if ( align == 2 ) n_pieces = ( size + 1 ) / 2U ; else n_pieces = size ; if ( n_pieces >= ( unsigned int ) ( optimize_size ? 3 : 15 ) ) return false ; if ( TARGET_LL64 && ( piece >= 4 ) && ( size >= 8 ) ) piece = 8 ; else if ( piece > 4 ) piece = 4 ; dst_addr = force_offsettable ( XEXP ( operands [ 0 ] , 0 ) , size , 0 ) ; src_addr = force_offsettable ( XEXP ( operands [ 1 ] , 0 ) , size , 0 ) ; store [ 0 ] = store [ 1 ] = NULL_RTX ; tmpx [ 0 ] = tmpx [ 1 ] = NULL_RTX ; for ( i = 0 ; size > 0 ; i ^= 1 , size -= piece ) { rtx tmp ; machine_mode mode ; while ( piece > size ) piece >>= 1 ; mode = smallest_mode_for_size ( piece * BITS_PER_UNIT , MODE_INT ) ; if ( 0 && tmpx [ i ] && GET_MODE ( tmpx [ i ] ) == mode ) tmp = tmpx [ i ] ; else tmpx [ i ] = tmp = gen_reg_rtx ( mode ) ; dst_addr = force_offsettable ( dst_addr , piece , 1 ) ; src_addr = force_offsettable ( src_addr , piece , 1 ) ; if ( store [ i ] ) emit_insn ( store [ i ] ) ; emit_move_insn ( tmp , change_address ( src , mode , src_addr ) ) ; store [ i ] = gen_move_insn ( change_address ( dst , mode , dst_addr ) , tmp ) ; dst_addr = plus_constant ( Pmode , dst_addr , piece ) ; src_addr = plus_constant ( Pmode , src_addr , piece ) ; } if ( store [ i ] ) emit_insn ( store [ i ] ) ; if ( store [ i ^ 1 ] ) emit_insn ( store [ i ^ 1 ] ) ; return true ; } </s>

Like move_by_pieces , but take account of load latency , and actual offset ranges . Return true on success .


<s> static void arc_finalize_pic ( void ) { rtx pat ; rtx baseptr_rtx = gen_rtx_REG ( Pmode , PIC_OFFSET_TABLE_REGNUM ) ; if ( crtl -> uses_pic_offset_table == 0 ) return ; gcc_assert ( flag_pic != 0 ) ; pat = gen_rtx_SYMBOL_REF ( Pmode , "_DYNAMIC" ) ; pat = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , pat ) , ARC_UNSPEC_GOT ) ; pat = gen_rtx_CONST ( Pmode , pat ) ; pat = gen_rtx_SET ( baseptr_rtx , pat ) ; emit_insn ( pat ) ; } </s>

If the function has any GOTOFF relocations , then the GOTBASE register has to be setup in the prologue The instruction needed at the function start for setting up the GOTBASE register is add rdest , pc , -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- The rtl to be emitted for this should be : set ( reg basereg ) ( plus ( reg pc ) ( const ( unspec ( symref _DYNAMIC ) 3 ) ) ) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --


"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\""

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


<s> int arc_hazard ( rtx_insn * pred , rtx_insn * succ ) { if ( ! pred || ! INSN_P ( pred ) || ! succ || ! INSN_P ( succ ) ) return 0 ; if ( arc_loop_hazard ( pred , succ ) ) return 4 ; 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 .


<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 : 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_FPU_UNEQmode ) arc_mode_class [ i ] = 1 << ( int ) C_MODE ; else arc_mode_class [ i ] = 0 ; break ; } } } </s>


<s> static void arc_override_options ( void ) { if ( arc_cpu == PROCESSOR_NONE ) arc_cpu = PROCESSOR_ARC700 ; if ( arc_size_opt_level == 3 ) optimize_size = 1 ; if ( flag_pic ) target_flags |= MASK_NO_SDATA_SET ; if ( flag_no_common == 255 ) flag_no_common = ! TARGET_NO_SDATA_SET ; if ( TARGET_MIXED_CODE ) TARGET_Q_CLASS = 1 ; if ( ! TARGET_Q_CLASS ) TARGET_COMPACT_CASESI = 0 ; if ( TARGET_COMPACT_CASESI ) TARGET_CASE_VECTOR_PC_RELATIVE = 1 ; arc_init ( ) ; } </s>

Check ARC options , generate derived target attributes .


<s> void arc_print_operand_address ( FILE * file , rtx addr ) { register rtx base , index = 0 ; switch ( GET_CODE ( addr ) ) { case REG : fputs ( reg_names [ REGNO ( addr ) ] , file ) ; break ; case SYMBOL_REF : output_addr_const ( file , addr ) ; if ( SYMBOL_REF_SMALL_P ( addr ) ) fprintf ( file , "@sda" ) ; 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 ) ; 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 ) { rtx dest = operands [ 0 ] ; rtx src = operands [ 1 ] ; enum usesDxState { none , srcDx , destDx , maxDx } ; enum usesDxState state = none ; if ( refers_to_regno_p ( 40 , 44 , src , 0 ) ) state = srcDx ; if ( refers_to_regno_p ( 40 , 44 , dest , 0 ) ) { 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 , 4 ) ; rtx destLow = simplify_gen_subreg ( SImode , dest , DFmode , 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 , 4 ) ; rtx srcLow = simplify_gen_subreg ( SImode , src , DFmode , 0 ) ; emit_insn ( gen_rtx_UNSPEC_VOLATILE ( Pmode , gen_rtvec ( 3 , dest , srcHigh , srcLow ) , VUNSPEC_ARC_DEXCL_NORES ) ) ; } else gcc_unreachable ( ) ; return true ; } </s>

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


<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 ( ( cl == LPCOUNT_REG || cl == WRITABLE_CORE_REGS ) && in_p && MEM_P ( x ) ) 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 ( 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 QImode : sri -> icode = in_p ? CODE_FOR_reload_qi_load : CODE_FOR_reload_qi_store ; break ; case 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> static void arc_setup_incoming_varargs ( cumulative_args_t args_so_far , machine_mode mode , tree type , 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 ) , mode , type , true ) ; 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> void arc_split_move ( rtx * operands ) { machine_mode mode = GET_MODE ( operands [ 0 ] ) ; int i ; int swap = 0 ; rtx xop [ 4 ] ; if ( TARGET_DPFP ) { if ( arc_process_double_reg_moves ( operands ) ) return ; } if ( TARGET_LL64 && ( ( memory_operand ( operands [ 0 ] , mode ) && even_register_operand ( operands [ 1 ] , mode ) ) || ( memory_operand ( operands [ 1 ] , mode ) && even_register_operand ( operands [ 0 ] , mode ) ) ) ) { emit_move_insn ( operands [ 0 ] , operands [ 1 ] ) ; return ; } for ( i = 0 ; i < 2 ; i ++ ) { if ( MEM_P ( operands [ i ] ) && auto_inc_p ( XEXP ( operands [ i ] , 0 ) ) ) { rtx addr = XEXP ( operands [ i ] , 0 ) ; rtx r , o ; enum rtx_code code ; gcc_assert ( ! reg_overlap_mentioned_p ( operands [ 0 ] , addr ) ) ; switch ( GET_CODE ( addr ) ) { case PRE_DEC : o = GEN_INT ( - 8 ) ; goto pre_modify ; case PRE_INC : o = GEN_INT ( 8 ) ; goto pre_modify ; case PRE_MODIFY : o = XEXP ( XEXP ( addr , 1 ) , 1 ) ; pre_modify : code = PRE_MODIFY ; break ; case POST_DEC : o = GEN_INT ( - 8 ) ; goto post_modify ; case POST_INC : o = GEN_INT ( 8 ) ; goto post_modify ; case POST_MODIFY : o = XEXP ( XEXP ( addr , 1 ) , 1 ) ; post_modify : code = POST_MODIFY ; swap = 2 ; break ; default : gcc_unreachable ( ) ; } r = XEXP ( addr , 0 ) ; xop [ 0 + i ] = adjust_automodify_address_nv ( operands [ i ] , SImode , gen_rtx_fmt_ee ( code , Pmode , r , gen_rtx_PLUS ( Pmode , r , o ) ) , 0 ) ; xop [ 2 + i ] = adjust_automodify_address_nv ( operands [ i ] , SImode , plus_constant ( Pmode , r , 4 ) , 4 ) ; } else { xop [ 0 + i ] = operand_subword ( operands [ i ] , 0 , 0 , mode ) ; xop [ 2 + i ] = operand_subword ( operands [ i ] , 1 , 0 , mode ) ; } } if ( reg_overlap_mentioned_p ( xop [ 0 ] , xop [ 3 ] ) ) { swap = 2 ; gcc_assert ( ! reg_overlap_mentioned_p ( xop [ 2 ] , xop [ 1 ] ) ) ; } emit_move_insn ( xop [ 0 + swap ] , xop [ 1 + swap ] ) ; emit_move_insn ( xop [ 2 - swap ] , xop [ 3 - swap ] ) ; } </s>

operands 0 .. 1 are the operands of a 64 bit move instruction . split it into two moves with operands 2/3 and 4/5 .


<s> static void emit_unlikely_jump ( rtx insn ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; insn = emit_jump_insn ( insn ) ; add_int_reg_note ( insn , REG_BR_PROB , very_unlikely ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> bool prepare_extend_operands ( rtx * operands , enum rtx_code code , machine_mode omode ) { if ( ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 1 ] , Pmode ) ) { operands [ 1 ] = gen_rtx_fmt_e ( code , omode , arc_rewrite_small_data ( operands [ 1 ] ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , operands [ 1 ] ) ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , operands [ 1 ] ) ; emit_move_insn ( operands [ 0 ] , operands [ 0 ] ) ; return true ; } return false ; } </s>

Prepare OPERANDS for an extension using CODE to OMODE . Return true iff the move has been emitted .


<s> bool prepare_move_operands ( rtx * operands , machine_mode mode ) { if ( 1 ) { if ( ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 0 ] , Pmode ) ) operands [ 0 ] = arc_rewrite_small_data ( operands [ 0 ] ) ; else if ( mode == SImode && flag_pic && SYMBOLIC_CONST ( operands [ 1 ] ) ) { emit_pic_move ( operands , SImode ) ; } else if ( GET_CODE ( operands [ 0 ] ) != MEM && ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 1 ] , Pmode ) ) { operands [ 1 ] = arc_rewrite_small_data ( operands [ 1 ] ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , operands [ 1 ] ) ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , operands [ 1 ] ) ; emit_move_insn ( operands [ 0 ] , operands [ 0 ] ) ; return true ; } } if ( MEM_P ( operands [ 0 ] ) && ! ( reload_in_progress || reload_completed ) ) { operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; if ( ! move_dest_operand ( operands [ 0 ] , mode ) ) { rtx addr = copy_to_mode_reg ( Pmode , XEXP ( operands [ 0 ] , 0 ) ) ; rtx pat = change_address ( operands [ 0 ] , mode , addr ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } if ( ! cse_not_expected ) { rtx pat = XEXP ( operands [ 0 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 0 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } } } if ( MEM_P ( operands [ 1 ] ) && ! cse_not_expected ) { rtx pat = XEXP ( operands [ 1 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 1 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 1 ] ) ; operands [ 1 ] = pat ; } } return false ; } </s>

Prepare operands for a move define_expand in MODE .


<s> static void workaround_arc_anomaly ( void ) { rtx_insn * insn , * succ0 ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { succ0 = next_real_insn ( insn ) ; if ( arc_hazard ( insn , succ0 ) ) { emit_insn_before ( gen_nopv ( ) , succ0 ) ; } } } </s>

The same functionality as arc_hazard . It is called in machine reorg before any other optimization . Hence , the NOP size is taken into account when doing branch shortening .


<s> int arc_address_cost ( rtx addr , machine_mode , addr_space_t , bool speed ) { switch ( GET_CODE ( addr ) ) { case REG : return speed || satisfies_constraint_Rcq ( addr ) ? 0 : 1 ; case PRE_INC : case PRE_DEC : case POST_INC : case POST_DEC : case PRE_MODIFY : case POST_MODIFY : return ! speed ; case LABEL_REF : case SYMBOL_REF : case CONST : if ( TARGET_NPS_CMEM && cmem_address ( addr , SImode ) ) return 0 ; return COSTS_N_INSNS ( 1 ) ; case PLUS : { register rtx plus0 = XEXP ( addr , 0 ) ; register rtx plus1 = XEXP ( addr , 1 ) ; if ( GET_CODE ( plus0 ) != REG && ( GET_CODE ( plus0 ) != MULT || ! CONST_INT_P ( XEXP ( plus0 , 1 ) ) || ( INTVAL ( XEXP ( plus0 , 1 ) ) != 2 && INTVAL ( XEXP ( plus0 , 1 ) ) != 4 ) ) ) break ; switch ( GET_CODE ( plus1 ) ) { case CONST_INT : return ( ! RTX_OK_FOR_OFFSET_P ( SImode , plus1 ) ? COSTS_N_INSNS ( 1 ) : speed ? 0 : ( satisfies_constraint_Rcq ( plus0 ) && satisfies_constraint_O ( plus1 ) ) ? 0 : 1 ) ; case REG : return ( speed < 1 ? 0 : ( satisfies_constraint_Rcq ( plus0 ) && satisfies_constraint_Rcq ( plus1 ) ) ? 0 : 1 ) ; case CONST : case SYMBOL_REF : case LABEL_REF : return COSTS_N_INSNS ( 1 ) ; default : break ; } break ; } default : break ; } return 4 ; } </s>

Provide the costs of an addressing mode that contains ADDR . If ADDR is not a valid address , its cost is irrelevant .


<s> static unsigned int arc_autovectorize_vector_sizes ( void ) { return TARGET_PLUS_QMACW ? ( 8 | 4 ) : 0 ; } </s>


<s> static rtx arc_emit_call_tls_get_addr ( rtx sym , int reloc , rtx eqv ) { rtx r0 = gen_rtx_REG ( Pmode , R0_REG ) ; rtx call_fusage = NULL_RTX ; start_sequence ( ) ; rtx x = arc_unspec_offset ( sym , reloc ) ; emit_move_insn ( r0 , x ) ; use_reg ( & call_fusage , r0 ) ; gcc_assert ( reloc == UNSPEC_TLS_GD ) ; rtx call_insn = emit_call_insn ( gen_tls_gd_get_addr ( sym ) ) ; RTL_PURE_CALL_P ( call_insn ) = 1 ; add_function_usage_to ( call_insn , call_fusage ) ; rtx_insn * insns = get_insns ( ) ; end_sequence ( ) ; rtx dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , r0 , eqv ) ; return dest ; } </s>

Helper to be used by TLS Global dynamic model .


<s> bool arc_epilogue_uses ( int regno ) { if ( regno == arc_tp_regno ) return true ; if ( reload_completed ) { if ( ARC_INTERRUPT_P ( cfun -> machine -> fn_type ) ) { if ( ! fixed_regs [ regno ] ) return true ; return ( ( regno == arc_return_address_regs [ cfun -> machine -> fn_type ] ) || ( regno == RETURN_ADDR_REGNUM ) ) ; } else return regno == RETURN_ADDR_REGNUM ; } else return regno == arc_return_address_regs [ arc_compute_function_type ( cfun ) ] ; } </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> static void arc_finalize_pic ( void ) { rtx pat ; rtx baseptr_rtx = gen_rtx_REG ( Pmode , PIC_OFFSET_TABLE_REGNUM ) ; if ( crtl -> uses_pic_offset_table == 0 ) return ; gcc_assert ( flag_pic != 0 ) ; pat = gen_rtx_SYMBOL_REF ( Pmode , "_DYNAMIC" ) ; pat = arc_unspec_offset ( pat , ARC_UNSPEC_GOT ) ; pat = gen_rtx_SET ( baseptr_rtx , pat ) ; emit_insn ( pat ) ; } </s>


<s> static rtx arc_get_tp ( void ) { if ( arc_tp_regno != - 1 ) return gen_rtx_REG ( Pmode , arc_tp_regno ) ; rtx reg = gen_reg_rtx ( Pmode ) ; emit_insn ( gen_tls_load_tp_soft ( ) ) ; emit_move_insn ( reg , gen_rtx_REG ( Pmode , R0_REG ) ) ; return reg ; } </s>


"-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"

"PIC is not supported for %s. Generating non-PIC code only.."

Called by OVERRIDE_OPTIONS to initialize various things .


<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_FPU_UNEQmode ) arc_mode_class [ i ] = 1 << ( int ) C_MODE ; else arc_mode_class [ i ] = 0 ; break ; } } } </s>


<s> int arc_label_align ( rtx_insn * label ) { int loop_align = LOOP_ALIGN ( LABEL ) ; if ( loop_align > align_labels_log ) { rtx_insn * prev = prev_nonnote_insn ( label ) ; if ( prev && NONJUMP_INSN_P ( prev ) && GET_CODE ( PATTERN ( prev ) ) == PARALLEL && recog_memoized ( prev ) == CODE_FOR_doloop_begin_i ) return loop_align ; } if ( align_labels_log < 1 ) { rtx_insn * next = next_nonnote_nondebug_insn ( label ) ; if ( INSN_P ( next ) && recog_memoized ( next ) >= 0 ) return 1 ; } return align_labels_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 ) { if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) ) return false ; if ( ! flag_pic && mode != Pmode ) return true ; switch ( GET_CODE ( x ) ) { case CONST : x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == PLUS ) { if ( flag_pic ? GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT : ! arc_legitimate_constant_p ( mode , XEXP ( x , 1 ) ) ) return false ; x = XEXP ( x , 0 ) ; } if ( GET_CODE ( x ) == UNSPEC ) switch ( XINT ( x , 1 ) ) { case ARC_UNSPEC_PLT : case ARC_UNSPEC_GOTOFF : case ARC_UNSPEC_GOTOFFPC : case ARC_UNSPEC_GOT : case UNSPEC_TLS_GD : case UNSPEC_TLS_IE : case UNSPEC_TLS_OFF : return true ; default : gcc_unreachable ( ) ; } if ( arc_raw_symbolic_reference_mentioned_p ( x , false ) ) return false ; break ; case SYMBOL_REF : if ( SYMBOL_REF_TLS_MODEL ( x ) ) return false ; case LABEL_REF : if ( flag_pic ) return false ; default : break ; } return true ; } </s>

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


<s> bool arc_legitimate_pc_offset_p ( rtx addr ) { if ( GET_CODE ( addr ) != CONST ) return false ; return arc_needs_pcl_p ( addr ) ; } </s>

Return true if ADDR is an address that needs to be expressed as an explicit sum of pcl + offset .


<s> bool arc_legitimate_pic_addr_p ( rtx addr ) { if ( GET_CODE ( addr ) == LABEL_REF ) return true ; 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_tls_address ( rtx addr , enum tls_model model ) { if ( ! flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC ) model = TLS_MODEL_LOCAL_EXEC ; switch ( model ) { case TLS_MODEL_LOCAL_DYNAMIC : rtx base ; tree decl ; const char * base_name ; rtvec v ; 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 ) ; if ( strcmp ( base_name , DTPOFF_ZERO_SYM ) == 0 ) { if ( ! flag_pic ) goto local_exec ; v = gen_rtvec ( 1 , addr ) ; } else v = gen_rtvec ( 2 , addr , base ) ; addr = gen_rtx_UNSPEC ( Pmode , v , UNSPEC_TLS_OFF ) ; addr = gen_rtx_CONST ( Pmode , addr ) ; base = arc_legitimize_tls_address ( base , TLS_MODEL_GLOBAL_DYNAMIC ) ; return gen_rtx_PLUS ( Pmode , force_reg ( Pmode , base ) , addr ) ; case TLS_MODEL_GLOBAL_DYNAMIC : return arc_emit_call_tls_get_addr ( addr , UNSPEC_TLS_GD , addr ) ; 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 , arc_get_tp ( ) , addr ) ; case TLS_MODEL_LOCAL_EXEC : local_exec : addr = arc_unspec_offset ( addr , UNSPEC_TLS_OFF ) ; return gen_rtx_PLUS ( Pmode , arc_get_tp ( ) , addr ) ; default : gcc_unreachable ( ) ; } } </s>

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


<s> static bool arc_needs_pcl_p ( rtx x ) { register const char * fmt ; register int i , j ; if ( ( GET_CODE ( x ) == UNSPEC ) && ( XVECLEN ( x , 0 ) == 1 ) && ( GET_CODE ( XVECEXP ( x , 0 , 0 ) ) == SYMBOL_REF ) ) switch ( XINT ( x , 1 ) ) { case ARC_UNSPEC_GOT : case ARC_UNSPEC_GOTOFFPC : case UNSPEC_TLS_GD : case UNSPEC_TLS_IE : return true ; default : break ; } fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'e' ) { if ( arc_needs_pcl_p ( XEXP ( x , i ) ) ) return true ; } else if ( fmt [ i ] == 'E' ) for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( arc_needs_pcl_p ( XVECEXP ( x , i , j ) ) ) return true ; } return false ; } </s>

Helper used by arc_legitimate_pc_offset_p .


<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 ; 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>
int
arc_output_commutative_cond_exec
(
rtx
*
operands
,
bool
output_p
)
{
enum
rtx_code
commutative_op
=
GET_CODE
(
operands
[
3
]
)
;
const
char
*
pat
=
;
gcc_assert
(
!
CONSTANT_P
(
operands
[
1
]
)
)
;
switch
(
commutative_op
)
{
case
AND
:
if
(
satisfies_constraint_C1p
(
operands
[
2
]
)
)
pat
=
"bmsk%? %0,%1,%Z2"
;
else
if
(
satisfies_constraint_C2p
(
operands
[
2
]
)
)
{
operands
[
2
]
=
GEN_INT
(
(
~
INTVAL
(
operands
[
2
]
)
)
)
;
pat
=
"bmskn%? %0,%1,%Z2"
;
}
else
if
(
satisfies_constraint_Ccp
(
operands
[
2
]
)
)
pat
=
"bclr%? %0,%1,%M2"
;
else
if
(
satisfies_constraint_CnL
(
operands
[
2
]
)
)
pat
=
"bic%? %0,%1,%n2-1"
;
break
;
case
IOR
:
if
(
satisfies_constraint_C0p
(
operands
[
2
]
)
)
pat
=
"bset%? %0,%1,%z2"
;
break
;
case
XOR
:
if
(
satisfies_constraint_C0p
(
operands
[
2
]
)
)
pat
=
"bxor%? %0,%1,%z2"
;
break
;
case
PLUS
:
return
arc_output_addsi
(
operands
,
true
,
output_p
)
;
default
:
break
;
}
if
(
output_p
)
output_asm_insn
(
pat
pat
:
"%O3.%d5 %0,%1,%2"
,
operands
)
;
if
(
pat
||
REG_P
(
operands
[
2
]
)
||
satisfies_constraint_L
(
operands
[
2
]
)
)
return
4
;
return
8
;
}
</s>

Emit code for an commutative_cond_exec instruction with OPERANDS . Return the length of the instruction . If OUTPUT_P is false , do n't actually output the instruction , just return its length .


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

Implements target hook TARGET_VECTORIZE_PREFERRED_SIMD_MODE .


<s> void arc_print_operand_address ( FILE * file , rtx addr ) { register rtx base , index = 0 ; switch ( GET_CODE ( addr ) ) { case REG : fputs ( reg_names [ REGNO ( addr ) ] , file ) ; break ; case SYMBOL_REF : output_addr_const ( file , addr ) ; if ( SYMBOL_REF_SMALL_P ( addr ) ) fprintf ( file , "@sda" ) ; 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 ) { rtx dest = operands [ 0 ] ; rtx src = operands [ 1 ] ; enum usesDxState { none , srcDx , destDx , maxDx } ; enum usesDxState state = none ; if ( refers_to_regno_p ( 40 , 44 , src , 0 ) ) state = srcDx ; if ( refers_to_regno_p ( 40 , 44 , dest , 0 ) ) { 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> static bool arc_rewrite_small_data_p ( const_rtx x ) { if ( GET_CODE ( x ) == CONST ) x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == PLUS ) { if ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) x = XEXP ( x , 0 ) ; } if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_SMALL_P ( x ) ) { gcc_assert ( SYMBOL_REF_TLS_MODEL ( x ) == 0 ) ; return true ; } return false ; } </s>

Return true if X is a small data address that can be rewritten as a gp+symref .


<s> bool arc_store_addr_hazard_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> static bool arc_vector_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case V2HImode : return TARGET_PLUS_DMPY ; case V4HImode : case V2SImode : return TARGET_PLUS_QMACW ; case V4SImode : case V8HImode : return TARGET_SIMD_SET ; default : return false ; } } </s>

Implements target hook vector_mode_supported_p .


<s> static void emit_unlikely_jump ( rtx insn ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; rtx_insn * jump = emit_jump_insn ( insn ) ; add_int_reg_note ( jump , REG_BR_PROB , very_unlikely ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> static rtx force_offsettable ( rtx addr , HOST_WIDE_INT size , bool reuse ) { rtx base = addr ; rtx offs = const0_rtx ; if ( GET_CODE ( base ) == PLUS ) { offs = XEXP ( base , 1 ) ; base = XEXP ( base , 0 ) ; } if ( ! REG_P ( base ) || ( REGNO ( base ) != STACK_POINTER_REGNUM && REGNO_PTR_FRAME_P ( REGNO ( base ) ) ) || ! CONST_INT_P ( offs ) || ! SMALL_INT ( INTVAL ( offs ) ) || ! SMALL_INT ( INTVAL ( offs ) + size ) ) { if ( reuse ) emit_insn ( gen_add2_insn ( addr , offs ) ) ; else addr = copy_to_mode_reg ( Pmode , addr ) ; } return addr ; } </s>

Helper function of arc_expand_movmem . ADDR points to a chunk of memory . Emit code and return an potentially modified address such that offsets up to SIZE are can be added to yield a legitimate address . if REUSE is set , ADDR is a register that may be modified .


<s> bool prepare_move_operands ( rtx * operands , machine_mode mode ) { if ( ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 0 ] , Pmode ) ) operands [ 0 ] = arc_rewrite_small_data ( operands [ 0 ] ) ; if ( mode == SImode && SYMBOLIC_CONST ( operands [ 1 ] ) ) { prepare_pic_move ( operands , SImode ) ; } if ( GET_CODE ( operands [ 0 ] ) != MEM && ! TARGET_NO_SDATA_SET && small_data_pattern ( operands [ 1 ] , Pmode ) ) { operands [ 1 ] = arc_rewrite_small_data ( operands [ 1 ] ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , operands [ 1 ] ) ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , operands [ 1 ] ) ; emit_move_insn ( operands [ 0 ] , operands [ 0 ] ) ; return true ; } if ( MEM_P ( operands [ 0 ] ) && ! ( reload_in_progress || reload_completed ) ) { operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; if ( ! move_dest_operand ( operands [ 0 ] , mode ) ) { rtx addr = copy_to_mode_reg ( Pmode , XEXP ( operands [ 0 ] , 0 ) ) ; rtx pat = change_address ( operands [ 0 ] , mode , addr ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } if ( ! cse_not_expected ) { rtx pat = XEXP ( operands [ 0 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 0 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 0 ] ) ; operands [ 0 ] = pat ; } } } if ( MEM_P ( operands [ 1 ] ) && ! cse_not_expected ) { rtx pat = XEXP ( operands [ 1 ] , 0 ) ; pat = arc_legitimize_address_0 ( pat , pat , mode ) ; if ( pat ) { pat = change_address ( operands [ 1 ] , mode , pat ) ; MEM_COPY_ATTRIBUTES ( pat , operands [ 1 ] ) ; operands [ 1 ] = pat ; } } return false ; } </s>

Prepare operands for a move define_expand in MODE .


<s> static void prepare_pic_move ( rtx * operands , machine_mode ) { if ( GET_CODE ( operands [ 0 ] ) == MEM && SYMBOLIC_CONST ( operands [ 1 ] ) && flag_pic ) operands [ 1 ] = force_reg ( Pmode , operands [ 1 ] ) ; else { rtx temp = ( reload_in_progress ? operands [ 0 ] : flag_pic ? gen_reg_rtx ( Pmode ) : NULL_RTX ) ; operands [ 1 ] = arc_legitimize_pic_address ( operands [ 1 ] , temp ) ; } } </s>

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


<s> static void workaround_arc_anomaly ( void ) { rtx_insn * insn , * succ0 ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { succ0 = next_real_insn ( insn ) ; if ( arc_hazard ( insn , succ0 ) ) { emit_insn_before ( gen_nopv ( ) , succ0 ) ; } } if ( TARGET_ARC700 ) { rtx_insn * succ1 ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { succ0 = next_real_insn ( insn ) ; if ( arc_store_addr_hazard_p ( insn , succ0 ) ) { emit_insn_after ( gen_nopv ( ) , insn ) ; emit_insn_after ( gen_nopv ( ) , insn ) ; continue ; } succ1 = next_real_insn ( succ0 ) ; if ( succ0 && ! JUMP_P ( succ0 ) && ! CALL_P ( succ0 ) && arc_store_addr_hazard_p ( insn , succ1 ) ) emit_insn_after ( gen_nopv ( ) , insn ) ; } } } </s>

The same functionality as arc_hazard . It is called in machine reorg before any other optimization . Hence , the NOP size is taken into account when doing branch shortening .


<s> static void arc_autovectorize_vector_sizes ( vector_sizes * sizes ) { if ( TARGET_PLUS_QMACW ) { sizes -> quick_push ( 8 ) ; sizes -> quick_push ( 4 ) ; } } </s>


<s> static rtx arc_builtin_setjmp_frame_value ( void ) { return gen_raw_REG ( Pmode , FRAME_POINTER_REGNUM ) ; } </s>

Return the frame pointer value to be backed up in the setjmp buffer .


<s> static bool arc_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( ( to == FRAME_POINTER_REGNUM ) || ! arc_frame_pointer_needed ( ) ) ; } </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 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 , reg_offset ; unsigned int gmask ; struct arc_frame_info * frame_info ; int size ; 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 <= 31 ; regno ++ ) { if ( arc_must_save_register ( regno , cfun ) ) { reg_size += UNITS_PER_WORD ; gmask |= 1L << regno ; } } if ( crtl -> calls_eh_return ) for ( regno = 0 ; EH_RETURN_DATA_REGNO ( regno ) != INVALID_REGNUM ; regno ++ ) { reg_size += UNITS_PER_WORD ; gmask |= 1 << regno ; } frame_info -> save_return_addr = ( ! crtl -> is_leaf || df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) || crtl -> calls_eh_return ) ; if ( optimize_size && ! TARGET_NO_MILLICODE_THUNK_SET && ! crtl -> calls_eh_return ) { if ( arc_compute_millicode_save_restore_regs ( gmask , frame_info ) ) frame_info -> save_return_addr = true ; } extra_size = 0 ; if ( arc_must_save_return_addr ( cfun ) ) extra_size = 4 ; if ( arc_frame_pointer_needed ( ) ) extra_size += 4 ; pretend_size = crtl -> args . pretend_args_size ; { unsigned int extra_plus_reg_size ; unsigned int extra_plus_reg_size_aligned ; 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 ) ) ; reg_offset = ( total_size - ( pretend_size + reg_size + extra_size ) + ( arc_frame_pointer_needed ( ) ? 4 : 0 ) ) ; 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 -> reg_offset = reg_offset ; 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> 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> rtx arc_eh_return_address_location ( void ) { 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 , frame_pointer_rtx , offset ) ) ; MEM_VOLATILE_P ( mem ) = 1 ; return mem ; } </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_epilogue_uses ( int regno ) { unsigned int fn_type ; if ( regno == arc_tp_regno ) return true ; fn_type = arc_compute_function_type ( cfun ) ; if ( reload_completed ) { if ( ARC_INTERRUPT_P ( cfun -> machine -> fn_type ) ) { if ( ! fixed_regs [ regno ] ) return true ; return ( ( regno == arc_return_address_register ( fn_type ) ) || ( regno == RETURN_ADDR_REGNUM ) ) ; } else return regno == RETURN_ADDR_REGNUM ; } else return regno == arc_return_address_register ( fn_type ) ; } </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> bool arc_expand_movmem ( rtx * operands ) { rtx dst = operands [ 0 ] ; rtx src = operands [ 1 ] ; rtx dst_addr , src_addr ; HOST_WIDE_INT size ; int align = INTVAL ( operands [ 3 ] ) ; unsigned n_pieces ; int piece = align ; rtx store [ 2 ] ; rtx tmpx [ 2 ] ; int i ; if ( ! CONST_INT_P ( operands [ 2 ] ) ) return false ; size = INTVAL ( operands [ 2 ] ) ; if ( align >= 4 ) { if ( TARGET_LL64 ) n_pieces = ( size + 4 ) / 8U + ( ( size >> 1 ) & 1 ) + ( size & 1 ) ; else n_pieces = ( size + 2 ) / 4U + ( size & 1 ) ; } else if ( align == 2 ) n_pieces = ( size + 1 ) / 2U ; else n_pieces = size ; if ( n_pieces >= ( unsigned int ) ( optimize_size ? 3 : 15 ) ) return false ; if ( TARGET_LL64 && ( piece >= 4 ) && ( size >= 8 ) ) piece = 8 ; else if ( piece > 4 ) piece = 4 ; dst_addr = force_offsettable ( XEXP ( operands [ 0 ] , 0 ) , size , 0 ) ; src_addr = force_offsettable ( XEXP ( operands [ 1 ] , 0 ) , size , 0 ) ; store [ 0 ] = store [ 1 ] = NULL_RTX ; tmpx [ 0 ] = tmpx [ 1 ] = NULL_RTX ; for ( i = 0 ; size > 0 ; i ^= 1 , size -= piece ) { rtx tmp ; machine_mode mode ; while ( piece > size ) piece >>= 1 ; mode = smallest_int_mode_for_size ( piece * BITS_PER_UNIT ) ; if ( 0 && tmpx [ i ] && GET_MODE ( tmpx [ i ] ) == mode ) tmp = tmpx [ i ] ; else tmpx [ i ] = tmp = gen_reg_rtx ( mode ) ; dst_addr = force_offsettable ( dst_addr , piece , 1 ) ; src_addr = force_offsettable ( src_addr , piece , 1 ) ; if ( store [ i ] ) emit_insn ( store [ i ] ) ; emit_move_insn ( tmp , change_address ( src , mode , src_addr ) ) ; store [ i ] = gen_move_insn ( change_address ( dst , mode , dst_addr ) , tmp ) ; dst_addr = plus_constant ( Pmode , dst_addr , piece ) ; src_addr = plus_constant ( Pmode , src_addr , piece ) ; } if ( store [ i ] ) emit_insn ( store [ i ] ) ; if ( store [ i ^ 1 ] ) emit_insn ( store [ i ^ 1 ] ) ; return true ; } </s>

Like move_by_pieces , but take account of load latency , and actual offset ranges . Return true on success .


<s> void arc_expand_prologue ( void ) { int size ; unsigned int gmask = cfun -> machine -> frame_info . gmask ; unsigned int frame_size_to_allocate ; int first_offset = 0 ; unsigned int fn_type = arc_compute_function_type ( cfun ) ; if ( ARC_NAKED_P ( fn_type ) ) { if ( flag_stack_usage_info ) current_function_static_stack_size = 0 ; return ; } size = arc_compute_frame_size ( ) ; if ( flag_stack_usage_info ) current_function_static_stack_size = size ; frame_size_to_allocate = size ; gcc_assert ( ! ( size == 0 && gmask ) ) ; if ( cfun -> machine -> frame_info . pretend_size != 0 ) { gcc_assert ( cfun -> machine -> frame_info . pretend_size <= 32 ) ; frame_stack_add ( - ( HOST_WIDE_INT ) cfun -> machine -> frame_info . pretend_size ) ; frame_size_to_allocate -= cfun -> machine -> frame_info . pretend_size ; } if ( ARC_AUTO_IRQ_P ( fn_type ) && ! ARC_FAST_INTERRUPT_P ( fn_type ) ) { arc_dwarf_emit_irq_save_regs ( ) ; } if ( arc_must_save_return_addr ( cfun ) && ! ARC_AUTOBLINK_IRQ_P ( fn_type ) ) { rtx ra = gen_rtx_REG ( SImode , RETURN_ADDR_REGNUM ) ; rtx mem = gen_frame_mem ( Pmode , gen_rtx_PRE_DEC ( Pmode , stack_pointer_rtx ) ) ; frame_move_inc ( mem , ra , stack_pointer_rtx , 0 ) ; frame_size_to_allocate -= UNITS_PER_WORD ; } if ( cfun -> machine -> frame_info . reg_size ) { first_offset = - cfun -> machine -> frame_info . reg_size ; arc_save_restore ( stack_pointer_rtx , gmask , 0 , & first_offset ) ; frame_size_to_allocate -= cfun -> machine -> frame_info . reg_size ; } if ( cfun -> machine -> frame_info . millicode_end_reg > 0 && arc_must_save_return_addr ( cfun ) ) { HOST_WIDE_INT tmp = cfun -> machine -> frame_info . reg_size ; emit_insn ( gen_rtx_SET ( gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) , gen_rtx_MEM ( Pmode , plus_constant ( Pmode , stack_pointer_rtx , tmp ) ) ) ) ; } if ( arc_frame_pointer_needed ( ) && ! ARC_AUTOFP_IRQ_P ( fn_type ) ) { rtx addr = gen_rtx_PLUS ( Pmode , stack_pointer_rtx , GEN_INT ( - UNITS_PER_WORD + first_offset ) ) ; rtx mem = gen_frame_mem ( Pmode , gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , addr ) ) ; frame_move_inc ( mem , frame_pointer_rtx , stack_pointer_rtx , 0 ) ; frame_size_to_allocate -= UNITS_PER_WORD ; first_offset = 0 ; } if ( arc_frame_pointer_needed ( ) ) { frame_move ( frame_pointer_rtx , stack_pointer_rtx ) ; } frame_size_to_allocate -= first_offset ; if ( frame_size_to_allocate > 0 ) { frame_stack_add ( ( HOST_WIDE_INT ) 0 - frame_size_to_allocate ) ; if ( arc_frame_pointer_needed ( ) ) emit_insn ( gen_stack_tie ( stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; } } </s>

Set up the stack and frame pointer ( if desired ) for the function .


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
)
;
cfun
->
machine
->
size_reason
=
0
;
}
</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 .


"%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 .


"-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"

"PIC is not supported for %s. Generating non-PIC code only.."

Called by OVERRIDE_OPTIONS to initialize various things .


<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 == 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 ) ) ; } 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> bool arc_is_uncached_mem_p ( rtx pat ) { tree attrs ; tree ttype ; struct mem_attrs * refattrs ; if ( ! MEM_P ( pat ) ) return false ; refattrs = MEM_ATTRS ( pat ) ; if ( ! refattrs || ! refattrs -> expr ) return false ; ttype = TREE_TYPE ( refattrs -> expr ) ; if ( ! ttype ) return false ; attrs = TYPE_ATTRIBUTES ( ttype ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; 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_log < 1 ) { rtx_insn * next = next_nonnote_nondebug_insn ( label ) ; if ( INSN_P ( next ) && recog_memoized ( next ) >= 0 ) return 1 ; } return align_labels_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> static bool arc_must_save_register ( int regno , struct function * func ) { 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 ; } if ( ( regno ) != RETURN_ADDR_REGNUM && ( regno ) != FRAME_POINTER_REGNUM && df_regs_ever_live_p ( regno ) && ( ! call_used_regs [ regno ] || ARC_INTERRUPT_P ( fn_type ) ) && ! 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
void
arc_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
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
;
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
)
;
}
</s>

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


<s> int arc_register_move_cost ( machine_mode , enum reg_class from_class , enum reg_class to_class ) { if ( TARGET_ARC600 ) { if ( to_class == MPY_WRITABLE_CORE_REGS ) return 3 ; else if ( to_class == LPCOUNT_REG ) return 6 ; else if ( to_class == WRITABLE_CORE_REGS ) return 6 ; } if ( from_class == LPCOUNT_REG ) return 1000 ; if ( to_class == LPCOUNT_REG ) return 6 ; if ( ( TARGET_ARC700 || TARGET_EM ) && TARGET_DPFP && from_class == DOUBLE_REGS && to_class == DOUBLE_REGS ) return 100 ; return 2 ; } </s>


<s> 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_REGNUM ; else if ( ( fn_type & ARC_FUNCTION_ILINK2 ) != 0 ) regno = ILINK2_REGNUM ; 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_rewrite_small_data ( rtx op ) { op = arc_rewrite_small_data_1 ( op ) ; if ( MEM_P ( op ) && ! LEGITIMATE_SMALL_DATA_ADDRESS_P ( XEXP ( op , 0 ) ) ) { rtx addr = XEXP ( op , 0 ) ; rtx tmp = gen_reg_rtx ( Pmode ) ; emit_move_insn ( tmp , addr ) ; op = replace_equiv_address_nv ( op , tmp ) ; } return op ; } </s>

If possible , rewrite OP so that it refers to small data using explicit relocations .


<s> static rtx arc_rewrite_small_data_1 ( rtx op ) { rtx rgp = gen_rtx_REG ( Pmode , SDATA_BASE_REGNUM ) ; op = copy_insn ( op ) ; subrtx_ptr_iterator :: array_type array ; FOR_EACH_SUBRTX_PTR ( iter , array , & op , ALL ) { rtx * loc = * iter ; if ( arc_rewrite_small_data_p ( * loc ) ) { * loc = gen_rtx_PLUS ( Pmode , rgp , * loc ) ; iter . skip_subrtxes ( ) ; } else if ( GET_CODE ( * loc ) == PLUS && rtx_equal_p ( XEXP ( * loc , 0 ) , rgp ) ) iter . skip_subrtxes ( ) ; } return op ; } </s>


<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 ( ( cl == LPCOUNT_REG || cl == WRITABLE_CORE_REGS ) && in_p && MEM_P ( x ) ) 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 ( 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> static int arc_verify_short ( rtx_insn * insn , int , int check_attr ) { enum attr_iscompact iscompact ; struct machine_function * machine ; if ( check_attr > 0 ) { iscompact = get_attr_iscompact ( insn ) ; if ( iscompact == ISCOMPACT_FALSE ) return 0 ; } machine = cfun -> machine ; if ( machine -> force_short_suffix >= 0 ) return machine -> force_short_suffix ; 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> bool compact_sda_memory_operand ( rtx op , machine_mode mode , bool short_p ) { rtx addr ; int size ; tree decl = NULL_TREE ; 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 ) ) return false ; if ( ! short_p || size == 1 ) return true ; if ( GET_CODE ( XEXP ( addr , 1 ) ) == SYMBOL_REF ) decl = SYMBOL_REF_DECL ( XEXP ( addr , 1 ) ) ; else if ( GET_CODE ( XEXP ( XEXP ( XEXP ( addr , 1 ) , 0 ) , 0 ) ) == SYMBOL_REF ) decl = SYMBOL_REF_DECL ( XEXP ( XEXP ( XEXP ( addr , 1 ) , 0 ) , 0 ) ) ; if ( decl ) align = DECL_ALIGN ( decl ) ; align = align / BITS_PER_UNIT ; 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 .


"value of -mirq-ctrl-saved must have form R0-REGx"

"last register name %s must be an odd register"

Parse -mirq-ctrl-saved=RegisterRange , blink , lp_copunt . The register range is specified as two registers separated by a dash . It always starts with r0 , and its upper limit is fp register . blink and lp_count registers are optional .


<s> static bool legitimate_scaled_address_p ( machine_mode mode , rtx op , bool strict ) { if ( GET_CODE ( op ) != PLUS ) return false ; if ( GET_CODE ( XEXP ( op , 0 ) ) != MULT ) return false ; if ( ! RTX_OK_FOR_INDEX_P ( XEXP ( XEXP ( op , 0 ) , 0 ) , strict ) ) return false ; if ( ! CONST_INT_P ( XEXP ( XEXP ( op , 0 ) , 1 ) ) ) return false ; switch ( GET_MODE_SIZE ( mode ) ) { case 2 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 2 ) return false ; break ; case 8 : if ( ! TARGET_LL64 ) return false ; case 4 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 4 ) return false ; default : return false ; } if ( RTX_OK_FOR_BASE_P ( XEXP ( op , 1 ) , ( strict ) ) ) return true ; if ( flag_pic ) { if ( CONST_INT_P ( XEXP ( op , 1 ) ) ) return true ; return false ; } if ( CONSTANT_P ( XEXP ( op , 1 ) ) ) { if ( GET_CODE ( XEXP ( op , 1 ) ) == SYMBOL_REF && SYMBOL_REF_SMALL_P ( XEXP ( op , 1 ) ) ) return false ; return true ; } return false ; } </s>


"invalid number in -mrgf-banked-regs=%s "

Parse -mrgf-banked-regs=NUM option string . Valid values for NUM are 4 , 8 , 16 , or 32 .


<s> bool small_data_pattern ( rtx op , machine_mode ) { if ( GET_CODE ( op ) == SEQUENCE ) return false ; rtx rgp = gen_rtx_REG ( Pmode , SDATA_BASE_REGNUM ) ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , op , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == PLUS && rtx_equal_p ( XEXP ( x , 0 ) , rgp ) ) iter . skip_subrtxes ( ) ; else if ( arc_rewrite_small_data_p ( x ) ) return true ; } return false ; } </s>

Return true if OP refers to small data symbols directly , not through a PLUS .


<s> static rtx arc_builtin_setjmp_frame_value ( void ) { return gen_raw_REG ( Pmode , HARD_FRAME_POINTER_REGNUM ) ; } </s>

Return the frame pointer value to be backed up in the setjmp buffer .


<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 ; unsigned int gmask ; struct arc_frame_info * frame_info ; int size ; unsigned int extra_plus_reg_size ; unsigned int extra_plus_reg_size_aligned ; 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 <= 31 ; regno ++ ) { if ( arc_must_save_register ( regno , cfun ) ) { reg_size += UNITS_PER_WORD ; gmask |= 1L << regno ; } } if ( crtl -> calls_eh_return ) for ( regno = 0 ; EH_RETURN_DATA_REGNO ( regno ) != INVALID_REGNUM ; regno ++ ) { reg_size += UNITS_PER_WORD ; gmask |= 1L << 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 && ! crtl -> calls_eh_return ) { if ( arc_compute_millicode_save_restore_regs ( gmask , frame_info ) ) frame_info -> save_return_addr = true ; } extra_size = 0 ; if ( arc_must_save_return_addr ( cfun ) ) extra_size = 4 ; if ( arc_frame_pointer_needed ( ) ) 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 bool arc_enter_leave_p ( unsigned int gmask ) { int regno ; unsigned int rmask = 0 ; if ( ! gmask ) return false ; for ( regno = ENTER_LEAVE_START_REG ; regno <= ENTER_LEAVE_END_REG && ( gmask & ( 1L << regno ) ) ; regno ++ ) rmask |= 1L << 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> void arc_expand_epilogue ( int sibcall_p ) { int size ; unsigned int fn_type = arc_compute_function_type ( cfun ) ; unsigned int size_to_deallocate ; int restored ; int can_trust_sp_p = ! cfun -> calls_alloca ; int first_offset ; bool restore_fp = arc_frame_pointer_needed ( ) && ! ARC_AUTOFP_IRQ_P ( fn_type ) ; bool restore_blink = arc_must_save_return_addr ( cfun ) && ! ARC_AUTOBLINK_IRQ_P ( fn_type ) ; unsigned int gmask = cfun -> machine -> frame_info . gmask ; bool return_p = ! sibcall_p && fn_type == ARC_FUNCTION_NORMAL && ! cfun -> machine -> frame_info . pretend_size ; struct arc_frame_info * frame = & cfun -> machine -> frame_info ; if ( ARC_NAKED_P ( fn_type ) ) return ; size = arc_compute_frame_size ( ) ; size_to_deallocate = size ; first_offset = size - ( frame -> pretend_size + frame -> reg_size + frame -> extra_size ) ; if ( ! can_trust_sp_p ) gcc_assert ( arc_frame_pointer_needed ( ) ) ; if ( size ) emit_insn ( gen_blockage ( ) ) ; if ( TARGET_CODE_DENSITY && TARGET_CODE_DENSITY_FRAME && ! ARC_AUTOFP_IRQ_P ( fn_type ) && ! ARC_AUTOBLINK_IRQ_P ( fn_type ) && ! ARC_INTERRUPT_P ( fn_type ) && arc_enter_leave_p ( gmask ) ) { size_to_deallocate -= arc_restore_callee_leave ( gmask , restore_blink , restore_fp , return_p , first_offset ) ; if ( return_p ) { gcc_assert ( size_to_deallocate == 0 ) ; return ; } } else if ( frame -> millicode_end_reg > 14 ) { size_to_deallocate -= arc_restore_callee_milli ( gmask , restore_blink , restore_fp , return_p , first_offset ) ; if ( return_p ) { gcc_assert ( size_to_deallocate == 0 ) ; return ; } } else size_to_deallocate -= arc_restore_callee_saves ( gmask , restore_blink , restore_fp , first_offset , size_to_deallocate ) ; restored = size - size_to_deallocate ; if ( size > restored ) frame_stack_add ( size - restored ) ; if ( crtl -> calls_eh_return ) emit_insn ( gen_add2_insn ( stack_pointer_rtx , EH_RETURN_STACKADJ_RTX ) ) ; if ( sibcall_p == FALSE ) emit_jump_insn ( gen_simple_return ( ) ) ; } </s>

Do any necessary cleanup after a function to restore stack , frame , and regs .


<s> void arc_expand_prologue ( void ) { int size ; unsigned int gmask = cfun -> machine -> frame_info . gmask ; struct arc_frame_info * frame = & cfun -> machine -> frame_info ; unsigned int frame_size_to_allocate ; int first_offset = 0 ; unsigned int fn_type = arc_compute_function_type ( cfun ) ; bool save_blink = false ; bool save_fp = false ; if ( ARC_NAKED_P ( fn_type ) ) { if ( flag_stack_usage_info ) current_function_static_stack_size = 0 ; return ; } size = arc_compute_frame_size ( ) ; if ( flag_stack_usage_info ) current_function_static_stack_size = size ; frame_size_to_allocate = size ; gcc_assert ( ! ( size == 0 && gmask ) ) ; if ( frame -> pretend_size != 0 ) first_offset = - frame -> pretend_size ; if ( ARC_AUTO_IRQ_P ( fn_type ) && ! ARC_FAST_INTERRUPT_P ( fn_type ) ) { frame_stack_add ( first_offset ) ; first_offset = 0 ; arc_dwarf_emit_irq_save_regs ( ) ; } save_blink = arc_must_save_return_addr ( cfun ) && ! ARC_AUTOBLINK_IRQ_P ( fn_type ) ; save_fp = arc_frame_pointer_needed ( ) && ! ARC_AUTOFP_IRQ_P ( fn_type ) ; if ( TARGET_CODE_DENSITY && TARGET_CODE_DENSITY_FRAME && ! ARC_AUTOFP_IRQ_P ( fn_type ) && ! ARC_AUTOBLINK_IRQ_P ( fn_type ) && ! ARC_INTERRUPT_P ( fn_type ) && arc_enter_leave_p ( gmask ) ) frame_size_to_allocate -= arc_save_callee_enter ( gmask , save_blink , save_fp , first_offset ) ; else if ( frame -> millicode_end_reg > 14 ) frame_size_to_allocate -= arc_save_callee_milli ( gmask , save_blink , save_fp , first_offset , frame -> reg_size ) ; else frame_size_to_allocate -= arc_save_callee_saves ( gmask , save_blink , save_fp , first_offset ) ; if ( frame_size_to_allocate > 0 ) frame_stack_add ( ( HOST_WIDE_INT ) 0 - frame_size_to_allocate ) ; emit_insn ( gen_blockage ( ) ) ; } </s>

Set up the stack and frame pointer ( if desired ) for the function .


"%<-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> 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 ) { 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 ; } if ( TREE_CODE ( addr ) == COMPONENT_REF ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( TREE_OPERAND ( addr , 1 ) ) ) ; if ( lookup_attribute ( "uncached" , attrs ) ) return true ; } return false ; } </s>

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

arc "uncached" 0 "uncached" 1 "uncached"


<s> static bool arc_must_save_register ( int regno , struct function * func ) { 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 RETURN_ADDR_REGNUM : case STACK_POINTER_REGNUM : return false ; case HARD_FRAME_POINTER_REGNUM : if ( arc_frame_pointer_needed ( ) ) return false ; default : if ( df_regs_ever_live_p ( regno ) && ( ! call_used_regs [ regno ] || ARC_INTERRUPT_P ( fn_type ) ) && ! 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 int arc_restore_callee_saves ( unsigned int 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 ; bool early_blink_restore ; 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 ; 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 ( int i = 0 ; i <= GMASK_LEN ; i ++ ) { machine_mode restore_mode = SImode ; if ( TARGET_LL64 && ( ( i % 2 ) == 0 ) && ( ( gmask & ( 1L << i ) ) != 0 ) && ( ( gmask & ( 1L << ( i + 1 ) ) ) != 0 ) ) restore_mode = DImode ; else if ( ( gmask & ( 1L << i ) ) == 0 ) continue ; reg = gen_rtx_REG ( restore_mode , i ) ; offs = 0 ; switch ( restore_mode ) { case E_DImode : if ( ( GMASK_LEN - __builtin_clz ( gmask ) ) == ( i + 1 ) && early_blink_restore ) offs = 4 ; break ; case E_SImode : if ( ( GMASK_LEN - __builtin_clz ( 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> 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> static int arc_save_callee_enter ( unsigned int 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 & ( 1L << 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 & ~ ( 1L << 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 ( unsigned int 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 & ( 1L << 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 & ~ ( 1L << 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 <= 31 ; regno ++ ) { if ( ( gmask & ( 1L << 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 ( unsigned int gmask , bool save_blink , bool save_fp , HOST_WIDE_INT offset ) { rtx reg ; int frame_allocated = 0 ; if ( save_blink ) { reg = gen_rtx_REG ( Pmode , RETURN_ADDR_REGNUM ) ; frame_allocated += frame_save_reg ( reg , offset ) ; offset = 0 ; } if ( gmask ) for ( int i = 31 ; i >= 0 ; i -- ) { machine_mode save_mode = SImode ; if ( TARGET_LL64 && ( ( i - 1 ) % 2 == 0 ) && ( ( gmask & ( 1L << i ) ) != 0 ) && ( ( gmask & ( 1L << ( i - 1 ) ) ) != 0 ) ) { save_mode = DImode ; -- i ; } else if ( ( gmask & ( 1L << 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 ( arc_frame_pointer_needed ( ) ) 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 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 ) ) 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 bool legitimate_scaled_address_p ( machine_mode mode , rtx op , bool strict ) { if ( GET_CODE ( op ) != PLUS ) return false ; if ( GET_CODE ( XEXP ( op , 0 ) ) != MULT ) return false ; if ( ! RTX_OK_FOR_INDEX_P ( XEXP ( XEXP ( op , 0 ) , 0 ) , strict ) ) return false ; if ( ! CONST_INT_P ( XEXP ( XEXP ( op , 0 ) , 1 ) ) ) return false ; switch ( GET_MODE_SIZE ( mode ) ) { case 2 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 2 ) return false ; break ; case 8 : if ( ! TARGET_LL64 ) return false ; case 4 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 4 ) return false ; default : return false ; } if ( RTX_OK_FOR_BASE_P ( XEXP ( op , 1 ) , ( strict ) ) ) return true ; if ( flag_pic ) { if ( CONST_INT_P ( XEXP ( op , 1 ) ) ) return true ; return false ; } if ( legitimate_small_data_address_p ( op ) ) return false ; if ( CONSTANT_P ( XEXP ( op , 1 ) ) ) return true ; return false ; } </s>


<s> static bool legitimate_small_data_address_p ( rtx x ) { switch ( GET_CODE ( x ) ) { case CONST : return legitimate_small_data_address_p ( XEXP ( x , 0 ) ) ; case SYMBOL_REF : return SYMBOL_REF_SMALL_P ( x ) ; case PLUS : { bool p0 = ( GET_CODE ( XEXP ( x , 0 ) ) == SYMBOL_REF ) && SYMBOL_REF_SMALL_P ( XEXP ( x , 0 ) ) ; bool p1 = CONST_INT_P ( XEXP ( x , 1 ) ) && ( INTVAL ( XEXP ( x , 1 ) ) <= g_switch_value ) ; return p0 && p1 ; } default : return false ; } } </s>

Return true if x is ok to be used as a small data address .


<s> static rtx_insn * apply_GEN_FCN ( enum insn_code icode , rtx * arg ) { switch ( insn_data [ icode ] . n_generator_args ) { case 0 : return GEN_FCN ( icode ) ( ) ; case 1 : return GEN_FCN ( icode ) ( arg [ 0 ] ) ; case 2 : return GEN_FCN ( icode ) ( arg [ 0 ] , arg [ 1 ] ) ; case 3 : return GEN_FCN ( icode ) ( arg [ 0 ] , arg [ 1 ] , arg [ 2 ] ) ; case 4 : return GEN_FCN ( icode ) ( arg [ 0 ] , arg [ 1 ] , arg [ 2 ] , arg [ 3 ] ) ; case 5 : return GEN_FCN ( icode ) ( arg [ 0 ] , arg [ 1 ] , arg [ 2 ] , arg [ 3 ] , arg [ 4 ] ) ; default : gcc_unreachable ( ) ; } } </s>

Helper arc_expand_builtin , generates a pattern for the given icode and arguments .


<s> static int arc600_corereg_hazard ( rtx_insn * pred , rtx_insn * succ ) { if ( ! TARGET_ARC600 ) return 0 ; if ( GET_CODE ( PATTERN ( pred ) ) == SEQUENCE ) pred = as_a < rtx_sequence * > ( PATTERN ( pred ) ) -> insn ( 1 ) ; if ( GET_CODE ( PATTERN ( succ ) ) == SEQUENCE ) succ = as_a < rtx_sequence * > ( PATTERN ( succ ) ) -> insn ( 0 ) ; if ( recog_memoized ( pred ) == CODE_FOR_mulsi_600 || recog_memoized ( pred ) == CODE_FOR_umul_600 || recog_memoized ( pred ) == CODE_FOR_mac_600 || recog_memoized ( pred ) == CODE_FOR_mul64_600 || recog_memoized ( pred ) == CODE_FOR_mac64_600 || recog_memoized ( pred ) == CODE_FOR_umul64_600 || recog_memoized ( pred ) == CODE_FOR_umac64_600 ) return 0 ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , PATTERN ( pred ) , 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 ; } rtx dest = XEXP ( x , 0 ) ; if ( REG_P ( dest ) && REGNO ( dest ) >= 32 && REGNO ( dest ) < 61 && ( refers_to_regno_p ( REGNO ( dest ) , REGNO ( dest ) + ( GET_MODE_SIZE ( GET_MODE ( dest ) ) + 3 ) / 4U , PATTERN ( succ ) , 0 ) ) ) return 4 ; } return 0 ; } </s>

Return length adjustment for INSN . 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 .


<s> static rtx_insn * arc_active_insn ( rtx_insn * insn ) { while ( insn ) { insn = NEXT_INSN ( insn ) ; if ( insn == 0 || ( active_insn_p ( insn ) && NONDEBUG_INSN_P ( insn ) && ! NOTE_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) != UNSPEC_VOLATILE && GET_CODE ( PATTERN ( insn ) ) != PARALLEL ) ) break ; } return insn ; } </s>

Return the next active insn , skiping the inline assembly code .


<s> static int arc_address_cost ( rtx addr , machine_mode , addr_space_t , bool speed ) { switch ( GET_CODE ( addr ) ) { case REG : return speed || satisfies_constraint_Rcq ( addr ) ? 0 : 1 ; case PRE_INC : case PRE_DEC : case POST_INC : case POST_DEC : case PRE_MODIFY : case POST_MODIFY : return ! speed ; case LABEL_REF : case SYMBOL_REF : case CONST : if ( TARGET_NPS_CMEM && cmem_address ( addr , SImode ) ) return 0 ; return COSTS_N_INSNS ( 1 ) ; case PLUS : { rtx plus0 = XEXP ( addr , 0 ) ; rtx plus1 = XEXP ( addr , 1 ) ; if ( GET_CODE ( plus0 ) != REG && ( GET_CODE ( plus0 ) != MULT || ! CONST_INT_P ( XEXP ( plus0 , 1 ) ) || ( INTVAL ( XEXP ( plus0 , 1 ) ) != 2 && INTVAL ( XEXP ( plus0 , 1 ) ) != 4 ) ) ) break ; switch ( GET_CODE ( plus1 ) ) { case CONST_INT : return ( ! RTX_OK_FOR_OFFSET_P ( SImode , plus1 ) ? COSTS_N_INSNS ( 1 ) : speed ? 0 : ( satisfies_constraint_Rcq ( plus0 ) && satisfies_constraint_O ( plus1 ) ) ? 0 : 1 ) ; case REG : return ( speed < 1 ? 0 : ( satisfies_constraint_Rcq ( plus0 ) && satisfies_constraint_Rcq ( plus1 ) ) ? 0 : 1 ) ; case CONST : case SYMBOL_REF : case LABEL_REF : return COSTS_N_INSNS ( 1 ) ; default : break ; } break ; } default : break ; } return 4 ; } </s>

Provide the costs of an addressing mode that contains ADDR . If ADDR is not a valid address , its cost is irrelevant .


<s> static void arc_add_jli_section ( rtx pat ) { const char * name ; tree attrs ; arc_jli_section * sec = arc_jli_sections , * new_section ; tree decl = SYMBOL_REF_DECL ( pat ) ; if ( ! pat ) return ; if ( decl ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "jli_fixed" , attrs ) ) return ; } name = XSTR ( pat , 0 ) ; while ( sec != NULL ) { if ( strcmp ( name , sec -> name ) == 0 ) return ; sec = sec -> next ; } new_section = ( arc_jli_section * ) xmalloc ( sizeof ( arc_jli_section ) ) ; gcc_assert ( new_section != NULL ) ; new_section -> name = name ; new_section -> next = arc_jli_sections ; arc_jli_sections = new_section ; } </s>

Add the given function declaration to emit code in JLI section .


<s> int arc_adjust_insn_length ( rtx_insn * insn , int len , bool ) { if ( ! INSN_P ( insn ) ) return len ; if ( GET_CODE ( PATTERN ( insn ) ) == SEQUENCE ) return len ; if ( TARGET_PAD_RETURN && JUMP_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) != ADDR_VEC && GET_CODE ( PATTERN ( insn ) ) != ADDR_DIFF_VEC && get_attr_type ( insn ) == TYPE_RETURN ) { rtx_insn * prev = prev_active_insn ( insn ) ; if ( ! prev || ! ( prev = prev_active_insn ( prev ) ) || ( ( NONJUMP_INSN_P ( prev ) && GET_CODE ( PATTERN ( prev ) ) == SEQUENCE ) ? CALL_ATTR ( as_a < rtx_sequence * > ( PATTERN ( prev ) ) -> insn ( 0 ) , NON_SIBCALL ) : CALL_ATTR ( prev , NON_SIBCALL ) ) ) return len + 4 ; } if ( TARGET_ARC600 ) { rtx_insn * succ = next_real_insn ( insn ) ; if ( succ && INSN_P ( succ ) ) len += arc600_corereg_hazard ( insn , succ ) ; } extract_constrain_insn_cached ( insn ) ; return len ; } </s>


<s> void arc_adjust_reg_alloc_order ( void ) { const int arc_default_alloc_order [ ] = REG_ALLOC_ORDER ; memcpy ( reg_alloc_order , arc_default_alloc_order , sizeof ( reg_alloc_order ) ) ; if ( optimize_size ) memcpy ( reg_alloc_order , size_alloc_order , sizeof ( size_alloc_order ) ) ; } </s>

Adjust register allocation order when compiling for size .


<s> static bool arc_allocate_stack_slots_for_args ( void ) { unsigned int fn_type = arc_compute_function_type ( cfun ) ; return ! ARC_NAKED_P ( fn_type ) ; } </s>

Implement ` TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS '


<s> static int arc_arg_partial_bytes ( 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 arg_num = * cum ; int ret ; arg_num = ROUND_ADVANCE_CUM ( arg_num , arg . mode , arg . type ) ; ret = GPR_REST_ARG_REGS ( arg_num ) ; ret = ( ret >= words ? 0 : ret * UNITS_PER_WORD ) ; return ret ; } </s>


<s> static int arc_asm_insn_p ( rtx x ) { int i , j ; if ( x == 0 ) return 0 ; switch ( GET_CODE ( x ) ) { case ASM_OPERANDS : case ASM_INPUT : return 1 ; case SET : return arc_asm_insn_p ( SET_SRC ( x ) ) ; case PARALLEL : j = 0 ; for ( i = XVECLEN ( x , 0 ) - 1 ; i >= 0 ; i -- ) j += arc_asm_insn_p ( XVECEXP ( x , 0 , i ) ) ; if ( j > 0 ) return 1 ; break ; default : break ; } return 0 ; } </s>

Given a rtx , check if it is an assembly instruction or not .


<s> void arc_asm_output_aligned_decl_local ( FILE * stream , tree decl , const char * name , unsigned HOST_WIDE_INT size , unsigned HOST_WIDE_INT align , unsigned HOST_WIDE_INT globalize_p ) { int in_small_data = arc_in_small_data_p ( decl ) ; rtx mem = decl == NULL_TREE ? NULL_RTX : DECL_RTL ( decl ) ; if ( mem != NULL_RTX && MEM_P ( mem ) && SYMBOL_REF_P ( XEXP ( mem , 0 ) ) && arc_is_aux_reg_p ( mem ) ) return ; if ( in_small_data ) switch_to_section ( get_named_section ( NULL , ".sbss" , 0 ) ) ; else switch_to_section ( bss_section ) ; if ( globalize_p ) ( * targetm . asm_out . globalize_label ) ( stream , name ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( ( align ) / BITS_PER_UNIT ) ) ; ASM_OUTPUT_TYPE_DIRECTIVE ( stream , name , "object" ) ; ASM_OUTPUT_SIZE_DIRECTIVE ( stream , name , size ) ; ASM_OUTPUT_LABEL ( stream , name ) ; if ( size != 0 ) ASM_OUTPUT_SKIP ( stream , size ) ; } </s>


<s> static void arc_asm_trampoline_template ( FILE * f ) { asm_fprintf ( f , "\tld_s\t%s,[pcl,8]\n" , ARC_TEMP_SCRATCH_REG ) ; asm_fprintf ( f , "\tld\t%s,[pcl,12]\n" , reg_names [ STATIC_CHAIN_REGNUM ] ) ; asm_fprintf ( f , "\tj_s\t[%s]\n" , ARC_TEMP_SCRATCH_REG ) ; assemble_aligned_integer ( UNITS_PER_WORD , const0_rtx ) ; assemble_aligned_integer ( UNITS_PER_WORD , const0_rtx ) ; } </s>

Output assembler code for a block containing the constant parts of a trampoline , leaving space for variable parts . A trampoline looks like this : ld_s r12 , [ pcl,8 ] ld r11 , [ pcl,12 ] j_s [ r12 ] .word function 's address .word static chain value


<s> static int arc_attr_type ( rtx_insn * insn ) { if ( NONJUMP_INSN_P ( insn ) ? ( GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER ) : JUMP_P ( insn ) ? ( GET_CODE ( PATTERN ( insn ) ) == ADDR_VEC || GET_CODE ( PATTERN ( insn ) ) == ADDR_DIFF_VEC ) : ! CALL_P ( insn ) ) return - 1 ; return get_attr_type ( insn ) ; } </s>

Return the integer value of the `` type '' attribute for INSN , or -1 if INSN ca n't have attributes .


<s> static unsigned int arc_autovectorize_vector_modes ( vector_modes * modes , bool ) { if ( TARGET_PLUS_QMACW ) { modes -> quick_push ( V4HImode ) ; modes -> quick_push ( V2HImode ) ; } return 0 ; } </s>


<s> bool arc_branch_size_unknown_p ( void ) { return ! optimize_size && arc_reorg_in_progress ; } </s>

When estimating sizes during arc_reorg , when optimizing for speed , there are three reasons why we need to consider branches to be length 6 : - annull-false delay slot insns are implemented using conditional execution , thus preventing short insn formation where used . - for ARC600 : annul-true delay slot insns are implemented where possible using conditional execution , preventing short insn formation where used . - for ARC700 : likely or somewhat likely taken branches are made long and unaligned if possible to avoid branch penalty .