<s> bool csky_emit_compare_float ( enum rtx_code code , rtx op0 , rtx op1 ) { rtx cc_reg = gen_rtx_REG ( CCmode , CSKY_CC_REGNUM ) ; bool invert ; machine_mode mode = GET_MODE ( op1 ) ; if ( op1 != CONST0_RTX ( mode ) ) op1 = force_reg ( mode , op1 ) ; invert = false ; switch ( code ) { case EQ : code = NE ; invert = true ; break ; case GT : case LT : case LE : if ( op1 == CONST0_RTX ( mode ) && TARGET_SUPPORT_FPV2 ) op1 = force_reg ( mode , op1 ) ; break ; case ORDERED : code = UNORDERED ; invert = true ; break ; default : break ; } emit_insn ( gen_rtx_SET ( cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return invert ; } </s>

Emit a comparison insn for float values . Return true if the comparison is inverted .


<s> static const char * csky_mangle_type ( const_tree type ) { if ( TREE_CODE ( type ) == REAL_TYPE && TYPE_PRECISION ( type ) == 16 && TYPE_MAIN_VARIANT ( type ) != float16_type_node ) return "Dh" ; return NULL ; } </s>


<s> static void csky_setup_incoming_varargs ( cumulative_args_t pcum_v , const function_arg_info & arg , int * pretend_size , int second_time ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; CUMULATIVE_ARGS local_cum ; cumulative_args_t local_cum_v = pack_cumulative_args ( & local_cum ) ; int regs_to_push ; cfun -> machine -> uses_anonymous_args = 1 ; local_cum = * pcum ; if ( ! TYPE_NO_NAMED_ARGS_STDARG_P ( TREE_TYPE ( current_function_decl ) ) ) csky_function_arg_advance ( local_cum_v , arg ) ; regs_to_push = CSKY_NPARM_REGS - local_cum . reg ; if ( regs_to_push ) * pretend_size = regs_to_push * UNITS_PER_WORD ; } </s>

Implement TARGET_SETUP_INCOMING_VARARGS . On C-Sky the copy from the argument registers to the stack is emitted by the prologue hooks , so here we just have to note how much stack space to save .


<s> static int csky_arg_partial_bytes ( cumulative_args_t pcum_v , machine_mode mode , tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; int param_size = csky_num_arg_regs ( mode , type ) ; if ( * pcum < CSKY_NPARM_REGS && * pcum + param_size > CSKY_NPARM_REGS ) return ( CSKY_NPARM_REGS - * pcum ) * UNITS_PER_WORD ; return 0 ; } </s>

Implement TARGET_ARG_PARTIAL_BYTES . Return the number of bytes at the beginning of an argument that must be put in registers . The value must be zero for arguments that are passed entirely in registers or that are entirely pushed on the stack .


<s> static void csky_conditional_register_usage ( void ) { if ( TARGET_MINI_REGISTERS ) { int i ; for ( i = ( CSKY_LAST_MINI_REGNUM + 1 ) ; i < 32 ; i ++ ) { fixed_regs [ i ] = 1 ; call_used_regs [ i ] = 1 ; call_really_used_regs [ i ] = 1 ; } } else if ( CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK803 ) || ! TARGET_HIGH_REGISTERS ) { int i ; for ( i = CSKY_FIRST_HIGH_REGNUM ; i <= CSKY_LAST_HIGH_REGNUM ; i ++ ) { fixed_regs [ i ] = 1 ; call_used_regs [ i ] = 1 ; call_really_used_regs [ i ] = 1 ; } } if ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) ) { fixed_regs [ CSKY_LR_REGNUM ] = 1 ; call_used_regs [ CSKY_LR_REGNUM ] = 1 ; call_really_used_regs [ CSKY_LR_REGNUM ] = 0 ; } if ( ! TARGET_DSP ) { fixed_regs [ CSKY_HI_REGNUM ] = 1 ; call_used_regs [ CSKY_HI_REGNUM ] = 1 ; call_really_used_regs [ CSKY_HI_REGNUM ] = 1 ; fixed_regs [ CSKY_LO_REGNUM ] = 1 ; call_used_regs [ CSKY_LO_REGNUM ] = 1 ; call_really_used_regs [ CSKY_LO_REGNUM ] = 1 ; } if ( ! TARGET_HARD_FLOAT ) { int regno ; for ( regno = CSKY_FIRST_VFP_REGNUM ; regno <= CSKY_LAST_VFP_REGNUM ; regno ++ ) { fixed_regs [ regno ] = 1 ; call_used_regs [ regno ] = 1 ; call_really_used_regs [ regno ] = 1 ; } } if ( flag_pic ) { fixed_regs [ PIC_OFFSET_TABLE_REGNUM ] = 1 ; call_used_regs [ PIC_OFFSET_TABLE_REGNUM ] = 1 ; call_really_used_regs [ PIC_OFFSET_TABLE_REGNUM ] = 0 ; } } </s>

Implement TARGET_CONDITIONAL_REGISTER_USAGE . Conditionally modify five variables fixed_regs , call_used_regs , global_regs , reg_names , and reg_class_contents , to take into account any dependence of these register sets on target flags . CK801 has registers r0-r8 and r13-r15 . CK802 and CK803 have registers r0-r15 ( the `` low '' registers ) . Other cpus use registers r0-r31 with -mhigh-registers , otherwise also only r0-r15 . CK801 only has 16-bit instructions , most of which can only reference r0-r7 ( the `` mini '' registers ) . So we mark regs outside that range as fixed . -msmart can be used on other arch variants to force the same behavior because it results in smaller code size . TODO : investigate whether it 's beneficial to use r8-r13 as a spill class when TARGET_MINI_REGISTERS instead of making them unusable by the register allocator .


<s> static rtx csky_function_arg ( cumulative_args_t pcum_v , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; if ( * pcum < CSKY_NPARM_REGS ) return gen_rtx_REG ( mode , CSKY_FIRST_PARM_REGNUM + * pcum ) ; return NULL_RTX ; } </s>

Determine where to put an argument to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) .


<s> static void csky_function_arg_advance ( cumulative_args_t pcum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; int param_size = csky_num_arg_regs ( mode , type ) ; if ( * pcum + param_size > CSKY_NPARM_REGS ) * pcum = CSKY_NPARM_REGS ; else * pcum += param_size ; } </s>


<s>
static
void
csky_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
thiz
=
"a0"
;
const
char
*
reg0
=
"t0"
;
const
char
*
reg1
=
"t1"
;
int
maxoff
=
4096
;
final_start_function
(
emit_barrier
(
)
,
file
,
1
)
;
rtx
fnaddr
=
XEXP
(
DECL_RTL
(
function
)
,
0
)
;
if
(
CSKY_TARGET_ARCH
(
CK801
)
)
{
reg0
=
"l0"
;
reg1
=
"l1"
;
maxoff
=
256
;
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
fprintf
(
file
,
"\tpush\tl0, l1\n"
)
;
else
if
(
delta
>
maxoff
||
delta
<
maxoff
)
fprintf
(
file
,
"\tpush\tl0\n"
)
;
}
if
(
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
)
thiz
=
"a1"
;
if
(
delta
!=
0
)
{
if
(
delta
>
maxoff
||
delta
<
maxoff
)
{
fprintf
(
file
,
"\tlrw\t%s, %ld\n"
,
reg0
,
(
long
)
delta
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
thiz
,
thiz
,
reg0
)
;
}
else
fprintf
(
file
,
"\t%s\t%s, %s, %ld\n"
,
(
delta
>
0
"addi"
:
"subi"
)
,
thiz
,
thiz
,
(
long
)
(
delta
>
0
delta
:
delta
)
)
;
}
if
(
vcall_offset
!=
0
)
{
fprintf
(
file
,
"\tld.w\t%s, (%s, 0)\n"
,
reg0
,
thiz
)
;
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
{
fprintf
(
file
,
"\tlrw\t%s, %ld\n"
,
reg1
,
(
long
)
vcall_offset
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
reg0
,
reg0
,
reg1
)
;
}
else
fprintf
(
file
,
"\t%s\t%s, %s, %ld\n"
,
(
vcall_offset
>
0
"addi"
:
"subi"
)
,
reg0
,
reg0
,
(
long
)
(
vcall_offset
>
0
vcall_offset
:
vcall_offset
)
)
;
fprintf
(
file
,
"\tld.w\t%s, (%s, 0)\n"
,
reg0
,
reg0
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
thiz
,
thiz
,
reg0
)
;
}
if
(
CSKY_TARGET_ARCH
(
CK801
)
)
{
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
{
fprintf
(
file
,
"\tld.w\tl0, (sp, 0)\n"
)
;
fprintf
(
file
,
"\tld.w\tl1, (sp, 4)\n"
)
;
fprintf
(
file
,
"\taddi\t sp, sp, 8\n"
)
;
}
else
if
(
delta
>
maxoff
||
delta
<
maxoff
)
{
fprintf
(
file
,
"\tld.w\tl0, (sp, 0)\n"
)
;
fprintf
(
file
,
"\taddi\tsp, sp, 4\n"
)
;
}
}
fprintf
(
file
,
"\tjbr\t"
)
;
output_addr_const
(
file
,
fnaddr
)
;
fprintf
(
file
,
"\n"
)
;
final_end_function
(
)
;
}
</s>

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


<s> static void csky_setup_incoming_varargs ( cumulative_args_t pcum_v , machine_mode mode , tree type , int * pretend_size , int second_time ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; CUMULATIVE_ARGS local_cum ; cumulative_args_t local_cum_v = pack_cumulative_args ( & local_cum ) ; int regs_to_push ; cfun -> machine -> uses_anonymous_args = 1 ; local_cum = * pcum ; csky_function_arg_advance ( local_cum_v , mode , type , true ) ; regs_to_push = CSKY_NPARM_REGS - local_cum ; if ( regs_to_push ) * pretend_size = regs_to_push * UNITS_PER_WORD ; } </s>


<s> static unsigned int get_csky_live_regs ( int * count ) { int reg ; unsigned int live_regs_mask = 0 ; * count = 0 ; for ( reg = 0 ; reg < CSKY_NGPR_REGS ; reg ++ ) { bool save = false ; if ( CSKY_TARGET_ARCH ( CK801 ) && reg > 8 && reg < 13 ) continue ; if ( ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK803 ) ) && reg > 15 ) break ; if ( df_regs_ever_live_p ( reg ) && ! call_really_used_regs [ reg ] ) save = true ; else if ( frame_pointer_needed && reg == FRAME_POINTER_REGNUM ) save = true ; else if ( crtl -> calls_eh_return && reg == FRAME_POINTER_REGNUM ) save = true ; else if ( ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) ) && reg == CSKY_LR_REGNUM && ( ! crtl -> is_leaf || csky_far_jump_used_p ( ) ) ) save = true ; else if ( crtl -> calls_eh_return && reg >= CSKY_FIRST_EH_RETDATA_REGNUM && reg <= CSKY_LAST_EH_RETDATA_REGNUM ) save = true ; if ( reg == CSKY_STACKADJUST_REGNUM && cfun -> machine -> reg_offset > CSKY_MAX_SP_ADJUST * 2 ) save = true ; if ( save ) { ( * count ) ++ ; live_regs_mask |= ( 1 << reg ) ; } } return live_regs_mask ; } </s>

Return the mask of registers used by the current function . Set COUNT to the number of registers used .


<s> static Mnode * add_csky_minipool_forward_ref ( Mfix * fix ) { Mnode * max_mp = NULL ; HOST_WIDE_INT max_address = fix -> address + fix -> forwards ; Mnode * mp ; if ( minipool_vector_head && ( fix -> address + get_attr_length ( fix -> insn ) >= minipool_vector_head -> max_address - fix -> fix_size ) ) return NULL ; for ( mp = minipool_vector_head ; mp != NULL ; mp = mp -> next ) { if ( GET_CODE ( fix -> value ) == GET_CODE ( mp -> value ) && fix -> mode == mp -> mode && ( GET_CODE ( fix -> value ) != CODE_LABEL || ( CODE_LABEL_NUMBER ( fix -> value ) == CODE_LABEL_NUMBER ( mp -> value ) ) ) && rtx_equal_p ( fix -> value , mp -> value ) ) { mp -> refcount ++ ; return mp ; } if ( max_mp == NULL && mp -> max_address > max_address ) max_mp = mp ; } mp = XNEW ( Mnode ) ; mp -> fix_size = fix -> fix_size ; mp -> mode = fix -> mode ; mp -> value = fix -> value ; mp -> refcount = 1 ; mp -> min_address = - 65536 ; if ( max_mp == NULL ) { mp -> max_address = max_address ; mp -> next = NULL ; mp -> prev = minipool_vector_tail ; if ( mp -> prev == NULL ) { minipool_vector_head = mp ; minipool_vector_label = gen_csky_constpool_label ( gen_rtx_CONST_INT ( VOIDmode , constpool_label_no ++ ) ) ; } else mp -> prev -> next = mp ; minipool_vector_tail = mp ; } else { if ( max_address > max_mp -> max_address - mp -> fix_size ) mp -> max_address = max_mp -> max_address - mp -> fix_size ; else mp -> max_address = max_address ; mp -> next = max_mp ; mp -> prev = max_mp -> prev ; max_mp -> prev = mp ; if ( mp -> prev != NULL ) mp -> prev -> next = mp ; else minipool_vector_head = mp ; } max_mp = mp ; while ( mp -> prev != NULL && mp -> prev -> max_address > mp -> max_address - mp -> prev -> fix_size ) { mp -> prev -> max_address = mp -> max_address - mp -> prev -> fix_size ; mp = mp -> prev ; } return max_mp ; } </s>

Add a constant to the minipool for a forward reference . Returns the node added or NULL if the constant will not fit in this pool .


<s> static void assign_csky_minipool_offsets ( Mfix * barrier ) { HOST_WIDE_INT offset = 0 ; Mnode * mp ; minipool_barrier = barrier ; for ( mp = minipool_vector_head ; mp != NULL ; mp = mp -> next ) { mp -> offset = offset ; if ( mp -> refcount > 0 ) offset += mp -> fix_size ; } } </s>

Fill in the offsets for minipool entries .


<s> static int ck801_legitimate_index_p ( machine_mode mode , rtx index , int strict_p ATTRIBUTE_UNUSED ) { enum rtx_code code = GET_CODE ( index ) ; if ( GET_MODE_SIZE ( mode ) >= 8 ) return ( code == CONST_INT && INTVAL ( index ) < CSKY_LD16_MAX_OFFSET ( SImode ) && INTVAL ( index ) >= 0 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( code == CONST_INT && GET_MODE_SIZE ( mode ) > 0 && INTVAL ( index ) <= CSKY_LD16_MAX_OFFSET ( mode ) && INTVAL ( index ) >= 0 ) return ( ( INTVAL ( index ) % GET_MODE_SIZE ( mode ) ) == 0 ) ; return 0 ; } </s>

Return nonzero if INDEX is valid for an address index operand . ck801 use 16 bits ld ck802 use 16 and 32 bits ld others use ld and ldr .


<s> static bool ck803_rtx_costs ( rtx x , int code , int outer_code ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { switch ( code ) { case SET : if ( MEM_P ( XEXP ( x , 1 ) ) ) { struct csky_address op1 ; bool address_valid = decompose_csky_address ( XEXP ( XEXP ( x , 1 ) , 0 ) , & op1 ) ; if ( op1 . index ) { * total = COSTS_N_INSNS ( 3 ) ; return true ; } else if ( address_valid ) { * total = COSTS_N_INSNS ( 1 ) ; return true ; } } if ( REG_P ( XEXP ( x , 0 ) ) && ( GET_CODE ( XEXP ( x , 1 ) ) == PLUS ) ) { rtx sub_exp = XEXP ( x , 1 ) ; if ( REG_P ( XEXP ( sub_exp , 0 ) ) && REG_P ( XEXP ( sub_exp , 1 ) ) ) { * total = COSTS_N_INSNS ( 1 ) ; return true ; } } return false ; case MULT : if ( REG_P ( XEXP ( x , 0 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { HOST_WIDE_INT val = INTVAL ( XEXP ( x , 1 ) ) ; if ( val % 2 == 0 && val < 0xffffffff && val > 0 ) { * total = COSTS_N_INSNS ( 1 ) ; return true ; } } return false ; case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( 3 ) ; return true ; default : return false ; } } </s>


<s> static bool ck807_ck810_rtx_costs ( rtx x , int code , int outer_code ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { switch ( code ) { case MULT : if ( REG_P ( XEXP ( x , 0 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { HOST_WIDE_INT val = INTVAL ( XEXP ( x , 1 ) ) ; if ( val % 2 == 0 && val < 0xffffffff && val > 0 ) { * total = COSTS_N_INSNS ( 1 ) ; return true ; } } return false ; case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( 3 ) ; return true ; default : return false ; } } </s>

TARGET_RTX_COSTS helper for ck807/ck810 arches .


<s> static bool ck860_rtx_costs ( rtx x , int code , machine_mode mode , int outer_code ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { switch ( code ) { case PLUS : if ( GET_CODE ( XEXP ( x , 0 ) ) == MULT && REG_P ( XEXP ( x , 1 ) ) && speed ) { rtx mul_op0 = XEXP ( XEXP ( x , 0 ) , 0 ) ; rtx mul_op1 = XEXP ( XEXP ( x , 0 ) , 1 ) ; if ( REG_P ( mul_op0 ) && REG_P ( mul_op1 ) ) { * total = COSTS_N_INSNS ( 1 ) ; * total += rtx_cost ( XEXP ( x , 0 ) , mode , ( enum rtx_code ) code , 0 , speed ) ; return true ; } } return false ; case MULT : if ( REG_P ( XEXP ( x , 0 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { HOST_WIDE_INT val = INTVAL ( XEXP ( x , 1 ) ) ; if ( val % 2 == 0 && val < 0xffffffff && val > 0 ) { * total = COSTS_N_INSNS ( 1 ) ; return true ; } } return false ; case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( 3 ) ; return true ; default : return false ; } } </s>

TARGET_RTX_COSTS helper for ck860 arches .


<s> static Mfix * create_csky_fix_barrier ( Mfix * fix , Mfix * fix_next , HOST_WIDE_INT max_address ) { rtx_barrier * barrier ; rtx_insn * from = ( fix ? fix -> insn : get_insns ( ) ) ; rtx_insn * selected = NULL ; int selected_cost ; HOST_WIDE_INT selected_address = 0 ; Mfix * new_fix ; HOST_WIDE_INT count = ( fix ? fix -> address : 0 ) ; HOST_WIDE_INT max_count = max_address ; rtx_code_label * label = gen_label_rtx ( ) ; selected_cost = get_csky_barrier_cost ( from ) ; while ( from && count < max_count ) { int new_cost ; rtx_jump_table_data * table ; count += get_attr_length ( from ) ; if ( tablejump_p ( from , NULL , & table ) ) { count += get_csky_jump_table_size ( table ) ; new_cost = get_csky_barrier_cost ( from ) ; if ( count < max_count && ( ! selected || new_cost <= selected_cost ) ) { selected = table ; selected_cost = new_cost ; selected_address = count ; } from = NEXT_INSN ( table ) ; continue ; } new_cost = get_csky_barrier_cost ( from ) ; if ( count < max_count && ( ! selected || new_cost <= selected_cost ) ) { selected = from ; selected_cost = new_cost ; selected_address = count ; } from = NEXT_INSN ( from ) ; } gcc_assert ( selected ) ; from = emit_jump_insn_after ( gen_jump ( label ) , selected ) ; JUMP_LABEL ( from ) = label ; barrier = emit_barrier_after ( from ) ; emit_label_after ( label , barrier ) ; new_fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * new_fix ) ) ; new_fix -> insn = barrier ; new_fix -> address = selected_address ; if ( fix ) { new_fix -> next = fix -> next ; fix -> next = new_fix ; } else new_fix -> next = fix_next ; return new_fix ; } </s>

Find the best place in the insn stream in the range ( FIX- > address , MAX_ADDRESS ) to forcibly insert a minipool barrier . Create the barrier by inserting a jump and add a new fix entry for it .


<s> static int csky_address_cost ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , addr_space_t as ATTRIBUTE_UNUSED , bool speed ATTRIBUTE_UNUSED ) { enum rtx_code code = GET_CODE ( x ) ; if ( code == REG ) return COSTS_N_INSNS ( 1 ) ; if ( code == PLUS && REG_P ( XEXP ( x , 0 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) return COSTS_N_INSNS ( 1 ) ; return COSTS_N_INSNS ( 3 ) ; } </s>

Implement TARGET_ADDRESS_COST to estimate cost of the memory address X . For C-SKY , ( register ) and ( register + offset ) have the same cost . Other situations cost more .


<s> static void csky_add_gc_roots ( void ) { gcc_obstack_init ( & minipool_obstack ) ; minipool_startobj = ( char * ) obstack_alloc ( & minipool_obstack , 0 ) ; } </s>

Allow GC scanning of the minipool obstack .


<s> static bool csky_allocate_stack_slots_for_args ( void ) { return ! CSKY_FUNCTION_IS_NAKED ( get_csky_current_func_type ( ) ) ; } </s>


<s> static int csky_arg_partial_bytes ( cumulative_args_t pcum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; int param_size = csky_num_arg_regs ( arg . mode , arg . type , pcum -> is_stdarg ) ; int reg = pcum -> reg ; if ( FUNCTION_VARG_MODE_P ( arg . mode ) && ! pcum -> is_stdarg ) return 0 ; if ( reg < CSKY_NPARM_REGS && reg + param_size > CSKY_NPARM_REGS ) return ( CSKY_NPARM_REGS - reg ) * UNITS_PER_WORD ; return 0 ; } </s>


"Nested function trampolines not supported on CK801."

Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE . Output assembler code for a block containing the constant parts of a trampoline , leaving space for the variable parts . Note that STATIC_CHAIN_REGNUM is t1 ( aka r12 ) on ck801 and t1 ( r13 ) otherwise .


<s> static rtx_insn * csky_call_tls_get_addr ( rtx x , rtx reg , rtx * valuep , int reloc ) { rtx label , labelno , unspec , tmp ; rtx_insn * insns ; start_sequence ( ) ; labelno = GEN_INT ( tls_labelno ++ ) ; label = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_TLS_LABEL ) ; unspec = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 3 , x , GEN_INT ( reloc ) , label ) , UNSPEC_TLS ) ; tmp = gen_reg_rtx ( SImode ) ; emit_move_insn ( reg , unspec ) ; emit_move_insn ( tmp , label ) ; emit_insn ( gen_addsi3 ( reg , reg , tmp ) ) ; * valuep = emit_library_call_value ( get_tls_get_addr ( ) , NULL_RTX , LCT_PURE , Pmode , reg , Pmode ) ; insns = get_insns ( ) ; end_sequence ( ) ; return insns ; } </s>


<s> static bool csky_cannot_copy_insn_p ( rtx_insn * insn ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , PATTERN ( insn ) , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == UNSPEC && ( XINT ( x , 1 ) == UNSPEC_TLS_LABEL || XINT ( x , 1 ) == UNSPEC_PIC_SYMBOL_GOTPC_GRS ) ) return true ; } return false ; } </s>

Implement TARGET_CANNOT_COPY_INSN_P . We must not copy any rtx that uses a pc-relative address .


<s> static bool csky_cannot_force_const_mem ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { return csky_tls_referenced_p ( x ) ; } </s>

Implement TARGET_CANNOT_FORCE_CONST_MEM . Determine if it 's legal to put X into the constant pool . This is not possible for the address of thread-local symbols , which is checked above .


<s> static bool csky_can_change_mode_class ( machine_mode from , machine_mode to , reg_class_t rclass ) { return ( GET_MODE_SIZE ( from ) == GET_MODE_SIZE ( to ) || ! reg_classes_intersect_p ( V_REGS , rclass ) ) ; } </s>

Implement TARGET_CAN_CHANGE_MODE_CLASS . V_REG registers ca n't do subreg as all values are reformatted to internal precision .


<s> static bool csky_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { if ( to == FRAME_POINTER_REGNUM ) return from != ARG_POINTER_REGNUM ; if ( to == STACK_POINTER_REGNUM ) return ! frame_pointer_needed ; return true ; } </s>


<s> static bool csky_can_use_ldstm ( int mask , int * br , int * er ) { int regno ; int begin_reg = 0 , end_reg = 0 ; int count = 0 ; if ( ! TARGET_MULTIPLE_STLD ) return false ; if ( mask & 0xf ) return false ; for ( regno = 4 ; regno <= 11 ; regno ++ ) { if ( mask & 1 << regno ) { if ( ! begin_reg ) begin_reg = regno ; end_reg = regno ; count ++ ; } else if ( begin_reg ) break ; } if ( count >= CSKY_MIN_MULTIPLE_STLD && count <= CSKY_MAX_MULTIPLE_STLD ) { if ( br ) * br = begin_reg ; if ( er ) * er = end_reg ; return true ; } return false ; } </s>

Return true if store/load multiple instructions can be used to save/restore at least some of the registers indicated by MASK . Unlike the push/pop case , this does handle partial ranges . Set * BR and * ER to the beginning and end ( respectively ) of the register range that can be handled .


<s> static bool csky_can_use_pushpop ( unsigned int mask ) { int i ; int end_reg ; if ( ! TARGET_PUSHPOP ) return false ; if ( mask == 0 ) return false ; if ( mask & 0xeffc700f ) return false ; for ( end_reg = 0 , i = 11 ; i >= 4 ; i -- ) { if ( ! end_reg && ( mask & ( 1 << i ) ) ) end_reg = i ; if ( end_reg && ! ( mask & ( 1 << i ) ) ) return false ; } for ( end_reg = 0 , i = 17 ; i >= 16 ; i -- ) { if ( ! end_reg && ( mask & ( 1 << i ) ) ) end_reg = i ; if ( end_reg && ! ( mask & ( 1 << i ) ) ) return false ; } return true ; } </s>

Return true if push/pop can be used to save/restore all the registers indicated by MASK . We currently do n't attempt to handle situations where some of the registers could be handled by push/pop and others saved and restored individually .


<s> static bool csky_class_likely_spilled_p ( reg_class_t rclass ) { if ( ( TARGET_MINI_REGISTERS && rclass == MINI_REGS ) || rclass == C_REGS ) return true ; return false ; } </s>

Implement TARGET_CLASS_LIKELY_SPILLED_P . We need to define this for MINI_REGS when we only use r0 - r7 . Otherwise we can end up using r0-r4 for function arguments , and do n't have enough left over to do doubleword arithmetic .


<s> static unsigned char csky_class_max_nregs ( reg_class_t rclass , machine_mode mode ) { if ( rclass == V_REGS ) return 1 ; else return CSKY_NUM_REGS ( mode ) ; } </s>

Implement TARGET_CLASS_MAX_NREGS . Return the maximum number of consecutive registers of class rclass needed to hold a value of mode mode . On the csky , this is the size of MODE in words , except in the FP regs , where a single reg is always enough .


<s> int csky_compute_pushpop_length ( rtx * operands ) { rtx parallel_op = operands [ 2 ] ; unsigned indx = XVECLEN ( parallel_op , 0 ) - 1 ; unsigned first_indx = 0 ; unsigned regno = REGNO ( operands [ 1 ] ) ; if ( regno > CSKY_LR_REGNUM ) return 4 ; for ( ; indx > first_indx ; indx -- ) { regno = REGNO ( XEXP ( XVECEXP ( parallel_op , 0 , indx ) , 0 ) ) ; if ( regno > CSKY_LR_REGNUM ) return 4 ; } return 2 ; } </s>

Compute the attribute `` length '' of push or pop insn , according to the registers it uses .


<s> static void csky_conditional_register_usage ( void ) { if ( TARGET_MINI_REGISTERS ) { int i ; for ( i = ( CSKY_LAST_MINI_REGNUM + 1 ) ; i < 32 ; i ++ ) { fixed_regs [ i ] = 1 ; call_used_regs [ i ] = 1 ; } } else if ( CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK803 ) || ! TARGET_HIGH_REGISTERS ) { int i ; for ( i = CSKY_FIRST_HIGH_REGNUM ; i <= CSKY_LAST_HIGH_REGNUM ; i ++ ) { fixed_regs [ i ] = 1 ; call_used_regs [ i ] = 1 ; } } if ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) ) { fixed_regs [ CSKY_LR_REGNUM ] = 1 ; call_used_regs [ CSKY_LR_REGNUM ] = 0 ; } if ( ! TARGET_DSP ) { fixed_regs [ CSKY_HI_REGNUM ] = 1 ; call_used_regs [ CSKY_HI_REGNUM ] = 1 ; fixed_regs [ CSKY_LO_REGNUM ] = 1 ; call_used_regs [ CSKY_LO_REGNUM ] = 1 ; } if ( ! TARGET_HARD_FLOAT ) { int regno ; for ( regno = CSKY_FIRST_VFP_REGNUM ; regno <= CSKY_LAST_VFP3_REGNUM ; regno ++ ) { fixed_regs [ regno ] = 1 ; call_used_regs [ regno ] = 1 ; } } if ( ! TARGET_SUPPORT_FPV3 ) { int regno ; for ( regno = CSKY_FIRST_VFP3_REGNUM ; regno <= CSKY_LAST_VFP3_REGNUM ; regno ++ ) { fixed_regs [ regno ] = 1 ; call_used_regs [ regno ] = 1 ; } } if ( flag_pic ) { fixed_regs [ PIC_OFFSET_TABLE_REGNUM ] = 1 ; call_used_regs [ PIC_OFFSET_TABLE_REGNUM ] = 0 ; } } </s>

Implement TARGET_CONDITIONAL_REGISTER_USAGE . Conditionally modify five variables fixed_regs , call_used_regs , global_regs , reg_names , and reg_class_contents , to take into account any dependence of these register sets on target flags . CK801 has registers r0-r8 and r13-r15 . CK802 and CK803 have registers r0-r15 ( the `` low '' registers ) . Other cpus use registers r0-r31 with -mhigh-registers , otherwise also only r0-r15 . CK801 only has 16-bit instructions , most of which can only reference r0-r7 ( the `` mini '' registers ) . So we mark regs outside that range as fixed . -msmart can be used on other arch variants to force the same behavior because it results in smaller code size . TODO : investigate whether it 's beneficial to use r8-r13 as a spill class when TARGET_MINI_REGISTERS instead of making them unusable by the register allocator .


"cpu %s is not based on arch %s, ignoring the arch"

Configure a build target TARGET from the user-specified options OPTS and OPTS_SET .


<s> static HOST_WIDE_INT csky_constant_alignment ( const_tree exp , HOST_WIDE_INT align ) { if ( TREE_CODE ( exp ) == STRING_CST && ! optimize_size && align < BITS_PER_WORD ) return BITS_PER_WORD ; return align ; } </s>

Implement TARGET_CONSTANT_ALIGNMENT . Make strings word-aligned so strcpy from constants will be faster .


<s> static rtx csky_dwarf_register_span ( rtx rtl ) { machine_mode mode ; unsigned regno ; rtx parts [ 16 ] ; int nregs ; int i ; regno = REGNO ( rtl ) ; if ( ! CSKY_VREG_P ( regno ) ) return NULL_RTX ; if ( CSKY_VREG_HI_P ( regno ) ) regno += 16 ; mode = GET_MODE ( rtl ) ; if ( GET_MODE_SIZE ( mode ) < 8 ) return NULL_RTX ; if ( TARGET_SINGLE_FPU ) { nregs = GET_MODE_SIZE ( mode ) / 4 ; for ( i = 0 ; i < nregs ; i += 2 ) if ( TARGET_BIG_ENDIAN ) { parts [ i ] = gen_rtx_REG ( SImode , regno + i + 1 ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i ) ; } else { parts [ i ] = gen_rtx_REG ( SImode , regno + i ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i + 1 ) ; } } else { nregs = GET_MODE_SIZE ( mode ) / 4 ; for ( i = 0 ; i < nregs ; i += 2 ) if ( TARGET_BIG_ENDIAN ) { parts [ i ] = gen_rtx_REG ( SImode , regno + i - 16 ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i ) ; } else { parts [ i ] = gen_rtx_REG ( SImode , regno + i ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i - 16 ) ; } } return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( nregs , parts ) ) ; } </s>

Implement TARGET_DWARF_REGISTER_SPAN . Dwarf models VFP registers as 64-bit or 128-bit registers default . GCC models tham as 32-bit registers , so we need to describe this to the DWARF generation code . Other registers can use the default .


<s> bool csky_emit_compare ( enum rtx_code code , rtx op0 , rtx op1 ) { bool invert ; rtx cc_reg = gen_rtx_REG ( CCmode , CSKY_CC_REGNUM ) ; if ( GET_MODE_CLASS ( GET_MODE ( op0 ) ) == MODE_FLOAT ) return csky_emit_compare_float ( code , op0 , op1 ) ; if ( GET_CODE ( op1 ) == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( op1 ) ; switch ( code ) { case GTU : if ( val == 0 ) code = NE ; else if ( TARGET_MINI_REGISTERS ? CSKY_CONST_OK_FOR_J ( val + 1 ) : CSKY_CONST_OK_FOR_Uk ( val + 1 ) ) { op1 = GEN_INT ( val + 1 ) ; code = GEU ; } break ; case GT : case LE : if ( TARGET_MINI_REGISTERS ? CSKY_CONST_OK_FOR_J ( val + 1 ) : CSKY_CONST_OK_FOR_Uk ( val + 1 ) ) { op1 = GEN_INT ( val + 1 ) ; code = code == LE ? LT : GE ; } break ; default : break ; } } if ( CONSTANT_P ( op1 ) && GET_CODE ( op1 ) != CONST_INT ) op1 = force_reg ( GET_MODE ( op1 ) , op1 ) ; invert = false ; switch ( code ) { case EQ : code = NE ; invert = true ; case NE : if ( GET_CODE ( op1 ) == CONST_INT && ( TARGET_MINI_REGISTERS ? ! csky_literal_K_operand ( op1 , SImode ) : ! csky_literal_I_operand ( op1 , SImode ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case LE : code = GT ; invert = true ; case GT : if ( GET_CODE ( op1 ) == CONST_INT ) op1 = force_reg ( SImode , op1 ) ; break ; case GE : code = LT ; invert = true ; case LT : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 && ( TARGET_MINI_REGISTERS ? ! csky_literal_J_operand ( op1 , SImode ) : ! csky_literal_Uk_operand ( op1 , SImode ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case GTU : gcc_assert ( GET_CODE ( op1 ) != CONST_INT || INTVAL ( op1 ) != 0 ) ; code = LEU ; invert = true ; case LEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; case LTU : code = GEU ; invert = true ; case GEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 && ( TARGET_MINI_REGISTERS ? ! csky_literal_J_operand ( op1 , SImode ) : ! csky_literal_Uk_operand ( op1 , SImode ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; default : break ; } emit_insn ( gen_rtx_SET ( cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return invert ; } </s>

Emit a comparison instruction . Return true if an inverted comparison is generated .


<s> bool csky_emit_compare_float ( enum rtx_code code , rtx op0 , rtx op1 ) { rtx cc_reg = gen_rtx_REG ( CCmode , CSKY_CC_REGNUM ) ; bool invert ; machine_mode mode = GET_MODE ( op1 ) ; if ( op1 != CONST0_RTX ( mode ) ) op1 = force_reg ( mode , op1 ) ; invert = false ; switch ( code ) { case EQ : code = NE ; invert = true ; break ; case GT : case LT : case LE : if ( op1 == CONST0_RTX ( mode ) && ( CSKY_ISA_FEATURE_GET ( fpv2_sf ) || CSKY_ISA_FEATURE_GET ( fpv2_df ) || CSKY_ISA_FEATURE_GET ( fpv2_divd ) ) ) op1 = force_reg ( mode , op1 ) ; break ; case ORDERED : code = UNORDERED ; invert = true ; break ; default : break ; } emit_insn ( gen_rtx_SET ( cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return invert ; } </s>

Emit a comparison insn for float values . Return true if the comparison is inverted .


<s> static bool csky_far_jump_used_p ( void ) { rtx_insn * insn ; if ( cfun -> machine -> far_jump_used ) return true ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) if ( GET_CODE ( insn ) == JUMP_INSN && GET_CODE ( PATTERN ( insn ) ) != ADDR_VEC && GET_CODE ( PATTERN ( insn ) ) != ADDR_DIFF_VEC && get_attr_far_jump ( insn ) == FAR_JUMP_YES ) { cfun -> machine -> far_jump_used = 1 ; return true ; } return false ; } </s>

Check to see if the current function contains a branch insn with the far jump attribute set . Such a function uses the LR register .


<s> static bool csky_fixed_condition_code_regs ( unsigned int * p1 , unsigned int * p2 ) { * p1 = CSKY_CC_REGNUM ; * p2 = INVALID_REGNUM ; return true ; } </s>


<s> static rtx csky_function_arg ( cumulative_args_t pcum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; int reg = pcum -> reg ; machine_mode mode = arg . mode ; if ( FUNCTION_VARG_MODE_P ( mode ) && ! pcum -> is_stdarg ) { reg = pcum -> freg ; if ( reg < CSKY_NPARM_FREGS ) return gen_rtx_REG ( mode , CSKY_FIRST_VFP_REGNUM + reg ) ; else return NULL_RTX ; } if ( reg < CSKY_NPARM_REGS ) return gen_rtx_REG ( mode , CSKY_FIRST_PARM_REGNUM + reg ) ; return NULL_RTX ; } </s>

Determine where to put an argument to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) .


<s> static void csky_function_arg_advance ( cumulative_args_t pcum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; int * reg = & pcum -> reg ; machine_mode mode = arg . mode ; int param_size = csky_num_arg_regs ( mode , arg . type , pcum -> is_stdarg ) ; int param_regs_nums = CSKY_NPARM_REGS ; if ( FUNCTION_VARG_MODE_P ( mode ) && ! pcum -> is_stdarg ) { reg = & pcum -> freg ; param_regs_nums = CSKY_NPARM_FREGS ; } if ( * reg + param_size > param_regs_nums ) * reg = param_regs_nums ; else * reg += param_size ; } </s>


<s> static rtx csky_function_value ( const_tree type , const_tree func , bool outgoing ATTRIBUTE_UNUSED ) { machine_mode mode ; int unsignedp ATTRIBUTE_UNUSED ; int size ; mode = TYPE_MODE ( type ) ; size = int_size_in_bytes ( type ) ; if ( FUNCTION_VARG_MODE_P ( mode ) ) { mode = promote_function_mode ( type , mode , & unsignedp , func , 1 ) ; return gen_rtx_REG ( mode , CSKY_FIRST_VFP_REGNUM ) ; } if ( INTEGRAL_TYPE_P ( type ) ) { mode = promote_function_mode ( type , mode , & unsignedp , func , 1 ) ; return gen_rtx_REG ( mode , CSKY_FIRST_RET_REGNUM ) ; } if ( mode == BLKmode && size > UNITS_PER_WORD && size <= UNITS_PER_WORD * 2 ) { rtx ret_regs [ 2 ] ; ret_regs [ 0 ] = gen_rtx_EXPR_LIST ( SImode , gen_rtx_REG ( SImode , CSKY_FIRST_RET_REGNUM ) , GEN_INT ( 0 * UNITS_PER_WORD ) ) ; ret_regs [ 1 ] = gen_rtx_EXPR_LIST ( SImode , gen_rtx_REG ( SImode , CSKY_FIRST_RET_REGNUM + 1 ) , GEN_INT ( 1 * UNITS_PER_WORD ) ) ; rtvec vec = gen_rtvec ( 2 , ret_regs [ 0 ] , ret_regs [ 1 ] ) ; return gen_rtx_PARALLEL ( mode , vec ) ; } return gen_rtx_REG ( mode , CSKY_FIRST_RET_REGNUM ) ; } </s>


<s> static bool csky_function_value_regno_p ( const unsigned int regno ) { if ( regno == CSKY_FIRST_RET_REGNUM || ( TARGET_HARD_FLOAT_ABI && regno == CSKY_FIRST_VFP_REGNUM ) ) return true ; return false ; } </s>

Implement TARGET_FUNCTION_VALUE_REGNO_P . On C-SKY , only r0 can return results .


<s> int csky_get_movedouble_length ( rtx operands [ ] ) { rtx dst = operands [ 0 ] ; rtx src = operands [ 1 ] ; if ( REG_P ( dst ) ) { if ( REG_P ( src ) ) { int dstreg = REGNO ( dst ) ; int srcreg = REGNO ( src ) ; if ( CSKY_VREG_P ( srcreg ) && CSKY_VREG_P ( dstreg ) ) return 4 ; else return 8 ; } else if ( GET_CODE ( src ) == MEM ) { rtx memexp = XEXP ( src , 0 ) ; int dstreg = REGNO ( dst ) ; struct csky_address op0 ; decompose_csky_address ( XEXP ( src , 0 ) , & op0 ) ; if ( GET_CODE ( memexp ) == LABEL_REF ) return 8 ; if ( CSKY_VREG_P ( dstreg ) ) return 4 ; return 8 ; } else if ( GET_CODE ( src ) == CONST_INT || GET_CODE ( src ) == CONST_DOUBLE ) { split_double ( src , operands + 2 , operands + 3 ) ; if ( CSKY_CONST_OK_FOR_N ( INTVAL ( operands [ 2 ] ) + 1 ) && CSKY_CONST_OK_FOR_N ( INTVAL ( operands [ 3 ] ) + 1 ) && REGNO ( operands [ 0 ] ) < 6 ) return 4 ; else return 8 ; } } else if ( GET_CODE ( dst ) == MEM && GET_CODE ( src ) == REG ) { rtx memexp = XEXP ( dst , 0 ) ; int srcreg = REGNO ( src ) ; int offset = - 1 ; if ( CSKY_VREG_P ( srcreg ) ) return 4 ; if ( GET_CODE ( memexp ) == REG ) offset = 0 ; else if ( GET_CODE ( memexp ) == PLUS ) { if ( GET_CODE ( XEXP ( memexp , 0 ) ) == REG ) offset = INTVAL ( XEXP ( memexp , 1 ) ) ; else if ( GET_CODE ( XEXP ( memexp , 1 ) ) == REG ) offset = INTVAL ( XEXP ( memexp , 0 ) ) ; else gcc_unreachable ( ) ; } else gcc_unreachable ( ) ; if ( srcreg <= 6 && offset <= 1020 ) return 4 ; else if ( ( srcreg == 7 && offset <= 1024 ) || ( srcreg <= 7 && offset == 1024 ) ) return 6 ; else return 8 ; } else gcc_unreachable ( ) ; return 0 ; } </s>

Calculate the instruction 's length for moving double-word data .


"%qE attribute only applies to functions"

Handle an attribute requiring a FUNCTION_DECL ; arguments as in struct attribute_spec.handler .


"%qE attribute ignored without %<-mistack%>"

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


<s> static bool csky_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { int nregs = CSKY_NUM_REGS ( mode ) ; if ( nregs > 2 ) return false ; if ( regno < CSKY_NGPR_REGS ) { if ( nregs < 2 ) return true ; else if ( TARGET_MINI_REGISTERS ) return ( regno < CSKY_LAST_MINI_REGNUM ) ; else if ( CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK803 ) || ! TARGET_HIGH_REGISTERS ) return ( regno < ( CSKY_SP_REGNUM - 1 ) ) ; else return ( regno < ( CSKY_SP_REGNUM - 1 ) || ( regno >= CSKY_LR_REGNUM && regno < CSKY_LAST_HIGH_UNFIXED_REGNUM ) ) ; } else if ( regno == CSKY_CC_REGNUM ) return ( mode == CCmode ) ; else if ( regno == CSKY_HI_REGNUM || regno == CSKY_LO_REGNUM ) { if ( ! TARGET_DSP || mode == SFmode || mode == DFmode ) return false ; else if ( nregs == 2 ) return ( regno == CSKY_HI_REGNUM ) ; else return true ; } else if ( CSKY_VREG_P ( regno ) && TARGET_HARD_FLOAT ) return true ; return false ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . Return true if REGNO is a valid register for holding a quantity of type MODE .


<s> static unsigned int csky_hard_regno_nregs ( unsigned int regno , machine_mode mode ) { if ( regno >= CSKY_FIRST_VFP_REGNUM && ! CSKY_TARGET_ARCH ( CK803 ) ) return 1 ; else return CSKY_NUM_REGS ( mode ) ; } </s>


<s> static void csky_initialize_isa ( sbitmap isa , const enum csky_isa_feature * isa_bits ) { bitmap_clear ( isa ) ; while ( * isa_bits != CSKY_ISA_FEATURE_GET ( none ) ) bitmap_set_bit ( isa , * ( isa_bits ++ ) ) ; } </s>

Convert a static initializer array of feature bits to sbitmap representation .


<s> HOST_WIDE_INT csky_initial_elimination_offset ( int from , int to ) { int offset ; csky_layout_stack_frame ( ) ; switch ( from ) { case FRAME_POINTER_REGNUM : case HARD_FRAME_POINTER_REGNUM : offset = cfun -> machine -> reg_offset ; break ; case ARG_POINTER_REGNUM : offset = cfun -> machine -> arg_offset ; break ; default : gcc_unreachable ( ) ; } if ( to == FRAME_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM ) offset -= cfun -> machine -> reg_offset ; return offset ; } </s>

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


<s> void csky_init_builtins ( void ) { static tree csky_floatHF_type_node = make_node ( REAL_TYPE ) ; TYPE_PRECISION ( csky_floatHF_type_node ) = GET_MODE_PRECISION ( HFmode ) ; layout_type ( csky_floatHF_type_node ) ; ( * lang_hooks . types . register_builtin_type ) ( csky_floatHF_type_node , "__fp16" ) ; } </s>

Implement the TARGET_INIT_BUILTINS target macro .


<s> void csky_init_expanders ( void ) { init_machine_status = csky_init_machine_status ; } </s>


<s> static struct machine_function * csky_init_machine_status ( void ) { struct machine_function * machine ; machine = ggc_cleared_alloc < machine_function > ( ) ; machine -> func_type = CSKY_FT_UNKNOWN ; return machine ; } </s>

Functions to save and restore machine-specific function data .


<s> bool csky_inlinable_constant ( HOST_WIDE_INT value ) { HOST_WIDE_INT x , y ; return ( ! ( CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK801 ) ) && try_csky_constant_tricks ( value , & x , & y ) ) ; } </s>

This is a helper function for the Uo constraint for movsi patterns .


<s> static unsigned long csky_isr_value ( tree argument ) { const isr_attribute_entry * ptr ; const char * arg ; if ( argument == NULL_TREE ) return CSKY_FT_ISR ; if ( TREE_VALUE ( argument ) == NULL_TREE || TREE_CODE ( TREE_VALUE ( argument ) ) != STRING_CST ) return CSKY_FT_UNKNOWN ; arg = TREE_STRING_POINTER ( TREE_VALUE ( argument ) ) ; for ( ptr = isr_attribute_map ; ptr -> arg != NULL ; ptr ++ ) if ( strcmp ( arg , ptr -> arg ) == 0 ) return ptr -> return_value ; return CSKY_FT_UNKNOWN ; } </s>

Returns the ( interrupt ) function type of the current function , or CSKY_FT_UNKNOWN if the type can not be determined .


<s> bool csky_label_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( GET_CODE ( x ) == LABEL_REF ) return true ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( csky_label_mentioned_p ( XVECEXP ( x , i , j ) ) ) return true ; } else if ( fmt [ i ] == 'e' && csky_label_mentioned_p ( XEXP ( x , i ) ) ) return true ; } return false ; } </s>

Return TRUE if X references a LABEL_REF .


<s> static void csky_layout_stack_frame ( void ) { machine_function * infp = cfun -> machine ; int reg_count ; if ( infp -> frame_init_p ) return ; infp -> outbound_size = CSKY_STACK_ALIGN ( crtl -> outgoing_args_size ) ; infp -> local_offset = infp -> outbound_size ; infp -> local_size = CSKY_STACK_ALIGN ( get_frame_size ( ) ) ; infp -> reg_offset = infp -> local_offset + infp -> local_size ; infp -> reg_mask = get_csky_live_regs ( & reg_count ) ; infp -> reg_size = reg_count * UNITS_PER_WORD ; infp -> arg_offset = infp -> reg_offset + infp -> reg_size ; infp -> arg_size = crtl -> args . pretend_args_size ; infp -> frame_size = infp -> arg_offset + infp -> arg_size ; infp -> frame_init_p = reload_completed ; } </s>

Compute the stack frame layout , storing sizes of the various pieces in cfun- > machine . Stack frames constructed in the prologue look like : ... caller 's frame ... incoming SP - > caller 's outbound argument overflow argument spill optional FP - > register save local variables alloca ( ) space adjusted SP - > outbound argument overflow with SP/FP pointing at the base ( low address ) of the respective area , and each area aligned to a word boundary .


<s> static bool csky_legitimate_address_p ( machine_mode mode , rtx addr , bool strict_p ) { enum rtx_code code = GET_CODE ( addr ) ; if ( reload_completed && ( ( code == LABEL_REF ) || ( code == CONST && GET_CODE ( XEXP ( addr , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( addr , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( addr , 0 ) , 1 ) ) ) ) ) return 1 ; if ( is_csky_address_register_rtx_p ( addr , strict_p ) ) return 1 ; else if ( GET_CODE ( addr ) == LABEL_REF ) return 1 ; if ( code == PLUS ) { rtx xop0 = XEXP ( addr , 0 ) ; rtx xop1 = XEXP ( addr , 1 ) ; return ( ( is_csky_address_register_rtx_p ( xop0 , strict_p ) && csky_legitimate_index_p ( mode , xop1 , strict_p ) ) || ( is_csky_address_register_rtx_p ( xop1 , strict_p ) && csky_legitimate_index_p ( mode , xop0 , strict_p ) ) ) ; } return 0 ; } </s>

Implement TARGET_LEGITIMATE_ADDRESS_P . Recognizes RTL expressions that are valid memory addresses for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . It only recognizes address in canonical form . LEGITIMIZE_ADDRESS should convert common non-canonical forms to canonical form so that they will be recognized .


<s> static bool csky_legitimate_constant_p ( machine_mode mode , rtx x ) { return ( ! csky_cannot_force_const_mem ( mode , x ) && CONSTANT_P ( x ) ) ; } </s>

Implement TARGET_LEGITIMATE_CONSTANT_P . Returns nonzero if the constant value X is a legitimate general operand . It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE .


<s> bool csky_legitimate_pic_operand_p ( rtx x ) { if ( tls_unspec_mentioned_p ( x ) ) return true ; if ( csky_symbol_mentioned_p ( x ) || csky_label_mentioned_p ( x ) ) return false ; return true ; } </s>


<s> static rtx csky_legitimize_address ( rtx x , rtx orig_x ATTRIBUTE_UNUSED , machine_mode mode ) { if ( csky_tls_symbol_p ( x ) ) return csky_legitimize_tls_address ( x , NULL_RTX ) ; if ( GET_CODE ( x ) == PLUS ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; if ( is_csky_address_register_rtx_p ( xop0 , 0 ) && CONST_INT_P ( xop1 ) ) { HOST_WIDE_INT offset = INTVAL ( xop1 ) ; if ( optimize_size && offset > CSKY_LD16_MAX_OFFSET ( mode ) && offset <= ( CSKY_ADDI16_MAX_IMM + CSKY_LD16_MAX_OFFSET ( mode ) ) ) { HOST_WIDE_INT new_ld_offset = offset & CSKY_LD16_OFFSET_MASK ( mode ) ; xop0 = force_operand ( plus_constant ( Pmode , xop0 , offset - new_ld_offset ) , NULL_RTX ) ; x = plus_constant ( Pmode , xop0 , new_ld_offset ) ; } else if ( offset < 0 && offset >= ( - CSKY_SUBI16_MAX_IMM ) ) x = force_operand ( x , NULL_RTX ) ; else if ( offset > CSKY_LD16_MAX_OFFSET ( mode ) || offset < 0 ) { xop1 = force_reg ( SImode , xop1 ) ; x = gen_rtx_PLUS ( SImode , xop0 , xop1 ) ; } } if ( is_csky_address_register_rtx_p ( xop1 , 0 ) && ! is_csky_address_register_rtx_p ( xop0 , 0 ) ) { xop0 = force_operand ( xop0 , NULL_RTX ) ; x = gen_rtx_PLUS ( SImode , xop0 , xop1 ) ; } } else if ( CONST_INT_P ( x ) && optimize > 0 ) { HOST_WIDE_INT mask , base , index ; rtx base_reg ; mask = CSKY_LD16_OFFSET_MASK ( mode ) ; base = INTVAL ( x ) & ~ mask ; index = INTVAL ( x ) & mask ; base_reg = force_reg ( SImode , GEN_INT ( base ) ) ; x = plus_constant ( Pmode , base_reg , index ) ; } return x ; } </s>


<s> rtx csky_legitimize_tls_address ( rtx x , rtx reg ) { rtx dest , tp , label , labelno , unspec , ret , eqv , addend , tmp ; rtx_insn * insns ; unsigned int model = SYMBOL_REF_TLS_MODEL ( x ) ; if ( ! reg ) reg = gen_reg_rtx ( SImode ) ; switch ( model ) { case TLS_MODEL_GLOBAL_DYNAMIC : insns = csky_call_tls_get_addr ( x , reg , & ret , TLS_GD32 ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , ret , x ) ; return dest ; case TLS_MODEL_LOCAL_DYNAMIC : insns = csky_call_tls_get_addr ( x , reg , & ret , TLS_LDM32 ) ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const1_rtx ) , UNSPEC_TLS ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , ret , eqv ) ; addend = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( TLS_LDO32 ) ) , UNSPEC_TLS ) ; addend = force_reg ( SImode , addend ) ; return gen_rtx_PLUS ( Pmode , dest , addend ) ; case TLS_MODEL_INITIAL_EXEC : labelno = GEN_INT ( tls_labelno ++ ) ; label = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_TLS_LABEL ) ; unspec = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 3 , x , GEN_INT ( TLS_IE32 ) , label ) , UNSPEC_TLS ) ; tmp = gen_reg_rtx ( SImode ) ; emit_move_insn ( reg , unspec ) ; emit_move_insn ( tmp , label ) ; emit_insn ( gen_addsi3 ( reg , reg , tmp ) ) ; emit_move_insn ( reg , gen_const_mem ( Pmode , reg ) ) ; tp = gen_rtx_REG ( SImode , CSKY_TLS_REGNUM ) ; return gen_rtx_PLUS ( Pmode , tp , reg ) ; case TLS_MODEL_LOCAL_EXEC : unspec = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( TLS_LE32 ) ) , UNSPEC_TLS ) ; emit_move_insn ( reg , unspec ) ; tp = gen_rtx_REG ( SImode , CSKY_TLS_REGNUM ) ; return gen_rtx_PLUS ( Pmode , tp , reg ) ; default : abort ( ) ; } } </s>

Helper function for csky_legitimize_address , to handle the TLS cases . REG is a scratch register and may be null .


<s> static rtx csky_libcall_value ( machine_mode mode , const_rtx libcall ATTRIBUTE_UNUSED ) { if ( FUNCTION_VARG_MODE_P ( mode ) ) { return gen_rtx_REG ( mode , CSKY_FIRST_VFP_REGNUM ) ; } return gen_rtx_REG ( mode , CSKY_FIRST_RET_REGNUM ) ; } </s>


<s> static const char * csky_mangle_type ( const_tree type ) { if ( TYPE_NAME ( type ) && TREE_CODE ( TYPE_NAME ( type ) ) == TYPE_DECL && DECL_NAME ( TYPE_NAME ( type ) ) && ! strcmp ( IDENTIFIER_POINTER ( DECL_NAME ( TYPE_NAME ( type ) ) ) , "__fp16" ) ) return "__fp16" ; return NULL ; } </s>


<s> int csky_memory_move_cost ( machine_mode mode , reg_class_t rclass , bool in ) { return ( 4 + memory_move_secondary_cost ( mode , rclass , in ) ) ; } </s>

Implement TARGET_MEMORY_MOVE_COST : compute the cost of moving data between registers and memory .


<s> bool csky_minipool_load_p ( rtx_insn * insn ) { rtx op1 , addr ; extract_insn_cached ( insn ) ; op1 = recog_data . operand [ 1 ] ; if ( CONSTANT_P ( op1 ) ) return true ; if ( GET_CODE ( op1 ) == ZERO_EXTEND || GET_CODE ( op1 ) == SIGN_EXTEND ) op1 = XEXP ( op1 , 0 ) ; if ( GET_CODE ( op1 ) != MEM ) return false ; addr = XEXP ( op1 , 0 ) ; if ( GET_CODE ( addr ) == PLUS && CONST_INT_P ( XEXP ( addr , 1 ) ) ) addr = XEXP ( addr , 0 ) ; return GET_CODE ( addr ) == LABEL_REF ; } </s>

Return true if INSN is a minipool load or instruction that will be converted to one . It is assumed that INSN has type attribute `` load '' .


<s> static bool csky_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { return ! ( TARGET_HARD_FLOAT && mode1 != mode2 && ( mode1 == DFmode || mode2 == DFmode ) ) ; } </s>

Implement TARGET_MODES_TIEABLE_P . We ca n't tie DFmode with other modes when V_REGs might be in use because those registers mess with the stored bits .


<s> static int csky_num_arg_regs ( machine_mode mode , const_tree type , bool is_stdarg ) { int size ; if ( type && mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; if ( TARGET_HARD_FLOAT_ABI && ! is_stdarg ) { if ( CSKY_VREG_MODE_P ( mode ) && ! TARGET_SINGLE_FPU ) return ( ( CSKY_NUM_WORDS ( size ) + 1 ) / 2 ) ; } return CSKY_NUM_WORDS ( size ) ; } </s>

Return the number of registers ( words ) needed to pass an argument of MODE and TYPE .


<s> char * csky_output_call ( rtx * operands , int index ) { static char buffer [ 20 ] ; rtx addr = operands [ index ] ; if ( REG_P ( addr ) ) sprintf ( buffer , "jsr\t%%%d" , index ) ; else if ( flag_pic && ( GET_CODE ( addr ) == UNSPEC ) ) sprintf ( buffer , "bsr\t%%%d" , index ) ; else sprintf ( buffer , "jbsr\t%%%d" , index ) ; return buffer ; } </s>

Functions to output assembly code for a function call .

csky 20 "jsr\t%%%d" "bsr\t%%%d" "jbsr\t%%%d"


<s> const char * csky_output_casesi ( rtx * operands ) { rtx diff_vec = PATTERN ( NEXT_INSN ( as_a < rtx_insn * > ( operands [ 0 ] ) ) ) ; gcc_assert ( GET_CODE ( diff_vec ) == ADDR_DIFF_VEC ) ; switch ( GET_MODE ( diff_vec ) ) { case E_QImode : return ( ADDR_DIFF_VEC_FLAGS ( diff_vec ) . offset_unsigned ? "jbsr\t___gnu_csky_case_uqi" : "jbsr\t___gnu_csky_case_sqi" ) ; case E_HImode : return ( ADDR_DIFF_VEC_FLAGS ( diff_vec ) . offset_unsigned ? "jbsr\t___gnu_csky_case_uhi" : "jbsr\t___gnu_csky_case_shi" ) ; case E_SImode : return "jbsr\t___gnu_csky_case_si" ; default : gcc_unreachable ( ) ; } } </s>

Emit assembly code for CASESI . This is only used on CK801 and CK802 when optimizing for size , and uses helper functions in libgcc instead of doing the control transfer inline .


<s>
const
char
*
csky_output_ck801_move
(
rtx
insn
ATTRIBUTE_UNUSED
,
rtx
operands
[
]
,
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
struct
csky_address
op1
;
if
(
REG_P
(
dst
)
)
{
if
(
REG_P
(
src
)
)
return
"mov\t%0, %1"
;
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
decompose_csky_address
(
XEXP
(
src
,
0
)
,
&
op1
)
;
if
(
op1
.
label
)
return
"lrw\t%0, %1"
;
else
switch
(
GET_MODE
(
src
)
)
{
case
E_HImode
:
return
"ld.h\t%0, %1"
;
case
E_QImode
:
return
"ld.b\t%0, %1"
;
case
E_SFmode
:
case
E_SImode
:
return
"ld.w\t%0, %1"
;
default
:
gcc_unreachable
(
)
;
}
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
if
(
REGNO
(
dst
)
>
7
)
return
"lrw\t%0, %x1\t"
;
else
if
(
CSKY_CONST_OK_FOR_N
(
INTVAL
(
src
)
+
1
)
)
return
"movi\t%0, %1"
;
else
if
(
CSKY_CONST_OK_FOR_T
(
INTVAL
(
src
)
)
)
return
"#"
;
else
if
(
csky_shifted_imm8_constant
(
INTVAL
(
src
)
,
,
)
)
return
"#"
;
else
return
"lrw\t%0, %x1\t"
;
}
else
if
(
GET_CODE
(
src
)
==
CONST_DOUBLE
&&
GET_MODE
(
src
)
==
SFmode
)
{
const
REAL_VALUE_TYPE
*
d
;
long
l
;
d
=
CONST_DOUBLE_REAL_VALUE
(
src
)
;
REAL_VALUE_TO_TARGET_SINGLE
(
*
d
,
l
)
;
operands
[
1
]
=
GEN_INT
(
l
)
;
src
=
operands
[
1
]
;
if
(
CSKY_CONST_OK_FOR_N
(
INTVAL
(
src
)
+
1
)
)
return
"movi\t%0, %1"
;
else
return
"lrw\t%0, %x1\t"
;
}
else
if
(
TARGET_ANCHOR
&&
GET_CODE
(
src
)
==
SYMBOL_REF
)
{
if
(
SYMBOL_REF_FUNCTION_P
(
src
)
)
return
"lrw\t%0, %1@BTEXT"
;
else
return
"lrw\t%0, %1@BDATA"
;
}
else
return
"lrw\t%0, %1"
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
)
switch
(
GET_MODE
(
dst
)
)
{
case
E_HImode
:
return
"st.h\t%1, %0"
;
case
E_QImode
:
return
"st.b\t%1, %0"
;
case
E_SImode
:
case
E_SFmode
:
return
"st.w\t%1, %0"
;
default
:
gcc_unreachable
(
)
;
}
gcc_unreachable
(
)
;
}
</s>

Output a move of a word or less value . Specific for ck801 .


<s> static void csky_output_constpool_label ( FILE * stream , rtx x ) { char buf [ 15 ] ; gcc_assert ( GET_CODE ( x ) == LABEL_REF ) ; x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == UNSPEC_VOLATILE && XINT ( x , 1 ) == VUNSPEC_POOL_LABEL ) { ASM_GENERATE_INTERNAL_LABEL ( buf , CSKY_CONSTPOOL_LABEL_PREFIX , INTVAL ( XVECEXP ( x , 0 , 0 ) ) ) ; assemble_name ( stream , buf ) ; } } </s>

Output the constpool label according to the rtx expression X .


<s>
static
void
csky_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
fnname
=
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
thunk
)
)
;
const
char
*
thiz
=
"a0"
;
const
char
*
reg0
=
"t0"
;
const
char
*
reg1
=
"t1"
;
int
maxoff
=
4096
;
assemble_start_function
(
thunk
,
fnname
)
;
final_start_function
(
emit_barrier
(
)
,
file
,
1
)
;
rtx
fnaddr
=
XEXP
(
DECL_RTL
(
function
)
,
0
)
;
if
(
CSKY_TARGET_ARCH
(
CK801
)
)
{
reg0
=
"l0"
;
reg1
=
"l1"
;
maxoff
=
256
;
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
fprintf
(
file
,
"\tpush\tl0, l1\n"
)
;
else
if
(
delta
>
maxoff
||
delta
<
maxoff
)
fprintf
(
file
,
"\tpush\tl0\n"
)
;
}
if
(
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
)
thiz
=
"a1"
;
if
(
delta
!=
0
)
{
if
(
delta
>
maxoff
||
delta
<
maxoff
)
{
fprintf
(
file
,
"\tlrw\t%s, %ld\n"
,
reg0
,
(
long
)
delta
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
thiz
,
thiz
,
reg0
)
;
}
else
fprintf
(
file
,
"\t%s\t%s, %s, %ld\n"
,
(
delta
>
0
"addi"
:
"subi"
)
,
thiz
,
thiz
,
(
long
)
(
delta
>
0
delta
:
delta
)
)
;
}
if
(
vcall_offset
!=
0
)
{
fprintf
(
file
,
"\tld.w\t%s, (%s, 0)\n"
,
reg0
,
thiz
)
;
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
{
fprintf
(
file
,
"\tlrw\t%s, %ld\n"
,
reg1
,
(
long
)
vcall_offset
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
reg0
,
reg0
,
reg1
)
;
}
else
fprintf
(
file
,
"\t%s\t%s, %s, %ld\n"
,
(
vcall_offset
>
0
"addi"
:
"subi"
)
,
reg0
,
reg0
,
(
long
)
(
vcall_offset
>
0
vcall_offset
:
vcall_offset
)
)
;
fprintf
(
file
,
"\tld.w\t%s, (%s, 0)\n"
,
reg0
,
reg0
)
;
fprintf
(
file
,
"\taddu\t%s, %s, %s\n"
,
thiz
,
thiz
,
reg0
)
;
}
if
(
CSKY_TARGET_ARCH
(
CK801
)
)
{
if
(
vcall_offset
>
maxoff
||
vcall_offset
<
maxoff
)
{
fprintf
(
file
,
"\tld.w\tl0, (sp, 0)\n"
)
;
fprintf
(
file
,
"\tld.w\tl1, (sp, 4)\n"
)
;
fprintf
(
file
,
"\taddi\t sp, sp, 8\n"
)
;
}
else
if
(
delta
>
maxoff
||
delta
<
maxoff
)
{
fprintf
(
file
,
"\tld.w\tl0, (sp, 0)\n"
)
;
fprintf
(
file
,
"\taddi\tsp, sp, 4\n"
)
;
}
}
fprintf
(
file
,
"\tjbr\t"
)
;
output_addr_const
(
file
,
fnaddr
)
;
fprintf
(
file
,
"\n"
)
;
final_end_function
(
)
;
assemble_end_function
(
thunk
,
fnname
)
;
}
</s>

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


<s> static void csky_output_pic_addr_const ( FILE * stream , rtx x , int code ) { if ( GET_CODE ( x ) != UNSPEC ) return ; if ( UNSPEC_TLS == XINT ( x , 1 ) ) { return ; } csky_print_operand ( stream , XVECEXP ( x , 0 , 0 ) , code ) ; switch ( XINT ( x , 1 ) ) { case UNSPEC_PIC_SYMBOL_GOTOFF : fputs ( "@GOTOFF" , stream ) ; break ; case UNSPEC_PIC_SYMBOL_PLT : fputs ( "@PLT" , stream ) ; break ; case UNSPEC_PIC_SYMBOL_GOT : fputs ( "@GOT" , stream ) ; break ; case UNSPEC_PIC_SYMBOL_GOTPC : fputs ( "@GOTPC" , stream ) ; break ; case UNSPEC_PIC_SYMBOL_BSR : break ; default : break ; } } </s>

Print the UNSPEC operand in X to the STREAM .


<s> static reg_class_t csky_preferred_reload_class ( rtx x , reg_class_t rclass ) { if ( TARGET_HARD_FLOAT && CONST_DOUBLE_P ( x ) && ( GET_MODE ( x ) == DFmode || GET_MODE ( x ) == SFmode ) && rclass == NO_REGS ) return GENERAL_REGS ; return rclass ; } </s>

Implement TARGET_PREFERRED_RELOAD_CLASS . Given an rtx X being reloaded into a reg required to be in class CLASS , return the class of reg to actually use . In general this is just CLASS .


<s> static void csky_print_operand ( FILE * stream , rtx x , int code ) { switch ( code ) { case 'N' : if ( ( INTVAL ( x ) & 0xffffffff ) == 0xffffffff ) fprintf ( stream , "0" ) ; else fprintf ( stream , "%d" , ( int ) exact_log2 ( ( INTVAL ( x ) & 0xffffffff ) + 1 ) % 32 ) ; break ; case 'P' : fprintf ( stream , "%d" , ( int ) exact_log2 ( INTVAL ( x ) & 0xffffffff ) ) ; break ; case 'Q' : fprintf ( stream , "%d" , ( int ) exact_log2 ( ~ INTVAL ( x ) & 0xffffffff ) ) ; break ; case 'O' : fprintf ( stream , "%d" , ( int ) INTVAL ( x ) ) ; break ; case 'M' : fprintf ( stream , "%d" , ( int ) ( - INTVAL ( x ) ) ) ; break ; case 'R' : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) + 1 ] , stream ) ; break ; case MEM : csky_print_operand_address ( stream , GET_MODE ( x ) , XEXP ( adjust_address ( x , SImode , 4 ) , 0 ) ) ; break ; default : gcc_unreachable ( ) ; } break ; case 'H' : fprintf ( stream , "%ld" , ( long ) ( ( INTVAL ( x ) & 0xFFFF0000 ) >> 16 ) ) ; break ; default : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) ] , stream ) ; break ; case MEM : output_address ( GET_MODE ( x ) , XEXP ( x , 0 ) ) ; break ; case UNSPEC : csky_output_pic_addr_const ( stream , x , code ) ; break ; case CONST_DOUBLE : { char fpstr [ 20 ] ; real_to_decimal ( fpstr , CONST_DOUBLE_REAL_VALUE ( x ) , sizeof ( fpstr ) , 0 , 1 ) ; fprintf ( stream , "%s" , fpstr ) ; } break ; default : output_addr_const ( stream , x ) ; break ; } break ; } } </s>

Implement TARGET_PRINT_OPERAND . Print operand X ( an rtx ) in assembler syntax to file STREAM according to modifier CODE . 'N' print the log2 ( X+1 ) , mainly used for bmaski ' P' print the log2 ( X ) ' Q' print the log2 ( ~X ) ' O' print a decimal number 'M' print a decimal number as its negative ' R' print the next register or memory location along , i.e . the lsw in a double word value ' H' print the high 16 bits of a constant .


<s>
static
void
csky_print_operand_address
(
FILE
*
stream
,
machine_mode
mode
ATTRIBUTE_UNUSED
,
rtx
x
)
{
struct
csky_address
addr
;
decompose_csky_address
(
x
,
&
addr
)
;
if
(
addr
.
label
&&
addr
.
disp
&&
GET_CODE
(
addr
.
disp
)
==
CONST_INT
)
{
fprintf
(
stream
,
"["
)
;
csky_output_constpool_label
(
stream
,
addr
.
label
)
;
fprintf
(
stream
,
"+%d]"
,
(
int
)
INTVAL
(
addr
.
disp
)
)
;
}
else
if
(
addr
.
label
)
{
fprintf
(
stream
,
"["
)
;
csky_output_constpool_label
(
stream
,
addr
.
label
)
;
fprintf
(
stream
,
"]"
)
;
}
else
if
(
addr
.
symbol
&&
addr
.
disp
&&
GET_CODE
(
addr
.
disp
)
==
CONST_INT
)
{
fprintf
(
stream
,
"["
)
;
output_addr_const
(
stream
,
addr
.
symbol
)
;
fprintf
(
stream
,
"+%d]"
,
(
int
)
INTVAL
(
addr
.
disp
)
)
;
}
else
if
(
addr
.
symbol
)
{
fprintf
(
stream
,
"["
)
;
output_addr_const
(
stream
,
addr
.
symbol
)
;
fprintf
(
stream
,
"]"
)
;
}
else
if
(
addr
.
disp
&&
GET_CODE
(
addr
.
disp
)
==
CONST_INT
)
fprintf
(
stream
,
"(%s, %d)"
,
reg_names
[
REGNO
(
addr
.
base
)
]
,
(
int
)
INTVAL
(
addr
.
disp
)
)
;
else
if
(
addr
.
disp
&&
GET_CODE
(
addr
.
disp
)
==
UNSPEC
)
{
if
(
REGNO
(
addr
.
base
)
!=
CSKY_GB_REGNUM
)
fprintf
(
stream
,
"(%s, "
,
reg_names
[
REGNO
(
addr
.
base
)
]
)
;
else
fprintf
(
stream
,
"["
)
;
csky_output_pic_addr_const
(
stream
,
addr
.
disp
,
0
)
;
fprintf
(
stream
,
"%s"
,
(
REGNO
(
addr
.
base
)
!=
CSKY_GB_REGNUM
)
")"
:
"]"
)
;
}
else
if
(
addr
.
index
)
fprintf
(
stream
,
"(%s, %s << %d)"
,
reg_names
[
REGNO
(
addr
.
base
)
]
,
reg_names
[
REGNO
(
addr
.
index
)
]
,
exact_log2
(
(
int
)
(
addr
.
scale
)
)
)
;
else
fprintf
(
stream
,
"(%s, 0)"
,
reg_names
[
REGNO
(
addr
.
base
)
]
)
;
}
</s>


<s> int csky_register_move_cost ( machine_mode mode ATTRIBUTE_UNUSED , reg_class_t from , reg_class_t to ) { ( ( CLASS ) == GENERAL_REGS || ( CLASS ) == MINI_REGS || ( CLASS ) == SP_REGS \ || ( CLASS ) == LOW_REGS ) ( ( CLASS ) == HILO_REGS ) ( ( CLASS ) == V_REGS ) if ( V_REG_CLASS_P ( from ) && V_REG_CLASS_P ( to ) ) return 2 ; if ( ( V_REG_CLASS_P ( from ) && GR_REG_CLASS_P ( to ) ) || ( GR_REG_CLASS_P ( from ) && V_REG_CLASS_P ( to ) ) ) return 6 ; if ( ( HILO_REG_CLASS_P ( from ) && GR_REG_CLASS_P ( to ) ) || ( GR_REG_CLASS_P ( from ) && HILO_REG_CLASS_P ( to ) ) ) return 16 ; if ( HILO_REG_CLASS_P ( from ) && HILO_REG_CLASS_P ( to ) ) return 32 ; if ( ( HILO_REG_CLASS_P ( from ) && V_REG_CLASS_P ( to ) ) || ( V_REG_CLASS_P ( from ) && HILO_REG_CLASS_P ( to ) ) ) return 64 ; return 2 ; } </s>

Implement TARGET_REGISTER_MOVE_COST : compute extra cost of moving data between one register class and another .


<s> static void csky_reorg ( void ) { if ( TARGET_CONSTANT_POOL ) csky_emit_constant_pools ( ) ; } </s>

Implement TARGET_MACHINE_DEPENDENT_REORG . This handles -mconstpool output .


<s> rtx csky_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return NULL_RTX ; return get_hard_reg_initial_val ( Pmode , CSKY_LR_REGNUM ) ; } </s>

Return an RTX indicating where the return address to the calling function can be found .


<s> static bool csky_return_in_memory ( const_tree type , const_tree fntype ATTRIBUTE_UNUSED ) { const HOST_WIDE_INT size = int_size_in_bytes ( type ) ; return ( size == - 1 || size > 2 * UNITS_PER_WORD ) ; } </s>

Implement TARGET_RETURN_IN_MEMORY to decide whether TYPE should be returned in memory ( true ) or in a register ( false ) . FNTYPE is the type of the function making the call .


<s> static bool csky_rtx_costs ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ) { int code = GET_CODE ( x ) ; if ( CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK801 ) ) return ck802_ck801_rtx_costs ( x , code , outer_code , total , speed ) ; else if ( CSKY_TARGET_ARCH ( CK803 ) ) return ck803_rtx_costs ( x , code , outer_code , total , speed ) ; else if ( CSKY_TARGET_ARCH ( CK807 ) || CSKY_TARGET_ARCH ( CK810 ) ) return ck807_ck810_rtx_costs ( x , code , outer_code , total , speed ) ; else if ( CSKY_TARGET_ARCH ( CK860 ) ) return ck860_rtx_costs ( x , code , mode , outer_code , total , speed ) ; else gcc_unreachable ( ) ; } </s>

Implement TARGET_RTX_COSTS , to 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> static int csky_sched_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int cost , unsigned int dw ATTRIBUTE_UNUSED ) { if ( dep_type == REG_DEP_ANTI || dep_type == REG_DEP_OUTPUT ) return 0 ; else if ( recog_memoized ( insn ) >= 0 && recog_memoized ( dep ) >= 0 ) { enum attr_type insn_type = get_attr_type ( insn ) ; if ( CSKY_TARGET_ARCH ( CK803 ) ) { if ( insn_type == TYPE_LOAD || insn_type == TYPE_STORE ) { rtx pattern = PATTERN ( insn ) ; gcc_assert ( GET_CODE ( pattern ) == SET ) ; rtx addr = ( insn_type == TYPE_LOAD ? SET_SRC ( pattern ) : SET_DEST ( pattern ) ) ; enum rtx_code code = GET_CODE ( addr ) ; if ( code == ZERO_EXTEND || code == SIGN_EXTEND ) addr = XEXP ( addr , 0 ) ; gcc_assert ( GET_CODE ( addr ) == MEM ) ; rtx base = XEXP ( addr , 0 ) ; rtx reg = NULL_RTX ; if ( REG_P ( base ) ) reg = base ; if ( GET_CODE ( base ) == PLUS && GET_CODE ( XEXP ( base , 0 ) ) == REG ) reg = XEXP ( base , 0 ) ; if ( ( reg != NULL_RTX ) && reg_set_p ( reg , PATTERN ( dep ) ) ) return 2 ; } } else if ( CSKY_TARGET_ARCH ( CK802 ) ) { if ( ( insn_type == TYPE_CALL_JSR || insn_type == TYPE_BRANCH_JMP ) && get_attr_type ( dep ) != TYPE_LOAD ) return 1 ; if ( insn_type == TYPE_LOAD || insn_type == TYPE_STORE ) { rtx pattern = PATTERN ( insn ) ; gcc_assert ( GET_CODE ( pattern ) == SET ) ; rtx addr = ( insn_type == TYPE_LOAD ? SET_SRC ( pattern ) : SET_DEST ( pattern ) ) ; enum rtx_code code = GET_CODE ( addr ) ; if ( code == ZERO_EXTEND || code == SIGN_EXTEND ) addr = XEXP ( addr , 0 ) ; gcc_assert ( GET_CODE ( addr ) == MEM ) ; rtx base = XEXP ( addr , 0 ) ; rtx reg = NULL_RTX ; if ( REG_P ( base ) ) reg = base ; if ( GET_CODE ( base ) == PLUS && GET_CODE ( XEXP ( base , 0 ) ) == REG ) reg = XEXP ( base , 0 ) ; if ( ( reg != NULL_RTX ) && reg_set_p ( reg , PATTERN ( dep ) ) && get_attr_type ( dep ) != TYPE_LOAD ) return 1 ; if ( insn_type == TYPE_STORE && reg_referenced_p ( SET_SRC ( pattern ) , PATTERN ( dep ) ) ) return 1 ; } } } return cost ; } </s>

This function implements the target macro TARGET_SCHED_ADJUST_COST . It corrects the value of COST based on the relationship between INSN and DEP through the dependence DEP_TYPE . It returns the new value .


<s> static int csky_sched_issue_rate ( void ) { if ( CSKY_TARGET_ARCH ( CK810 ) ) return 2 ; else return 1 ; } </s>

Implement TARGET_SCHED_ISSUE_RATE . Lookup the issue rate in the per-core tuning structs .


<s> reg_class_t csky_secondary_reload ( bool in_p ATTRIBUTE_UNUSED , rtx x , reg_class_t rclass , machine_mode mode , secondary_reload_info * sri ATTRIBUTE_UNUSED ) { int regno = - 1 ; if ( GET_CODE ( x ) == SIGN_EXTEND ) { int off = 0 ; x = XEXP ( x , 0 ) ; if ( reg_renumber ) regno = true_regnum ( x ) ; else { while ( GET_CODE ( x ) == SUBREG ) { off += subreg_regno_offset ( REGNO ( SUBREG_REG ( x ) ) , GET_MODE ( SUBREG_REG ( x ) ) , SUBREG_BYTE ( x ) , GET_MODE ( x ) ) ; x = SUBREG_REG ( x ) ; } if ( GET_CODE ( x ) == REG ) regno = REGNO ( x ) + off ; } } else if ( GET_CODE ( x ) == REG || GET_CODE ( x ) == SUBREG ) regno = true_regnum ( x ) ; if ( rclass == HILO_REGS && ! CSKY_GENERAL_REGNO_P ( regno ) ) return GENERAL_REGS ; if ( rclass == V_REGS && ! CSKY_GENERAL_REGNO_P ( regno ) ) { if ( MEM_P ( x ) && ( mode == SFmode || mode == DFmode ) ) return NO_REGS ; else return GENERAL_REGS ; } return NO_REGS ; } </s>

Implement TARGET_SECONDARY_RELOAD . If copying a register of RCLASS from/to X requires an intermediate register , the hook should return the REGISTER_CLASS required for this intermediate register . If no intermediate register is required , it should return NO_REGS . If more than one intermediate register is required , describe the one that is closest in the copy chain to the reload register .


Implement TARGET_SETUP_INCOMING_VARARGS . On C-Sky the copy from the argument registers to the stack is emitted by the prologue hooks , so here we just have to note how much stack space to save .


<s> void csky_set_eh_return_address ( rtx source , rtx scratch ) { HOST_WIDE_INT delta = 0 ; rtx basereg , addr ; unsigned int reg_mask ; csky_layout_stack_frame ( ) ; reg_mask = cfun -> machine -> reg_mask ; if ( reg_mask & ( 1 << CSKY_LR_REGNUM ) ) { int i = 0 ; if ( frame_pointer_needed ) { basereg = hard_frame_pointer_rtx ; delta = 0 ; } else { basereg = stack_pointer_rtx ; delta = cfun -> machine -> reg_offset ; } for ( i = 0 ; i < CSKY_LR_REGNUM ; i ++ ) if ( reg_mask & ( 1 << i ) ) delta += 4 ; if ( ( CSKY_TARGET_ARCH ( CK801 ) && delta >= CSKY_LD16_MAX_OFFSET ( Pmode ) ) || delta >= CSKY_LD32_MAX_OFFSET ( Pmode ) ) { emit_insn ( gen_movsi ( scratch , GEN_INT ( delta ) ) ) ; emit_insn ( gen_addsi3 ( scratch , scratch , basereg ) ) ; addr = scratch ; } else addr = plus_constant ( Pmode , basereg , delta ) ; emit_move_insn ( gen_frame_mem ( Pmode , addr ) , source ) ; } else emit_move_insn ( gen_rtx_REG ( Pmode , CSKY_LR_REGNUM ) , source ) ; } </s>

Helper for csky_eh_return splitter : store the call frame exception handler address in lr .


<s> bool csky_shifted_imm8_constant ( unsigned HOST_WIDE_INT val , unsigned int * base , unsigned int * shift ) { unsigned HOST_WIDE_INT mask = 0xff ; int i ; val = val & ( unsigned HOST_WIDE_INT ) 0xffffffffu ; if ( val == 0 ) return 0 ; for ( i = 0 ; i < 25 ; i ++ ) if ( ( val & ( mask << i ) ) == val ) { if ( base ) * base = ( unsigned int ) ( val >> i ) ; if ( shift ) * shift = ( unsigned int ) i ; return true ; } return false ; } </s>

Return true if the constant VAL can be expressed by an 8-bit constant with a shift value , filling in * BASE and * SHIFT .


<s> bool csky_simple_addr_operand_p ( rtx op ) { struct csky_address addr ; if ( ! decompose_csky_address ( op , & addr ) ) return false ; if ( addr . disp && GET_CODE ( addr . disp ) == UNSPEC ) return false ; if ( ! addr . index && ! addr . symbol ) return true ; return false ; } </s>

Helper function for the csky_simple_mem_operand predicate . Returns true if OP is an address of the form reg + displacement .


<s> static reg_class_t csky_spill_class ( reg_class_t rclass , machine_mode mode ATTRIBUTE_UNUSED ) { if ( ( rclass == MINI_REGS && ! TARGET_MINI_REGISTERS ) || ( rclass == LOW_REGS && TARGET_HIGH_REGISTERS ) ) return GENERAL_REGS ; return NO_REGS ; } </s>

Implement TARGET_SPILL_CLASS . Try spilling to a larger register class before spilling to memory .


<s> bool csky_split_ior ( rtx * operands ) { HOST_WIDE_INT mask = INTVAL ( operands [ 2 ] ) ; int i ; if ( mask == 0 ) { emit_move_insn ( operands [ 0 ] , operands [ 1 ] ) ; return true ; } if ( mask == - 1 ) { emit_move_insn ( operands [ 0 ] , gen_int_mode ( - 1 , SImode ) ) ; return true ; } if ( CSKY_ISA_FEATURE ( E2 ) && csky_literal_I_operand ( operands [ 2 ] , SImode ) ) return false ; if ( popcount_hwi ( mask & 0xffffffff ) <= ( reload_completed && ! CSKY_ISA_FEATURE ( E2 ) ? 1 : 2 ) ) { rtx input = operands [ 1 ] ; if ( ! CSKY_ISA_FEATURE ( E2 ) ) { emit_move_insn ( operands [ 0 ] , input ) ; input = operands [ 0 ] ; } for ( i = 0 ; i < 32 ; i ++ ) if ( mask & ( 1 << i ) ) { emit_insn ( gen_bseti ( operands [ 0 ] , input , GEN_INT ( i ) ) ) ; input = operands [ 0 ] ; } return true ; } if ( reload_completed ) { emit_move_insn ( operands [ 0 ] , operands [ 2 ] ) ; operands [ 2 ] = operands [ 1 ] ; operands [ 1 ] = operands [ 0 ] ; } else operands [ 2 ] = copy_to_mode_reg ( SImode , operands [ 2 ] ) ; return false ; } </s>

Split operands for an IOR expression when OPERANDS [ 2 ] is a constant . Note operands [ 0 ] is marked earlyclobber in this case and can be overwritten . Return true if `` DONE '' , false otherwise .


<s> bool csky_split_xor ( rtx * operands ) { HOST_WIDE_INT mask = INTVAL ( operands [ 2 ] ) ; if ( mask == 0 ) { emit_move_insn ( operands [ 0 ] , operands [ 1 ] ) ; return true ; } if ( mask == - 1 ) { if ( CSKY_ISA_FEATURE ( E2 ) ) emit_insn ( gen_cskyv2_one_cmplsi2 ( operands [ 0 ] , operands [ 1 ] ) ) ; else { emit_move_insn ( operands [ 0 ] , operands [ 1 ] ) ; emit_insn ( gen_ck801_one_cmplsi2 ( operands [ 0 ] , operands [ 0 ] ) ) ; } return true ; } if ( CSKY_ISA_FEATURE ( E2 ) && csky_arith_O_operand ( operands [ 2 ] , SImode ) ) return false ; if ( reload_completed ) { emit_move_insn ( operands [ 0 ] , operands [ 2 ] ) ; operands [ 2 ] = operands [ 1 ] ; operands [ 1 ] = operands [ 0 ] ; } else operands [ 2 ] = copy_to_mode_reg ( SImode , operands [ 2 ] ) ; return false ; } </s>

Split operands for an XOR expression when OPERANDS [ 2 ] is a constant . Note operands [ 0 ] is marked earlyclobber in this case and can be overwritten . Return true if `` DONE '' , false otherwise .


<s> bool csky_symbolic_address_p ( rtx x ) { switch ( GET_CODE ( x ) ) { case SYMBOL_REF : case LABEL_REF : return 1 ; case CONST : x = XEXP ( x , 0 ) ; return ( ( GET_CODE ( XEXP ( x , 0 ) ) == SYMBOL_REF || GET_CODE ( XEXP ( x , 0 ) ) == LABEL_REF ) && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) ; default : return 0 ; } } </s>

Return true if X is an address form involving a symbol or label ref .


<s> bool csky_symbol_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( GET_CODE ( x ) == SYMBOL_REF ) return true ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( csky_symbol_mentioned_p ( XVECEXP ( x , i , j ) ) ) return true ; } else if ( fmt [ i ] == 'e' && csky_symbol_mentioned_p ( XEXP ( x , i ) ) ) return true ; } return false ; } </s>

Return TRUE if X references a SYMBOL_REF .


<s> bool csky_tls_referenced_p ( rtx x ) { if ( ! TARGET_TLS ) return false ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) != 0 ) return true ; if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) iter . skip_subrtxes ( ) ; } return false ; } </s>

Return TRUE if X contains any references to TLS symbols .


<s> static bool csky_tls_symbol_p ( rtx x ) { if ( ! TARGET_TLS ) return false ; if ( GET_CODE ( x ) != SYMBOL_REF ) return false ; return SYMBOL_REF_TLS_MODEL ( x ) != 0 ; } </s>

Return TRUE if X is a thread-local symbol .


<s> static void csky_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx mem , a_tramp ; int pool = TRAMPOLINE_SIZE - 8 ; emit_block_move ( m_tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; mem = adjust_address ( m_tramp , SImode , pool ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , pool + 4 ) ; emit_move_insn ( mem , fnaddr ) ; a_tramp = XEXP ( m_tramp , 0 ) ; maybe_emit_call_builtin___clear_cache ( a_tramp , plus_constant ( Pmode , a_tramp , TRAMPOLINE_SIZE ) ) ; } </s>

Worker function for TARGET_TRAMPOLINE_INIT .


<s> bool csky_valid_fpuv2_mem_operand ( rtx op ) { struct csky_address addr ; if ( GET_CODE ( op ) != MEM ) return false ; if ( ! decompose_csky_address ( XEXP ( op , 0 ) , & addr ) ) return false ; if ( ! is_csky_address_register_rtx_p ( addr . base , 0 ) ) return false ; if ( addr . index ) { if ( ! is_csky_address_register_rtx_p ( addr . index , 0 ) ) return false ; if ( addr . scale == 1 || addr . scale == 2 || addr . scale == 4 || addr . scale == 8 ) return true ; return false ; } else if ( addr . disp ) { rtx disp = addr . disp ; if ( ! CONST_INT_P ( disp ) ) return false ; if ( ( ( unsigned ) INTVAL ( disp ) % 4 ) == 0 && ( unsigned ) INTVAL ( disp ) <= ( unsigned ) 1020 ) return true ; return false ; } return true ; } </s>

Support for the Q memory constraint . Returns true if OP is a MEM RTX with an address consisting of base + index or base + displacement .


<s> bool csky_valid_mem_constraint_operand ( rtx op , const char * constraint ) { struct csky_address addr ; if ( GET_CODE ( op ) != MEM ) return false ; if ( ! decompose_csky_address ( XEXP ( op , 0 ) , & addr ) ) return false ; if ( ! is_csky_address_register_rtx_p ( addr . base , 0 ) ) return false ; if ( addr . index && ( constraint [ 0 ] == 'Q' || constraint [ 0 ] == 'W' ) ) { if ( ! is_csky_address_register_rtx_p ( addr . index , 0 ) ) return false ; if ( addr . scale == 1 || addr . scale == 2 || addr . scale == 4 || addr . scale == 8 ) return true ; return false ; } else if ( addr . disp && constraint [ 0 ] == 'Q' ) { rtx disp = addr . disp ; if ( ! CONST_INT_P ( disp ) ) return false ; if ( ( ( unsigned ) INTVAL ( disp ) % 4 ) == 0 && ( unsigned ) INTVAL ( disp ) <= ( unsigned ) 1020 ) return true ; return false ; } else if ( constraint [ 0 ] == 'Q' ) return true ; return false ; } </s>

Support for the Q or W memory constraint . Returns true if OP is a MEM RTX with an address consisting of base + index or base + displacement .


";; Emitting minipool after insn %u;\ address %ld; align %d (bytes)\n"


<s> static void emit_csky_regs_pop ( unsigned long mask ) { int num_regs = 0 ; int i , j ; rtx par ; for ( i = 0 ; i < CSKY_NGPR_REGS ; i ++ ) if ( mask & ( 1 << i ) ) num_regs ++ ; gcc_assert ( num_regs && num_regs <= 12 ) ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs + 1 ) ) ; XVECEXP ( par , 0 , 0 ) = ret_rtx ; for ( i = 0 ; i < CSKY_NGPR_REGS ; i ++ ) if ( mask & ( 1 << i ) ) { rtx reg = gen_rtx_REG ( SImode , i ) ; rtx addr = plus_constant ( Pmode , stack_pointer_rtx , 4 * num_regs ) ; rtx tmp = gen_frame_mem ( SImode , gen_rtx_POST_MODIFY ( Pmode , stack_pointer_rtx , addr ) ) ; XVECEXP ( par , 0 , 1 ) = gen_rtx_SET ( reg , gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , tmp ) , UNSPEC_PUSHPOP_MULT ) ) ; break ; } for ( j = 2 , i ++ ; j < ( num_regs + 1 ) ; i ++ ) if ( mask & ( 1 << i ) ) { rtx reg = gen_rtx_REG ( SImode , i ) ; XVECEXP ( par , 0 , j ) = gen_rtx_USE ( VOIDmode , reg ) ; j ++ ; } par = emit_jump_insn ( par ) ; } </s>

Generate and emit an insn pattern that we will recognize as a pop_multi . SAVED_REGS_MASK shows which registers need to be restored . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information .


<s> static rtx emit_csky_regs_push ( unsigned long mask ) { int num_regs = 0 ; int i , j ; rtx par ; rtx dwarf ; rtx tmp ; int dwarf_par_index ; for ( i = 0 ; i < CSKY_NGPR_REGS ; i ++ ) { if ( mask & ( 1 << i ) ) num_regs ++ ; } gcc_assert ( num_regs && num_regs <= 12 ) ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs ) ) ; dwarf = gen_rtx_SEQUENCE ( VOIDmode , rtvec_alloc ( num_regs + 1 ) ) ; dwarf_par_index = 1 ; for ( i = 0 ; i < CSKY_NGPR_REGS ; i ++ ) if ( mask & ( 1 << i ) ) { rtx reg = gen_rtx_REG ( SImode , i ) ; rtx addr = plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ; tmp = gen_frame_mem ( BLKmode , gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , addr ) ) ; XVECEXP ( par , 0 , 0 ) = gen_rtx_SET ( tmp , gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSHPOP_MULT ) ) ; tmp = gen_rtx_SET ( gen_frame_mem ( SImode , stack_pointer_rtx ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; break ; } for ( j = 1 , i ++ ; j < num_regs ; i ++ ) if ( mask & ( 1 << i ) ) { rtx reg = gen_rtx_REG ( SImode , i ) ; rtx addr = plus_constant ( Pmode , stack_pointer_rtx , 4 * j ) ; tmp = gen_rtx_SET ( gen_frame_mem ( SImode , addr ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j ) = gen_rtx_USE ( VOIDmode , reg ) ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; j ++ ; } par = emit_insn ( par ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 0 ) = tmp ; add_reg_note ( par , REG_FRAME_RELATED_EXPR , dwarf ) ; RTX_FRAME_RELATED_P ( par ) = 1 ; return par ; } </s>

Generate and emit an insn that we will recognize as a push_multi . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information . DWARF_REGS_MASK is a subset of MASK for registers that should be annotated for DWARF2 frame unwind information .


<s> static void expand_csky_stack_adjust ( int offset ) { rtx set ; rtx_insn * insn ; int size = ( offset > 0 ? offset : - offset ) ; if ( offset == 0 ) return ; if ( size > CSKY_MAX_SP_ADJUST * 2 ) { rtx tmp , dwarf ; gcc_assert ( cfun -> machine -> reg_size != 0 && ( cfun -> machine -> reg_mask & ( 1 << CSKY_STACKADJUST_REGNUM ) ) ) ; if ( ! flag_sched_prolog ) emit_insn ( gen_blockage ( ) ) ; tmp = gen_rtx_REG ( SImode , CSKY_STACKADJUST_REGNUM ) ; emit_move_insn ( tmp , GEN_INT ( size ) ) ; if ( offset > 0 ) set = gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , tmp ) ; else set = gen_subsi3 ( stack_pointer_rtx , stack_pointer_rtx , tmp ) ; insn = emit_insn ( set ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; dwarf = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , dwarf ) ; if ( ! flag_sched_prolog ) emit_insn ( gen_blockage ( ) ) ; } else while ( size ) { int delta = ( size > CSKY_MAX_SP_ADJUST ? CSKY_MAX_SP_ADJUST : size ) ; if ( offset > 0 ) set = gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( delta ) ) ; else set = gen_subsi3 ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( delta ) ) ; insn = emit_insn ( set ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; size -= delta ; } } </s>

Adjust the stack pointer by OFFSET bytes . OFFSET is negative if this is in the prologue , positive if in the epilogue . This may require multiple instructions and/or use of CSKY_STACKADJUST_REGNUM as a scratch register . Emit CFA notes as appropriate .


<s> int fpuv3_const_double_rtx ( rtx x ) { REAL_VALUE_TYPE r , m ; r = * CONST_DOUBLE_REAL_VALUE ( x ) ; if ( REAL_VALUE_ISINF ( r ) || REAL_VALUE_ISNAN ( r ) || REAL_VALUE_MINUS_ZERO ( r ) || r . cl == rvc_zero ) return 0 ; int exponent ; r = real_value_abs ( & r ) ; exponent = REAL_EXP ( & r ) ; bool fail ; unsigned HOST_WIDE_INT mantissa , mant_hi ; unsigned HOST_WIDE_INT mask ; int point_pos = 2 * HOST_BITS_PER_WIDE_INT - 1 ; real_ldexp ( & m , & r , point_pos - exponent ) ; wide_int w = real_to_integer ( & m , & fail , HOST_BITS_PER_WIDE_INT * 2 ) ; mantissa = w . elt ( 0 ) ; mant_hi = w . elt ( 1 ) ; exponent -= 1 ; if ( ! IN_RANGE ( exponent , - 4 , 11 ) ) return 0 ; if ( mantissa != 0 ) return 0 ; point_pos -= HOST_BITS_PER_WIDE_INT ; mantissa = mant_hi ; mask = ( ( unsigned HOST_WIDE_INT ) 1 << ( point_pos - 9 ) ) - 1 ; if ( ( mantissa & mask ) != 0 ) return 0 ; return 1 ; } </s>

Check if a const_double can be used by a VFP fmovi instruction .


<s>
const
char
*
fpuv3_output_move
(
rtx
*
operands
)
{
rtx
reg
,
mem
,
addr
,
ops
[
2
]
;
bool
isload
=
REG_P
(
operands
[
0
]
)
;
const
char
*
templ
=
"f%s%s.%s\t%%0, %%1"
;
char
buff
[
50
]
;
machine_mode
mode
;
reg
=
operands
[
isload
0
:
1
]
;
mem
=
operands
[
isload
1
:
0
]
;
gcc_assert
(
REG_P
(
reg
)
)
;
gcc_assert
(
CSKY_VREG_P
(
REGNO
(
reg
)
)
)
;
gcc_assert
(
MEM_P
(
mem
)
)
;
mode
=
GET_MODE
(
reg
)
;
const
char
*
type
=
mode
==
DFmode
"64"
:
mode
==
SFmode
"32"
:
mode
==
HFmode
"16"
:
;
gcc_assert
(
type
!=
)
;
addr
=
XEXP
(
mem
,
0
)
;
struct
csky_address
caddr
;
decompose_csky_address
(
addr
,
&
caddr
)
;
ops
[
0
]
=
reg
;
ops
[
1
]
=
mem
;
sprintf
(
buff
,
templ
,
isload
"ld"
:
"st"
,
caddr
.
index
"r"
:
""
,
type
)
;
output_asm_insn
(
buff
,
ops
)
;
return
""
;
}
</s>

Output float point load/store instructions for fpuv3 .


<s> static int get_csky_barrier_cost ( rtx_insn * insn ) { int base_cost = 50 ; rtx next = next_nonnote_insn ( insn ) ; if ( next != NULL && GET_CODE ( next ) == CODE_LABEL ) base_cost -= 20 ; switch ( GET_CODE ( insn ) ) { case CODE_LABEL : return 50 ; case INSN : case CALL_INSN : return base_cost ; case JUMP_INSN : return base_cost - 10 ; default : return base_cost + 10 ; } } </s>

Return the cost of forcibly inserting a barrier after INSN .


<s> static unsigned long get_csky_current_func_type ( void ) { if ( CSKY_FUNCTION_TYPE ( cfun -> machine -> func_type ) == CSKY_FT_UNKNOWN ) { unsigned long type = CSKY_FT_UNKNOWN ; tree a ; tree attr ; gcc_assert ( TREE_CODE ( current_function_decl ) == FUNCTION_DECL ) ; attr = DECL_ATTRIBUTES ( current_function_decl ) ; a = lookup_attribute ( "naked" , attr ) ; if ( a != NULL_TREE ) type |= CSKY_FT_NAKED ; a = lookup_attribute ( "isr" , attr ) ; if ( a == NULL_TREE ) a = lookup_attribute ( "interrupt" , attr ) ; if ( a == NULL_TREE ) type |= CSKY_FT_NORMAL ; else type |= get_csky_isr_type ( TREE_VALUE ( a ) ) ; cfun -> machine -> func_type = type ; } return cfun -> machine -> func_type ; } </s>

Classify cfun as a normal function or some sort of interrupt handler , and set the corresponding bits in cfun- > machine- > func_type .


<s> static unsigned long get_csky_isr_type ( tree argument ) { const isr_attribute_entry * ptr ; const char * arg ; if ( argument == NULL_TREE ) return CSKY_FT_ISR ; if ( TREE_VALUE ( argument ) == NULL_TREE || TREE_CODE ( TREE_VALUE ( argument ) ) != STRING_CST ) return CSKY_FT_UNKNOWN ; arg = TREE_STRING_POINTER ( TREE_VALUE ( argument ) ) ; for ( ptr = isr_attribute_map ; ptr -> arg != NULL ; ptr ++ ) if ( strcmp ( arg , ptr -> arg ) == 0 ) return ptr -> return_value ; return CSKY_FT_UNKNOWN ; } </s>

Return the function type of the current function , if it has not been determined , return CSKY_FT_UNKNOWN .


<s> static HOST_WIDE_INT get_csky_jump_table_size ( rtx insn ) { if ( JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section ) { rtx body = PATTERN ( insn ) ; int elt = GET_CODE ( body ) == ADDR_DIFF_VEC ? 1 : 0 ; HOST_WIDE_INT size ; HOST_WIDE_INT modesize ; modesize = GET_MODE_SIZE ( GET_MODE ( body ) ) ; size = modesize * XVECLEN ( body , elt ) ; switch ( modesize ) { case 1 : size = ( size + 1 ) & ~ ( HOST_WIDE_INT ) 1 ; break ; case 2 : break ; case 4 : break ; default : gcc_unreachable ( ) ; } return size ; } return 0 ; } </s>

Compute the size of a vector jump table .


<s> static unsigned int get_csky_live_regs ( int * count ) { int reg ; unsigned int live_regs_mask = 0 ; * count = 0 ; for ( reg = 0 ; reg < CSKY_NGPR_REGS ; reg ++ ) { bool save = false ; if ( CSKY_TARGET_ARCH ( CK801 ) && reg > 8 && reg < 13 ) continue ; if ( ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) || CSKY_TARGET_ARCH ( CK803 ) ) && reg > 15 ) break ; if ( df_regs_ever_live_p ( reg ) && ! call_used_regs [ reg ] ) save = true ; else if ( frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM ) save = true ; else if ( crtl -> calls_eh_return && reg == HARD_FRAME_POINTER_REGNUM ) save = true ; else if ( ( CSKY_TARGET_ARCH ( CK801 ) || CSKY_TARGET_ARCH ( CK802 ) ) && reg == CSKY_LR_REGNUM && ( ! crtl -> is_leaf || csky_far_jump_used_p ( ) ) ) save = true ; else if ( crtl -> calls_eh_return && reg >= CSKY_FIRST_EH_RETDATA_REGNUM && reg <= CSKY_LAST_EH_RETDATA_REGNUM ) save = true ; if ( reg == CSKY_STACKADJUST_REGNUM && cfun -> machine -> reg_offset > CSKY_MAX_SP_ADJUST * 2 ) save = true ; if ( save ) { ( * count ) ++ ; live_regs_mask |= ( 1 << reg ) ; } } return live_regs_mask ; } </s>

Return the mask of registers used by the current function . Set COUNT to the number of registers used .


<s> static bool is_csky_address_register_rtx_p ( rtx x , int strict_p ) { int regno ; if ( ! x ) return false ; if ( ! REG_P ( x ) ) return false ; regno = REGNO ( x ) ; if ( strict_p ) return ( CSKY_GENERAL_REGNO_P ( regno ) || CSKY_GENERAL_REGNO_P ( reg_renumber [ regno ] ) ) ; else return CSKY_GENERAL_REGNO_P ( regno ) || regno >= FIRST_PSEUDO_REGISTER ; } </s>

Return true if X is valid as an CSKY addressing register .


<s> static bool is_ldr_shift_p ( HOST_WIDE_INT shift , enum rtx_code code ) { if ( code == ASHIFT ) return ( shift >= 0 && shift <= 3 ) ; else if ( code == MULT ) return ( shift == 1 || shift == 2 || shift == 4 || shift == 8 ) ; else return false ; } </s>

The instruction ldr rz , ( rx , ry < < i ) , i can be 0,1,2,3 . Check that SHIFT is valid , that the code is MULT , and that the shift is a power of 2 .


<s> static bool note_csky_invalid_constants ( rtx_insn * insn , HOST_WIDE_INT address , int do_pushes ) { bool result = false ; int opno ; extract_constrain_insn ( insn ) ; if ( recog_data . n_alternatives == 0 ) return false ; preprocess_constraints ( insn ) ; const operand_alternative * op_alt = which_op_alt ( ) ; for ( opno = 0 ; opno < recog_data . n_operands ; opno ++ ) { if ( recog_data . operand_type [ opno ] != OP_IN ) continue ; if ( op_alt [ opno ] . memory_ok ) { rtx op = recog_data . operand [ opno ] ; if ( CONSTANT_P ( op ) ) { if ( do_pushes ) push_csky_minipool_fix ( insn , address , recog_data . operand_loc [ opno ] , recog_data . operand_mode [ opno ] , op ) ; result = true ; } } } return result ; } </s>

Scan INSN and note any of its operands that need fixing . If DO_PUSHES is false we do not actually push any of the fixups needed . The function returns TRUE if any fixups were needed/pushed .


<s> static void print_csky_value ( FILE * f , rtx x ) { switch ( GET_CODE ( x ) ) { case CONST_INT : fprintf ( f , HOST_WIDE_INT_PRINT_HEX , INTVAL ( x ) ) ; return ; case CONST_DOUBLE : fprintf ( f , "<0x%lx,0x%lx>" , ( long ) XWINT ( x , 2 ) , ( long ) XWINT ( x , 3 ) ) ; return ; case CONST_VECTOR : { int i ; fprintf ( f , "<" ) ; for ( i = 0 ; i < CONST_VECTOR_NUNITS ( x ) ; i ++ ) { fprintf ( f , HOST_WIDE_INT_PRINT_HEX , INTVAL ( CONST_VECTOR_ELT ( x , i ) ) ) ; if ( i < ( CONST_VECTOR_NUNITS ( x ) - 1 ) ) fputc ( ',' , f ) ; } fprintf ( f , ">" ) ; } return ; case CONST_STRING : fprintf ( f , "\"%s\"" , XSTR ( x , 0 ) ) ; return ; case SYMBOL_REF : fprintf ( f , "`%s'" , XSTR ( x , 0 ) ) ; return ; case LABEL_REF : fprintf ( f , "L%d" , INSN_UID ( XEXP ( x , 0 ) ) ) ; return ; case CONST : print_csky_value ( f , XEXP ( x , 0 ) ) ; return ; case PLUS : print_csky_value ( f , XEXP ( x , 0 ) ) ; fprintf ( f , "+" ) ; print_csky_value ( f , XEXP ( x , 1 ) ) ; return ; case PC : fprintf ( f , "pc" ) ; return ; default : fprintf ( f , "????" ) ; return ; } } </s>

Print a symbolic form of the constant X to the dump file F. This is used for dump output for -mconstpool in the target-dependent reorg pass .


<s> static void push_csky_minipool_barrier ( rtx_insn * insn , HOST_WIDE_INT address ) { Mfix * fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * fix ) ) ; fix -> insn = insn ; fix -> address = address ; fix -> next = NULL ; if ( minipool_fix_head != NULL ) minipool_fix_tail -> next = fix ; else minipool_fix_head = fix ; minipool_fix_tail = fix ; } </s>

Record that there is a natural barrier in the insn stream at ADDRESS .


";; %smode fixup for i%d; addr %lu, range (%ld,%ld): "

Record INSN , which will need fixing up to load a value from the minipool . ADDRESS is the offset of the insn since the start of the function ; LOC is a pointer to the part of the insn which requires fixing ; VALUE is the constant that must be loaded , which is of type MODE .