<s> void arc_cpu_cpp_builtins ( cpp_reader * pfile ) { builtin_assert ( "cpu=arc" ) ; builtin_assert ( "machine=arc" ) ; builtin_define ( "__arc__" ) ; def_or_undef_macro ( pfile , NAME , CONDITION ) ; builtin_define_with_int_value ( "__ARC_TLS_REGNO__" , arc_tp_regno ) ; builtin_define ( TARGET_BIG_ENDIAN ? "__BIG_ENDIAN__" : "__LITTLE_ENDIAN__" ) ; if ( TARGET_BIG_ENDIAN ) builtin_define ( "__big_endian__" ) ; } </s>

Helper for TARGET_CPU_CPP_BUILTINS hook .


<s> void arc_cpu_cpp_builtins ( cpp_reader * pfile ) { builtin_assert ( "cpu=arc" ) ; builtin_assert ( "machine=arc" ) ; builtin_define ( "__arc__" ) ; def_or_undef_macro ( pfile , NAME , CONDITION ) ; builtin_define_with_int_value ( "__ARC_TLS_REGNO__" , arc_tp_regno ) ; builtin_define_with_int_value ( "__ARC_LPC_WIDTH__" , arc_lpcwidth ) ; builtin_define ( TARGET_BIG_ENDIAN ? "__BIG_ENDIAN__" : "__LITTLE_ENDIAN__" ) ; if ( TARGET_BIG_ENDIAN ) builtin_define ( "__big_endian__" ) ; } </s>


<s> void arc_cpu_cpp_builtins ( cpp_reader * pfile ) { builtin_assert ( "cpu=arc" ) ; builtin_assert ( "machine=arc" ) ; builtin_define ( "__arc__" ) ; def_or_undef_macro ( pfile , NAME , CONDITION ) ; builtin_define_with_int_value ( "__ARC_TLS_REGNO__" , arc_tp_regno ) ; builtin_define_with_int_value ( "__ARC_LPC_WIDTH__" , arc_lpcwidth ) ; builtin_define ( TARGET_BIG_ENDIAN ? "__BIG_ENDIAN__" : "__LITTLE_ENDIAN__" ) ; if ( TARGET_BIG_ENDIAN ) builtin_define ( "__big_endian__" ) ; if ( TARGET_HARD_FLOAT ) { builtin_define ( "__arc_hard_float__" ) ; builtin_define ( "__ARC_HARD_FLOAT__" ) ; } else { builtin_define ( "__arc_soft_float__" ) ; builtin_define ( "__ARC_SOFT_FLOAT__" ) ; } } </s>


<s> static void def_or_undef_macro ( cpp_reader * pfile , const char * name , bool def_p ) { if ( def_p ) cpp_define ( pfile , name ) ; else cpp_undef ( pfile , name ) ; } </s>

Define or undefine macros based on the current target . If the user does # pragma GCC target , we need to adjust the macros dynamically .


<s> static int arc_address_cost ( rtx addr , machine_mode , addr_space_t , bool speed ) { switch ( GET_CODE ( addr ) ) { case REG : return speed || arc_check_short_reg_p ( 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 : ( arc_check_short_reg_p ( plus0 ) && satisfies_constraint_O ( plus1 ) ) ? 0 : 1 ) ; case REG : return ( speed < 1 ? 0 : ( arc_check_short_reg_p ( plus0 ) && arc_check_short_reg_p ( 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 int arc_check_release31a ( rtx_insn * pred , rtx_insn * succ ) { if ( ! pred || ! INSN_P ( pred ) || ! succ || ! INSN_P ( succ ) ) return 0 ; if ( ! JUMP_P ( pred ) && ! single_set ( pred ) ) return 0 ; if ( ! JUMP_P ( succ ) && ! single_set ( succ ) ) return 0 ; if ( TARGET_HS && ( arc_tune == ARC_TUNE_ARCHS4X_REL31A ) ) switch ( get_attr_type ( pred ) ) { case TYPE_STORE : switch ( get_attr_type ( succ ) ) { case TYPE_BRCC : case TYPE_BRCC_NO_DELAY_SLOT : case TYPE_LOOP_END : return 1 ; default : break ; } break ; case TYPE_BRCC : case TYPE_BRCC_NO_DELAY_SLOT : case TYPE_LOOP_END : if ( get_attr_type ( succ ) == TYPE_STORE ) return 1 ; break ; default : break ; } return 0 ; } </s>

When compiling for release 310a , insert a nop before any conditional jump .


<s> static bool arc_check_short_reg_p ( rtx op ) { if ( ! REG_P ( op ) ) return false ; if ( IN_RANGE ( REGNO ( op ) ^ 4 , 4 , 11 ) ) return true ; return false ; } </s>

Return TRUE if reg is ok for short instrcutions .


<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 = arc_check_short_reg_p ( operands [ 0 ] ) ; int short_p = ( ! cond_p && short_0 && arc_check_short_reg_p ( operands [ 1 ] ) ) ; int ret = 0 ; && REGNO ( OP ) != 30 ) \ || ! TARGET_V2 ) ) if ( output_p ) \ output_asm_insn ( FORMAT , operands ) ; \ return ret ; \ } </s>

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


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

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


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

Implements target hook TARGET_SCHED_ISSUE_RATE .


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

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


<s> void split_addsi ( rtx * operands ) { int val = INTVAL ( operands [ 2 ] ) ; if ( val > 127 && val <= 255 && arc_check_short_reg_p ( operands [ 0 ] ) ) { operands [ 3 ] = operands [ 2 ] ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 1 ] ) ; } else { operands [ 3 ] = operands [ 1 ] ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 2 ] ) ; } } </s>

Operands 0 .. 2 are the operands of a addsi which uses a 12 bit constant in operand 2 , but which would require a LIMM because of operand mismatch . operands 3 and 4 are new SET_SRCs for operands 0 .


<s> void split_subsi ( rtx * operands ) { int val = INTVAL ( operands [ 1 ] ) ; if ( arc_check_short_reg_p ( operands [ 0 ] ) && arc_check_short_reg_p ( operands [ 2 ] ) ) { if ( val >= - 31 && val <= 127 ) { operands [ 3 ] = gen_rtx_NEG ( SImode , operands [ 2 ] ) ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 1 ] ) ; return ; } else if ( val >= 0 && val < 255 ) { operands [ 3 ] = operands [ 1 ] ; operands [ 4 ] = gen_rtx_MINUS ( SImode , operands [ 0 ] , operands [ 2 ] ) ; return ; } } operands [ 3 ] = operands [ 2 ] ; operands [ 4 ] = gen_rtx_MINUS ( SImode , operands [ 1 ] , operands [ 0 ] ) ; } </s>

Operands 0 .. 2 are the operands of a subsi which uses a 12 bit constant in operand 1 , but which would require a LIMM because of operand mismatch . operands 3 and 4 are new SET_SRCs for 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 ) || arc_check_release31a ( insn , succ0 ) ) emit_insn_before ( gen_nopv ( ) , succ0 ) ; } if ( ! TARGET_ARC700 ) return ; if ( arc_tune != ARC_TUNE_ARC7XX ) check_store_cacheline_hazard ( ) ; } </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_ccfsm_branch_deleted_p ( ) { if ( arc_ccfsm_state == 1 || arc_ccfsm_state == 2 ) return 1 ; return 0 ; } </s>

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


<s> void arc_ccfsm_record_branch_deleted ( ) { arc_ccfsm_state += 2 ; current_insn_set_cc_p = last_insn_set_cc_p ; } </s>

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


<s> int arc_delay_slots_for_epilogue ( ) { if ( arc_compute_function_type ( current_function_decl ) != ARC_FUNCTION_NORMAL ) return 0 ; if ( ! current_frame_info . initialized ) ( void ) arc_compute_frame_size ( get_frame_size ( ) ) ; if ( current_frame_info . total_size == 0 ) return 1 ; return 0 ; } </s>

Define the number of delay slots needed for the function epilogue . Interrupt handlers ca n't have any epilogue delay slots ( it 's always needed for something else , I think ) . For normal functions , we have to worry about using call-saved regs as they 'll be restored before the delay slot insn . Functions with non-empty frames already have enough choices for the epilogue delay slot so for now we only consider functions with empty frames .


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


<s>
void
arc_init
(
void
)
{
char
*
tmp
;
if
(
arc_cpu_string
==
0
||
!
strcmp
(
arc_cpu_string
,
"base"
)
)
{
arc_cpu_string
=
"base"
;
arc_cpu_type
=
0
;
arc_mangle_cpu
=
;
}
else
if
(
ARC_EXTENSION_CPU
(
arc_cpu_string
)
)
;
else
{
error
(
"bad value (%s) for -mcpu switch"
,
arc_cpu_string
)
;
arc_cpu_string
=
"base"
;
arc_cpu_type
=
0
;
arc_mangle_cpu
=
;
}
arc_text_section
=
tmp
=
xmalloc
(
strlen
(
arc_text_string
)
+
sizeof
(
ARC_SECTION_FORMAT
)
+
1
)
;
sprintf
(
tmp
,
ARC_SECTION_FORMAT
,
arc_text_string
)
;
arc_data_section
=
tmp
=
xmalloc
(
strlen
(
arc_data_string
)
+
sizeof
(
ARC_SECTION_FORMAT
)
+
1
)
;
sprintf
(
tmp
,
ARC_SECTION_FORMAT
,
arc_data_string
)
;
arc_rodata_section
=
tmp
=
xmalloc
(
strlen
(
arc_rodata_string
)
+
sizeof
(
ARC_SECTION_FORMAT
)
+
1
)
;
sprintf
(
tmp
,
ARC_SECTION_FORMAT
,
arc_rodata_string
)
;
arc_init_reg_tables
(
)
;
memset
(
arc_punct_chars
,
0
,
sizeof
(
arc_punct_chars
)
)
;
arc_punct_chars
[
'#'
]
=
1
;
arc_punct_chars
[
'*'
]
=
1
;
arc_punct_chars
[
'?'
]
=
1
;
arc_punct_chars
[
'!'
]
=
1
;
arc_punct_chars
[
'~'
]
=
1
;
}
</s>

Called by OVERRIDE_OPTIONS to initialize various things .


<s> static void arc_init_reg_tables ( ) { int i ; for ( i = 0 ; i < NUM_MACHINE_MODES ; i ++ ) { switch ( GET_MODE_CLASS ( i ) ) { case MODE_INT : case MODE_PARTIAL_INT : case MODE_COMPLEX_INT : if ( GET_MODE_SIZE ( i ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) S_MODE ; else if ( GET_MODE_SIZE ( i ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) D_MODE ; else if ( GET_MODE_SIZE ( i ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) T_MODE ; else if ( GET_MODE_SIZE ( i ) == 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 ( i ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) SF_MODE ; else if ( GET_MODE_SIZE ( i ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) DF_MODE ; else if ( GET_MODE_SIZE ( i ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) TF_MODE ; else if ( GET_MODE_SIZE ( i ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) OF_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_CC : default : if ( i == ( int ) CCmode || i == ( int ) CCZNmode || i == ( int ) CCZNCmode ) arc_mode_class [ i ] = 1 << ( int ) C_MODE ; else arc_mode_class [ i ] = 0 ; break ; } } for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) { if ( i < 60 ) arc_regno_reg_class [ i ] = GENERAL_REGS ; else if ( i == 60 ) arc_regno_reg_class [ i ] = LPCOUNT_REG ; else if ( i == 61 ) arc_regno_reg_class [ i ] = NO_REGS ; else arc_regno_reg_class [ i ] = NO_REGS ; } } </s>


<s> static int arc_address_cost ( rtx addr ) { switch ( GET_CODE ( addr ) ) { case REG : return 1 ; case LABEL_REF : case SYMBOL_REF : case CONST : return 2 ; case PLUS : { register rtx plus0 = XEXP ( addr , 0 ) ; register rtx plus1 = XEXP ( addr , 1 ) ; if ( GET_CODE ( plus0 ) != REG ) break ; switch ( GET_CODE ( plus1 ) ) { case CONST_INT : return SMALL_INT ( plus1 ) ? 1 : 2 ; case CONST : case SYMBOL_REF : case LABEL_REF : return 2 ; default : break ; } break ; } default : break ; } return 4 ; } </s>


<s> static bool arc_assemble_integer ( rtx x , unsigned int size , int aligned_p ) { if ( size == UNITS_PER_WORD && aligned_p && ( ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P ( x ) ) || GET_CODE ( x ) == LABEL_REF ) ) { fputs ( "\t.word\t%st(" , asm_out_file ) ; output_addr_const ( asm_out_file , x ) ; fputs ( ")\n" , asm_out_file ) ; return true ; } return default_assemble_integer ( x , size , aligned_p ) ; } </s>

Target hook to assemble an integer object . The ARC version needs to emit a special directive for references to labels and function symbols .


<s> void arc_ccfsm_at_label ( const char * prefix , int num ) { if ( arc_ccfsm_state == 3 && arc_ccfsm_target_label == num && ! strcmp ( prefix , "L" ) ) { arc_ccfsm_state = 0 ; arc_ccfsm_target_insn = NULL_RTX ; } } </s>

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


<s> int arc_ccfsm_branch_deleted_p ( void ) { if ( arc_ccfsm_state == 1 || arc_ccfsm_state == 2 ) return 1 ; return 0 ; } </s>


<s> void arc_ccfsm_record_branch_deleted ( void ) { arc_ccfsm_state += 2 ; current_insn_set_cc_p = last_insn_set_cc_p ; } </s>


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


<s> enum arc_function_type arc_compute_function_type ( tree decl ) { tree a ; static enum arc_function_type fn_type = ARC_FUNCTION_UNKNOWN ; static tree last_fn = NULL_TREE ; if ( decl == NULL_TREE ) { fn_type = ARC_FUNCTION_UNKNOWN ; last_fn = NULL_TREE ; return fn_type ; } if ( decl == last_fn && fn_type != ARC_FUNCTION_UNKNOWN ) return fn_type ; fn_type = ARC_FUNCTION_NORMAL ; for ( a = DECL_ATTRIBUTES ( current_function_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" ) ) fn_type = ARC_FUNCTION_ILINK1 ; else if ( ! strcmp ( TREE_STRING_POINTER ( value ) , "ilink2" ) ) fn_type = ARC_FUNCTION_ILINK2 ; else gcc_unreachable ( ) ; break ; } } last_fn = decl ; return 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> int arc_delay_slots_for_epilogue ( void ) { if ( arc_compute_function_type ( current_function_decl ) != ARC_FUNCTION_NORMAL ) return 0 ; if ( ! current_frame_info . initialized ) ( void ) arc_compute_frame_size ( get_frame_size ( ) ) ; if ( current_frame_info . total_size == 0 ) return 1 ; return 0 ; } </s>


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

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


<s> int arc_eligible_for_epilogue_delay ( rtx trial , int slot ) { gcc_assert ( ! slot ) ; if ( get_attr_length ( trial ) == 1 && current_frame_info . gmask == 0 && ! reg_mentioned_p ( stack_pointer_rtx , PATTERN ( trial ) ) && ! reg_mentioned_p ( frame_pointer_rtx , PATTERN ( trial ) ) ) return 1 ; return 0 ; } </s>

Return true if TRIAL is a valid insn for the epilogue delay slot . Any single length instruction which does n't reference the stack or frame pointer or any call-saved register is OK. SLOT will always be 0 .


<s>
static
void
arc_external_libcall
(
rtx
fun
ATTRIBUTE_UNUSED
)
{
if
(
TARGET_MANGLE_CPU_LIBGCC
)
{
fprintf
(
FILE
,
"\t.rename\t_%s, _%s%s\n"
,
XSTR
(
SYMREF
,
0
)
,
XSTR
(
SYMREF
,
0
)
,
arc_mangle_suffix
)
;
}
}
</s>

Worker function for TARGET_ASM_EXTERNAL_LIBCALL .


<s>
static
void
arc_file_start
(
void
)
{
default_file_start
(
)
;
fprintf
(
asm_out_file
,
"\t.cpu %s\n"
,
arc_cpu_string
)
;
}
</s>

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


<s> static bool arc_handle_option ( size_t code , const char * arg , int value ATTRIBUTE_UNUSED ) { switch ( code ) { case OPT_mcpu_ : return strcmp ( arg , "base" ) == 0 || ARC_EXTENSION_CPU ( arg ) ; default : return true ; } } </s>


<s> void arc_init ( void ) { char * tmp ; arc_text_section = tmp = xmalloc ( strlen ( arc_text_string ) + sizeof ( ARC_SECTION_FORMAT ) + 1 ) ; sprintf ( tmp , ARC_SECTION_FORMAT , arc_text_string ) ; arc_data_section = tmp = xmalloc ( strlen ( arc_data_string ) + sizeof ( ARC_SECTION_FORMAT ) + 1 ) ; sprintf ( tmp , ARC_SECTION_FORMAT , arc_data_string ) ; arc_rodata_section = tmp = xmalloc ( strlen ( arc_rodata_string ) + sizeof ( ARC_SECTION_FORMAT ) + 1 ) ; sprintf ( tmp , ARC_SECTION_FORMAT , arc_rodata_string ) ; arc_init_reg_tables ( ) ; memset ( arc_punct_chars , 0 , sizeof ( arc_punct_chars ) ) ; arc_punct_chars [ '#' ] = 1 ; arc_punct_chars [ '*' ] = 1 ; arc_punct_chars [ '?' ] = 1 ; arc_punct_chars [ '!' ] = 1 ; arc_punct_chars [ '~' ] = 1 ; } </s>


<s> void arc_initialize_trampoline ( rtx tramp ATTRIBUTE_UNUSED , rtx fnaddr ATTRIBUTE_UNUSED , rtx cxt ATTRIBUTE_UNUSED ) { } </s>

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


<s> static void arc_init_reg_tables ( void ) { int i ; for ( i = 0 ; i < NUM_MACHINE_MODES ; i ++ ) { switch ( GET_MODE_CLASS ( i ) ) { case MODE_INT : case MODE_PARTIAL_INT : case MODE_COMPLEX_INT : if ( GET_MODE_SIZE ( i ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) S_MODE ; else if ( GET_MODE_SIZE ( i ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) D_MODE ; else if ( GET_MODE_SIZE ( i ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) T_MODE ; else if ( GET_MODE_SIZE ( i ) == 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 ( i ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) SF_MODE ; else if ( GET_MODE_SIZE ( i ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) DF_MODE ; else if ( GET_MODE_SIZE ( i ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) TF_MODE ; else if ( GET_MODE_SIZE ( i ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) OF_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_CC : arc_mode_class [ i ] = 1 << ( int ) C_MODE ; break ; default : arc_mode_class [ i ] = 0 ; break ; } } for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) { if ( i < 60 ) arc_regno_reg_class [ i ] = GENERAL_REGS ; else if ( i == 60 ) arc_regno_reg_class [ i ] = LPCOUNT_REG ; else if ( i == 61 ) arc_regno_reg_class [ i ] = NO_REGS ; else arc_regno_reg_class [ i ] = NO_REGS ; } } </s>


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

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


"\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n"

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


<s> void arc_print_operand_address ( FILE * file , rtx addr ) { register rtx base , index = 0 ; int offset = 0 ; switch ( GET_CODE ( addr ) ) { case REG : fputs ( reg_names [ REGNO ( addr ) ] , file ) ; break ; case SYMBOL_REF : if ( 0 && SYMBOL_REF_FUNCTION_P ( addr ) ) { fprintf ( file , "%%st(" ) ; output_addr_const ( file , addr ) ; fprintf ( file , ")" ) ; } else output_addr_const ( file , addr ) ; break ; case PLUS : if ( GET_CODE ( XEXP ( addr , 0 ) ) == CONST_INT ) offset = INTVAL ( XEXP ( addr , 0 ) ) , base = XEXP ( addr , 1 ) ; else if ( GET_CODE ( XEXP ( addr , 1 ) ) == CONST_INT ) offset = INTVAL ( XEXP ( addr , 1 ) ) , base = XEXP ( addr , 0 ) ; else base = XEXP ( addr , 0 ) , index = XEXP ( addr , 1 ) ; gcc_assert ( GET_CODE ( base ) == REG ) ; fputs ( reg_names [ REGNO ( base ) ] , file ) ; if ( index == 0 ) { if ( offset != 0 ) fprintf ( file , ",%d" , offset ) ; } else { switch ( GET_CODE ( index ) ) { case REG : fprintf ( file , ",%s" , reg_names [ REGNO ( index ) ] ) ; break ; case SYMBOL_REF : fputc ( ',' , file ) , output_addr_const ( file , index ) ; break ; default : gcc_unreachable ( ) ; } } break ; case PRE_INC : case PRE_DEC : gcc_unreachable ( ) ; break ; default : output_addr_const ( file , addr ) ; break ; } } </s>

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


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

Worker function for TARGET_RETURN_IN_MEMORY .


<s> static bool arc_rtx_costs ( rtx x , int code , int outer_code ATTRIBUTE_UNUSED , int * total ) { switch ( code ) { case CONST_INT : if ( SMALL_INT ( INTVAL ( x ) ) ) { * total = 0 ; return true ; } case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( 1 ) ; return true ; case CONST_DOUBLE : { rtx high , low ; split_double ( x , & high , & low ) ; * total = COSTS_N_INSNS ( ! SMALL_INT ( INTVAL ( high ) ) + ! SMALL_INT ( INTVAL ( low ) ) ) ; return true ; } case ASHIFT : case ASHIFTRT : case LSHIFTRT : if ( TARGET_SHIFTER ) * total = COSTS_N_INSNS ( 1 ) ; else if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) * total = COSTS_N_INSNS ( 16 ) ; else * total = COSTS_N_INSNS ( INTVAL ( XEXP ( ( x ) , 1 ) ) ) ; return false ; default : return false ; } } </s>

Compute a ( partial ) cost for rtx X . Return true if the complete cost has been computed , and false if subexpressions should be scanned . In either case , * TOTAL contains the cost result .


<s>
void
arc_save_restore
(
FILE
*
file
,
const
char
*
base_reg
,
unsigned
int
offset
,
unsigned
int
gmask
,
const
char
*
op
)
{
int
regno
;
if
(
gmask
==
0
)
return
;
for
(
regno
=
0
;
regno
<=
31
;
regno
++
)
{
if
(
(
gmask
&
(
1L
<<
regno
)
)
!=
0
)
{
fprintf
(
file
,
"\t%s %s,[%s,%d]\n"
,
op
,
reg_names
[
regno
]
,
base_reg
,
offset
)
;
offset
+=
UNITS_PER_WORD
;
}
}
}
</s>

BASE_REG is the base register to use for addressing and to adjust . GMASK is a bitmask of general purpose registers to save/restore . epilogue_p 0 : prologue 1 : epilogue 2 : epilogue , sibling thunk If * FIRST_OFFSET is non-zero , add it first to BASE_REG - preferably using a pre-modify for the first memory access . * FIRST_OFFSET is then zeroed .


<s> enum machine_mode arc_select_cc_mode ( enum rtx_code op , rtx x ATTRIBUTE_UNUSED , rtx y ATTRIBUTE_UNUSED ) { switch ( op ) { case EQ : case NE : return CCZNmode ; default : switch ( GET_CODE ( x ) ) { case AND : case IOR : case XOR : case SIGN_EXTEND : case ZERO_EXTEND : return CCZNmode ; case ASHIFT : case ASHIFTRT : case LSHIFTRT : return CCZNCmode ; default : break ; } } return CCmode ; } </s>

Given a comparison code ( EQ , NE , etc . ) and the first operand of a COMPARE , return the mode to be used for the comparison .


<s> static void arc_setup_incoming_varargs ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type ATTRIBUTE_UNUSED , int * pretend_size , int no_rtl ) { int first_anon_arg ; gcc_assert ( mode != BLKmode ) ; first_anon_arg = * cum + ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; if ( first_anon_arg < MAX_ARC_PARM_REGS && ! no_rtl ) { int first_reg_offset = first_anon_arg ; int size = MAX_ARC_PARM_REGS - first_reg_offset ; int align_slop = size & 1 ; rtx regblock ; regblock = gen_rtx_MEM ( BLKmode , plus_constant ( arg_pointer_rtx , FIRST_PARM_OFFSET ( 0 ) + align_slop * UNITS_PER_WORD ) ) ; set_mem_alias_set ( regblock , get_varargs_alias_set ( ) ) ; set_mem_align ( regblock , BITS_PER_WORD ) ; move_block_from_reg ( first_reg_offset , regblock , MAX_ARC_PARM_REGS - first_reg_offset ) ; * pretend_size = ( ( MAX_ARC_PARM_REGS - first_reg_offset + align_slop ) * 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> int call_address_operand ( rtx op , enum machine_mode mode ) { return ( symbolic_operand ( op , mode ) || ( GET_CODE ( op ) == CONST_INT && LEGITIMATE_CONSTANT_P ( op ) ) || ( GET_CODE ( op ) == REG ) ) ; } </s>

Return true if OP is a valid call operand .


<s> int call_operand ( rtx op , enum machine_mode mode ) { if ( GET_CODE ( op ) != MEM ) return 0 ; op = XEXP ( op , 0 ) ; return call_address_operand ( op , mode ) ; } </s>

Call insn on SPARC can take a PC-relative constant address , or any regular memory address .


<s> int const_sint32_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { return ( GET_CODE ( op ) == CONST_INT && ( INTVAL ( op ) >= ( - 0x7fffffff - 1 ) && INTVAL ( op ) <= 0x7fffffff ) ) ; } </s>

Accept integer operands in the range -0x80000000 .. 0x7fffffff . We have to check the range carefully since this predicate is used in DImode contexts .


<s> int const_uint32_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { return ( GET_CODE ( op ) == CONST_INT && ( INTVAL ( op ) >= 0 && INTVAL ( op ) <= 0xffffffffL ) ) ; return ( ( GET_CODE ( op ) == CONST_INT && INTVAL ( op ) >= 0 ) || ( GET_CODE ( op ) == CONST_DOUBLE && CONST_DOUBLE_HIGH ( op ) == 0 ) ) ; } </s>

Accept integer operands in the range 0 .. 0xffffffff . We have to check the range carefully since this predicate is used in DImode contexts . Also , we need some extra crud to make it work when hosted on 64-bit machines .


<s> rtx gen_compare_reg ( enum rtx_code code , rtx x , rtx y ) { enum machine_mode mode = SELECT_CC_MODE ( code , x , y ) ; rtx cc_reg ; cc_reg = gen_rtx_REG ( mode , 61 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , cc_reg , gen_rtx_COMPARE ( mode , x , y ) ) ) ; return cc_reg ; } </s>

Emit the compare insn and return the CC reg for the comparison in CMP .


<s> static int get_arc_condition_code ( rtx comparison ) { switch ( GET_CODE ( comparison ) ) { case EQ : return 2 ; case NE : return 3 ; case GT : return 10 ; case LE : return 11 ; case GE : return 12 ; case LT : return 13 ; case GTU : return 14 ; case LEU : return 15 ; case LTU : return 6 ; case GEU : return 7 ; default : gcc_unreachable ( ) ; } return ( 42 ) ; } </s>

Returns the index of the ARC condition code string in ` arc_condition_codes ' . COMPARISON should be an rtx like ` ( eq ( ... ) ( ... ) ) ' .


<s> int load_update_operand ( rtx op , enum machine_mode mode ) { if ( GET_CODE ( op ) != MEM || GET_MODE ( op ) != mode ) return 0 ; op = XEXP ( op , 0 ) ; if ( GET_CODE ( op ) != PLUS || GET_MODE ( op ) != Pmode || ! register_operand ( XEXP ( op , 0 ) , Pmode ) || ! nonmemory_operand ( XEXP ( op , 1 ) , Pmode ) ) return 0 ; return 1 ; } </s>

Return true if OP is valid load with update operand .


<s> int long_immediate_loadstore_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { if ( GET_CODE ( op ) != MEM ) return 0 ; op = XEXP ( op , 0 ) ; switch ( GET_CODE ( op ) ) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1 ; case CONST_INT : return 1 ; case CONST_DOUBLE : return 1 ; case REG : return 0 ; case PLUS : if ( GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT && ! SMALL_INT ( INTVAL ( XEXP ( op , 1 ) ) ) ) return 1 ; return 0 ; default : break ; } return 0 ; } </s>

Return true if OP is a MEM that when used as a load or store address will require an 8 byte insn . Load and store instructions do n't allow the same possibilities but they 're similar enough that this one function will do . This is currently only used when calculating length attributes .


<s> int long_immediate_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1 ; case CONST_INT : return ! SMALL_INT ( INTVAL ( op ) ) ; case CONST_DOUBLE : return 1 ; default : break ; } return 0 ; } </s>

Return true if OP will require a long immediate ( limm ) value . This is currently only used when calculating length attributes .


<s> int move_dest_operand ( rtx op , enum machine_mode mode ) { switch ( GET_CODE ( op ) ) { case REG : return register_operand ( op , mode ) ; case SUBREG : if ( GET_CODE ( SUBREG_REG ( op ) ) == MEM ) return address_operand ( XEXP ( SUBREG_REG ( op ) , 0 ) , mode ) ; else return register_operand ( op , mode ) ; case MEM : return address_operand ( XEXP ( op , 0 ) , mode ) ; default : return 0 ; } } </s>

Return true if OP is an acceptable argument for a move destination .


<s> int move_double_src_operand ( rtx op , enum machine_mode mode ) { switch ( GET_CODE ( op ) ) { case REG : return register_operand ( op , mode ) ; case SUBREG : if ( GET_CODE ( SUBREG_REG ( op ) ) == MEM ) return move_double_src_operand ( SUBREG_REG ( op ) , mode ) ; else return register_operand ( op , mode ) ; case MEM : if ( GET_CODE ( XEXP ( op , 0 ) ) == PRE_DEC || GET_CODE ( XEXP ( op , 0 ) ) == PRE_INC ) return 0 ; return address_operand ( XEXP ( op , 0 ) , mode ) ; case CONST_INT : case CONST_DOUBLE : return 1 ; default : return 0 ; } } </s>

Return true if OP is an acceptable argument for a double word move source .


<s> int move_src_operand ( rtx op , enum machine_mode mode ) { switch ( GET_CODE ( op ) ) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1 ; case CONST_INT : return ( LARGE_INT ( INTVAL ( op ) ) ) ; case CONST_DOUBLE : if ( mode == SImode ) return arc_double_limm_p ( op ) ; if ( mode == SFmode ) return GET_MODE ( op ) == SFmode ; return 0 ; case REG : return register_operand ( op , mode ) ; case SUBREG : if ( GET_CODE ( SUBREG_REG ( op ) ) == MEM ) return address_operand ( XEXP ( SUBREG_REG ( op ) , 0 ) , mode ) ; else return register_operand ( op , mode ) ; case MEM : return address_operand ( XEXP ( op , 0 ) , mode ) ; default : return 0 ; } } </s>

Return true if OP is an acceptable argument for a single word move source .


<s> int nonvol_nonimm_operand ( rtx op , enum machine_mode mode ) { if ( GET_CODE ( op ) == MEM && MEM_VOLATILE_P ( op ) ) return 0 ; return nonimmediate_operand ( op , mode ) ; } </s>

Return true if OP is a non-volatile non-immediate operand . Volatile memory refs require a special `` cache-bypass '' instruction and only the standard movXX patterns are set up to handle them .


"lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start"

"mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2"

FIXME : This probably can be done using a define_split in arc.md . Alternately , generate rtx rather than output instructions .


<s> int proper_comparison_operator ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { enum rtx_code code ; if ( ! COMPARISON_P ( op ) ) return 0 ; code = GET_CODE ( op ) ; if ( GET_MODE ( XEXP ( op , 0 ) ) == CCZNmode ) return ( code == EQ || code == NE ) ; if ( GET_MODE ( XEXP ( op , 0 ) ) == CCZNCmode ) return ( code == EQ || code == NE || code == LTU || code == GEU || code == GTU || code == LEU ) ; return 1 ; } </s>

Return 1 if OP is a comparison operator valid for the mode of CC . This allows the use of MATCH_OPERATOR to recognize all the branch insns . Some insns only set a few bits in the condition code . So only allow those comparisons that use the bits that are valid .


<s> static void record_cc_ref ( rtx insn ) { last_insn_set_cc_p = current_insn_set_cc_p ; switch ( get_attr_cond ( insn ) ) { case COND_SET : case COND_SET_ZN : case COND_SET_ZNC : if ( get_attr_length ( insn ) == 1 ) current_insn_set_cc_p = 1 ; else current_insn_set_cc_p = 0 ; break ; default : current_insn_set_cc_p = 0 ; break ; } } </s>

Update compare/branch separation marker .


<s> int shift_operator ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case ASHIFTRT : case LSHIFTRT : case ASHIFT : return 1 ; default : return 0 ; } } </s>


<s> int short_immediate_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { if ( GET_CODE ( op ) != CONST_INT ) return 0 ; return SMALL_INT ( INTVAL ( op ) ) ; } </s>

Return true if OP is a short immediate ( shimm ) value .


<s> int store_update_operand ( rtx op , enum machine_mode mode ) { if ( GET_CODE ( op ) != MEM || GET_MODE ( op ) != mode ) return 0 ; op = XEXP ( op , 0 ) ; if ( GET_CODE ( op ) != PLUS || GET_MODE ( op ) != Pmode || ! register_operand ( XEXP ( op , 0 ) , Pmode ) || ! ( GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT && SMALL_INT ( INTVAL ( XEXP ( op , 1 ) ) ) ) ) return 0 ; return 1 ; } </s>

Return true if OP is valid store with update operand .


<s> int symbolic_memory_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { if ( GET_CODE ( op ) == SUBREG ) op = SUBREG_REG ( op ) ; if ( GET_CODE ( op ) != MEM ) return 0 ; op = XEXP ( op , 0 ) ; return ( GET_CODE ( op ) == SYMBOL_REF || GET_CODE ( op ) == CONST || GET_CODE ( op ) == LABEL_REF ) ; } </s>

Returns 1 if OP is a memory reference involving a symbolic constant that is not in the constant pool .


<s> int symbolic_operand ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1 ; default : return 0 ; } } </s>

Return 1 if X contains a symbolic expression . We know these expressions will have one of a few well defined forms , so we need only check those forms .


<s> static int arc600_corereg_hazard ( rtx_insn * pred , rtx_insn * succ ) { if ( ! TARGET_ARC600 ) return 0 ; if ( recog_memoized ( succ ) == CODE_FOR_doloop_end_i && LABEL_P ( prev_nonnote_insn ( succ ) ) ) return 0 ; if ( recog_memoized ( succ ) == CODE_FOR_doloop_begin_i ) 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> 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 : 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> 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 ( recog_memoized ( insn ) == CODE_FOR_doloop_end_i ) { rtx_insn * prev = prev_nonnote_insn ( insn ) ; return ( ( LABEL_P ( prev ) || ( TARGET_ARC600 && ( JUMP_P ( prev ) || CALL_P ( prev ) || ( NONJUMP_INSN_P ( prev ) && GET_CODE ( PATTERN ( prev ) ) == SEQUENCE ) ) ) ) ? len + 4 : 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> static int arc_arg_partial_bytes ( cumulative_args_t cum_v , machine_mode mode , tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int bytes = ( mode == BLKmode ? int_size_in_bytes ( type ) : ( int ) GET_MODE_SIZE ( mode ) ) ; int words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; int arg_num = * cum ; int ret ; arg_num = ROUND_ADVANCE_CUM ( arg_num , mode , type ) ; ret = GPR_REST_ARG_REGS ( arg_num ) ; ret = ( ret >= words ? 0 : ret * UNITS_PER_WORD ) ; return ret ; } </s>


<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 ) ; 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> 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 bool arc_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return to == FRAME_POINTER_REGNUM || ! arc_frame_pointer_required ( ) ; } </s>

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


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

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


<s> static bool arc_can_use_doloop_p ( const widest_int & iterations , const widest_int & , unsigned int loop_depth , bool entered_at_top ) { if ( loop_depth > 1 ) return false ; if ( TARGET_ARC700 && ! entered_at_top && wi :: gtu_p ( iterations , 0 ) && wi :: leu_p ( iterations , flag_pic ? 6 : 3 ) ) return false ; return true ; } </s>


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

Update * STATE as we would when we emit INSN .


<s> unsigned int arc_compute_frame_size ( int size ) { int regno ; unsigned int total_size , var_size , args_size , pretend_size , extra_size ; unsigned int reg_size , reg_offset ; unsigned int gmask ; enum arc_function_type fn_type ; int interrupt_p ; struct arc_frame_info * frame_info = & cfun -> machine -> frame_info ; size = ARC_STACK_ALIGN ( size ) ; var_size = size ; args_size = crtl -> outgoing_args_size ; reg_size = 0 ; gmask = 0 ; fn_type = arc_compute_function_type ( cfun ) ; interrupt_p = ARC_INTERRUPT_P ( fn_type ) ; for ( regno = 0 ; regno <= 31 ; regno ++ ) { if ( MUST_SAVE_REGISTER ( regno , interrupt_p ) ) { reg_size += UNITS_PER_WORD ; gmask |= 1 << regno ; } } frame_info -> save_return_addr = ( ! crtl -> is_leaf || df_regs_ever_live_p ( RETURN_ADDR_REGNUM ) ) ; if ( optimize_size && ! TARGET_NO_MILLICODE_THUNK_SET ) { if ( arc_compute_millicode_save_restore_regs ( gmask , frame_info ) ) frame_info -> save_return_addr = true ; } extra_size = 0 ; if ( MUST_SAVE_RETURN_ADDR ) extra_size = 4 ; if ( 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 ; total_size = ARC_STACK_ALIGN ( total_size ) ; reg_offset = ( total_size - ( pretend_size + reg_size + extra_size ) + ( 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> 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" ) ) 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 int arc_compute_millicode_save_restore_regs ( unsigned int gmask , struct arc_frame_info * frame ) { int regno ; int start_reg = 13 , end_reg = 25 ; for ( regno = start_reg ; regno <= end_reg && ( gmask & ( 1L << regno ) ) ; ) regno ++ ; end_reg = regno - 1 ; if ( regno - start_reg >= 3 - ( crtl -> is_leaf == 0 ) ) { frame -> millicode_start_reg = 13 ; frame -> millicode_end_reg = regno - 1 ; return 1 ; } return 0 ; } </s>

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


<s> int arc_decl_pretend_args ( tree decl ) { gcc_assert ( decl == current_function_decl ) ; return crtl -> args . pretend_args_size ; } </s>

Return the size of the pretend args for DECL .


<s> static void arc_encode_section_info ( tree decl , rtx rtl , int first ) { default_encode_section_info ( decl , rtl , first ) ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { rtx symbol = XEXP ( rtl , 0 ) ; int flags = SYMBOL_REF_FLAGS ( symbol ) ; tree attr = ( TREE_TYPE ( decl ) != error_mark_node ? TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) : NULL_TREE ) ; tree long_call_attr = lookup_attribute ( "long_call" , attr ) ; tree medium_call_attr = lookup_attribute ( "medium_call" , attr ) ; tree short_call_attr = lookup_attribute ( "short_call" , attr ) ; if ( long_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_LONG_CALL ; else if ( medium_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_MEDIUM_CALL ; else if ( short_call_attr != NULL_TREE ) flags |= SYMBOL_FLAG_SHORT_CALL ; SYMBOL_REF_FLAGS ( symbol ) = flags ; } } </s>

Implement TARGET_ENCODE_SECTION_INFO hook .


<s> bool arc_epilogue_uses ( int regno ) { 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 ] ; } 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> 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 ) 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 ( 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 ; if ( piece > size ) piece = size & - size ; 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> void arc_expand_prologue ( void ) { int size = get_frame_size ( ) ; unsigned int gmask = cfun -> machine -> frame_info . gmask ; unsigned int frame_size_to_allocate ; int first_offset = 0 ; size = ARC_STACK_ALIGN ( size ) ; size = ( ! cfun -> machine -> frame_info . initialized ? arc_compute_frame_size ( size ) : cfun -> machine -> frame_info . total_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 ( MUST_SAVE_RETURN_ADDR ) { 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 ( frame_pointer_needed ) { 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 ; 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 ( crtl -> uses_pic_offset_table ) arc_finalize_pic ( ) ; } </s>

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


<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 ( VOIDmode , 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 ) ) ) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --


<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
(
PREV_INSN
(
insn
)
&&
PREV_INSN
(
NEXT_INSN
(
insn
)
)
==
insn
&&
arc_hazard
(
prev_real_insn
(
insn
)
,
insn
)
)
{
current_output_insn
=
emit_insn_before
(
gen_nop
(
)
,
NEXT_INSN
(
PREV_INSN
(
insn
)
)
)
;
final_scan_insn
(
current_output_insn
,
asm_out_file
,
optimize
,
1
,
)
;
current_output_insn
=
insn
;
}
extract_constrain_insn_cached
(
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 .


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

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


<s> static void arc_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int bytes = ( mode == BLKmode ? int_size_in_bytes ( type ) : ( int ) GET_MODE_SIZE ( mode ) ) ; int words = ( bytes + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; int i ; if ( words ) * cum = ROUND_ADVANCE_CUM ( * cum , mode , type ) ; for ( i = 0 ; i < words ; i ++ ) * cum = ARC_NEXT_ARG_REG ( * cum ) ; } </s>

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


<s> static bool arc_function_ok_for_sibcall ( tree decl ATTRIBUTE_UNUSED , tree exp ATTRIBUTE_UNUSED ) { if ( ARC_INTERRUPT_P ( arc_compute_function_type ( cfun ) ) ) return false ; return true ; } </s>

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


<s> int arc_get_unalign ( void ) { return cfun -> machine -> unalign ; } </s>

Accessor functions for cfun- > machine- > unalign .


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

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

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


<s> int arc_hazard ( rtx_insn * pred , rtx_insn * succ ) { if ( ! TARGET_ARC600 ) return 0 ; if ( ! pred || ! INSN_P ( pred ) || ! succ || ! INSN_P ( succ ) ) return 0 ; if ( recog_memoized ( succ ) == CODE_FOR_doloop_end_i && ( JUMP_P ( pred ) || CALL_P ( pred ) || GET_CODE ( PATTERN ( pred ) ) == SEQUENCE ) ) return 4 ; return arc600_corereg_hazard ( pred , succ ) ; } </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 .


"-mmul32x16 supported only for ARC600 or ARC601"

"-mno-dpfp-lrsr supported only with -mdpfp"

"FPX fast and compact options cannot be specified together"

"-mspfp_fast not available on ARC600 or ARC601"

"FPX extensions not available on pre-ARC600 cores"

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

Called by OVERRIDE_OPTIONS to initialize various things .


<s> static void arc_initialize_trampoline ( rtx tramp , tree fndecl , rtx cxt ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; emit_store_direct ( tramp , 0 , TARGET_BIG_ENDIAN ? 0x78e0d403 : 0xd40378e0 ) ; emit_store_direct ( tramp , 4 , TARGET_BIG_ENDIAN ? 0x170c700b : 0x700b170c ) ; emit_store_direct ( tramp , 8 , TARGET_BIG_ENDIAN ? 0x7c0078e0 : 0x78e07c00 ) ; emit_move_insn ( adjust_address ( tramp , SImode , 12 ) , fnaddr ) ; emit_move_insn ( adjust_address ( tramp , SImode , 16 ) , cxt ) ; emit_insn ( gen_flush_icache ( adjust_address ( tramp , SImode , 0 ) ) ) ; } </s>

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


<s> int arc_initial_elimination_offset ( int from , int to ) { if ( ! cfun -> machine -> frame_info . initialized ) arc_compute_frame_size ( get_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> static struct machine_function * arc_init_machine_status ( void ) { struct machine_function * machine ; machine = ggc_cleared_alloc < machine_function > ( ) ; machine -> fn_type = ARC_FUNCTION_UNKNOWN ; machine -> force_short_suffix = - 1 ; return machine ; } </s>

The usual ; we set up our machine_function data .


<s> static void arc_init_reg_tables ( void ) { int i ; for ( i = 0 ; i < NUM_MACHINE_MODES ; i ++ ) { machine_mode m = ( machine_mode ) i ; switch ( GET_MODE_CLASS ( m ) ) { case MODE_INT : case MODE_PARTIAL_INT : case MODE_COMPLEX_INT : if ( GET_MODE_SIZE ( m ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) S_MODE ; else if ( GET_MODE_SIZE ( m ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) D_MODE ; else if ( GET_MODE_SIZE ( m ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) T_MODE ; else if ( GET_MODE_SIZE ( m ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) O_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_FLOAT : case MODE_COMPLEX_FLOAT : if ( GET_MODE_SIZE ( m ) <= 4 ) arc_mode_class [ i ] = 1 << ( int ) SF_MODE ; else if ( GET_MODE_SIZE ( m ) == 8 ) arc_mode_class [ i ] = 1 << ( int ) DF_MODE ; else if ( GET_MODE_SIZE ( m ) == 16 ) arc_mode_class [ i ] = 1 << ( int ) TF_MODE ; else if ( GET_MODE_SIZE ( m ) == 32 ) arc_mode_class [ i ] = 1 << ( int ) OF_MODE ; else arc_mode_class [ i ] = 0 ; break ; case MODE_VECTOR_INT : 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 ) arc_mode_class [ i ] = 1 << ( int ) C_MODE ; else arc_mode_class [ i ] = 0 ; break ; } } } </s>


<s> static bool arc_in_small_data_p ( const_tree decl ) { HOST_WIDE_INT size ; if ( TREE_CODE ( decl ) == STRING_CST || TREE_CODE ( decl ) == FUNCTION_DECL ) return false ; if ( TARGET_NO_SDATA_SET ) return false ; if ( TREE_CODE ( decl ) == VAR_DECL && DECL_SECTION_NAME ( decl ) != 0 ) { const char * name ; name = DECL_SECTION_NAME ( decl ) ; if ( strcmp ( name , ".sdata" ) != 0 && strcmp ( name , ".sbss" ) != 0 ) return false ; if ( ! DECL_EXTERNAL ( decl ) ) return true ; } else if ( 1 ) { if ( TREE_CODE ( decl ) != VAR_DECL ) return false ; if ( TREE_READONLY ( decl ) && ! TREE_SIDE_EFFECTS ( decl ) && ( ! DECL_INITIAL ( decl ) || TREE_CONSTANT ( DECL_INITIAL ( decl ) ) ) ) return false ; if ( default_binds_local_p_1 ( decl , 1 ) || arc_decl_anon_ns_mem_p ( decl ) ) return false ; if ( TREE_THIS_VOLATILE ( decl ) ) return false ; } if ( DECL_WEAK ( decl ) ) return false ; size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; return ( size > 0 && size <= 4 ) ; } </s>

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


<s> int arc_label_align ( rtx 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 , rtx x ) { if ( ! flag_pic ) return true ; switch ( GET_CODE ( x ) ) { case CONST : x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == PLUS ) { if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) 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_GOT : case UNSPEC_PROF : return true ; default : gcc_unreachable ( ) ; } if ( arc_raw_symbolic_reference_mentioned_p ( x , false ) ) return false ; break ; case LABEL_REF : case SYMBOL_REF : 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 ; addr = XEXP ( addr , 0 ) ; if ( GET_CODE ( addr ) == PLUS ) { if ( GET_CODE ( XEXP ( addr , 1 ) ) != CONST_INT ) return false ; addr = XEXP ( addr , 0 ) ; } return ( GET_CODE ( addr ) == UNSPEC && XVECLEN ( addr , 0 ) == 1 && XINT ( addr , 1 ) == ARC_UNSPEC_GOT && GET_CODE ( XVECEXP ( addr , 0 , 0 ) ) == SYMBOL_REF ) ; } </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 ) 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> bool arc_legitimate_pic_operand_p ( rtx x ) { return ! arc_raw_symbolic_reference_mentioned_p ( x , true ) ; } </s>

Nonzero if the constant value X is a legitimate general operand when generating PIC code . It is given that flag_pic is on and that X satisfies CONSTANT_P or is a CONST_DOUBLE .


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

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


<s> static bool arc_lra_p ( void ) { return ! TARGET_NO_LRA ; } </s>

Return true if we use LRA instead of reload pass .


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

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


<s> static rtx_insn * arc_next_active_insn ( rtx_insn * insn , struct arc_ccfsm * statep ) { rtx pat ; do { if ( statep ) arc_ccfsm_post_advance ( insn , statep ) ; insn = NEXT_INSN ( insn ) ; if ( ! insn || BARRIER_P ( insn ) ) return NULL ; if ( statep ) arc_ccfsm_advance ( insn , statep ) ; } while ( NOTE_P ( insn ) || ( cfun -> machine -> arc_reorg_started && LABEL_P ( insn ) && ! label_to_alignment ( insn ) ) || ( NONJUMP_INSN_P ( insn ) && ( GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER ) ) ) ; if ( ! LABEL_P ( insn ) ) { gcc_assert ( INSN_P ( insn ) ) ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == ADDR_VEC || GET_CODE ( pat ) == ADDR_DIFF_VEC ) return NULL ; if ( GET_CODE ( pat ) == SEQUENCE ) return as_a < rtx_insn * > ( XVECEXP ( pat , 0 , 0 ) ) ; } return insn ; } </s>

Like next_active_insn , but return NULL if we find an ADDR_ ( DIFF_ ) VEC , and look inside SEQUENCEs .


<s> int arc_output_addsi ( rtx * operands , bool cond_p , bool output_p ) { char format [ 32 ] ; 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_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 .


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


<s>
static
void
arc_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
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
)
)
fputs
(
"\tj\t"
,
file
)
;
else
fputs
(
"\tb\t"
,
file
)
;
assemble_name
(
file
,
XSTR
(
fnaddr
,
0
)
)
;
fputc
(
'\n'
,
file
)
;
}
</s>

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


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


"call/return and return/return must be 6 bytes apart to avoid mispredict"

"Long unaligned jump avoids non-delay slot penalty"

We are about to output a return insn . Add padding if necessary to avoid a mispredict . A return could happen immediately after the function start , but after a call we know that there will be at least a blink restore .


<s> static bool arc_pass_by_reference ( cumulative_args_t ca_v ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , const_tree type , bool named ATTRIBUTE_UNUSED ) { return ( type != 0 && ( TREE_CODE ( TYPE_SIZE ( type ) ) != INTEGER_CST || TREE_ADDRESSABLE ( type ) ) ) ; } </s>

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


<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 ( 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 rtx arc_process_double_reg_moves ( rtx * operands ) { rtx dest = operands [ 0 ] ; rtx src = operands [ 1 ] ; rtx val ; 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 NULL_RTX ; start_sequence ( ) ; if ( state == srcDx ) { if ( TARGET_DPFP_DISABLE_LRSR ) { rtx set = gen_rtx_SET ( VOIDmode , 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 ( VOIDmode , destHigh , gen_rtx_UNSPEC_VOLATILE ( Pmode , gen_rtvec ( 1 , src ) , VUNSPEC_LR_HIGH ) ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , destLow , gen_rtx_UNSPEC_VOLATILE ( Pmode , gen_rtvec ( 1 , src ) , VUNSPEC_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_DEXCL_NORES ) ) ; } else gcc_unreachable ( ) ; val = get_insns ( ) ; end_sequence ( ) ; return val ; } </s>

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


<s> bool arc_profile_call ( rtx callee ) { rtx from = XEXP ( DECL_RTL ( current_function_decl ) , 0 ) ; if ( TARGET_UCB_MCOUNT ) return false ; if ( CONSTANT_P ( callee ) ) { rtx count_ptr = gen_rtx_CONST ( Pmode , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 3 , from , callee , CONST0_RTX ( Pmode ) ) , UNSPEC_PROF ) ) ; rtx counter = gen_rtx_MEM ( SImode , count_ptr ) ; emit_move_insn ( counter , force_reg ( SImode , plus_constant ( SImode , counter , 1 ) ) ) ; return false ; } else { rtx count_list_ptr = gen_rtx_CONST ( Pmode , gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 3 , from , CONST0_RTX ( Pmode ) , CONST0_RTX ( Pmode ) ) , UNSPEC_PROF ) ) ; emit_move_insn ( gen_rtx_REG ( Pmode , 8 ) , count_list_ptr ) ; emit_move_insn ( gen_rtx_REG ( Pmode , 9 ) , callee ) ; return true ; } } </s>

Emit profiling code for calling CALLEE . Return true if a special call pattern needs to be generated .


<s> bool arc_raw_symbolic_reference_mentioned_p ( rtx op , bool skip_local ) { register const char * fmt ; register int i ; if ( GET_CODE ( op ) == UNSPEC ) return false ; if ( GET_CODE ( op ) == SYMBOL_REF ) { tree decl = SYMBOL_REF_DECL ( op ) ; return ! skip_local || ! decl || ! default_binds_local_p ( decl ) ; } fmt = GET_RTX_FORMAT ( GET_CODE ( op ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( op ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { register int j ; for ( j = XVECLEN ( op , i ) - 1 ; j >= 0 ; j -- ) if ( arc_raw_symbolic_reference_mentioned_p ( XVECEXP ( op , i , j ) , skip_local ) ) return true ; } else if ( fmt [ i ] == 'e' && arc_raw_symbolic_reference_mentioned_p ( XEXP ( op , i ) , skip_local ) ) return true ; } return false ; } </s>

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


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

Worker function for TARGET_RETURN_IN_MEMORY .


<s> int arc_return_slot_offset ( ) { struct arc_frame_info * afi = & cfun -> machine -> frame_info ; return ( afi -> save_return_addr ? afi -> total_size - afi -> pretend_size - afi -> extra_size : - 1 ) ; } </s>

Return the offset relative to the stack pointer where the return address is stored , or -1 if it is not stored .


<s> rtx arc_rewrite_small_data ( rtx op ) { 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 ) ) { gcc_assert ( SDATA_BASE_REGNUM == PIC_OFFSET_TABLE_REGNUM ) ; * loc = gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , * loc ) ; if ( loc != & op ) { if ( GET_CODE ( op ) == MEM && & XEXP ( op , 0 ) == loc ) ; else if ( GET_CODE ( op ) == MEM && GET_CODE ( XEXP ( op , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( op , 0 ) , 0 ) ) == MULT ) * loc = force_reg ( Pmode , * loc ) ; else gcc_unreachable ( ) ; } iter . skip_subrtxes ( ) ; } else if ( GET_CODE ( * loc ) == PLUS && rtx_equal_p ( XEXP ( * loc , 0 ) , pic_offset_table_rtx ) ) iter . skip_subrtxes ( ) ; } return op ; } </s>

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


<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 ) ; } return ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_SMALL_P ( x ) ) ; } </s>

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


<s> static reg_class_t arc_secondary_reload ( bool in_p , rtx x , reg_class_t cl , machine_mode , secondary_reload_info * ) { if ( cl == DOUBLE_REGS ) return GENERAL_REGS ; if ( ( cl == LPCOUNT_REG || cl == WRITABLE_CORE_REGS ) && in_p && MEM_P ( x ) ) return GENERAL_REGS ; 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> machine_mode arc_select_cc_mode ( enum rtx_code op , rtx x , rtx y ) { machine_mode mode = GET_MODE ( x ) ; rtx x1 ; if ( GET_MODE_CLASS ( mode ) == MODE_INT && y == const0_rtx && ( op == EQ || op == NE || ( ( op == LT || op == GE ) && GET_MODE_SIZE ( GET_MODE ( x ) ) <= 4 ) ) ) return CC_ZNmode ; if ( mode == SImode && GET_CODE ( y ) == NEG && ( op == EQ || op == NE ) ) return CC_ZNmode ; if ( mode == SImode && ( op == EQ || op == NE ) && CONST_INT_P ( y ) && ( ( INTVAL ( y ) - 1 ) & INTVAL ( y ) ) == 0 && INTVAL ( y ) ) return CC_Zmode ; if ( mode == SImode && ( op == EQ || op == NE ) && CONST_INT_P ( y ) && GET_CODE ( x ) == AND && CONST_INT_P ( ( x1 = XEXP ( x , 1 ) ) ) && ( ( INTVAL ( x1 ) + 1 ) & INTVAL ( x1 ) ) == 0 && ( ~ INTVAL ( x1 ) | INTVAL ( y ) ) < 0 && ( ~ INTVAL ( x1 ) | INTVAL ( y ) ) > - 0x800 ) return CC_Zmode ; if ( GET_MODE ( x ) == SImode && ( op == LTU || op == GEU ) && GET_CODE ( x ) == PLUS && ( rtx_equal_p ( XEXP ( x , 0 ) , y ) || rtx_equal_p ( XEXP ( x , 1 ) , y ) ) ) return CC_Cmode ; if ( TARGET_ARGONAUT_SET && ( ( mode == SFmode && TARGET_SPFP ) || ( mode == DFmode && TARGET_DPFP ) ) ) switch ( op ) { case EQ : case NE : case UNEQ : case LTGT : case ORDERED : case UNORDERED : return CC_FPXmode ; case LT : case UNGE : case GT : case UNLE : return CC_FP_GTmode ; case LE : case UNGT : case GE : case UNLT : return CC_FP_GEmode ; default : gcc_unreachable ( ) ; } else if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT && TARGET_OPTFPE ) switch ( op ) { case EQ : case NE : return CC_Zmode ; case LT : case UNGE : case GT : case UNLE : return CC_FP_GTmode ; case LE : case UNGT : case GE : case UNLT : return CC_FP_GEmode ; case UNEQ : case LTGT : return CC_FP_UNEQmode ; case ORDERED : case UNORDERED : return CC_FP_ORDmode ; default : gcc_unreachable ( ) ; } return CCmode ; } </s>

Given a comparison code ( EQ , NE , etc . ) and the first operand of a COMPARE , return the mode to be used for the comparison .


<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 , 1 ) ; first_anon_arg = next_cum ; if ( first_anon_arg < MAX_ARC_PARM_REGS ) { 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_set_default_type_attributes ( tree type ATTRIBUTE_UNUSED ) { gcc_unreachable ( ) ; } </s>


<s> static rtx arc_trampoline_adjust_address ( rtx addr ) { return plus_constant ( Pmode , addr , 2 ) ; } </s>

Allow the profiler to easily distinguish trampolines from normal functions .


<s> static bool arc_vector_mode_supported_p ( machine_mode mode ) { if ( ! TARGET_SIMD_SET ) return false ; if ( ( mode == V4SImode ) || ( mode == V8HImode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


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

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


"register number must be a compile-time constant. Try giving higher optimization levels"

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


"operand for sleep instruction must be an unsigned 6 bit compile-time constant"

Check that after all the constant folding , whether the operand to __builtin_arc_sleep is an unsigned int of 6 bits . If not , flag an error .


<s> bool compact_sda_memory_operand ( rtx op , machine_mode mode ) { rtx addr ; int size ; 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 ) ; return LEGITIMATE_SMALL_DATA_ADDRESS_P ( addr ) ; } </s>

volatile cache option still to be handled .


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

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


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

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


<s> static void emit_store_direct ( rtx block , int offset , int value ) { emit_insn ( gen_store_direct ( adjust_address ( block , SImode , offset ) , force_reg ( SImode , gen_int_mode ( value , SImode ) ) ) ) ; } </s>

Directly store VALUE into memory object BLOCK at OFFSET .


<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 ( addr ) ) ) || ! 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> static rtx frame_move ( rtx dst , rtx src ) { return frame_insn ( gen_rtx_SET ( VOIDmode , dst , src ) ) ; } </s>


<s> rtx gen_mhi ( void ) { return gen_rtx_REG ( SImode , TARGET_BIG_ENDIAN ? 58 : 59 ) ; } </s>

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


<s> rtx gen_mlo ( void ) { return gen_rtx_REG ( SImode , TARGET_BIG_ENDIAN ? 59 : 58 ) ; } </s>

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


<s> static int get_arc_condition_code ( rtx comparison ) { switch ( GET_MODE ( XEXP ( comparison , 0 ) ) ) { case CCmode : case SImode : switch ( GET_CODE ( comparison ) ) { case EQ : return ARC_CC_EQ ; case NE : return ARC_CC_NE ; case GT : return ARC_CC_GT ; case LE : return ARC_CC_LE ; case GE : return ARC_CC_GE ; case LT : return ARC_CC_LT ; case GTU : return ARC_CC_HI ; case LEU : return ARC_CC_LS ; case LTU : return ARC_CC_LO ; case GEU : return ARC_CC_HS ; default : gcc_unreachable ( ) ; } case CC_ZNmode : switch ( GET_CODE ( comparison ) ) { case EQ : return ARC_CC_EQ ; case NE : return ARC_CC_NE ; case GE : return ARC_CC_P ; case LT : return ARC_CC_N ; case GT : return ARC_CC_PNZ ; default : gcc_unreachable ( ) ; } case CC_Zmode : switch ( GET_CODE ( comparison ) ) { case EQ : return ARC_CC_EQ ; case NE : return ARC_CC_NE ; default : gcc_unreachable ( ) ; } case CC_Cmode : switch ( GET_CODE ( comparison ) ) { case LTU : return ARC_CC_C ; case GEU : return ARC_CC_NC ; default : gcc_unreachable ( ) ; } case CC_FP_GTmode : if ( TARGET_ARGONAUT_SET && TARGET_SPFP ) switch ( GET_CODE ( comparison ) ) { case GT : return ARC_CC_N ; case UNLE : return ARC_CC_P ; default : gcc_unreachable ( ) ; } else switch ( GET_CODE ( comparison ) ) { case GT : return ARC_CC_HI ; case UNLE : return ARC_CC_LS ; default : gcc_unreachable ( ) ; } case CC_FP_GEmode : switch ( GET_CODE ( comparison ) ) { case GE : return ARC_CC_HS ; case UNLT : return ARC_CC_LO ; default : gcc_unreachable ( ) ; } case CC_FP_UNEQmode : switch ( GET_CODE ( comparison ) ) { case UNEQ : return ARC_CC_EQ ; case LTGT : return ARC_CC_NE ; default : gcc_unreachable ( ) ; } case CC_FP_ORDmode : switch ( GET_CODE ( comparison ) ) { case UNORDERED : return ARC_CC_C ; case ORDERED : return ARC_CC_NC ; default : gcc_unreachable ( ) ; } case CC_FPXmode : switch ( GET_CODE ( comparison ) ) { case EQ : return ARC_CC_EQ ; case NE : return ARC_CC_NE ; case UNORDERED : return ARC_CC_C ; case ORDERED : return ARC_CC_NC ; case LTGT : return ARC_CC_HI ; case UNEQ : return ARC_CC_LS ; default : gcc_unreachable ( ) ; } default : gcc_unreachable ( ) ; } return ( 42 ) ; } </s>

Returns the index of the ARC condition code string in ` arc_condition_codes ' . COMPARISON should be an rtx like ` ( eq ( ... ) ( ... ) ) ' .


<s> static void output_short_suffix ( FILE * file ) { rtx_insn * insn = current_output_insn ; if ( arc_verify_short ( insn , cfun -> machine -> unalign , 1 ) ) { fprintf ( file , "_s" ) ; cfun -> machine -> unalign ^= 2 ; } extract_insn_cached ( insn ) ; } </s>

When outputting an instruction ( alternative ) that can potentially be short , output the short suffix if the insn is in fact short , and update cfun- > machine- > unalign accordingly .


<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 ( omode , 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 .