<s> static void epiphany_setup_incoming_varargs ( cumulative_args_t cum , const function_arg_info & arg , int * pretend_size , int no_rtl ) { int first_anon_arg ; CUMULATIVE_ARGS next_cum ; machine_function_t * mf = MACHINE_FUNCTION ( cfun ) ; if ( ! TYPE_NO_NAMED_ARGS_STDARG_P ( TREE_TYPE ( current_function_decl ) ) ) gcc_assert ( arg . mode != BLKmode ) ; next_cum = * get_cumulative_args ( cum ) ; if ( ! TYPE_NO_NAMED_ARGS_STDARG_P ( TREE_TYPE ( current_function_decl ) ) ) next_cum = ( ROUND_ADVANCE_CUM ( next_cum , arg . mode , arg . type ) + ROUND_ADVANCE_ARG ( arg . mode , arg . type ) ) ; first_anon_arg = next_cum ; if ( first_anon_arg < MAX_EPIPHANY_PARM_REGS && ! no_rtl ) { int first_reg_offset = first_anon_arg ; * pretend_size = ( ( MAX_EPIPHANY_PARM_REGS - first_reg_offset ) * UNITS_PER_WORD ) ; } mf -> args_parsed = 1 ; mf -> pretend_args_odd = ( ( * pretend_size & UNITS_PER_WORD ) ? 1 : 0 ) ; } </s>

Do any needed setup for a variadic function . For the EPIPHANY , we actually emit the code in epiphany_expand_prologue . CUM has not been updated for the last named argument which has type TYPE and mode MODE , and we rely on this fact .


<s> static int epiphany_adjust_cost ( rtx_insn * insn , rtx link , rtx_insn * dep_insn , int cost ) { if ( REG_NOTE_KIND ( link ) == 0 ) { rtx dep_set ; if ( recog_memoized ( insn ) < 0 || recog_memoized ( dep_insn ) < 0 ) return cost ; dep_set = single_set ( dep_insn ) ; if ( dep_set && MEM_P ( SET_SRC ( dep_set ) ) && cost > 1 ) { rtx set = single_set ( insn ) ; if ( set && ! reg_overlap_mentioned_p ( SET_DEST ( dep_set ) , SET_SRC ( set ) ) && ( ! MEM_P ( SET_DEST ( set ) ) || ! reg_overlap_mentioned_p ( SET_DEST ( dep_set ) , XEXP ( SET_DEST ( set ) , 0 ) ) ) ) cost = 1 ; } } return cost ; } </s>

Function to update the integer COST based on the relationship between INSN that is dependent on DEP_INSN through the dependence LINK . The default is to make no adjustment to COST . This can be used for example to specify to the scheduler that an output- or anti-dependence does not incur the same cost as a data-dependence . The return value should be the new value for COST .


<s> unsigned epiphany_adjust_field_align ( tree field , unsigned computed ) { if ( computed == 32 && TREE_CODE ( TREE_TYPE ( field ) ) == ARRAY_TYPE ) { tree elmsz = TYPE_SIZE ( TREE_TYPE ( TREE_TYPE ( field ) ) ) ; if ( ! tree_fits_uhwi_p ( elmsz ) || tree_to_uhwi ( elmsz ) >= 32 ) return 64 ; } return computed ; } </s>

Upping the alignment of arrays in structs is not only a performance enhancement , it also helps preserve assumptions about how arrays-at-the-end-of-structs work , like for struct gcov_fn_info in libgcov.c .


<s> static rtx epiphany_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS cum = * get_cumulative_args ( cum_v ) ; if ( PASS_IN_REG_P ( cum , mode , type ) ) return gen_rtx_REG ( mode , ROUND_ADVANCE_CUM ( cum , mode , type ) ) ; return 0 ; } </s>

On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in registers and the rest are pushed .


<s> static void epiphany_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 ) ; * cum = ROUND_ADVANCE_CUM ( * cum , mode , type ) + ROUND_ADVANCE_ARG ( mode , type ) ; } </s>

Update the data in CUM to advance over an argument of mode MODE and data type TYPE . ( TYPE is null for libcalls where that information may not be available . )


<s>
static
void
epiphany_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
int
this_regno
=
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
1
:
0
;
const
char
*
this_name
=
reg_names
[
this_regno
]
;
const
char
*
fname
;
gcc_assert
(
call_used_regs
[
GPR_IP
]
)
;
gcc_assert
(
call_used_regs
[
GPR_16
]
)
;
if
(
delta
==
0
)
;
else
if
(
SIMM11
(
delta
)
)
asm_fprintf
(
file
,
"\tadd\t%s,%s,%d\n"
,
this_name
,
this_name
,
(
int
)
delta
)
;
else
if
(
delta
<
0
&&
delta
>=
0xffff
)
{
asm_fprintf
(
file
,
"\tmov\tip,%d\n"
,
(
int
)
delta
)
;
asm_fprintf
(
file
,
"\tsub\t%s,%s,ip\n"
,
this_name
,
this_name
)
;
}
else
{
asm_fprintf
(
file
,
"\tmov\tip,%%low(%ld)\n"
,
(
long
)
delta
)
;
if
(
delta
&
~
0xffff
)
asm_fprintf
(
file
,
"\tmovt\tip,%%high(%ld)\n"
,
(
long
)
delta
)
;
asm_fprintf
(
file
,
"\tadd\t%s,%s,ip\n"
,
this_name
,
this_name
)
;
}
if
(
vcall_offset
!=
0
)
{
asm_fprintf
(
file
,
"\tldr\tip, [%s]\n"
,
this_name
)
;
if
(
vcall_offset
<
0x7ff
*
4
||
vcall_offset
>
0x7ff
*
4
||
(
vcall_offset
&
3
)
!=
0
)
{
asm_fprintf
(
file
,
"\tmov\tr16, %%low(%ld)\n"
,
(
long
)
vcall_offset
)
;
asm_fprintf
(
file
,
"\tmovt\tr16, %%high(%ld)\n"
,
(
long
)
vcall_offset
)
;
asm_fprintf
(
file
,
"\tldr\tip, [ip,r16]\n"
)
;
}
else
asm_fprintf
(
file
,
"\tldr\tip, [ip,%d]\n"
,
(
int
)
vcall_offset
/
4
)
;
asm_fprintf
(
file
,
"\tadd\t%s, %s, ip\n"
,
this_name
,
this_name
)
;
}
fname
=
XSTR
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
0
)
;
if
(
epiphany_is_long_call_p
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
)
)
{
fputs
(
"\tmov\tip,%low("
,
file
)
;
assemble_name
(
file
,
fname
)
;
fputs
(
")\n\tmovt\tip,%high("
,
file
)
;
assemble_name
(
file
,
fname
)
;
fputs
(
")\n\tjr ip\n"
,
file
)
;
}
else
{
fputs
(
"\tb\t"
,
file
)
;
assemble_name
(
file
,
fname
)
;
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 bool epiphany_pass_by_reference ( cumulative_args_t ca ATTRIBUTE_UNUSED , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { if ( type ) { if ( AGGREGATE_TYPE_P ( type ) && ( mode == BLKmode || TYPE_NEEDS_CONSTRUCTING ( type ) ) ) return true ; } return false ; } </s>

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


<s> static void epiphany_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 ) ) { output_addr_const ( file , addr ) ; } 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 ) { fprintf ( file , ",%s%d" , IMMEDIATE_PREFIX , offset / current_frame_info . stld_sz ) ; } 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 : case POST_INC : case POST_DEC : case POST_MODIFY : 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 epiphany_rtx_costs ( rtx x , int code , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { switch ( code ) { case CONST_INT : if ( ( outer_code == PLUS || outer_code == MINUS ) && SIMM11 ( INTVAL ( x ) ) ) { * total = 0 ; return true ; } if ( IMM16 ( INTVAL ( x ) ) ) { * total = outer_code == SET ? 0 : COSTS_N_INSNS ( 1 ) ; return true ; } case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( ( epiphany_small16 ( x ) ? 0 : 1 ) + ( outer_code == SET ? 0 : 1 ) ) ; return true ; case CONST_DOUBLE : { rtx high , low ; split_double ( x , & high , & low ) ; * total = COSTS_N_INSNS ( ! IMM16 ( INTVAL ( high ) ) + ! IMM16 ( INTVAL ( low ) ) ) ; return true ; } case ASHIFT : case ASHIFTRT : case LSHIFTRT : * total = COSTS_N_INSNS ( 1 ) ; return true ; case COMPARE : switch ( GET_MODE ( x ) ) { case CC_N_NEmode : case CC_C_LTUmode : case CC_C_GTUmode : return true ; default : return false ; } case SET : { rtx src = SET_SRC ( x ) ; if ( BINARY_P ( src ) ) * total = 0 ; 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> static void epiphany_setup_incoming_varargs ( cumulative_args_t cum , machine_mode mode , tree type , int * pretend_size , int no_rtl ) { int first_anon_arg ; CUMULATIVE_ARGS next_cum ; machine_function_t * mf = MACHINE_FUNCTION ( cfun ) ; gcc_assert ( mode != BLKmode ) ; next_cum = * get_cumulative_args ( cum ) ; next_cum = ROUND_ADVANCE_CUM ( next_cum , mode , type ) + ROUND_ADVANCE_ARG ( mode , type ) ; first_anon_arg = next_cum ; if ( first_anon_arg < MAX_EPIPHANY_PARM_REGS && ! no_rtl ) { int first_reg_offset = first_anon_arg ; * pretend_size = ( ( MAX_EPIPHANY_PARM_REGS - first_reg_offset ) * UNITS_PER_WORD ) ; } mf -> args_parsed = 1 ; mf -> pretend_args_odd = ( ( * pretend_size & UNITS_PER_WORD ) ? 1 : 0 ) ; } </s>


<s> static rtx frame_subreg_note ( rtx set , int offset ) { rtx src = simplify_gen_subreg ( SImode , SET_SRC ( set ) , DImode , offset ) ; rtx dst = simplify_gen_subreg ( SImode , SET_DEST ( set ) , DImode , offset ) ; set = gen_rtx_SET ( VOIDmode , dst , src ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; return set ; } </s>

For a DImode load / store SET , make a SImode set for a REG_FRAME_RELATED_EXPR note , using OFFSET to create a high or lowpart subreg .


<s> static int get_epiphany_condition_code ( rtx comparison ) { switch ( GET_MODE ( XEXP ( comparison , 0 ) ) ) { case CCmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; case LTU : return 2 ; case GEU : return 3 ; case GT : return 4 ; case LE : return 5 ; case GE : return 6 ; case LT : return 7 ; case GTU : return 8 ; case LEU : return 9 ; default : gcc_unreachable ( ) ; } case CC_N_NEmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 6 ; case NE : return 7 ; default : gcc_unreachable ( ) ; } case CC_C_LTUmode : switch ( GET_CODE ( comparison ) ) { case GEU : return 2 ; case LTU : return 3 ; default : gcc_unreachable ( ) ; } case CC_C_GTUmode : switch ( GET_CODE ( comparison ) ) { case LEU : return 3 ; case GTU : return 2 ; default : gcc_unreachable ( ) ; } case CC_FPmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 10 ; case NE : return 11 ; case LT : return 12 ; case LE : return 13 ; default : gcc_unreachable ( ) ; } case CC_FP_EQmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; default : gcc_unreachable ( ) ; } case CC_FP_GTEmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; case GT : return 4 ; case GE : return 6 ; case UNLE : return 5 ; case UNLT : return 7 ; default : gcc_unreachable ( ) ; } case CC_FP_ORDmode : switch ( GET_CODE ( comparison ) ) { case ORDERED : return 9 ; case UNORDERED : return 8 ; default : gcc_unreachable ( ) ; } case CC_FP_UNEQmode : switch ( GET_CODE ( comparison ) ) { case UNEQ : return 9 ; case LTGT : return 8 ; default : gcc_unreachable ( ) ; } default : gcc_unreachable ( ) ; } return ( 42 ) ; } </s>

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


<s> int hard_regno_mode_ok ( int regno , machine_mode mode ) { if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return ( regno & 1 ) == 0 && GPR_P ( regno ) ; else return 1 ; } </s>

Value is 1 if hard register REGNO can hold a value of machine-mode MODE .


<s> static bool epiphany_rtx_costs ( rtx x , machine_mode mode , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { int code = GET_CODE ( x ) ; switch ( code ) { case CONST_INT : if ( ( outer_code == PLUS || outer_code == MINUS ) && SIMM11 ( INTVAL ( x ) ) ) { * total = 0 ; return true ; } if ( IMM16 ( INTVAL ( x ) ) ) { * total = outer_code == SET ? 0 : COSTS_N_INSNS ( 1 ) ; return true ; } case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( ( epiphany_small16 ( x ) ? 0 : 1 ) + ( outer_code == SET ? 0 : 1 ) ) ; return true ; case CONST_DOUBLE : { rtx high , low ; split_double ( x , & high , & low ) ; * total = COSTS_N_INSNS ( ! IMM16 ( INTVAL ( high ) ) + ! IMM16 ( INTVAL ( low ) ) ) ; return true ; } case ASHIFT : case ASHIFTRT : case LSHIFTRT : * total = COSTS_N_INSNS ( 1 ) ; return true ; case COMPARE : switch ( mode ) { case CC_N_NEmode : case CC_C_LTUmode : case CC_C_GTUmode : return true ; default : return false ; } case SET : { rtx src = SET_SRC ( x ) ; if ( BINARY_P ( src ) ) * total = 0 ; return false ; } default : return false ; } } </s>


<s> static int epiphany_address_cost ( rtx addr , machine_mode mode , addr_space_t as ATTRIBUTE_UNUSED , bool speed ) { rtx reg ; rtx off = const0_rtx ; int i ; if ( speed ) return 0 ; switch ( GET_CODE ( addr ) ) { case PLUS : reg = XEXP ( addr , 0 ) ; off = XEXP ( addr , 1 ) ; break ; case POST_MODIFY : reg = XEXP ( addr , 0 ) ; off = XEXP ( addr , 1 ) ; gcc_assert ( GET_CODE ( off ) == PLUS && rtx_equal_p ( reg , XEXP ( off , 0 ) ) ) ; off = XEXP ( off , 1 ) ; if ( satisfies_constraint_Rgs ( reg ) && satisfies_constraint_Rgs ( off ) ) return 0 ; return 1 ; case REG : default : reg = addr ; break ; } if ( ! satisfies_constraint_Rgs ( reg ) ) return 1 ; if ( ! satisfies_constraint_L ( off ) ) return 1 ; i = INTVAL ( off ) ; switch ( GET_MODE_SIZE ( mode ) ) { default : case 4 : if ( i & 1 ) return 1 ; i >>= 1 ; case 2 : if ( i & 1 ) return 1 ; i >>= 1 ; case 1 : return i < - 7 || i > 7 ; } } </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 epiphany_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep_insn , int cost , unsigned int ) { if ( dep_type == 0 ) { rtx dep_set ; if ( recog_memoized ( insn ) < 0 || recog_memoized ( dep_insn ) < 0 ) return cost ; dep_set = single_set ( dep_insn ) ; if ( dep_set && MEM_P ( SET_SRC ( dep_set ) ) && cost > 1 ) { rtx set = single_set ( insn ) ; if ( set && ! reg_overlap_mentioned_p ( SET_DEST ( dep_set ) , SET_SRC ( set ) ) && ( ! MEM_P ( SET_DEST ( set ) ) || ! reg_overlap_mentioned_p ( SET_DEST ( dep_set ) , XEXP ( SET_DEST ( set ) , 0 ) ) ) ) cost = 1 ; } } return cost ; } </s>


<s> unsigned epiphany_adjust_field_align ( tree type , unsigned computed ) { if ( computed == 32 && TREE_CODE ( type ) == ARRAY_TYPE ) { tree elmsz = TYPE_SIZE ( TREE_TYPE ( type ) ) ; if ( ! tree_fits_uhwi_p ( elmsz ) || tree_to_uhwi ( elmsz ) >= 32 ) return 64 ; } return computed ; } </s>


<s> static enum epiphany_function_type epiphany_compute_function_type ( tree decl ) { tree a ; static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN ; static tree last_fn = NULL_TREE ; if ( decl == NULL_TREE ) { fn_type = EPIPHANY_FUNCTION_UNKNOWN ; last_fn = NULL_TREE ; return fn_type ; } if ( decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN ) return fn_type ; fn_type = EPIPHANY_FUNCTION_NORMAL ; for ( a = DECL_ATTRIBUTES ( decl ) ; a ; a = TREE_CHAIN ( a ) ) { tree name = TREE_PURPOSE ( a ) ; if ( name == get_identifier ( "interrupt" ) ) fn_type = EPIPHANY_FUNCTION_INTERRUPT ; } 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> static HOST_WIDE_INT epiphany_constant_alignment ( const_tree exp , HOST_WIDE_INT align ) { if ( TREE_CODE ( exp ) == STRING_CST ) return MAX ( align , FASTEST_ALIGNMENT ) ; return align ; } </s>


<s> static rtx epiphany_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS cum = * get_cumulative_args ( cum_v ) ; if ( PASS_IN_REG_P ( cum , arg . mode , arg . type ) ) return gen_rtx_REG ( arg . mode , ROUND_ADVANCE_CUM ( cum , arg . mode , arg . type ) ) ; return 0 ; } </s>


<s> static void epiphany_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; * cum = ( ROUND_ADVANCE_CUM ( * cum , arg . mode , arg . type ) + ROUND_ADVANCE_ARG ( arg . mode , arg . type ) ) ; } </s>


<s> static bool epiphany_function_ok_for_sibcall ( tree decl , tree exp ) { bool cfun_interrupt_p , call_interrupt_p ; cfun_interrupt_p = EPIPHANY_INTERRUPT_P ( epiphany_compute_function_type ( current_function_decl ) ) ; if ( decl ) call_interrupt_p = EPIPHANY_INTERRUPT_P ( epiphany_compute_function_type ( decl ) ) ; else { tree fn_type = TREE_TYPE ( CALL_EXPR_FN ( exp ) ) ; gcc_assert ( POINTER_TYPE_P ( fn_type ) ) ; fn_type = TREE_TYPE ( fn_type ) ; gcc_assert ( TREE_CODE ( fn_type ) == FUNCTION_TYPE || TREE_CODE ( fn_type ) == METHOD_TYPE ) ; call_interrupt_p = lookup_attribute ( "interrupt" , TYPE_ATTRIBUTES ( fn_type ) ) != NULL ; } if ( cfun_interrupt_p || call_interrupt_p ) return false ; return true ; } </s>

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


"%qE attribute only applies to functions"

"interrupt handlers cannot have arguments"

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

"argument of %qE attribute is not %qs, %qs %qs, %qs, %qs, "

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


<s> static bool epiphany_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return ( regno & 1 ) == 0 && GPR_P ( regno ) ; else return true ; } </s>


<s> static void epiphany_init ( void ) { pass_mode_switch_use = make_pass_mode_switch_use ( g ) ; struct register_pass_info insert_use_info = { pass_mode_switch_use , "mode_sw" , 1 , PASS_POS_INSERT_AFTER } ; opt_pass * mode_sw2 = g -> get_passes ( ) -> get_pass_mode_switching ( ) -> clone ( ) ; struct register_pass_info mode_sw2_info = { mode_sw2 , "mode_sw" , 1 , PASS_POS_INSERT_AFTER } ; opt_pass * mode_sw3 = make_pass_resolve_sw_modes ( g ) ; struct register_pass_info mode_sw3_info = { mode_sw3 , "mode_sw" , 1 , PASS_POS_INSERT_AFTER } ; opt_pass * mode_sw4 = g -> get_passes ( ) -> get_pass_split_all_insns ( ) -> clone ( ) ; struct register_pass_info mode_sw4_info = { mode_sw4 , "mode_sw" , 1 , PASS_POS_INSERT_AFTER } ; static const int num_modes [ ] = NUM_MODES_FOR_MODE_SWITCHING ; epiphany_init_reg_tables ( ) ; memset ( epiphany_punct_chars , 0 , sizeof ( epiphany_punct_chars ) ) ; epiphany_punct_chars [ '-' ] = 1 ; epiphany_normal_fp_rounding = ( epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST ) ; register_pass ( & mode_sw4_info ) ; register_pass ( & mode_sw2_info ) ; register_pass ( & mode_sw3_info ) ; register_pass ( & insert_use_info ) ; register_pass ( & mode_sw2_info ) ; gcc_assert ( N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM ) ; { opt_pass * extra_peephole2 = g -> get_passes ( ) -> get_pass_peephole2 ( ) -> clone ( ) ; struct register_pass_info peep2_2_info = { extra_peephole2 , "peephole2" , 1 , PASS_POS_INSERT_AFTER } ; register_pass ( & peep2_2_info ) ; } } </s>

Called from epiphany_override_options . We use this to initialize various things .


<s> void epiphany_init_expanders ( void ) { init_machine_status = epiphany_init_machine_status ; } </s>

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


<s> static struct machine_function * epiphany_init_machine_status ( void ) { struct machine_function * machine ; current_frame_info = zero_frame_info ; machine = ggc_cleared_alloc < machine_function_t > ( ) ; return machine ; } </s>

The usual ; we set up our machine_function data .


<s> static int epiphany_memory_move_cost ( machine_mode mode , reg_class_t rclass ATTRIBUTE_UNUSED , bool in ATTRIBUTE_UNUSED ) { return GET_MODE_CLASS ( mode ) == MODE_INT ? 3 : 4 ; } </s>

Compute the cost of moving data between registers and memory . For integer , load latency is twice as long as register-register moves , but issue pich is the same . For floating point , load latency is three times as much as a reg-reg move .


<s>
static
void
epiphany_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
fnname
=
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
thunk
)
)
;
int
this_regno
=
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
1
:
0
;
const
char
*
this_name
=
reg_names
[
this_regno
]
;
const
char
*
fname
;
assemble_start_function
(
thunk
,
fnname
)
;
gcc_assert
(
call_used_or_fixed_reg_p
(
GPR_IP
)
)
;
gcc_assert
(
call_used_or_fixed_reg_p
(
GPR_16
)
)
;
if
(
delta
==
0
)
;
else
if
(
SIMM11
(
delta
)
)
asm_fprintf
(
file
,
"\tadd\t%s,%s,%d\n"
,
this_name
,
this_name
,
(
int
)
delta
)
;
else
if
(
delta
<
0
&&
delta
>=
0xffff
)
{
asm_fprintf
(
file
,
"\tmov\tip,%d\n"
,
(
int
)
delta
)
;
asm_fprintf
(
file
,
"\tsub\t%s,%s,ip\n"
,
this_name
,
this_name
)
;
}
else
{
asm_fprintf
(
file
,
"\tmov\tip,%%low(%ld)\n"
,
(
long
)
delta
)
;
if
(
delta
&
~
0xffff
)
asm_fprintf
(
file
,
"\tmovt\tip,%%high(%ld)\n"
,
(
long
)
delta
)
;
asm_fprintf
(
file
,
"\tadd\t%s,%s,ip\n"
,
this_name
,
this_name
)
;
}
if
(
vcall_offset
!=
0
)
{
asm_fprintf
(
file
,
"\tldr\tip, [%s]\n"
,
this_name
)
;
if
(
vcall_offset
<
0x7ff
*
4
||
vcall_offset
>
0x7ff
*
4
||
(
vcall_offset
&
3
)
!=
0
)
{
asm_fprintf
(
file
,
"\tmov\tr16, %%low(%ld)\n"
,
(
long
)
vcall_offset
)
;
asm_fprintf
(
file
,
"\tmovt\tr16, %%high(%ld)\n"
,
(
long
)
vcall_offset
)
;
asm_fprintf
(
file
,
"\tldr\tip, [ip,r16]\n"
)
;
}
else
asm_fprintf
(
file
,
"\tldr\tip, [ip,%d]\n"
,
(
int
)
vcall_offset
/
4
)
;
asm_fprintf
(
file
,
"\tadd\t%s, %s, ip\n"
,
this_name
,
this_name
)
;
}
fname
=
XSTR
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
0
)
;
if
(
epiphany_is_long_call_p
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
)
)
{
fputs
(
"\tmov\tip,%low("
,
file
)
;
assemble_name
(
file
,
fname
)
;
fputs
(
")\n\tmovt\tip,%high("
,
file
)
;
assemble_name
(
file
,
fname
)
;
fputs
(
")\n\tjr ip\n"
,
file
)
;
}
else
{
fputs
(
"\tb\t"
,
file
)
;
assemble_name
(
file
,
fname
)
;
fputc
(
'\n'
,
file
)
;
}
assemble_end_function
(
thunk
,
fnname
)
;
}
</s>


"%<stack_offset%> must be a multiple of 4"


<s> static bool epiphany_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { if ( tree type = arg . type ) { if ( AGGREGATE_TYPE_P ( type ) && ( arg . mode == BLKmode || TYPE_NEEDS_CONSTRUCTING ( type ) ) ) return true ; } return false ; } </s>


<s> static void epiphany_print_operand_address ( FILE * file , machine_mode , rtx addr ) { 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 ) ) { output_addr_const ( file , addr ) ; } 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 ) { fprintf ( file , ",%s%d" , IMMEDIATE_PREFIX , offset / current_frame_info . stld_sz ) ; } 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 : case POST_INC : case POST_DEC : case POST_MODIFY : gcc_unreachable ( ) ; break ; default : output_addr_const ( file , addr ) ; break ; } } </s>


<s> static bool epiphany_return_in_memory ( const_tree type , const_tree fntype ATTRIBUTE_UNUSED ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( AGGREGATE_TYPE_P ( type ) && ( TYPE_MODE ( type ) == BLKmode || TYPE_NEEDS_CONSTRUCTING ( type ) ) ) return true ; return ( size == - 1 || size > 8 ) ; } </s>

Worker function for TARGET_RETURN_IN_MEMORY .


<s> static bool epiphany_rtx_costs ( rtx x , machine_mode mode , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { int code = GET_CODE ( x ) ; switch ( code ) { case CONST_INT : if ( ( outer_code == PLUS || outer_code == MINUS ) && SIMM11 ( INTVAL ( x ) ) ) { * total = 0 ; return true ; } if ( IMM16 ( INTVAL ( x ) ) ) { * total = outer_code == SET ? 0 : COSTS_N_INSNS ( 1 ) ; return true ; } case CONST : case LABEL_REF : case SYMBOL_REF : * total = COSTS_N_INSNS ( ( epiphany_small16 ( x ) ? 0 : 1 ) + ( outer_code == SET ? 0 : 1 ) ) ; return true ; case CONST_DOUBLE : { rtx high , low ; split_double ( x , & high , & low ) ; * total = COSTS_N_INSNS ( ! IMM16 ( INTVAL ( high ) ) + ! IMM16 ( INTVAL ( low ) ) ) ; return true ; } case ASHIFT : case ASHIFTRT : case LSHIFTRT : * total = COSTS_N_INSNS ( 1 ) ; return true ; case COMPARE : switch ( mode ) { case E_CC_N_NEmode : case E_CC_C_LTUmode : case E_CC_C_GTUmode : return true ; default : return false ; } case SET : { rtx src = SET_SRC ( x ) ; if ( BINARY_P ( src ) ) * total = 0 ; return false ; } default : return false ; } } </s>


<s> machine_mode epiphany_select_cc_mode ( enum rtx_code op , rtx x ATTRIBUTE_UNUSED , rtx y ATTRIBUTE_UNUSED ) { if ( GET_MODE_CLASS ( GET_MODE ( x ) ) == MODE_FLOAT ) { if ( TARGET_SOFT_CMPSF || op == ORDERED || op == UNORDERED ) { if ( op == EQ || op == NE ) return CC_FP_EQmode ; if ( op == ORDERED || op == UNORDERED ) return CC_FP_ORDmode ; if ( op == UNEQ || op == LTGT ) return CC_FP_UNEQmode ; return CC_FP_GTEmode ; } return CC_FPmode ; } else if ( ( op == EQ || op == NE ) && GET_CODE ( x ) == ZERO_EXTRACT && XEXP ( x , 1 ) == const1_rtx && CONST_INT_P ( XEXP ( x , 2 ) ) ) return CC_N_NEmode ; else if ( ( op == GEU || op == LTU ) && GET_CODE ( x ) == PLUS ) return CC_C_LTUmode ; else if ( ( op == LEU || op == GTU ) && GET_CODE ( x ) == MINUS ) return CC_C_GTUmode ; else 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 epiphany_setup_incoming_varargs ( cumulative_args_t cum , const function_arg_info & arg , int * pretend_size , int no_rtl ) { int first_anon_arg ; CUMULATIVE_ARGS next_cum ; machine_function_t * mf = MACHINE_FUNCTION ( cfun ) ; gcc_assert ( arg . mode != BLKmode ) ; next_cum = * get_cumulative_args ( cum ) ; next_cum = ( ROUND_ADVANCE_CUM ( next_cum , arg . mode , arg . type ) + ROUND_ADVANCE_ARG ( arg . mode , arg . type ) ) ; first_anon_arg = next_cum ; if ( first_anon_arg < MAX_EPIPHANY_PARM_REGS && ! no_rtl ) { int first_reg_offset = first_anon_arg ; * pretend_size = ( ( MAX_EPIPHANY_PARM_REGS - first_reg_offset ) * UNITS_PER_WORD ) ; } mf -> args_parsed = 1 ; mf -> pretend_args_odd = ( ( * pretend_size & UNITS_PER_WORD ) ? 1 : 0 ) ; } </s>

Do any needed setup for a variadic function . For the EPIPHANY , we actually emit the code in epiphany_expand_prologue . CUM has not been updated for the last named argument which has type TYPE and mode MODE , and we rely on this fact .


<s> unsigned epiphany_special_round_type_align ( tree type , unsigned computed , unsigned specified ) { unsigned align = MAX ( computed , specified ) ; tree field ; HOST_WIDE_INT total , max ; unsigned try_align = FASTEST_ALIGNMENT ; if ( maximum_field_alignment && try_align > maximum_field_alignment ) try_align = maximum_field_alignment ; if ( align >= try_align ) return align ; for ( max = 0 , field = TYPE_FIELDS ( type ) ; field ; field = DECL_CHAIN ( field ) ) { tree offset , size ; if ( TREE_CODE ( field ) != FIELD_DECL || TREE_TYPE ( field ) == error_mark_node ) continue ; offset = bit_position ( field ) ; size = DECL_SIZE ( field ) ; if ( ! tree_fits_uhwi_p ( offset ) || ! tree_fits_uhwi_p ( size ) || tree_to_uhwi ( offset ) >= try_align || tree_to_uhwi ( size ) >= try_align ) return try_align ; total = tree_to_uhwi ( offset ) + tree_to_uhwi ( size ) ; if ( total > max ) max = total ; } if ( max >= ( HOST_WIDE_INT ) try_align ) align = try_align ; else if ( try_align > 32 && max >= 32 ) align = max > 32 ? 64 : 32 ; return align ; } </s>

STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small structs . Make structs double-word-aligned it they are a double word or ( potentially ) larger ; failing that , do the same for a size of 32 bits .


<s> static HOST_WIDE_INT epiphany_starting_frame_offset ( void ) { return epiphany_stack_offset ; } </s>


<s> static void epiphany_trampoline_init ( rtx tramp_mem , tree fndecl , rtx cxt ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx tramp = force_reg ( Pmode , XEXP ( tramp_mem , 0 ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( Pmode , tramp , 0 ) ) , gen_rtx_IOR ( SImode , GEN_INT ( 0x4002000b ) , EPIPHANY_LOW_RTX ( fnaddr ) ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( Pmode , tramp , 4 ) ) , gen_rtx_IOR ( SImode , GEN_INT ( 0x5002000b ) , EPIPHANY_HIGH_RTX ( fnaddr ) ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( Pmode , tramp , 8 ) ) , gen_rtx_IOR ( SImode , GEN_INT ( 0x2002800b ) , EPIPHANY_LOW_RTX ( cxt ) ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( Pmode , tramp , 12 ) ) , gen_rtx_IOR ( SImode , GEN_INT ( 0x3002800b ) , EPIPHANY_HIGH_RTX ( cxt ) ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( Pmode , tramp , 16 ) ) , GEN_INT ( 0x0802014f ) ) ; } </s>

Emit RTL insns to initialize the variable parts of a trampoline . FNADDR is an RTX for the address of the function 's pure code . CXT is an RTX for the static chain value for the function .


<s> bool epiphany_uninterruptible_p ( tree t ) { tree attrs ; if ( t ) { attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( t ) ) ; if ( lookup_attribute ( "disinterrupt" , attrs ) ) return true ; } return false ; } </s>

T is a function declaration or the MEM_EXPR of a MEM passed to a call expander . Return true iff the type of T has the uninterruptible attribute . If T is NULL , return false .


<s> static rtx_insn * frame_insn ( rtx x ) { int i ; rtx note = NULL_RTX ; rtx_insn * insn ; if ( GET_CODE ( x ) == PARALLEL ) { rtx part = XVECEXP ( x , 0 , 0 ) ; if ( GET_MODE ( SET_DEST ( part ) ) == DImode ) { note = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( XVECLEN ( x , 0 ) + 1 ) ) ; XVECEXP ( note , 0 , 0 ) = frame_subreg_note ( part , 0 ) ; XVECEXP ( note , 0 , 1 ) = frame_subreg_note ( part , UNITS_PER_WORD ) ; for ( i = XVECLEN ( x , 0 ) - 1 ; i >= 1 ; i -- ) { part = copy_rtx ( XVECEXP ( x , 0 , i ) ) ; if ( GET_CODE ( part ) == SET ) RTX_FRAME_RELATED_P ( part ) = 1 ; XVECEXP ( note , 0 , i + 1 ) = part ; } } else { for ( i = XVECLEN ( x , 0 ) - 1 ; i >= 0 ; i -- ) { part = XVECEXP ( x , 0 , i ) ; if ( GET_CODE ( part ) == SET ) RTX_FRAME_RELATED_P ( part ) = 1 ; } } } else if ( GET_CODE ( x ) == SET && GET_MODE ( SET_DEST ( x ) ) == DImode ) note = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , frame_subreg_note ( x , 0 ) , frame_subreg_note ( x , UNITS_PER_WORD ) ) ) ; insn = emit_insn ( x ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( note ) add_reg_note ( insn , REG_FRAME_RELATED_EXPR , note ) ; return insn ; } </s>

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


<s> static rtx frame_subreg_note ( rtx set , int offset ) { rtx src = simplify_gen_subreg ( SImode , SET_SRC ( set ) , DImode , offset ) ; rtx dst = simplify_gen_subreg ( SImode , SET_DEST ( set ) , DImode , offset ) ; set = gen_rtx_SET ( dst , src ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; return set ; } </s>

For a DImode load / store SET , make a SImode set for a REG_FRAME_RELATED_EXPR note , using OFFSET to create a high or lowpart subreg .


<s> static rtx gen_varargs_mem ( machine_mode mode , rtx addr ) { rtx mem = gen_rtx_MEM ( mode , addr ) ; MEM_NOTRAP_P ( mem ) = 1 ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; return mem ; } </s>

Generate a MEM referring to a varargs argument slot .


<s> static int get_epiphany_condition_code ( rtx comparison ) { switch ( GET_MODE ( XEXP ( comparison , 0 ) ) ) { case E_CCmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; case LTU : return 2 ; case GEU : return 3 ; case GT : return 4 ; case LE : return 5 ; case GE : return 6 ; case LT : return 7 ; case GTU : return 8 ; case LEU : return 9 ; default : gcc_unreachable ( ) ; } case E_CC_N_NEmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 6 ; case NE : return 7 ; default : gcc_unreachable ( ) ; } case E_CC_C_LTUmode : switch ( GET_CODE ( comparison ) ) { case GEU : return 2 ; case LTU : return 3 ; default : gcc_unreachable ( ) ; } case E_CC_C_GTUmode : switch ( GET_CODE ( comparison ) ) { case LEU : return 3 ; case GTU : return 2 ; default : gcc_unreachable ( ) ; } case E_CC_FPmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 10 ; case NE : return 11 ; case LT : return 12 ; case LE : return 13 ; default : gcc_unreachable ( ) ; } case E_CC_FP_EQmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; default : gcc_unreachable ( ) ; } case E_CC_FP_GTEmode : switch ( GET_CODE ( comparison ) ) { case EQ : return 0 ; case NE : return 1 ; case GT : return 4 ; case GE : return 6 ; case UNLE : return 5 ; case UNLT : return 7 ; default : gcc_unreachable ( ) ; } case E_CC_FP_ORDmode : switch ( GET_CODE ( comparison ) ) { case ORDERED : return 9 ; case UNORDERED : return 8 ; default : gcc_unreachable ( ) ; } case E_CC_FP_UNEQmode : switch ( GET_CODE ( comparison ) ) { case UNEQ : return 9 ; case LTGT : return 8 ; default : gcc_unreachable ( ) ; } default : gcc_unreachable ( ) ; } return ( 42 ) ; } </s>

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


<s> rtx sfunc_symbol ( const char * name ) { rtx sym = gen_rtx_SYMBOL_REF ( Pmode , name ) ; SYMBOL_REF_FLAGS ( sym ) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL ; if ( TARGET_SHORT_CALLS ) ; else if ( can_create_pseudo_p ( ) ) sym = copy_to_mode_reg ( Pmode , sym ) ; else gcc_assert ( ! reload_in_progress || reload_completed ) ; return sym ; } </s>

Generate a SYMBOL_REF for the special function NAME . When the address ca n't be placed directly into a call instruction , and if possible , copy it to a register so that cse / code hoisting is possible .


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