<s> static rtx_insn * mn10300_md_asm_adjust ( vec < rtx > & , vec < rtx > & , vec < machine_mode > & , vec < const char * > & , vec < rtx > & clobbers , HARD_REG_SET & clobbered_regs ) { clobbers . safe_push ( gen_rtx_REG ( CCmode , CC_REG ) ) ; SET_HARD_REG_BIT ( clobbered_regs , CC_REG ) ; return NULL ; } </s>

Worker function for TARGET_MD_ASM_ADJUST . We do this in the mn10300 backend to maintain source compatibility with the old cc0-based compiler .


<s> void expand_epilogue ( ) { HOST_WIDE_INT size ; size = get_frame_size ( ) + current_function_outgoing_args_size ; size += ( current_function_outgoing_args_size ? 4 : 0 ) ; if ( frame_pointer_needed ) { emit_move_insn ( stack_pointer_rtx , frame_pointer_rtx ) ; size = 0 ; } else if ( size + REG_SAVE_BYTES > 255 ) { emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( size ) ) ) ; size = 0 ; } if ( size || regs_ever_live [ 2 ] || regs_ever_live [ 3 ] || regs_ever_live [ 6 ] || regs_ever_live [ 7 ] || regs_ever_live [ 14 ] || regs_ever_live [ 15 ] || regs_ever_live [ 16 ] || regs_ever_live [ 17 ] || frame_pointer_needed ) emit_jump_insn ( gen_return_internal_regs ( GEN_INT ( size + REG_SAVE_BYTES ) ) ) ; else emit_jump_insn ( gen_return_internal ( ) ) ; } </s>


<s> void expand_prologue ( ) { HOST_WIDE_INT size ; size = get_frame_size ( ) + current_function_outgoing_args_size ; size += ( current_function_outgoing_args_size ? 4 : 0 ) ; if ( current_function_varargs ) { emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( stack_pointer_rtx , 4 ) ) , gen_rtx_REG ( SImode , 0 ) ) ; emit_move_insn ( gen_rtx_MEM ( SImode , plus_constant ( stack_pointer_rtx , 8 ) ) , gen_rtx_REG ( SImode , 1 ) ) ; } mn10300_gen_multiple_store ( mn10300_get_live_callee_saved_regs ( ) ) ; if ( frame_pointer_needed ) emit_move_insn ( frame_pointer_rtx , stack_pointer_rtx ) ; if ( size ) emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , GEN_INT ( - size ) ) ) ; } </s>


<s> rtx mn10300_builtin_saveregs ( ) { rtx offset , mem ; tree fntype = TREE_TYPE ( current_function_decl ) ; int argadj = ( ( ! ( TYPE_ARG_TYPES ( fntype ) != 0 && ( TREE_VALUE ( tree_last ( TYPE_ARG_TYPES ( fntype ) ) ) != void_type_node ) ) ) ? UNITS_PER_WORD : 0 ) ; int set = get_varargs_alias_set ( ) ; if ( argadj ) offset = plus_constant ( current_function_arg_offset_rtx , argadj ) ; else offset = current_function_arg_offset_rtx ; mem = gen_rtx_MEM ( SImode , current_function_internal_arg_pointer ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 0 ) ) ; mem = gen_rtx_MEM ( SImode , plus_constant ( current_function_internal_arg_pointer , 4 ) ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 1 ) ) ; return copy_to_reg ( expand_binop ( Pmode , add_optab , current_function_internal_arg_pointer , offset , 0 , 0 , OPTAB_LIB_WIDEN ) ) ; } </s>

Flush the argument registers to the stack for a stdarg function ; return the new argument pointer .


<s> int mn10300_get_live_callee_saved_regs ( ) { int mask ; int i ; mask = 0 ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( regs_ever_live [ i ] && ! call_used_regs [ i ] ) mask |= ( 1 << i ) ; if ( ( mask & 0x3c000 ) != 0 ) mask |= 0x3c000 ; return mask ; } </s>

Returns the set of live , callee-saved registers as a bitmask . The callee-saved extended registers can not be stored individually , so all of them will be included in the mask if any one of them is used .


<s> static int fp_regs_to_save ( void ) { int i , n = 0 ; if ( ! TARGET_AM33_2 ) return 0 ; for ( i = FIRST_FP_REGNUM ; i <= LAST_FP_REGNUM ; ++ i ) if ( regs_ever_live [ i ] && ! call_used_regs [ i ] ) ++ n ; return n ; } </s>

Count the number of FP registers that have to be saved .


<s> rtx function_arg ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int named ATTRIBUTE_UNUSED ) { rtx result = 0 ; int size , align ; int nregs = 2 ; if ( mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; align = size ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return 0 ; if ( type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return 0 ; switch ( cum -> nbytes / UNITS_PER_WORD ) { case 0 : result = gen_rtx_REG ( mode , 0 ) ; break ; case 1 : result = gen_rtx_REG ( mode , 1 ) ; break ; default : result = 0 ; } return result ; } </s>

Return an RTL expression containing the register for the given mode , or 0 if the argument is to be passed on the stack . INCOMING_P is nonzero if this is an incoming argument to the current function .


<s> int initial_offset ( int from , int to ) { if ( from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM ) { if ( regs_ever_live [ 2 ] || regs_ever_live [ 3 ] || regs_ever_live [ 6 ] || regs_ever_live [ 7 ] || regs_ever_live [ 14 ] || regs_ever_live [ 15 ] || regs_ever_live [ 16 ] || regs_ever_live [ 17 ] || fp_regs_to_save ( ) || frame_pointer_needed ) return REG_SAVE_BYTES + 4 * fp_regs_to_save ( ) ; else return 0 ; } if ( from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) { if ( regs_ever_live [ 2 ] || regs_ever_live [ 3 ] || regs_ever_live [ 6 ] || regs_ever_live [ 7 ] || regs_ever_live [ 14 ] || regs_ever_live [ 15 ] || regs_ever_live [ 16 ] || regs_ever_live [ 17 ] || fp_regs_to_save ( ) || frame_pointer_needed ) return ( get_frame_size ( ) + REG_SAVE_BYTES + 4 * fp_regs_to_save ( ) + ( current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0 ) ) ; else return ( get_frame_size ( ) + ( current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0 ) ) ; } if ( from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) return ( get_frame_size ( ) + ( current_function_outgoing_args_size ? current_function_outgoing_args_size + 4 : 0 ) ) ; gcc_unreachable ( ) ; } </s>

Function for INITIAL_ELIMINATION_OFFSET ( FROM , TO , OFFSET ) . Define the offset between two registers , one to be eliminated , and the other its replacement , at the start of a routine .


<s> bool legitimate_address_p ( enum machine_mode mode , rtx x , int strict ) { if ( CONSTANT_ADDRESS_P ( x ) && ( ! flag_pic || legitimate_pic_operand_p ( x ) ) ) return TRUE ; if ( RTX_OK_FOR_BASE_P ( x , strict ) ) return TRUE ; if ( TARGET_AM33 && GET_CODE ( x ) == POST_INC && RTX_OK_FOR_BASE_P ( XEXP ( x , 0 ) , strict ) && ( mode == SImode || mode == SFmode || mode == HImode ) ) return TRUE ; if ( GET_CODE ( x ) == PLUS ) { rtx base = 0 , index = 0 ; if ( REG_P ( XEXP ( x , 0 ) ) && REGNO_STRICT_OK_FOR_BASE_P ( REGNO ( XEXP ( x , 0 ) ) , strict ) ) { base = XEXP ( x , 0 ) ; index = XEXP ( x , 1 ) ; } if ( REG_P ( XEXP ( x , 1 ) ) && REGNO_STRICT_OK_FOR_BASE_P ( REGNO ( XEXP ( x , 1 ) ) , strict ) ) { base = XEXP ( x , 1 ) ; index = XEXP ( x , 0 ) ; } if ( base != 0 && index != 0 ) { if ( GET_CODE ( index ) == CONST_INT ) return TRUE ; if ( GET_CODE ( index ) == CONST && GET_CODE ( XEXP ( index , 0 ) ) != PLUS && ( ! flag_pic || legitimate_pic_operand_p ( index ) ) ) return TRUE ; } } return FALSE ; } </s>

legitimate_address_p returns 1 if it recognizes an RTL expression `` x '' that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address .


<s> int legitimate_pic_operand_p ( rtx x ) { register const char * fmt ; register int i ; if ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) return 0 ; if ( GET_CODE ( x ) == UNSPEC && ( XINT ( x , 1 ) == UNSPEC_PIC || XINT ( x , 1 ) == UNSPEC_GOT || XINT ( x , 1 ) == UNSPEC_GOTOFF || XINT ( x , 1 ) == UNSPEC_PLT ) ) return 1 ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { register int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( ! legitimate_pic_operand_p ( XVECEXP ( x , i , j ) ) ) return 0 ; } else if ( fmt [ i ] == 'e' && ! legitimate_pic_operand_p ( XEXP ( x , i ) ) ) return 0 ; } return 1 ; } </s>

Return true if OP is a legitimate general operand when generating PIC code . It is given that flag_pic is on and that OP satisfies CONSTANT_P or is a CONST_DOUBLE .


<s> rtx legitimize_address ( rtx x , rtx oldx ATTRIBUTE_UNUSED , enum machine_mode mode ATTRIBUTE_UNUSED ) { if ( flag_pic && ! legitimate_pic_operand_p ( x ) ) x = legitimize_pic_address ( oldx , NULL_RTX ) ; if ( GET_CODE ( x ) == PLUS && symbolic_operand ( XEXP ( x , 1 ) , VOIDmode ) ) { rtx regx1 , regy1 , regy2 , y ; y = XEXP ( x , 1 ) ; if ( GET_CODE ( y ) == CONST ) y = XEXP ( y , 0 ) ; if ( GET_CODE ( y ) == PLUS || GET_CODE ( y ) == MINUS ) { regx1 = force_reg ( Pmode , force_operand ( XEXP ( x , 0 ) , 0 ) ) ; regy1 = force_reg ( Pmode , force_operand ( XEXP ( y , 0 ) , 0 ) ) ; regy2 = force_reg ( Pmode , force_operand ( XEXP ( y , 1 ) , 0 ) ) ; regx1 = force_reg ( Pmode , gen_rtx_fmt_ee ( GET_CODE ( y ) , Pmode , regx1 , regy2 ) ) ; return force_reg ( Pmode , gen_rtx_PLUS ( Pmode , regx1 , regy1 ) ) ; } } return x ; } </s>

Try machine-dependent ways of modifying an illegitimate address X to be legitimate . If we find one , return the new , valid address . OLDX is the address as it was before break_out_memory_refs was called . In some cases it is useful to look at this to decide what needs to be done . MODE is the mode of the operand pointed to by X .


<s> rtx legitimize_pic_address ( rtx orig , rtx reg ) { if ( GET_CODE ( orig ) == LABEL_REF || ( GET_CODE ( orig ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( orig ) || ! MN10300_GLOBAL_P ( orig ) ) ) ) { if ( reg == 0 ) reg = gen_reg_rtx ( Pmode ) ; emit_insn ( gen_symGOTOFF2reg ( reg , orig ) ) ; return reg ; } else if ( GET_CODE ( orig ) == SYMBOL_REF ) { if ( reg == 0 ) reg = gen_reg_rtx ( Pmode ) ; emit_insn ( gen_symGOT2reg ( reg , orig ) ) ; return reg ; } return orig ; } </s>

Legitimize PIC addresses . If the address is already position-independent , we return ORIG . Newly generated position-independent addresses go into a reg . This is REG if nonzero , otherwise we allocate register ( s ) as necessary .


<s> int mask_ok_for_mem_btst ( int len , int bit ) { unsigned int mask = 0 ; while ( len > 0 ) { mask |= ( 1 << bit ) ; bit ++ ; len -- ; } return ( ( ( mask & 0xff ) == mask ) || ( ( mask & 0xff00 ) == mask ) || ( ( mask & 0xff0000 ) == mask ) || ( ( mask & 0xff000000 ) == mask ) ) ; } </s>

Similarly , but when using a zero_extract pattern for a btst where the source operand might end up in memory .


<s> static int mn10300_address_cost ( rtx x ) { int s = 0 ; return mn10300_address_cost_1 ( x , & s ) ; } </s>

For addresses , costs are relative to `` MOV ( Rm ) , Rn '' . For AM33 this is the 3-byte fully general instruction ; for MN103 this is the 2-byte form with an address register .


<s> static int mn10300_arg_partial_bytes ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , bool named ATTRIBUTE_UNUSED ) { int size , align ; int nregs = 2 ; if ( mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; align = size ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return 0 ; if ( cum -> nbytes + size <= nregs * UNITS_PER_WORD ) return 0 ; if ( type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return 0 ; return nregs * UNITS_PER_WORD - cum -> nbytes ; } </s>

Return the number of bytes of registers to use for an argument passed partially in registers and partially in memory .


<s> static rtx mn10300_builtin_saveregs ( void ) { rtx offset , mem ; tree fntype = TREE_TYPE ( current_function_decl ) ; int argadj = ( ( ! ( TYPE_ARG_TYPES ( fntype ) != 0 && ( TREE_VALUE ( tree_last ( TYPE_ARG_TYPES ( fntype ) ) ) != void_type_node ) ) ) ? UNITS_PER_WORD : 0 ) ; int set = get_varargs_alias_set ( ) ; if ( argadj ) offset = plus_constant ( current_function_arg_offset_rtx , argadj ) ; else offset = current_function_arg_offset_rtx ; mem = gen_rtx_MEM ( SImode , current_function_internal_arg_pointer ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 0 ) ) ; mem = gen_rtx_MEM ( SImode , plus_constant ( current_function_internal_arg_pointer , 4 ) ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 1 ) ) ; return copy_to_reg ( expand_binop ( Pmode , add_optab , current_function_internal_arg_pointer , offset , 0 , 0 , OPTAB_LIB_WIDEN ) ) ; } </s>


<s> static void mn10300_encode_section_info ( tree decl , rtx rtl , int first ATTRIBUTE_UNUSED ) { rtx symbol ; if ( GET_CODE ( rtl ) != MEM ) return ; symbol = XEXP ( rtl , 0 ) ; if ( GET_CODE ( symbol ) != SYMBOL_REF ) return ; if ( flag_pic ) SYMBOL_REF_FLAG ( symbol ) = ( * targetm . binds_local_p ) ( decl ) ; } </s>

If using PIC , mark a SYMBOL_REF for a non-global symbol so that we may access it using GOTOFF instead of GOT .


<s> rtx mn10300_function_value ( tree valtype , tree func , int outgoing ) { rtx rv ; enum machine_mode mode = TYPE_MODE ( valtype ) ; if ( ! POINTER_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , FIRST_DATA_REGNUM ) ; else if ( ! TARGET_PTR_A0D0 || ! outgoing || current_function_returns_struct ) return gen_rtx_REG ( mode , FIRST_ADDRESS_REGNUM ) ; rv = gen_rtx_PARALLEL ( mode , rtvec_alloc ( 2 ) ) ; XVECEXP ( rv , 0 , 0 ) = gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , FIRST_ADDRESS_REGNUM ) , GEN_INT ( 0 ) ) ; XVECEXP ( rv , 0 , 1 ) = gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , FIRST_DATA_REGNUM ) , GEN_INT ( 0 ) ) ; return rv ; } </s>

Return the location of the function 's value . This will be either $ d0 for integer functions , $ a0 for pointers , or a PARALLEL of both $ d0 and $ a0 if the -mreturn-pointer-on-do flag is set . Note that we only return the PARALLEL for outgoing values ; we do not want callers relying on this extra copy .


<s> void mn10300_gen_multiple_store ( int mask ) { if ( mask != 0 ) { int i ; int count ; rtx par ; int pari ; count = 0 ; for ( i = 0 ; i <= LAST_EXTENDED_REGNUM ; i ++ ) if ( ( mask & ( 1 << i ) ) != 0 ) count += 1 ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count + 1 ) ) ; XVECEXP ( par , 0 , 0 ) = gen_rtx_SET ( SImode , stack_pointer_rtx , gen_rtx_PLUS ( SImode , stack_pointer_rtx , GEN_INT ( - count * 4 ) ) ) ; pari = 1 ; for ( i = LAST_EXTENDED_REGNUM ; i >= 0 ; i -- ) if ( ( mask & ( 1 << i ) ) != 0 ) { rtx address = gen_rtx_PLUS ( SImode , stack_pointer_rtx , GEN_INT ( - pari * 4 ) ) ; XVECEXP ( par , 0 , pari ) = gen_rtx_SET ( VOIDmode , gen_rtx_MEM ( SImode , address ) , gen_rtx_REG ( SImode , i ) ) ; pari += 1 ; } par = emit_insn ( par ) ; RTX_FRAME_RELATED_P ( par ) = 1 ; } } </s>

Generate an instruction that pushes several registers onto the stack . Register K will be saved if bit K in MASK is set . The function does nothing if MASK is zero . To be compatible with the `` movm '' instruction , the lowest-numbered register must be stored in the lowest slot . If MASK is the set { R1 , ... , RN } , where R1 ... RN are ordered least first , the generated instruction will have the form : ( parallel ( set ( reg : SI 9 ) ( plus : SI ( reg : SI 9 ) ( const_int -N * 4 ) ) ) ( set ( mem : SI ( plus : SI ( reg : SI 9 ) ( const_int -1 * 4 ) ) ) ( reg : SI RN ) ) ... ( set ( mem : SI ( plus : SI ( reg : SI 9 ) ( const_int -N * 4 ) ) ) ( reg : SI R1 ) ) )


<s> int mn10300_get_live_callee_saved_regs ( void ) { int mask ; int i ; mask = 0 ; for ( i = 0 ; i <= LAST_EXTENDED_REGNUM ; i ++ ) if ( regs_ever_live [ i ] && ! call_used_regs [ i ] ) mask |= ( 1 << i ) ; if ( ( mask & 0x3c000 ) != 0 ) mask |= 0x3c000 ; return mask ; } </s>


<s> static bool mn10300_handle_option ( size_t code , const char * arg ATTRIBUTE_UNUSED , int value ) { switch ( code ) { case OPT_mam33 : mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300 ; return true ; case OPT_mam33_2 : mn10300_processor = ( value ? PROCESSOR_AM33_2 : MIN ( PROCESSOR_AM33 , PROCESSOR_DEFAULT ) ) ; return true ; default : return true ; } } </s>


<s> void mn10300_override_options ( void ) { if ( TARGET_AM33 ) target_flags &= ~ MASK_MULT_BUG ; } </s>


<s> static bool mn10300_return_in_memory ( tree type , tree fntype ATTRIBUTE_UNUSED ) { return ( int_size_in_bytes ( type ) > 8 || int_size_in_bytes ( type ) == 0 || TYPE_MODE ( type ) == BLKmode ) ; } </s>

Worker function for TARGET_RETURN_IN_MEMORY .


<s> static bool mn10300_rtx_costs ( rtx x , int code , int outer_code , int * total ) { switch ( code ) { case CONST_INT : if ( INTVAL ( x ) == 0 && outer_code == SET ) * total = 0 ; else if ( INT_8_BITS ( INTVAL ( x ) ) ) * total = 1 ; else if ( INT_16_BITS ( INTVAL ( x ) ) || ( INTVAL ( x ) & 0xffff ) == 0 || ( INTVAL ( x ) & 0xffff0000 ) == 0 ) * total = 2 ; else * total = 4 ; return true ; case CONST : case LABEL_REF : case SYMBOL_REF : * total = 6 ; return true ; case CONST_DOUBLE : * total = 8 ; return true ; case MOD : case DIV : case MULT : * total = 8 ; return true ; default : return false ; } } </s>

Implement the TARGET_RTX_COSTS hook . Speed-relative costs are relative to COSTS_N_INSNS , which is intended to represent cycles . Size-relative costs are in bytes .


<s> bool mn10300_wide_const_load_uses_clr ( rtx operands [ 2 ] ) { long val [ 2 ] ; if ( GET_CODE ( operands [ 0 ] ) != REG || REGNO_REG_CLASS ( REGNO ( operands [ 0 ] ) ) != DATA_REGS ) return false ; switch ( GET_CODE ( operands [ 1 ] ) ) { case CONST_INT : { rtx low , high ; split_double ( operands [ 1 ] , & low , & high ) ; val [ 0 ] = INTVAL ( low ) ; val [ 1 ] = INTVAL ( high ) ; } break ; case CONST_DOUBLE : if ( GET_MODE ( operands [ 1 ] ) == DFmode ) { REAL_VALUE_TYPE rv ; REAL_VALUE_FROM_CONST_DOUBLE ( rv , operands [ 1 ] ) ; REAL_VALUE_TO_TARGET_DOUBLE ( rv , val ) ; } else if ( GET_MODE ( operands [ 1 ] ) == VOIDmode || GET_MODE ( operands [ 1 ] ) == DImode ) { val [ 0 ] = CONST_DOUBLE_LOW ( operands [ 1 ] ) ; val [ 1 ] = CONST_DOUBLE_HIGH ( operands [ 1 ] ) ; } break ; default : return false ; } return val [ 0 ] == 0 || val [ 1 ] == 0 ; } </s>

Check whether a constant used to initialize a DImode or DFmode can use a clr instruction . The code here must be kept in sync with movdf and movdi .


<s> void notice_update_cc ( rtx body , rtx insn ) { switch ( get_attr_cc ( insn ) ) { case CC_NONE : break ; case CC_NONE_0HIT : if ( cc_status . value1 != 0 && reg_overlap_mentioned_p ( recog_data . operand [ 0 ] , cc_status . value1 ) ) cc_status . value1 = 0 ; break ; case CC_SET_ZN : CC_STATUS_INIT ; cc_status . flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE ; cc_status . value1 = recog_data . operand [ 0 ] ; break ; case CC_SET_ZNV : CC_STATUS_INIT ; cc_status . flags |= CC_NO_CARRY ; cc_status . value1 = recog_data . operand [ 0 ] ; break ; case CC_COMPARE : CC_STATUS_INIT ; cc_status . value1 = SET_SRC ( body ) ; if ( GET_CODE ( cc_status . value1 ) == COMPARE && GET_MODE ( XEXP ( cc_status . value1 , 0 ) ) == SFmode ) cc_status . mdep . fpCC = 1 ; break ; case CC_CLOBBER : CC_STATUS_INIT ; break ; default : gcc_unreachable ( ) ; } } </s>

On the 68000 , all the insns to store in an address register fail to set the cc 's . However , in some cases these instructions can make it possibly invalid to use the saved cc 's . In those cases we clear out some or all of the saved cc 's so they wo n't be used .


<s>
const
char
*
output_tst
(
rtx
operand
,
rtx
insn
)
{
rtx
temp
;
int
past_call
=
0
;
temp
=
PREV_INSN
(
insn
)
;
while
(
optimize
&&
temp
)
{
rtx
set
;
if
(
GET_CODE
(
temp
)
==
CODE_LABEL
||
GET_CODE
(
temp
)
==
JUMP_INSN
||
GET_CODE
(
temp
)
==
BARRIER
)
break
;
if
(
GET_CODE
(
temp
)
==
CALL_INSN
)
past_call
=
1
;
if
(
GET_CODE
(
temp
)
==
NOTE
)
{
temp
=
PREV_INSN
(
temp
)
;
continue
;
}
set
=
single_set
(
temp
)
;
if
(
!
set
)
{
temp
=
PREV_INSN
(
temp
)
;
continue
;
}
if
(
REG_P
(
SET_DEST
(
set
)
)
&&
SET_SRC
(
set
)
==
CONST0_RTX
(
GET_MODE
(
SET_DEST
(
set
)
)
)
&&
!
reg_set_between_p
(
SET_DEST
(
set
)
,
temp
,
insn
)
&&
(
REGNO_REG_CLASS
(
REGNO
(
SET_DEST
(
set
)
)
)
==
REGNO_REG_CLASS
(
REGNO
(
operand
)
)
)
&&
REGNO_REG_CLASS
(
REGNO
(
SET_DEST
(
set
)
)
)
!=
EXTENDED_REGS
&&
REGNO
(
SET_DEST
(
set
)
)
!=
REGNO
(
operand
)
&&
(
!
past_call
||
!
call_used_regs
[
REGNO
(
SET_DEST
(
set
)
)
]
)
)
{
rtx
xoperands
[
2
]
;
xoperands
[
0
]
=
operand
;
xoperands
[
1
]
=
SET_DEST
(
set
)
;
output_asm_insn
(
"cmp %1,%0"
,
xoperands
)
;
return
""
;
}
if
(
REGNO_REG_CLASS
(
REGNO
(
operand
)
)
==
EXTENDED_REGS
&&
REG_P
(
SET_DEST
(
set
)
)
&&
SET_SRC
(
set
)
==
CONST0_RTX
(
GET_MODE
(
SET_DEST
(
set
)
)
)
&&
!
reg_set_between_p
(
SET_DEST
(
set
)
,
temp
,
insn
)
&&
(
REGNO_REG_CLASS
(
REGNO
(
SET_DEST
(
set
)
)
)
!=
REGNO_REG_CLASS
(
REGNO
(
operand
)
)
)
&&
REGNO_REG_CLASS
(
REGNO
(
SET_DEST
(
set
)
)
)
==
EXTENDED_REGS
&&
REGNO
(
SET_DEST
(
set
)
)
!=
REGNO
(
operand
)
&&
(
!
past_call
||
!
call_used_regs
[
REGNO
(
SET_DEST
(
set
)
)
]
)
)
{
rtx
xoperands
[
2
]
;
xoperands
[
0
]
=
operand
;
xoperands
[
1
]
=
SET_DEST
(
set
)
;
output_asm_insn
(
"cmp %1,%0"
,
xoperands
)
;
return
""
;
}
temp
=
PREV_INSN
(
temp
)
;
}
return
"cmp 0,%0"
;
}
</s>


<s> void print_operand_address ( FILE * file , rtx addr ) { switch ( GET_CODE ( addr ) ) { case POST_INC : print_operand_address ( file , XEXP ( addr , 0 ) ) ; fputc ( '+' , file ) ; break ; case REG : print_operand ( file , addr , 0 ) ; break ; case PLUS : { rtx base , index ; if ( REG_P ( XEXP ( addr , 0 ) ) && REG_OK_FOR_BASE_P ( XEXP ( addr , 0 ) ) ) base = XEXP ( addr , 0 ) , index = XEXP ( addr , 1 ) ; else if ( REG_P ( XEXP ( addr , 1 ) ) && REG_OK_FOR_BASE_P ( XEXP ( addr , 1 ) ) ) base = XEXP ( addr , 1 ) , index = XEXP ( addr , 0 ) ; else gcc_unreachable ( ) ; print_operand ( file , index , 0 ) ; fputc ( ',' , file ) ; print_operand ( file , base , 0 ) ; ; break ; } case SYMBOL_REF : output_addr_const ( file , addr ) ; break ; default : output_addr_const ( file , addr ) ; break ; } } </s>

Print the operand address represented by the rtx addr


<s> enum reg_class secondary_reload_class ( enum reg_class class , enum machine_mode mode , rtx in ) { if ( ( GET_CODE ( in ) == MEM || ( GET_CODE ( in ) == REG && REGNO ( in ) >= FIRST_PSEUDO_REGISTER ) || ( GET_CODE ( in ) == SUBREG && GET_CODE ( SUBREG_REG ( in ) ) == REG && REGNO ( SUBREG_REG ( in ) ) >= FIRST_PSEUDO_REGISTER ) ) && ( mode == QImode || mode == HImode ) && ( class == ADDRESS_REGS || class == SP_REGS || class == SP_OR_ADDRESS_REGS ) ) { if ( TARGET_AM33 ) return DATA_OR_EXTENDED_REGS ; return DATA_REGS ; } if ( class != SP_REGS && class != ADDRESS_REGS && class != SP_OR_ADDRESS_REGS && class != SP_OR_EXTENDED_REGS && class != ADDRESS_OR_EXTENDED_REGS && class != SP_OR_ADDRESS_OR_EXTENDED_REGS && ( in == stack_pointer_rtx || ( GET_CODE ( in ) == PLUS && ( XEXP ( in , 0 ) == stack_pointer_rtx || XEXP ( in , 1 ) == stack_pointer_rtx ) ) ) ) return ADDRESS_REGS ; if ( GET_CODE ( in ) == PLUS && ( XEXP ( in , 0 ) == stack_pointer_rtx || XEXP ( in , 1 ) == stack_pointer_rtx ) ) { if ( TARGET_AM33 ) return DATA_OR_EXTENDED_REGS ; return DATA_REGS ; } if ( TARGET_AM33_2 && class == FP_REGS && GET_CODE ( in ) == MEM && ! OK_FOR_Q ( in ) ) { if ( TARGET_AM33 ) return DATA_OR_EXTENDED_REGS ; return DATA_REGS ; } return NO_REGS ; } </s>

Return the class of any secondary reload register that is needed to move IN into a register in class CLASS using mode MODE . Profiling has showed this routine and its descendants account for a significant amount of compile time ( ~7 % ) . So it has been optimized to reduce redundant computations and eliminate useless function calls . It might be worthwhile to try and make this a leaf function too .


<s> int store_multiple_operation ( rtx op , enum machine_mode mode ATTRIBUTE_UNUSED ) { int count ; int mask ; int i ; unsigned int last ; rtx elt ; count = XVECLEN ( op , 0 ) ; if ( count < 2 ) return 0 ; elt = XVECEXP ( op , 0 , 0 ) ; if ( GET_CODE ( elt ) != SET || GET_CODE ( SET_DEST ( elt ) ) != REG || REGNO ( SET_DEST ( elt ) ) != STACK_POINTER_REGNUM || GET_CODE ( SET_SRC ( elt ) ) != PLUS ) return 0 ; elt = SET_SRC ( elt ) ; if ( GET_CODE ( XEXP ( elt , 0 ) ) != REG || REGNO ( XEXP ( elt , 0 ) ) != STACK_POINTER_REGNUM || GET_CODE ( XEXP ( elt , 1 ) ) != CONST_INT || INTVAL ( XEXP ( elt , 1 ) ) != - ( count - 1 ) * 4 ) return 0 ; last = LAST_EXTENDED_REGNUM + 1 ; mask = 0 ; for ( i = 1 ; i < count ; i ++ ) { elt = XVECEXP ( op , 0 , i ) ; if ( GET_CODE ( elt ) != SET || GET_CODE ( SET_DEST ( elt ) ) != MEM || GET_CODE ( SET_SRC ( elt ) ) != REG || REGNO ( SET_SRC ( elt ) ) >= last ) return 0 ; last = REGNO ( SET_SRC ( elt ) ) ; mask |= ( 1 << last ) ; elt = XEXP ( SET_DEST ( elt ) , 0 ) ; if ( GET_CODE ( elt ) != PLUS || GET_CODE ( XEXP ( elt , 0 ) ) != REG || REGNO ( XEXP ( elt , 0 ) ) != STACK_POINTER_REGNUM || GET_CODE ( XEXP ( elt , 1 ) ) != CONST_INT || INTVAL ( XEXP ( elt , 1 ) ) != - i * 4 ) return 0 ; } if ( ( mask & 0x3c000 ) != 0 && ( mask & 0x3c000 ) != 0x3c000 ) return 0 ; return mask ; } </s>

Return true if OP is a store multiple operation . It is known to be a PARALLEL and the first section will be tested . OP is the current operation . MODE is the current operation mode .


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

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


<s> static int fp_regs_to_save ( void ) { int i , n = 0 ; if ( ! TARGET_AM33_2 ) return 0 ; for ( i = FIRST_FP_REGNUM ; i <= LAST_FP_REGNUM ; ++ i ) if ( df_regs_ever_live_p ( i ) && ! call_really_used_regs [ i ] ) ++ n ; return n ; } </s>

Count the number of FP registers that have to be saved .


<s> static int mn10300_address_cost ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , addr_space_t as ATTRIBUTE_UNUSED , bool speed ) { HOST_WIDE_INT i ; rtx base , index ; switch ( GET_CODE ( x ) ) { case CONST : case SYMBOL_REF : case LABEL_REF : return speed ? 1 : 4 ; case REG : case SUBREG : case POST_INC : return 0 ; case POST_MODIFY : i = ( CONST_INT_P ( XEXP ( x , 1 ) ) ? INTVAL ( XEXP ( x , 1 ) ) : 0x12345678 ) ; if ( IN_RANGE ( i , - 128 , 127 ) ) return speed ? 0 : 1 ; if ( speed ) return 1 ; if ( IN_RANGE ( i , - 0x800000 , 0x7fffff ) ) return 3 ; return 4 ; case PLUS : base = XEXP ( x , 0 ) ; index = XEXP ( x , 1 ) ; if ( register_operand ( index , SImode ) ) { if ( register_operand ( base , SImode ) ) return 1 ; base = XEXP ( x , 1 ) ; index = XEXP ( x , 0 ) ; } i = ( CONST_INT_P ( XEXP ( x , 1 ) ) ? INTVAL ( XEXP ( x , 1 ) ) : 0x12345678 ) ; if ( IN_RANGE ( i , - 128 , 127 ) ) return speed ? 0 : 1 ; if ( IN_RANGE ( i , - 32768 , 32767 ) ) return speed ? 0 : 2 ; return speed ? 2 : 6 ; default : return rtx_cost ( x , MEM , 0 , speed ) ; } } </s>


<s> static int mn10300_adjust_sched_cost ( rtx_insn * insn , rtx link , rtx_insn * dep , int cost ) { rtx insn_set ; rtx dep_set ; int timings ; if ( ! TARGET_AM33 ) return 1 ; insn_set = single_set ( insn ) ; if ( ! insn_set ) return cost ; dep_set = single_set ( dep ) ; if ( ! dep_set ) return cost ; if ( mn10300_tune_cpu == PROCESSOR_AM34 && set_is_load_p ( dep_set ) && set_is_store_p ( insn_set ) ) cost += 1 ; else if ( mn10300_tune_cpu == PROCESSOR_AM34 && ! set_is_store_p ( insn_set ) && ! JUMP_P ( insn ) && GET_MODE_CLASS ( GET_MODE ( SET_SRC ( dep_set ) ) ) == MODE_FLOAT && GET_MODE_CLASS ( GET_MODE ( SET_SRC ( insn_set ) ) ) == MODE_FLOAT ) cost += 1 ; if ( ! TARGET_AM33_2 ) return cost ; if ( REG_NOTE_KIND ( link ) == 0 ) return cost ; if ( GET_MODE_CLASS ( GET_MODE ( SET_SRC ( dep_set ) ) ) != MODE_FLOAT ) return cost ; if ( ! set_is_load_p ( insn_set ) && ! set_is_store_p ( insn_set ) ) return cost ; if ( GET_MODE_CLASS ( GET_MODE ( SET_SRC ( insn_set ) ) ) != MODE_INT ) return cost ; timings = get_attr_timings ( insn ) ; return timings < 100 ? ( timings % 10 ) : ( timings % 100 ) ; } </s>

Update scheduling costs for situations that can not be described using the attributes and DFA machinery . DEP is the insn being scheduled . INSN is the previous insn . COST is the current cycle cost for DEP .


<s> static int mn10300_arg_partial_bytes ( cumulative_args_t cum_v , machine_mode mode , tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int size ; int nregs = 2 ; if ( mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return 0 ; if ( cum -> nbytes + size <= nregs * UNITS_PER_WORD ) return 0 ; if ( type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return 0 ; return nregs * UNITS_PER_WORD - cum -> nbytes ; } </s>


<s>
static
void
mn10300_asm_output_mi_thunk
(
FILE
*
file
,
tree
thunk_fndecl
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
_this
;
if
(
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
)
_this
=
reg_names
[
FIRST_ARGUMENT_REGNUM
+
1
]
;
else
_this
=
reg_names
[
FIRST_ARGUMENT_REGNUM
]
;
fprintf
(
file
,
"\t%s Thunk Entry Point:\n"
,
ASM_COMMENT_START
)
;
if
(
delta
)
fprintf
(
file
,
"\tadd %d, %s\n"
,
(
int
)
delta
,
_this
)
;
if
(
vcall_offset
)
{
const
char
*
scratch
=
reg_names
[
FIRST_ADDRESS_REGNUM
+
1
]
;
fprintf
(
file
,
"\tmov %s, %s\n"
,
_this
,
scratch
)
;
fprintf
(
file
,
"\tmov (%s), %s\n"
,
scratch
,
scratch
)
;
fprintf
(
file
,
"\tadd %d, %s\n"
,
(
int
)
vcall_offset
,
scratch
)
;
fprintf
(
file
,
"\tmov (%s), %s\n"
,
scratch
,
scratch
)
;
fprintf
(
file
,
"\tadd %s, %s\n"
,
scratch
,
_this
)
;
}
fputs
(
"\tjmp "
,
file
)
;
assemble_name
(
file
,
XSTR
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
0
)
)
;
putc
(
'\n'
,
file
)
;
}
</s>

Output the assembler code for a C++ thunk function . THUNK_DECL is the declaration for the thunk function itself , FUNCTION is the decl for the target function . DELTA is an immediate constant offset to be added to the THIS parameter . If VCALL_OFFSET is nonzero the word at the adjusted address * ( * THIS ' + VCALL_OFFSET ) should be additionally added to THIS . Finally jump to the entry point of FUNCTION .


<s> static rtx mn10300_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 ) ; rtx result = NULL_RTX ; int size ; int nregs = 2 ; if ( mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return result ; if ( type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return result ; switch ( cum -> nbytes / UNITS_PER_WORD ) { case 0 : result = gen_rtx_REG ( mode , FIRST_ARGUMENT_REGNUM ) ; break ; case 1 : result = gen_rtx_REG ( mode , FIRST_ARGUMENT_REGNUM + 1 ) ; break ; default : break ; } return result ; } </s>

Return an RTX to represent where a value with mode MODE will be returned from a function . If the result is NULL_RTX , the argument is pushed .


<s> static void mn10300_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 -> nbytes += ( mode != BLKmode ? ( GET_MODE_SIZE ( mode ) + 3 ) & ~ 3 : ( int_size_in_bytes ( type ) + 3 ) & ~ 3 ) ; } </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 mn10300_gen_multiple_store ( unsigned int mask ) { static const unsigned int store_order [ 8 ] = { FIRST_EXTENDED_REGNUM + 4 , FIRST_EXTENDED_REGNUM + 5 , FIRST_EXTENDED_REGNUM + 6 , FIRST_EXTENDED_REGNUM + 7 , FIRST_DATA_REGNUM + 2 , FIRST_DATA_REGNUM + 3 , FIRST_ADDRESS_REGNUM + 2 , FIRST_ADDRESS_REGNUM + 3 , } ; rtx x , elts [ 9 ] ; unsigned int i ; int count ; if ( mask == 0 ) return ; for ( i = count = 0 ; i < ARRAY_SIZE ( store_order ) ; ++ i ) { unsigned regno = store_order [ i ] ; if ( ( ( mask >> regno ) & 1 ) == 0 ) continue ; ++ count ; x = plus_constant ( Pmode , stack_pointer_rtx , count * - 4 ) ; x = gen_frame_mem ( SImode , x ) ; x = gen_rtx_SET ( VOIDmode , x , gen_rtx_REG ( SImode , regno ) ) ; elts [ count ] = F ( x ) ; mask &= ~ ( 1u << regno ) ; } gcc_assert ( mask == 0 ) ; x = plus_constant ( Pmode , stack_pointer_rtx , count * - 4 ) ; x = gen_rtx_SET ( VOIDmode , stack_pointer_rtx , x ) ; elts [ 0 ] = F ( x ) ; x = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( count + 1 , elts ) ) ; F ( emit_insn ( x ) ) ; } </s>


<s> unsigned int mn10300_get_live_callee_saved_regs ( unsigned int * bytes_saved ) { int mask ; int i ; unsigned int count ; count = mask = 0 ; for ( i = 0 ; i <= LAST_EXTENDED_REGNUM ; i ++ ) if ( df_regs_ever_live_p ( i ) && ! call_really_used_regs [ i ] ) { mask |= ( 1 << i ) ; ++ count ; } if ( ( mask & 0x3c000 ) != 0 ) { for ( i = 0x04000 ; i < 0x40000 ; i <<= 1 ) if ( ( mask & i ) == 0 ) ++ count ; mask |= 0x3c000 ; } if ( bytes_saved ) * bytes_saved = count * UNITS_PER_WORD ; return mask ; } </s>

Returns the set of live , callee-saved registers as a bitmask . The callee-saved extended registers can not be stored individually , so all of them will be included in the mask if any one of them is used .


<s> bool mn10300_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( REGNO_REG_CLASS ( regno ) == FP_REGS || REGNO_REG_CLASS ( regno ) == FP_ACC_REGS ) return GET_MODE_CLASS ( mode ) == MODE_FLOAT && ( ( regno & 1 ) == 0 ) ; if ( ! TARGET_AM33 && REGNO_REG_CLASS ( regno ) == EXTENDED_REGS ) return false ; if ( ( ( regno ) & 1 ) == 0 || GET_MODE_SIZE ( mode ) == 4 ) return true ; if ( REGNO_REG_CLASS ( regno ) == DATA_REGS || ( TARGET_AM33 && REGNO_REG_CLASS ( regno ) == ADDRESS_REGS ) || REGNO_REG_CLASS ( regno ) == EXTENDED_REGS ) return GET_MODE_SIZE ( mode ) <= 4 ; return false ; } </s>


<s>
static
void
mn10300_insert_setlb_lcc
(
rtx
label
,
rtx
branch
)
{
rtx
lcc
,
comparison
,
cmp_reg
;
if
(
LABEL_NUSES
(
label
)
>
1
)
{
rtx_insn
*
insn
;
DUMP
(
"Inserting SETLB insn after:"
,
label
)
;
insn
=
emit_insn_after
(
gen_setlb
(
)
,
label
)
;
label
=
gen_label_rtx
(
)
;
emit_label_after
(
label
,
insn
)
;
DUMP
(
"Created new loop-back label:"
,
label
)
;
}
else
{
DUMP
(
"Inserting SETLB insn before:"
,
label
)
;
emit_insn_before
(
gen_setlb
(
)
,
label
)
;
}
comparison
=
XEXP
(
SET_SRC
(
PATTERN
(
branch
)
)
,
0
)
;
cmp_reg
=
XEXP
(
comparison
,
0
)
;
gcc_assert
(
REG_P
(
cmp_reg
)
)
;
gcc_assert
(
REGNO
(
cmp_reg
)
==
CC_REG
)
;
if
(
GET_MODE
(
cmp_reg
)
==
CC_FLOATmode
)
lcc
=
gen_FLcc
(
comparison
,
label
)
;
else
lcc
=
gen_Lcc
(
comparison
,
label
)
;
rtx_insn
*
jump
=
emit_jump_insn_before
(
lcc
,
branch
)
;
mark_jump_label
(
XVECEXP
(
lcc
,
0
,
0
)
,
jump
,
0
)
;
JUMP_LABEL
(
jump
)
=
label
;
DUMP
(
"Replacing branch insn..."
,
branch
)
;
DUMP
(
"... with Lcc insn:"
,
jump
)
;
delete_insn
(
branch
)
;
}
</s>

Replace the BRANCH insn with a Lcc insn that goes to LABEL . Insert a SETLB insn just before LABEL .


<s> rtx mn10300_legitimize_pic_address ( rtx orig , rtx reg ) { rtx x ; if ( GET_CODE ( orig ) == LABEL_REF || ( GET_CODE ( orig ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( orig ) || ! MN10300_GLOBAL_P ( orig ) ) ) ) { if ( reg == NULL ) reg = gen_reg_rtx ( Pmode ) ; x = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , orig ) , UNSPEC_GOTOFF ) ; x = gen_rtx_CONST ( SImode , x ) ; emit_move_insn ( reg , x ) ; x = emit_insn ( gen_addsi3 ( reg , reg , pic_offset_table_rtx ) ) ; } else if ( GET_CODE ( orig ) == SYMBOL_REF ) { if ( reg == NULL ) reg = gen_reg_rtx ( Pmode ) ; x = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , orig ) , UNSPEC_GOT ) ; x = gen_rtx_CONST ( SImode , x ) ; x = gen_rtx_PLUS ( SImode , pic_offset_table_rtx , x ) ; x = gen_const_mem ( SImode , x ) ; x = emit_move_insn ( reg , x ) ; } else return orig ; set_unique_reg_note ( x , REG_EQUAL , orig ) ; return reg ; } </s>

Convert a non-PIC address in ` orig ' to a PIC address using @ GOT or @ GOTOFF in ` reg ' .


<s> bool mn10300_match_ccmode ( rtx insn , machine_mode cc_mode ) { rtx op1 , flags ; machine_mode flags_mode ; gcc_checking_assert ( XVECLEN ( PATTERN ( insn ) , 0 ) == 2 ) ; op1 = XVECEXP ( PATTERN ( insn ) , 0 , 1 ) ; gcc_checking_assert ( GET_CODE ( SET_SRC ( op1 ) ) == COMPARE ) ; flags = SET_DEST ( op1 ) ; flags_mode = GET_MODE ( flags ) ; if ( GET_MODE ( SET_SRC ( op1 ) ) != flags_mode ) return false ; if ( GET_MODE_CLASS ( flags_mode ) != MODE_CC ) return false ; if ( cc_flags_for_mode ( flags_mode ) & ~ cc_flags_for_mode ( cc_mode ) ) return false ; return true ; } </s>

A helper function for matching parallels that set the flags .


<s> static tree mn10300_md_asm_clobbers ( tree outputs ATTRIBUTE_UNUSED , tree inputs ATTRIBUTE_UNUSED , tree clobbers ) { clobbers = tree_cons ( NULL_TREE , build_string ( 5 , "EPSW" ) , clobbers ) ; return clobbers ; } </s>

Worker function for TARGET_MD_ASM_CLOBBERS . We do this in the mn10300 backend to maintain source compatibility with the old cc0-based compiler .


"-mtune= expects mn10300, am33, am33-2, or am34"


<s> static bool mn10300_pass_by_reference ( cumulative_args_t cum ATTRIBUTE_UNUSED , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { unsigned HOST_WIDE_INT size ; if ( type ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; return ( size > 8 || size == 0 ) ; } </s>

Return true when a parameter should be passed by reference .


<s> void mn10300_split_cbranch ( machine_mode cmp_mode , rtx cmp_op , rtx label_ref ) { rtx flags , x ; flags = gen_rtx_REG ( cmp_mode , CC_REG ) ; x = gen_rtx_COMPARE ( cmp_mode , XEXP ( cmp_op , 0 ) , XEXP ( cmp_op , 1 ) ) ; x = gen_rtx_SET ( VOIDmode , flags , x ) ; emit_insn ( x ) ; x = gen_rtx_fmt_ee ( GET_CODE ( cmp_op ) , VOIDmode , flags , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , label_ref , pc_rtx ) ; x = gen_rtx_SET ( VOIDmode , pc_rtx , x ) ; emit_jump_insn ( x ) ; } </s>

A helper function for splitting cbranch patterns after reload .


<s> static bool check_liw_constraints ( struct liw_data * pliw1 , struct liw_data * pliw2 ) { if ( pliw2 -> slot == pliw1 -> slot && pliw1 -> slot != LIW_EITHER ) return false ; if ( pliw1 -> op == LIW_OP_CMP ) { gcc_assert ( pliw1 -> op != pliw2 -> op ) ; return true ; } if ( pliw2 -> op == LIW_OP_CMP ) { if ( REGNO ( pliw2 -> dest ) == REGNO ( pliw1 -> dest ) ) return false ; if ( REG_P ( pliw2 -> src ) ) return REGNO ( pliw2 -> src ) != REGNO ( pliw1 -> dest ) ; return true ; } if ( REGNO ( pliw2 -> dest ) == REGNO ( pliw1 -> dest ) ) return false ; if ( REG_P ( pliw2 -> src ) && REGNO ( pliw2 -> src ) == REGNO ( pliw1 -> dest ) ) { if ( pliw1 -> op == LIW_OP_MOV && REG_P ( pliw1 -> src ) ) { if ( ! REG_P ( pliw1 -> src ) && ( pliw2 -> op == LIW_OP_AND || pliw2 -> op == LIW_OP_OR || pliw2 -> op == LIW_OP_XOR ) ) return false ; pliw2 -> src = pliw1 -> src ; return true ; } return false ; } return true ; } </s>

Make sure that it is OK to execute LIW1 and LIW2 in parallel . GCC generated the instructions with the assumption that LIW1 would be executed before LIW2 so we must check for overlaps between their sources and destinations .


<s> static bool extract_bundle ( rtx_insn * insn , struct liw_data * pdata ) { bool allow_consts = true ; rtx p ; gcc_assert ( pdata != NULL ) ; if ( insn == NULL ) return false ; p = single_set ( insn ) ; if ( p == NULL_RTX ) return false ; pdata -> slot = get_attr_liw ( insn ) ; if ( pdata -> slot == LIW_BOTH ) return false ; pdata -> op = get_attr_liw_op ( insn ) ; switch ( pdata -> op ) { case LIW_OP_MOV : pdata -> dest = SET_DEST ( p ) ; pdata -> src = SET_SRC ( p ) ; break ; case LIW_OP_CMP : pdata -> dest = XEXP ( SET_SRC ( p ) , 0 ) ; pdata -> src = XEXP ( SET_SRC ( p ) , 1 ) ; break ; case LIW_OP_NONE : return false ; case LIW_OP_AND : case LIW_OP_OR : case LIW_OP_XOR : allow_consts = false ; default : pdata -> dest = SET_DEST ( p ) ; pdata -> src = XEXP ( SET_SRC ( p ) , 1 ) ; break ; } if ( ! REG_P ( pdata -> dest ) ) return false ; if ( REG_P ( pdata -> src ) ) return true ; return allow_consts && satisfies_constraint_O ( pdata -> src ) ; } </s>

Decide if the given insn is a candidate for LIW bundling . If it is then extract the operands and LIW attributes from the insn and use them to fill in the liw_data structure . Return true upon success or false if the insn can not be bundled .


<s> static rtx F ( rtx r ) { RTX_FRAME_RELATED_P ( r ) = 1 ; return r ; } </s>

We use this to wrap all emitted insns in the prologue , so they get the `` frame-related '' ( /f ) flag set .


<s> static int fp_regs_to_save ( void ) { int i , n = 0 ; if ( ! TARGET_AM33_2 ) return 0 ; for ( i = FIRST_FP_REGNUM ; i <= LAST_FP_REGNUM ; ++ i ) if ( df_regs_ever_live_p ( i ) && ! call_used_regs [ i ] ) ++ n ; return n ; } </s>


<s> static int mn10300_address_cost ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , addr_space_t as ATTRIBUTE_UNUSED , bool speed ) { HOST_WIDE_INT i ; rtx base , index ; switch ( GET_CODE ( x ) ) { case CONST : case SYMBOL_REF : case LABEL_REF : return speed ? 1 : 4 ; case REG : case SUBREG : case POST_INC : return 0 ; case POST_MODIFY : i = ( CONST_INT_P ( XEXP ( x , 1 ) ) ? INTVAL ( XEXP ( x , 1 ) ) : 0x12345678 ) ; if ( IN_RANGE ( i , - 128 , 127 ) ) return speed ? 0 : 1 ; if ( speed ) return 1 ; if ( IN_RANGE ( i , - 0x800000 , 0x7fffff ) ) return 3 ; return 4 ; case PLUS : base = XEXP ( x , 0 ) ; index = XEXP ( x , 1 ) ; if ( register_operand ( index , SImode ) ) { if ( register_operand ( base , SImode ) ) return 1 ; base = XEXP ( x , 1 ) ; index = XEXP ( x , 0 ) ; } i = ( CONST_INT_P ( XEXP ( x , 1 ) ) ? INTVAL ( XEXP ( x , 1 ) ) : 0x12345678 ) ; if ( IN_RANGE ( i , - 128 , 127 ) ) return speed ? 0 : 1 ; if ( IN_RANGE ( i , - 32768 , 32767 ) ) return speed ? 0 : 2 ; return speed ? 2 : 6 ; default : return rtx_cost ( x , Pmode , MEM , 0 , speed ) ; } } </s>

For addresses , costs are relative to `` MOV ( Rm ) , Rn '' . For AM33 this is the 3-byte fully general instruction ; for MN103 this is the 2-byte form with an address register .


<s> static int mn10300_adjust_sched_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int cost , unsigned int ) { rtx insn_set ; rtx dep_set ; int timings ; if ( ! TARGET_AM33 ) return 1 ; insn_set = single_set ( insn ) ; if ( ! insn_set ) return cost ; dep_set = single_set ( dep ) ; if ( ! dep_set ) return cost ; if ( mn10300_tune_cpu == PROCESSOR_AM34 && set_is_load_p ( dep_set ) && set_is_store_p ( insn_set ) ) cost += 1 ; else if ( mn10300_tune_cpu == PROCESSOR_AM34 && ! set_is_store_p ( insn_set ) && ! JUMP_P ( insn ) && GET_MODE_CLASS ( GET_MODE ( SET_SRC ( dep_set ) ) ) == MODE_FLOAT && GET_MODE_CLASS ( GET_MODE ( SET_SRC ( insn_set ) ) ) == MODE_FLOAT ) cost += 1 ; if ( ! TARGET_AM33_2 ) return cost ; if ( dep_type == 0 ) return cost ; if ( GET_MODE_CLASS ( GET_MODE ( SET_SRC ( dep_set ) ) ) != MODE_FLOAT ) return cost ; if ( ! set_is_load_p ( insn_set ) && ! set_is_store_p ( insn_set ) ) return cost ; if ( GET_MODE_CLASS ( GET_MODE ( SET_SRC ( insn_set ) ) ) != MODE_INT ) return cost ; timings = get_attr_timings ( insn ) ; return timings < 100 ? ( timings % 10 ) : ( timings % 100 ) ; } </s>


<s> static int mn10300_arg_partial_bytes ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int size ; int nregs = 2 ; size = arg . promoted_size_in_bytes ( ) ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return 0 ; if ( cum -> nbytes + size <= nregs * UNITS_PER_WORD ) return 0 ; if ( arg . type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return 0 ; return nregs * UNITS_PER_WORD - cum -> nbytes ; } </s>

Return the number of bytes of registers to use for an argument passed partially in registers and partially in memory .


<s> static bool mn10300_asm_output_addr_const_extra ( FILE * file , rtx x ) { if ( GET_CODE ( x ) == UNSPEC ) { switch ( XINT ( x , 1 ) ) { case UNSPEC_PIC : output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; break ; case UNSPEC_GOT : output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; fputs ( "@GOT" , file ) ; break ; case UNSPEC_GOTOFF : output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; fputs ( "@GOTOFF" , file ) ; break ; case UNSPEC_PLT : output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; fputs ( "@PLT" , file ) ; break ; case UNSPEC_GOTSYM_OFF : assemble_name ( file , GOT_SYMBOL_NAME ) ; fputs ( "-(" , file ) ; output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; fputs ( "-.)" , file ) ; break ; default : return false ; } return true ; } else return false ; } </s>

Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA . Used for PIC-specific UNSPECs .


<s>
static
void
mn10300_asm_output_mi_thunk
(
FILE
*
file
,
tree
thunk_fndecl
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
,
tree
function
)
{
const
char
*
fnname
=
IDENTIFIER_POINTER
(
DECL_ASSEMBLER_NAME
(
thunk_fndecl
)
)
;
const
char
*
_this
;
assemble_start_function
(
thunk_fndecl
,
fnname
)
;
if
(
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
)
_this
=
reg_names
[
FIRST_ARGUMENT_REGNUM
+
1
]
;
else
_this
=
reg_names
[
FIRST_ARGUMENT_REGNUM
]
;
fprintf
(
file
,
"\t%s Thunk Entry Point:\n"
,
ASM_COMMENT_START
)
;
if
(
delta
)
fprintf
(
file
,
"\tadd %d, %s\n"
,
(
int
)
delta
,
_this
)
;
if
(
vcall_offset
)
{
const
char
*
scratch
=
reg_names
[
FIRST_ADDRESS_REGNUM
+
1
]
;
fprintf
(
file
,
"\tmov %s, %s\n"
,
_this
,
scratch
)
;
fprintf
(
file
,
"\tmov (%s), %s\n"
,
scratch
,
scratch
)
;
fprintf
(
file
,
"\tadd %d, %s\n"
,
(
int
)
vcall_offset
,
scratch
)
;
fprintf
(
file
,
"\tmov (%s), %s\n"
,
scratch
,
scratch
)
;
fprintf
(
file
,
"\tadd %s, %s\n"
,
scratch
,
_this
)
;
}
fputs
(
"\tjmp "
,
file
)
;
assemble_name
(
file
,
XSTR
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
0
)
)
;
putc
(
'\n'
,
file
)
;
assemble_end_function
(
thunk_fndecl
,
fnname
)
;
}
</s>


<s> static rtx mn10300_builtin_saveregs ( void ) { rtx offset , mem ; tree fntype = TREE_TYPE ( current_function_decl ) ; int argadj = ( ( ! stdarg_p ( fntype ) ) ? UNITS_PER_WORD : 0 ) ; alias_set_type set = get_varargs_alias_set ( ) ; if ( argadj ) offset = plus_constant ( Pmode , crtl -> args . arg_offset_rtx , argadj ) ; else offset = crtl -> args . arg_offset_rtx ; mem = gen_rtx_MEM ( SImode , crtl -> args . internal_arg_pointer ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 0 ) ) ; mem = gen_rtx_MEM ( SImode , plus_constant ( Pmode , crtl -> args . internal_arg_pointer , 4 ) ) ; set_mem_alias_set ( mem , set ) ; emit_move_insn ( mem , gen_rtx_REG ( SImode , 1 ) ) ; return copy_to_reg ( expand_binop ( Pmode , add_optab , crtl -> args . internal_arg_pointer , offset , 0 , 0 , OPTAB_LIB_WIDEN ) ) ; } </s>

Flush the argument registers to the stack for a stdarg function ; return the new argument pointer .


<s> static void mn10300_bundle_liw ( void ) { rtx_insn * r ; for ( r = get_insns ( ) ; r != NULL ; r = next_nonnote_nondebug_insn ( r ) ) { rtx_insn * insn1 , * insn2 ; struct liw_data liw1 , liw2 ; insn1 = r ; if ( ! extract_bundle ( insn1 , & liw1 ) ) continue ; insn2 = next_nonnote_nondebug_insn ( insn1 ) ; if ( ! extract_bundle ( insn2 , & liw2 ) ) continue ; if ( ! check_liw_constraints ( & liw1 , & liw2 ) ) continue ; if ( liw1 . slot == LIW_OP2 || liw2 . slot == LIW_OP1 ) { struct liw_data temp ; temp = liw1 ; liw1 = liw2 ; liw2 = temp ; } delete_insn ( insn2 ) ; rtx insn2_pat ; if ( liw1 . op == LIW_OP_CMP ) insn2_pat = gen_cmp_liw ( liw2 . dest , liw2 . src , liw1 . dest , liw1 . src , GEN_INT ( liw2 . op ) ) ; else if ( liw2 . op == LIW_OP_CMP ) insn2_pat = gen_liw_cmp ( liw1 . dest , liw1 . src , liw2 . dest , liw2 . src , GEN_INT ( liw1 . op ) ) ; else insn2_pat = gen_liw ( liw1 . dest , liw2 . dest , liw1 . src , liw2 . src , GEN_INT ( liw1 . op ) , GEN_INT ( liw2 . op ) ) ; insn2 = emit_insn_after ( insn2_pat , insn1 ) ; delete_insn ( insn1 ) ; r = insn2 ; } } </s>

Combine pairs of insns into LIW bundles .


Return true if mn10300_output_mi_thunk would be able to output the assembler code for the thunk function specified by the arguments it is passed , and false otherwise .


<s> bool mn10300_can_use_retf_insn ( void ) { if ( ! optimize ) return false ; if ( crtl -> calls_eh_return ) return false ; if ( df_regs_ever_live_p ( MDR_REG ) ) return false ; gcc_assert ( ! in_sequence_p ( ) ) ; return leaf_function_p ( ) ; } </s>

If the MDR register is never clobbered , we can use the RETF instruction which takes the address from the MDR register . This is 3 cycles faster than having to load the address from the stack .


<s> static unsigned int mn10300_case_values_threshold ( void ) { return 6 ; } </s>

Dispatch tables on the mn10300 are extremely expensive in terms of code and readonly data size . So we crank up the case threshold value to encourage a series of if/else comparisons to implement many small switch statements . In theory , this value could be increased much more if we were solely optimizing for space , but we keep it `` reasonable '' to avoid serious code efficiency lossage .


<s> static rtx mn10300_delegitimize_address ( rtx orig_x ) { rtx x = orig_x , ret , addend = NULL ; bool need_mem ; if ( MEM_P ( x ) ) x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) != PLUS || GET_MODE ( x ) != Pmode ) return orig_x ; if ( XEXP ( x , 0 ) == pic_offset_table_rtx ) ; else if ( GET_CODE ( XEXP ( x , 0 ) ) == PLUS ) { rtx x0 = XEXP ( x , 0 ) ; rtx x00 = XEXP ( x0 , 0 ) ; rtx x01 = XEXP ( x0 , 1 ) ; if ( x00 == pic_offset_table_rtx ) addend = x01 ; else if ( x01 == pic_offset_table_rtx ) addend = x00 ; else return orig_x ; } else return orig_x ; x = XEXP ( x , 1 ) ; if ( GET_CODE ( x ) != CONST ) return orig_x ; x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) != UNSPEC ) return orig_x ; ret = XVECEXP ( x , 0 , 0 ) ; if ( XINT ( x , 1 ) == UNSPEC_GOTOFF ) need_mem = false ; else if ( XINT ( x , 1 ) == UNSPEC_GOT ) need_mem = true ; else return orig_x ; gcc_assert ( GET_CODE ( ret ) == SYMBOL_REF ) ; if ( need_mem != MEM_P ( orig_x ) ) return orig_x ; if ( need_mem && addend ) return orig_x ; if ( addend ) ret = gen_rtx_PLUS ( Pmode , addend , ret ) ; return ret ; } </s>

Undo pic address legitimization for the benefit of debug info .


<s> static void mn10300_encode_section_info ( tree decl , rtx rtl , int first ) { rtx symbol ; default_encode_section_info ( decl , rtl , first ) ; if ( ! MEM_P ( rtl ) ) return ; symbol = XEXP ( rtl , 0 ) ; if ( GET_CODE ( symbol ) != SYMBOL_REF ) return ; if ( flag_pic ) SYMBOL_REF_FLAG ( symbol ) = ( * targetm . binds_local_p ) ( decl ) ; } </s>

If using PIC , mark a SYMBOL_REF for a non-global symbol so that we may access it using GOTOFF instead of GOT .


<s> static rtx mn10300_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; rtx result = NULL_RTX ; int size ; int nregs = 2 ; size = arg . promoted_size_in_bytes ( ) ; cum -> nbytes = ( cum -> nbytes + 3 ) & ~ 3 ; if ( cum -> nbytes > nregs * UNITS_PER_WORD ) return result ; if ( arg . type == NULL_TREE && cum -> nbytes + size > nregs * UNITS_PER_WORD ) return result ; switch ( cum -> nbytes / UNITS_PER_WORD ) { case 0 : result = gen_rtx_REG ( arg . mode , FIRST_ARGUMENT_REGNUM ) ; break ; case 1 : result = gen_rtx_REG ( arg . mode , FIRST_ARGUMENT_REGNUM + 1 ) ; break ; default : break ; } return result ; } </s>

Return an RTX to represent where a value with mode MODE will be returned from a function . If the result is NULL_RTX , the argument is pushed .


<s> static void mn10300_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; cum -> nbytes += ( arg . promoted_size_in_bytes ( ) + 3 ) & ~ 3 ; } </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 rtx mn10300_function_value ( const_tree valtype , const_tree fn_decl_or_type ATTRIBUTE_UNUSED , bool outgoing ) { rtx rv ; machine_mode mode = TYPE_MODE ( valtype ) ; if ( ! POINTER_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , FIRST_DATA_REGNUM ) ; else if ( ! TARGET_PTR_A0D0 || ! outgoing || cfun -> returns_struct ) return gen_rtx_REG ( mode , FIRST_ADDRESS_REGNUM ) ; rv = gen_rtx_PARALLEL ( mode , rtvec_alloc ( 2 ) ) ; XVECEXP ( rv , 0 , 0 ) = gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , FIRST_ADDRESS_REGNUM ) , GEN_INT ( 0 ) ) ; XVECEXP ( rv , 0 , 1 ) = gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , FIRST_DATA_REGNUM ) , GEN_INT ( 0 ) ) ; return rv ; } </s>

Return the location of the function 's value . This will be either $ d0 for integer functions , $ a0 for pointers , or a PARALLEL of both $ d0 and $ a0 if the -mreturn-pointer-on-do flag is set . Note that we only return the PARALLEL for outgoing values ; we do not want callers relying on this extra copy .


<s> bool mn10300_function_value_regno_p ( const unsigned int regno ) { return ( regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM ) ; } </s>


<s> static void mn10300_gen_multiple_store ( unsigned int mask ) { static const unsigned int store_order [ 8 ] = { FIRST_EXTENDED_REGNUM + 4 , FIRST_EXTENDED_REGNUM + 5 , FIRST_EXTENDED_REGNUM + 6 , FIRST_EXTENDED_REGNUM + 7 , FIRST_DATA_REGNUM + 2 , FIRST_DATA_REGNUM + 3 , FIRST_ADDRESS_REGNUM + 2 , FIRST_ADDRESS_REGNUM + 3 , } ; rtx x , elts [ 9 ] ; unsigned int i ; int count ; if ( mask == 0 ) return ; for ( i = count = 0 ; i < ARRAY_SIZE ( store_order ) ; ++ i ) { unsigned regno = store_order [ i ] ; if ( ( ( mask >> regno ) & 1 ) == 0 ) continue ; ++ count ; x = plus_constant ( Pmode , stack_pointer_rtx , count * - 4 ) ; x = gen_frame_mem ( SImode , x ) ; x = gen_rtx_SET ( x , gen_rtx_REG ( SImode , regno ) ) ; elts [ count ] = F ( x ) ; mask &= ~ ( 1u << regno ) ; } gcc_assert ( mask == 0 ) ; x = plus_constant ( Pmode , stack_pointer_rtx , count * - 4 ) ; x = gen_rtx_SET ( stack_pointer_rtx , x ) ; elts [ 0 ] = F ( x ) ; x = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( count + 1 , elts ) ) ; F ( emit_insn ( x ) ) ; } </s>

Generate an instruction that pushes several registers onto the stack . Register K will be saved if bit K in MASK is set . The function does nothing if MASK is zero . To be compatible with the `` movm '' instruction , the lowest-numbered register must be stored in the lowest slot . If MASK is the set { R1 , ... , RN } , where R1 ... RN are ordered least first , the generated instruction will have the form : ( parallel ( set ( reg : SI 9 ) ( plus : SI ( reg : SI 9 ) ( const_int -N * 4 ) ) ) ( set ( mem : SI ( plus : SI ( reg : SI 9 ) ( const_int -1 * 4 ) ) ) ( reg : SI RN ) ) ... ( set ( mem : SI ( plus : SI ( reg : SI 9 ) ( const_int -N * 4 ) ) ) ( reg : SI R1 ) ) )


<s> unsigned int mn10300_get_live_callee_saved_regs ( unsigned int * bytes_saved ) { int mask ; int i ; unsigned int count ; count = mask = 0 ; for ( i = 0 ; i <= LAST_EXTENDED_REGNUM ; i ++ ) if ( df_regs_ever_live_p ( i ) && ! call_used_regs [ i ] ) { mask |= ( 1 << i ) ; ++ count ; } if ( ( mask & 0x3c000 ) != 0 ) { for ( i = 0x04000 ; i < 0x40000 ; i <<= 1 ) if ( ( mask & i ) == 0 ) ++ count ; mask |= 0x3c000 ; } if ( bytes_saved ) * bytes_saved = count * UNITS_PER_WORD ; return mask ; } </s>

Returns the set of live , callee-saved registers as a bitmask . The callee-saved extended registers can not be stored individually , so all of them will be included in the mask if any one of them is used .


<s> static bool mn10300_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( REGNO_REG_CLASS ( regno ) == FP_REGS || REGNO_REG_CLASS ( regno ) == FP_ACC_REGS ) return GET_MODE_CLASS ( mode ) == MODE_FLOAT && ( ( regno & 1 ) == 0 ) ; if ( ! TARGET_AM33 && REGNO_REG_CLASS ( regno ) == EXTENDED_REGS ) return false ; if ( ( ( regno ) & 1 ) == 0 || GET_MODE_SIZE ( mode ) == 4 ) return true ; if ( REGNO_REG_CLASS ( regno ) == DATA_REGS || ( TARGET_AM33 && REGNO_REG_CLASS ( regno ) == ADDRESS_REGS ) || REGNO_REG_CLASS ( regno ) == EXTENDED_REGS ) return GET_MODE_SIZE ( mode ) <= 4 ; return false ; } </s>


<s>
static
void
mn10300_insert_setlb_lcc
(
rtx_insn
*
label
,
rtx_insn
*
branch
)
{
rtx
lcc
,
comparison
,
cmp_reg
;
if
(
LABEL_NUSES
(
label
)
>
1
)
{
rtx_insn
*
insn
;
DUMP
(
"Inserting SETLB insn after:"
,
label
)
;
insn
=
emit_insn_after
(
gen_setlb
(
)
,
label
)
;
label
=
gen_label_rtx
(
)
;
emit_label_after
(
label
,
insn
)
;
DUMP
(
"Created new loop-back label:"
,
label
)
;
}
else
{
DUMP
(
"Inserting SETLB insn before:"
,
label
)
;
emit_insn_before
(
gen_setlb
(
)
,
label
)
;
}
comparison
=
XEXP
(
SET_SRC
(
PATTERN
(
branch
)
)
,
0
)
;
cmp_reg
=
XEXP
(
comparison
,
0
)
;
gcc_assert
(
REG_P
(
cmp_reg
)
)
;
gcc_assert
(
REGNO
(
cmp_reg
)
==
CC_REG
)
;
if
(
GET_MODE
(
cmp_reg
)
==
CC_FLOATmode
)
lcc
=
gen_FLcc
(
comparison
,
label
)
;
else
lcc
=
gen_Lcc
(
comparison
,
label
)
;
rtx_insn
*
jump
=
emit_jump_insn_before
(
lcc
,
branch
)
;
mark_jump_label
(
XVECEXP
(
lcc
,
0
,
0
)
,
jump
,
0
)
;
JUMP_LABEL
(
jump
)
=
label
;
DUMP
(
"Replacing branch insn..."
,
branch
)
;
DUMP
(
"... with Lcc insn:"
,
jump
)
;
delete_insn
(
branch
)
;
}
</s>

Replace the BRANCH insn with a Lcc insn that goes to LABEL . Insert a SETLB insn just before LABEL .


<s> static bool mn10300_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { rtx base , index ; if ( CONSTANT_ADDRESS_P ( x ) ) return ! flag_pic || mn10300_legitimate_pic_operand_p ( x ) ; if ( RTX_OK_FOR_BASE_P ( x , strict ) ) return true ; if ( TARGET_AM33 && ( mode == SImode || mode == SFmode || mode == HImode ) ) { if ( GET_CODE ( x ) == POST_INC ) return RTX_OK_FOR_BASE_P ( XEXP ( x , 0 ) , strict ) ; if ( GET_CODE ( x ) == POST_MODIFY ) return ( RTX_OK_FOR_BASE_P ( XEXP ( x , 0 ) , strict ) && CONSTANT_ADDRESS_P ( XEXP ( x , 1 ) ) ) ; } if ( GET_CODE ( x ) != PLUS ) return false ; base = XEXP ( x , 0 ) ; index = XEXP ( x , 1 ) ; if ( ! REG_P ( base ) ) return false ; if ( REG_P ( index ) ) { if ( ! TARGET_AM33 ) return false ; return ( REGNO_GENERAL_P ( REGNO ( base ) , strict ) && REGNO_GENERAL_P ( REGNO ( index ) , strict ) ) ; } if ( ! REGNO_STRICT_OK_FOR_BASE_P ( REGNO ( base ) , strict ) ) return false ; if ( CONST_INT_P ( index ) ) return IN_RANGE ( INTVAL ( index ) , - 1 - 0x7fffffff , 0x7fffffff ) ; if ( CONSTANT_ADDRESS_P ( index ) ) return ! flag_pic || mn10300_legitimate_pic_operand_p ( index ) ; return false ; } </s>

Return TRUE if the address X , taken from a ( MEM : MODE X ) rtx , is legitimate , and FALSE otherwise . On the mn10300 , the value in the address register must be in the same memory space/segment as the effective address . This is problematical for reload since it does not understand that base+index ! = index+base in a memory reference . Note it is still possible to use reg+reg addressing modes , it 's just much more difficult . For a discussion of a possible workaround and solution , see the comments in pa.cc before the function record_unscaled_index_insn_codes .


<s> static bool mn10300_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { switch ( GET_CODE ( x ) ) { case CONST : x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == PLUS ) { if ( ! CONST_INT_P ( XEXP ( x , 1 ) ) ) return false ; x = XEXP ( x , 0 ) ; } if ( GET_CODE ( x ) == UNSPEC ) { switch ( XINT ( x , 1 ) ) { case UNSPEC_PIC : case UNSPEC_GOT : case UNSPEC_GOTOFF : case UNSPEC_PLT : return true ; default : return false ; } } if ( ! mn10300_symbolic_operand ( x , Pmode ) ) return false ; break ; default : break ; } return true ; } </s>

Implement TARGET_LEGITIMATE_CONSTANT_P . Returns TRUE if X is a valid constant . Note that some `` constants '' are n't valid , such as TLS symbols and unconverted GOT-based references , so we eliminate those here .


<s> int mn10300_legitimate_pic_operand_p ( rtx x ) { const char * fmt ; int i ; if ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) return 0 ; if ( GET_CODE ( x ) == UNSPEC && ( XINT ( x , 1 ) == UNSPEC_PIC || XINT ( x , 1 ) == UNSPEC_GOT || XINT ( x , 1 ) == UNSPEC_GOTOFF || XINT ( x , 1 ) == UNSPEC_PLT || XINT ( x , 1 ) == UNSPEC_GOTSYM_OFF ) ) return 1 ; 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 ( ! mn10300_legitimate_pic_operand_p ( XVECEXP ( x , i , j ) ) ) return 0 ; } else if ( fmt [ i ] == 'e' && ! mn10300_legitimate_pic_operand_p ( XEXP ( x , i ) ) ) return 0 ; } return 1 ; } </s>

Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol is n't protected by a PIC unspec ; nonzero otherwise .


<s> static rtx mn10300_legitimize_address ( rtx x , rtx oldx ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED ) { if ( flag_pic && ! mn10300_legitimate_pic_operand_p ( x ) ) x = mn10300_legitimize_pic_address ( oldx , NULL_RTX ) ; if ( GET_CODE ( x ) == PLUS && mn10300_symbolic_operand ( XEXP ( x , 1 ) , VOIDmode ) ) { rtx regx1 , regy1 , regy2 , y ; y = XEXP ( x , 1 ) ; if ( GET_CODE ( y ) == CONST ) y = XEXP ( y , 0 ) ; if ( GET_CODE ( y ) == PLUS || GET_CODE ( y ) == MINUS ) { regx1 = force_reg ( Pmode , force_operand ( XEXP ( x , 0 ) , 0 ) ) ; regy1 = force_reg ( Pmode , force_operand ( XEXP ( y , 0 ) , 0 ) ) ; regy2 = force_reg ( Pmode , force_operand ( XEXP ( y , 1 ) , 0 ) ) ; regx1 = force_reg ( Pmode , gen_rtx_fmt_ee ( GET_CODE ( y ) , Pmode , regx1 , regy2 ) ) ; return force_reg ( Pmode , gen_rtx_PLUS ( Pmode , regx1 , regy1 ) ) ; } } return x ; } </s>

Try machine dependent ways of modifying an illegitimate address to be legitimate . If we find one , return the new valid address . This macro is used in only one place : ` memory_address ' in explow.cc . OLDX is the address as it was before break_out_memory_refs was called . In some cases it is useful to look at this to decide what needs to be done . Normally it is always safe for this macro to do nothing . It exists to recognize opportunities to optimize the output . But on a few ports with segmented architectures and indexed addressing ( mn10300 , hppa ) it is used to rewrite certain problematical addresses .


<s> rtx mn10300_legitimize_pic_address ( rtx orig , rtx reg ) { rtx x ; rtx_insn * insn ; if ( GET_CODE ( orig ) == LABEL_REF || ( GET_CODE ( orig ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( orig ) || ! MN10300_GLOBAL_P ( orig ) ) ) ) { if ( reg == NULL ) reg = gen_reg_rtx ( Pmode ) ; x = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , orig ) , UNSPEC_GOTOFF ) ; x = gen_rtx_CONST ( SImode , x ) ; emit_move_insn ( reg , x ) ; insn = emit_insn ( gen_addsi3 ( reg , reg , pic_offset_table_rtx ) ) ; } else if ( GET_CODE ( orig ) == SYMBOL_REF ) { if ( reg == NULL ) reg = gen_reg_rtx ( Pmode ) ; x = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , orig ) , UNSPEC_GOT ) ; x = gen_rtx_CONST ( SImode , x ) ; x = gen_rtx_PLUS ( SImode , pic_offset_table_rtx , x ) ; x = gen_const_mem ( SImode , x ) ; insn = emit_move_insn ( reg , x ) ; } else return orig ; set_unique_reg_note ( insn , REG_EQUAL , orig ) ; return reg ; } </s>

Convert a non-PIC address in ` orig ' to a PIC address using @ GOT or @ GOTOFF in ` reg ' .


<s> static rtx mn10300_libcall_value ( machine_mode mode , const_rtx fun ATTRIBUTE_UNUSED ) { return gen_rtx_REG ( mode , FIRST_DATA_REGNUM ) ; } </s>


<s> bool mn10300_match_ccmode ( rtx insn , machine_mode cc_mode ) { rtx op1 , flags ; machine_mode flags_mode ; gcc_checking_assert ( XVECLEN ( PATTERN ( insn ) , 0 ) == 2 ) ; op1 = XVECEXP ( PATTERN ( insn ) , 0 , 0 ) ; gcc_checking_assert ( GET_CODE ( SET_SRC ( op1 ) ) == COMPARE ) ; flags = SET_DEST ( op1 ) ; flags_mode = GET_MODE ( flags ) ; if ( GET_MODE ( SET_SRC ( op1 ) ) != flags_mode ) return false ; if ( GET_MODE_CLASS ( flags_mode ) != MODE_CC ) return false ; if ( cc_flags_for_mode ( flags_mode ) & ~ cc_flags_for_mode ( cc_mode ) ) return false ; return true ; } </s>

A helper function for matching parallels that set the flags .


<s> static rtx_insn * mn10300_md_asm_adjust ( vec < rtx > & , vec < rtx > & , vec < machine_mode > & , vec < const char * > & , vec < rtx > & clobbers , HARD_REG_SET & clobbered_regs , location_t ) { clobbers . safe_push ( gen_rtx_REG ( CCmode , CC_REG ) ) ; SET_HARD_REG_BIT ( clobbered_regs , CC_REG ) ; return NULL ; } </s>

Worker function for TARGET_MD_ASM_ADJUST . We do this in the mn10300 backend to maintain source compatibility with the old cc0-based compiler .


<s> static int mn10300_memory_move_cost ( machine_mode mode ATTRIBUTE_UNUSED , reg_class_t iclass , bool in ATTRIBUTE_UNUSED ) { enum reg_class rclass = ( enum reg_class ) iclass ; if ( rclass == FP_REGS ) return 8 ; return 6 ; } </s>

Implement the TARGET_MEMORY_MOVE_COST hook . Given lack of the form of the address , this must be speed-relative , though we should never be less expensive than a size-relative register move cost above . This is not a problem .


<s> static bool mn10300_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { if ( GET_MODE_CLASS ( mode1 ) == MODE_FLOAT && GET_MODE_CLASS ( mode2 ) != MODE_FLOAT ) return false ; if ( GET_MODE_CLASS ( mode2 ) == MODE_FLOAT && GET_MODE_CLASS ( mode1 ) != MODE_FLOAT ) return false ; if ( TARGET_AM33 || mode1 == mode2 || ( GET_MODE_SIZE ( mode1 ) <= 4 && GET_MODE_SIZE ( mode2 ) <= 4 ) ) return true ; return false ; } </s>


<s>
const
char
*
mn10300_output_add
(
rtx
operands
[
3
]
,
bool
need_flags
)
{
rtx
dest
,
src1
,
src2
;
unsigned
int
dest_regnum
,
src1_regnum
,
src2_regnum
;
enum
reg_class
src1_class
,
src2_class
,
dest_class
;
dest
=
operands
[
0
]
;
src1
=
operands
[
1
]
;
src2
=
operands
[
2
]
;
dest_regnum
=
true_regnum
(
dest
)
;
src1_regnum
=
true_regnum
(
src1
)
;
dest_class
=
REGNO_REG_CLASS
(
dest_regnum
)
;
src1_class
=
REGNO_REG_CLASS
(
src1_regnum
)
;
if
(
CONST_INT_P
(
src2
)
)
{
gcc_assert
(
dest_regnum
==
src1_regnum
)
;
if
(
src2
==
const1_rtx
&&
!
need_flags
)
return
"inc %0"
;
if
(
INTVAL
(
src2
)
==
4
&&
!
need_flags
&&
dest_class
!=
DATA_REGS
)
return
"inc4 %0"
;
gcc_assert
(
!
need_flags
||
dest_class
!=
SP_REGS
)
;
return
"add %2,%0"
;
}
else
if
(
CONSTANT_P
(
src2
)
)
return
"add %2,%0"
;
src2_regnum
=
true_regnum
(
src2
)
;
src2_class
=
REGNO_REG_CLASS
(
src2_regnum
)
;
if
(
dest_regnum
==
src1_regnum
)
return
"add %2,%0"
;
if
(
dest_regnum
==
src2_regnum
)
return
"add %1,%0"
;
if
(
TARGET_AM33
&&
optimize_insn_for_speed_p
(
)
)
return
"add %2,%1,%0"
;
if
(
src1_class
!=
EXTENDED_REGS
&&
src2_class
!=
EXTENDED_REGS
&&
dest_class
!=
EXTENDED_REGS
)
{
if
(
src1_class
==
dest_class
)
return
"mov %1,%0\n\tadd %2,%0"
;
else
return
"mov %2,%0\n\tadd %1,%0"
;
}
if
(
dest_class
==
EXTENDED_REGS
||
src1_class
==
src2_class
)
return
"add %2,%1,%0"
;
if
(
src1_class
==
EXTENDED_REGS
)
return
"mov %1,%0\n\tadd %2,%0"
;
else
return
"mov %2,%0\n\tadd %1,%0"
;
}
</s>


<s> static bool mn10300_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { unsigned HOST_WIDE_INT size = arg . type_size_in_bytes ( ) ; return ( size > 8 || size == 0 ) ; } </s>

Return true when a parameter should be passed by reference .


<s> static reg_class_t mn10300_preferred_output_reload_class ( rtx x , reg_class_t rclass ) { if ( x == stack_pointer_rtx && rclass != SP_REGS ) return ( TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS ) ; return rclass ; } </s>


<s> static reg_class_t mn10300_preferred_reload_class ( rtx x , reg_class_t rclass ) { if ( x == stack_pointer_rtx && rclass != SP_REGS ) return ( TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS ) ; else if ( MEM_P ( x ) || ( REG_P ( x ) && ! HARD_REGISTER_P ( x ) ) || ( GET_CODE ( x ) == SUBREG && REG_P ( SUBREG_REG ( x ) ) && ! HARD_REGISTER_P ( SUBREG_REG ( x ) ) ) ) return LIMIT_RELOAD_CLASS ( GET_MODE ( x ) , rclass ) ; else return rclass ; } </s>


<s> void mn10300_print_operand_address ( FILE * file , rtx addr ) { switch ( GET_CODE ( addr ) ) { case POST_INC : mn10300_print_operand ( file , XEXP ( addr , 0 ) , 0 ) ; fputc ( '+' , file ) ; break ; case POST_MODIFY : mn10300_print_operand ( file , XEXP ( addr , 0 ) , 0 ) ; fputc ( '+' , file ) ; fputc ( ',' , file ) ; mn10300_print_operand ( file , XEXP ( addr , 1 ) , 0 ) ; break ; case REG : mn10300_print_operand ( file , addr , 0 ) ; break ; case PLUS : { rtx base = XEXP ( addr , 0 ) ; rtx index = XEXP ( addr , 1 ) ; if ( REG_P ( index ) && ! REG_OK_FOR_INDEX_P ( index ) ) { rtx x = base ; base = index ; index = x ; gcc_assert ( REG_P ( index ) && REG_OK_FOR_INDEX_P ( index ) ) ; } gcc_assert ( REG_OK_FOR_BASE_P ( base ) ) ; mn10300_print_operand ( file , index , 0 ) ; fputc ( ',' , file ) ; mn10300_print_operand ( file , base , 0 ) ; break ; } case SYMBOL_REF : output_addr_const ( file , addr ) ; break ; default : output_addr_const ( file , addr ) ; break ; } } </s>

Output assembly language output for the address ADDR to FILE .


<s> void mn10300_print_reg_list ( FILE * file , int mask ) { int need_comma ; int i ; need_comma = 0 ; fputc ( '[' , file ) ; for ( i = 0 ; i < FIRST_EXTENDED_REGNUM ; i ++ ) if ( ( mask & ( 1 << i ) ) != 0 ) { if ( need_comma ) fputc ( ',' , file ) ; fputs ( reg_names [ i ] , file ) ; need_comma = 1 ; } if ( ( mask & 0x3c000 ) != 0 ) { gcc_assert ( ( mask & 0x3c000 ) == 0x3c000 ) ; if ( need_comma ) fputc ( ',' , file ) ; fputs ( "exreg1" , file ) ; need_comma = 1 ; } fputc ( ']' , file ) ; } </s>

Print a set of registers in the format required by `` movm '' and `` ret '' . Register K is saved if bit K of MASK is set . The data and address registers can be stored individually , but the extended registers can not . We assume that the mask alread takes that into account . For instance , bits 14 to 17 must have the same value .


<s> static int mn10300_register_move_cost ( machine_mode mode ATTRIBUTE_UNUSED , reg_class_t ifrom , reg_class_t ito ) { enum reg_class from = ( enum reg_class ) ifrom ; enum reg_class to = ( enum reg_class ) ito ; enum reg_class scratch , test ; if ( to == FP_ACC_REGS ) to = FP_REGS ; if ( from == FP_ACC_REGS ) from = FP_REGS ; scratch = NO_REGS ; test = from ; if ( to == SP_REGS ) scratch = ( TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS ) ; else if ( to == MDR_REGS ) scratch = DATA_REGS ; else if ( to == FP_REGS && to != from ) scratch = GENERAL_REGS ; else { test = to ; if ( from == SP_REGS ) scratch = ( TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS ) ; else if ( from == MDR_REGS ) scratch = DATA_REGS ; else if ( from == FP_REGS && to != from ) scratch = GENERAL_REGS ; } if ( scratch != NO_REGS && ! reg_class_subset_p ( test , scratch ) ) return ( mn10300_register_move_cost ( VOIDmode , from , scratch ) + mn10300_register_move_cost ( VOIDmode , scratch , to ) ) ; if ( optimize_size ) { if ( from == to && ( to == ADDRESS_REGS || to == DATA_REGS ) ) return 2 ; if ( from == SP_REGS ) return ( to == ADDRESS_REGS ? 2 : 6 ) ; if ( TARGET_AM33 ) return 4 ; if ( to == SP_REGS ) return ( from == ADDRESS_REGS ? 4 : 6 ) ; if ( ( from == ADDRESS_REGS || from == DATA_REGS ) && ( to == ADDRESS_REGS || to == DATA_REGS ) ) return 4 ; if ( to == EXTENDED_REGS ) return ( to == from ? 6 : 4 ) ; return 6 ; } else { if ( to == FP_REGS ) return 8 ; if ( from == FP_REGS ) return 4 ; return 2 ; } } </s>

Implement the TARGET_REGISTER_MOVE_COST hook . Recall that the base value of 2 is required by assumptions elsewhere in the body of the compiler , and that cost 2 is special-cased as an early exit from reload meaning no work is required .


<s> static bool mn10300_return_in_memory ( const_tree type , const_tree fntype ATTRIBUTE_UNUSED ) { return ( int_size_in_bytes ( type ) > 8 || int_size_in_bytes ( type ) == 0 || TYPE_MODE ( type ) == BLKmode ) ; } </s>

Worker function for TARGET_RETURN_IN_MEMORY .


<s> static reg_class_t mn10300_secondary_reload ( bool in_p , rtx x , reg_class_t rclass_i , machine_mode mode , secondary_reload_info * sri ) { enum reg_class rclass = ( enum reg_class ) rclass_i ; enum reg_class xclass = NO_REGS ; unsigned int xregno = INVALID_REGNUM ; if ( REG_P ( x ) ) { xregno = REGNO ( x ) ; if ( xregno >= FIRST_PSEUDO_REGISTER ) xregno = true_regnum ( x ) ; if ( xregno != INVALID_REGNUM ) xclass = REGNO_REG_CLASS ( xregno ) ; } if ( ! TARGET_AM33 ) { if ( rclass != DATA_REGS && ( mode == QImode || mode == HImode ) && xclass == NO_REGS ) return DATA_REGS ; if ( in_p && rclass == SP_REGS && xclass != ADDRESS_REGS ) return ADDRESS_REGS ; if ( ! in_p && xclass == SP_REGS && rclass != ADDRESS_REGS && rclass != SP_OR_ADDRESS_REGS ) return ADDRESS_REGS ; } if ( in_p && rclass != SP_REGS && rclass != SP_OR_ADDRESS_REGS && rclass != SP_OR_GENERAL_REGS && GET_CODE ( x ) == PLUS && ( XEXP ( x , 0 ) == stack_pointer_rtx || XEXP ( x , 1 ) == stack_pointer_rtx ) ) { sri -> icode = CODE_FOR_reload_plus_sp_const ; return NO_REGS ; } if ( rclass == MDR_REGS && xclass != DATA_REGS ) return DATA_REGS ; if ( xclass == MDR_REGS && rclass != DATA_REGS ) return DATA_REGS ; if ( TARGET_AM33_2 && ( rclass == FP_REGS || xclass == FP_REGS ) && ( xclass == NO_REGS || rclass == NO_REGS ) ) { rtx addr = NULL ; if ( xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM ) { addr = reg_equiv_mem ( xregno ) ; if ( addr ) addr = XEXP ( addr , 0 ) ; } else if ( MEM_P ( x ) ) addr = XEXP ( x , 0 ) ; if ( addr && CONSTANT_ADDRESS_P ( addr ) ) return GENERAL_REGS ; } return NO_REGS ; } </s>


<s> int mn10300_split_and_operand_count ( rtx op ) { HOST_WIDE_INT val = INTVAL ( op ) ; int count ; if ( val < 0 ) { count = exact_log2 ( - val ) ; if ( count < 0 ) return 0 ; if ( count > ( optimize_insn_for_speed_p ( ) ? 2 : 4 ) ) return 0 ; return count ; } else { count = exact_log2 ( val + 1 ) ; count = 32 - count ; if ( count > ( optimize_insn_for_speed_p ( ) ? 2 : 4 ) ) return 0 ; return - count ; } } </s>

This function is used to help split : ( set ( reg ) ( and ( reg ) ( int ) ) ) into : ( set ( reg ) ( shift ( reg ) ( int ) ) ( set ( reg ) ( shift ( reg ) ( int ) ) where the shitfs will be shorter than the `` and '' insn . It returns the number of bits that should be shifted . A positive values means that the low bits are to be cleared ( and hence the shifts should be right followed by left ) whereas a negative value means that the high bits are to be cleared ( left followed by right ) . Zero is returned when it would not be economical to split the AND .


<s> void mn10300_split_cbranch ( machine_mode cmp_mode , rtx cmp_op , rtx label_ref ) { rtx flags , x ; flags = gen_rtx_REG ( cmp_mode , CC_REG ) ; x = gen_rtx_COMPARE ( cmp_mode , XEXP ( cmp_op , 0 ) , XEXP ( cmp_op , 1 ) ) ; x = gen_rtx_SET ( flags , x ) ; emit_insn ( x ) ; x = gen_rtx_fmt_ee ( GET_CODE ( cmp_op ) , VOIDmode , flags , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , label_ref , pc_rtx ) ; x = gen_rtx_SET ( pc_rtx , x ) ; emit_jump_insn ( x ) ; } </s>

A helper function for splitting cbranch patterns after reload .


<s> unsigned int mn10300_store_multiple_regs ( rtx op ) { int count ; int mask ; int i ; unsigned int last ; rtx elt ; count = XVECLEN ( op , 0 ) ; if ( count < 2 ) return 0 ; elt = XVECEXP ( op , 0 , 0 ) ; if ( GET_CODE ( elt ) != SET || ( ! REG_P ( SET_DEST ( elt ) ) ) || REGNO ( SET_DEST ( elt ) ) != STACK_POINTER_REGNUM || GET_CODE ( SET_SRC ( elt ) ) != PLUS ) return 0 ; elt = SET_SRC ( elt ) ; if ( ( ! REG_P ( XEXP ( elt , 0 ) ) ) || REGNO ( XEXP ( elt , 0 ) ) != STACK_POINTER_REGNUM || ( ! CONST_INT_P ( XEXP ( elt , 1 ) ) ) || INTVAL ( XEXP ( elt , 1 ) ) != - ( count - 1 ) * 4 ) return 0 ; mask = 0 ; for ( i = 1 ; i < count ; i ++ ) { elt = XVECEXP ( op , 0 , i ) ; if ( GET_CODE ( elt ) != SET || ( ! MEM_P ( SET_DEST ( elt ) ) ) || ( ! REG_P ( SET_SRC ( elt ) ) ) ) return 0 ; last = REGNO ( SET_SRC ( elt ) ) ; mask |= ( 1 << last ) ; elt = XEXP ( SET_DEST ( elt ) , 0 ) ; if ( GET_CODE ( elt ) != PLUS || ( ! REG_P ( XEXP ( elt , 0 ) ) ) || REGNO ( XEXP ( elt , 0 ) ) != STACK_POINTER_REGNUM || ( ! CONST_INT_P ( XEXP ( elt , 1 ) ) ) || INTVAL ( XEXP ( elt , 1 ) ) != - i * 4 ) return 0 ; } if ( ( mask & 0x3c000 ) != 0 && ( mask & 0x3c000 ) != 0x3c000 ) return 0 ; return mask ; } </s>

Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store ( ) . This function is for MATCH_PARALLEL and so assumes OP is known to be parallel . If OP is a multiple store , return a mask indicating which registers it saves . Return 0 otherwise .


<s> int mn10300_symbolic_operand ( rtx op , machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case SYMBOL_REF : case LABEL_REF : return 1 ; case CONST : op = XEXP ( op , 0 ) ; return ( ( GET_CODE ( XEXP ( op , 0 ) ) == SYMBOL_REF || GET_CODE ( XEXP ( op , 0 ) ) == LABEL_REF ) && CONST_INT_P ( XEXP ( op , 1 ) ) ) ; default : return 0 ; } } </s>

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


<s> static void mn10300_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx mem , disp , fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; disp = expand_binop ( SImode , sub_optab , fnaddr , plus_constant ( Pmode , XEXP ( m_tramp , 0 ) , 11 ) , NULL_RTX , 1 , OPTAB_DIRECT ) ; mem = adjust_address ( m_tramp , SImode , 0 ) ; emit_move_insn ( mem , gen_int_mode ( 0xddfc0028 , SImode ) ) ; mem = adjust_address ( m_tramp , SImode , 4 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , 8 ) ; emit_move_insn ( mem , gen_int_mode ( 0xdc00edf8 , SImode ) ) ; mem = adjust_address ( m_tramp , SImode , 12 ) ; emit_move_insn ( mem , disp ) ; } </s>

Worker function for TARGET_TRAMPOLINE_INIT .