<s> static void mcore_setup_incoming_varargs ( cumulative_args_t args_so_far_v , const function_arg_info & arg , int * ptr_pretend_size ATTRIBUTE_UNUSED , int second_time ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * args_so_far = get_cumulative_args ( args_so_far_v ) ; current_function_anonymous_args = 1 ; number_of_regs_before_varargs = * args_so_far ; if ( ! TYPE_NO_NAMED_ARGS_STDARG_P ( TREE_TYPE ( current_function_decl ) ) ) number_of_regs_before_varargs += mcore_num_arg_regs ( arg . mode , arg . type ) ; number_of_regs_before_varargs = * args_so_far ; if ( number_of_regs_before_varargs > NPARM_REGS ) number_of_regs_before_varargs = NPARM_REGS ; } </s>

Keep track of some information about varargs for the prolog .


<s> static void mcore_add_gc_roots ( ) { ggc_add_rtx_root ( & arch_compare_op0 , 1 ) ; ggc_add_rtx_root ( & arch_compare_op1 , 1 ) ; } </s>

Called to register all of our global variables with the garbage collector .


<s>
const
char
*
mcore_output_jump_label_table
(
)
{
int
i
;
if
(
pool_size
)
{
fprintf
(
asm_out_file
,
"\t.align 2\n"
)
;
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
pool_node
*
p
=
pool_vector
+
i
;
ASM_OUTPUT_INTERNAL_LABEL
(
asm_out_file
,
"L"
,
CODE_LABEL_NUMBER
(
p
->
label
)
)
;
output_asm_insn
(
".long	%0"
,
&
p
->
value
)
;
}
pool_size
=
0
;
}
return
""
;
}
</s>

Dump out any constants accumulated in the final pass . These will only be labels .

mcore
"\t.align 2\n"
0
"L"
".long	%0"
0
""


<s> static void block_move_sequence ( rtx dst_mem , rtx src_mem , int size , int align ) { rtx temp [ 2 ] ; enum machine_mode mode [ 2 ] ; int amount [ 2 ] ; bool active [ 2 ] ; int phase = 0 ; int next ; int offset_ld = 0 ; int offset_st = 0 ; rtx x ; x = XEXP ( dst_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; dst_mem = replace_equiv_address ( dst_mem , x ) ; } x = XEXP ( src_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; src_mem = replace_equiv_address ( src_mem , x ) ; } active [ 0 ] = active [ 1 ] = false ; do { next = phase ; phase ^= 1 ; if ( size > 0 ) { int next_amount ; next_amount = ( size >= 4 ? 4 : ( size >= 2 ? 2 : 1 ) ) ; next_amount = MIN ( next_amount , align ) ; amount [ next ] = next_amount ; mode [ next ] = mode_from_align [ next_amount ] ; temp [ next ] = gen_reg_rtx ( mode [ next ] ) ; x = adjust_address ( src_mem , mode [ next ] , offset_ld ) ; emit_insn ( gen_rtx_SET ( VOIDmode , temp [ next ] , x ) ) ; offset_ld += next_amount ; size -= next_amount ; active [ next ] = true ; } if ( active [ phase ] ) { active [ phase ] = false ; x = adjust_address ( dst_mem , mode [ phase ] , offset_st ) ; emit_insn ( gen_rtx_SET ( VOIDmode , x , temp [ phase ] ) ) ; offset_st += amount [ phase ] ; } } while ( active [ next ] ) ; } </s>

Emit code to perform a block move with an offset sequence of ld/st instructions ( ... , ld 0 , st 1 , ld 1 , st 0 , ... ) . SIZE and ALIGN are known constants . DEST and SRC are registers . OFFSET is the known starting point for the output pattern .


<s> static int calc_live_regs ( int * count ) { int reg ; int live_regs_mask = 0 ; * count = 0 ; for ( reg = 0 ; reg < FIRST_PSEUDO_REGISTER ; reg ++ ) { if ( regs_ever_live [ reg ] && ! call_used_regs [ reg ] ) { ( * count ) ++ ; live_regs_mask |= ( 1 << reg ) ; } } return live_regs_mask ; } </s>

Work out the registers which need to be saved , both as a mask and a count


<s> static rtx conditionalize_block ( rtx first ) { rtx insn ; rtx br_pat ; rtx end_blk_1_br = 0 ; rtx end_blk_2_insn = 0 ; rtx start_blk_3_lab = 0 ; int cond ; int br_lab_num ; int blk_size = 0 ; if ( GET_CODE ( first ) != JUMP_INSN || GET_CODE ( PATTERN ( first ) ) != SET || GET_CODE ( XEXP ( PATTERN ( first ) , 1 ) ) != IF_THEN_ELSE ) return NEXT_INSN ( first ) ; end_blk_1_br = first ; br_pat = PATTERN ( end_blk_1_br ) ; cond = ( GET_CODE ( XEXP ( XEXP ( br_pat , 1 ) , 0 ) ) == EQ ) ; if ( GET_CODE ( XEXP ( XEXP ( br_pat , 1 ) , 1 ) ) == LABEL_REF ) { br_lab_num = CODE_LABEL_NUMBER ( XEXP ( XEXP ( XEXP ( br_pat , 1 ) , 1 ) , 0 ) ) ; } else { cond = ( cond == 0 ) ; br_lab_num = CODE_LABEL_NUMBER ( XEXP ( XEXP ( XEXP ( br_pat , 1 ) , 2 ) , 0 ) ) ; } for ( insn = NEXT_INSN ( first ) ; insn ; insn = NEXT_INSN ( insn ) ) { enum rtx_code code ; code = GET_CODE ( insn ) ; if ( code == CODE_LABEL && CODE_LABEL_NUMBER ( insn ) == br_lab_num ) break ; if ( code != BARRIER && code != NOTE && ! is_cond_candidate ( insn ) ) return NEXT_INSN ( insn ) ; if ( code == JUMP_INSN || code == INSN ) { blk_size ++ ; end_blk_2_insn = insn ; } } if ( ! insn ) return insn ; if ( optimize > 1 && blk_size > 2 ) return insn ; start_blk_3_lab = insn ; for ( insn = NEXT_INSN ( end_blk_1_br ) ; insn != start_blk_3_lab ; insn = NEXT_INSN ( insn ) ) { rtx newinsn ; if ( INSN_DELETED_P ( insn ) ) continue ; if ( ( newinsn = emit_new_cond_insn ( insn , cond ) ) ) { if ( end_blk_2_insn == insn ) end_blk_2_insn = newinsn ; insn = newinsn ; } } if ( LABEL_NUSES ( start_blk_3_lab ) == 1 ) { start_blk_3_lab = 0 ; } delete_insn ( end_blk_1_br ) ; if ( ! start_blk_3_lab ) return end_blk_2_insn ; return NEXT_INSN ( start_blk_3_lab ) ; } </s>

Attempt to change a basic block into a series of conditional insns . This works by taking the branch at the end of the 1st block and scanning for the end of the 2nd block . If all instructions in the 2nd block have cond . versions and the label at the start of block 3 is the same as the target from the branch at block 1 , then conditionalize all insn in block 2 using the inverse condition of the branch at block 1 . ( Note I 'm bending the definition of basic block here . ) e.g. , change : bt L2 < -- end of block 1 ( delete ) mov r7 , r8 addu r7,1 br L3 < -- end of block 2 L2 : ... < -- start of block 3 ( NUSES==1 ) L3 : ... to : movf r7 , r8 incf r7 bf L3 L3 : ... we can delete the L2 label if NUSES==1 and re-apply the optimization starting at the last instruction of block 2 . This may allow an entire if-then-else statement to be conditionalized . BRC


<s> static void conditionalize_optimization ( void ) { rtx insn ; for ( insn = get_insns ( ) ; insn ; insn = conditionalize_block ( insn ) ) continue ; } </s>

Apply the conditionalization of blocks optimization . This is the outer loop that traverses through the insns scanning for a branch that signifies an opportunity to apply the optimization . Note that this optimization is applied late . If we could apply it earlier , say before cse 2 , it may expose more optimization opportunities . but , the pay back probably is n't really worth the effort ( we 'd have to update all reg/flow/notes/links/etc to make it work - and stick it in before cse 2 ) .


<s> static rtx emit_new_cond_insn ( rtx insn , int cond ) { rtx c_insn = 0 ; rtx pat , dst , src ; cond_type num ; if ( ( num = is_cond_candidate ( insn ) ) == COND_NO ) return NULL ; pat = PATTERN ( insn ) ; if ( GET_CODE ( insn ) == INSN ) { dst = SET_DEST ( pat ) ; src = SET_SRC ( pat ) ; } else { dst = JUMP_LABEL ( insn ) ; src = NULL_RTX ; } switch ( num ) { case COND_MOV_INSN : case COND_CLR_INSN : if ( cond ) c_insn = gen_movt0 ( dst , src , dst ) ; else c_insn = gen_movt0 ( dst , dst , src ) ; break ; case COND_INC_INSN : if ( cond ) c_insn = gen_incscc ( dst , dst ) ; else c_insn = gen_incscc_false ( dst , dst ) ; break ; case COND_DEC_INSN : if ( cond ) c_insn = gen_decscc ( dst , dst ) ; else c_insn = gen_decscc_false ( dst , dst ) ; break ; case COND_BRANCH_INSN : if ( cond ) c_insn = gen_branch_true ( dst ) ; else c_insn = gen_branch_false ( dst ) ; break ; default : return NULL ; } if ( rtx_length [ GET_CODE ( c_insn ) ] >= 7 && rtx_length [ GET_CODE ( insn ) ] >= 7 ) { REG_NOTES ( c_insn ) = REG_NOTES ( insn ) ; } if ( num == COND_BRANCH_INSN ) { c_insn = emit_jump_insn_before ( c_insn , insn ) ; ++ LABEL_NUSES ( dst ) ; JUMP_LABEL ( c_insn ) = dst ; } else c_insn = emit_insn_after ( c_insn , insn ) ; delete_insn ( insn ) ; return c_insn ; } </s>

Emit a conditional version of insn and replace the old insn with the new one . Return the new insn if emitted .


<s> static cond_type is_cond_candidate ( rtx insn ) { if ( GET_CODE ( insn ) == INSN ) { rtx pat = PATTERN ( insn ) ; rtx src , dst ; if ( GET_CODE ( pat ) != SET ) return COND_NO ; dst = XEXP ( pat , 0 ) ; if ( ( GET_CODE ( dst ) != REG && GET_CODE ( dst ) != SUBREG ) || GET_MODE ( dst ) != SImode ) return COND_NO ; src = XEXP ( pat , 1 ) ; if ( ( GET_CODE ( src ) == REG || ( GET_CODE ( src ) == SUBREG && GET_CODE ( SUBREG_REG ( src ) ) == REG ) ) && GET_MODE ( src ) == SImode ) return COND_MOV_INSN ; else if ( GET_CODE ( src ) == CONST_INT && INTVAL ( src ) == 0 ) return COND_CLR_INSN ; else if ( GET_CODE ( src ) == PLUS && ( GET_CODE ( XEXP ( src , 0 ) ) == REG || ( GET_CODE ( XEXP ( src , 0 ) ) == SUBREG && GET_CODE ( SUBREG_REG ( XEXP ( src , 0 ) ) ) == REG ) ) && GET_MODE ( XEXP ( src , 0 ) ) == SImode && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == 1 ) return COND_INC_INSN ; else if ( ( ( GET_CODE ( src ) == MINUS && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == 1 ) || ( GET_CODE ( src ) == PLUS && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == - 1 ) ) && ( GET_CODE ( XEXP ( src , 0 ) ) == REG || ( GET_CODE ( XEXP ( src , 0 ) ) == SUBREG && GET_CODE ( SUBREG_REG ( XEXP ( src , 0 ) ) ) == REG ) ) && GET_MODE ( XEXP ( src , 0 ) ) == SImode ) return COND_DEC_INSN ; } else if ( GET_CODE ( insn ) == JUMP_INSN && GET_CODE ( PATTERN ( insn ) ) == SET && GET_CODE ( XEXP ( PATTERN ( insn ) , 1 ) ) == LABEL_REF ) return COND_BRANCH_INSN ; return COND_NO ; } </s>

Check whether insn is a candidate for a conditional .


<s> static int mcore_and_cost ( rtx x ) { int val ; if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) return 2 ; val = INTVAL ( XEXP ( x , 1 ) ) ; if ( CONST_OK_FOR_K ( val ) || CONST_OK_FOR_M ( ~ val ) ) return 2 ; else if ( const_ok_for_mcore ( val ) ) return 3 ; else if ( TARGET_HARDLIT && mcore_const_ok_for_inline ( val ) ) return 4 ; return 5 ; } </s>

What does an and instruction cost - we do this b/c immediates may have been relaxed . We want to ensure that cse will cse relaxed immeds out . Otherwise we 'll get bad code ( multiple reloads of the same const ) .


<s> static int mcore_arg_partial_bytes ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , bool named ) { int reg = ROUND_REG ( * cum , mode ) ; if ( named == 0 ) return 0 ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; if ( reg >= NPARM_REGS ) return 0 ; if ( reg + mcore_num_arg_regs ( mode , type ) <= NPARM_REGS ) return 0 ; reg = NPARM_REGS - reg ; return reg * UNITS_PER_WORD ; } </s>

Returns the number of bytes of argument registers required to hold * part * of a parameter of machine mode MODE and type TYPE ( which may be NULL if the type is not known ) . If the argument fits entirely in the argument registers , or entirely on the stack , then 0 is returned . CUM is the number of argument registers already used by earlier parameters to the function .


<s> int mcore_expand_insv ( rtx operands [ ] ) { int width = INTVAL ( operands [ 1 ] ) ; int posn = INTVAL ( operands [ 2 ] ) ; int mask ; rtx mreg , sreg , ereg ; if ( width == 1 && GET_CODE ( operands [ 3 ] ) == CONST_INT ) { if ( ( INTVAL ( operands [ 3 ] ) & 1 ) == 0 ) { mask = ~ ( 1 << posn ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } else { mask = 1 << posn ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } return 1 ; } if ( ! TARGET_W_FIELD ) return 0 ; if ( width == 8 && posn % 8 == 0 ) return 0 ; if ( width == 16 && posn % 16 == 0 ) return 0 ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == ( ( 1 << width ) - 1 ) ) { mreg = force_reg ( SImode , GEN_INT ( INTVAL ( operands [ 3 ] ) << posn ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , mreg ) ) ) ; return 1 ; } mreg = force_reg ( SImode , GEN_INT ( ~ ( ( ( 1 << width ) - 1 ) << posn ) ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , mreg ) ) ) ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == 0 ) return 1 ; sreg = copy_to_mode_reg ( SImode , operands [ 3 ] ) ; if ( width + posn != ( int ) GET_MODE_SIZE ( SImode ) ) { ereg = force_reg ( SImode , GEN_INT ( ( 1 << width ) - 1 ) ) ; emit_insn ( gen_rtx_SET ( SImode , sreg , gen_rtx_AND ( SImode , sreg , ereg ) ) ) ; } if ( posn != 0 ) emit_insn ( gen_rtx_SET ( SImode , sreg , gen_rtx_ASHIFT ( SImode , sreg , GEN_INT ( posn ) ) ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , sreg ) ) ) ; return 1 ; } </s>


<s> rtx mcore_function_arg ( CUMULATIVE_ARGS cum , enum machine_mode mode , tree type , int named ) { int arg_reg ; if ( ! named || mode == VOIDmode ) return 0 ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; arg_reg = ROUND_REG ( cum , mode ) ; if ( arg_reg < NPARM_REGS ) return handle_structs_in_regs ( mode , type , FIRST_PARM_REG + arg_reg ) ; return 0 ; } </s>

Define where to put the arguments to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) . On MCore the first args are normally in registers and the rest are pushed . Any arg that starts within the first NPARM_REGS words is at least partially passed in a register unless its data type forbids .


<s> rtx mcore_gen_compare_reg ( enum rtx_code code ) { rtx op0 = arch_compare_op0 ; rtx op1 = arch_compare_op1 ; rtx cc_reg = gen_rtx_REG ( CCmode , CC_REG ) ; if ( CONSTANT_P ( op1 ) && GET_CODE ( op1 ) != CONST_INT ) op1 = force_reg ( SImode , op1 ) ; switch ( code ) { case EQ : code = NE ; case NE : if ( GET_CODE ( op1 ) == CONST_INT && ! CONST_OK_FOR_K ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case LE : code = GT ; case GT : if ( GET_CODE ( op1 ) == CONST_INT ) op1 = force_reg ( SImode , op1 ) ; break ; case GE : code = LT ; case LT : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 && ! CONST_OK_FOR_J ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case GTU : gcc_assert ( GET_CODE ( op1 ) != CONST_INT || INTVAL ( op1 ) != 0 ) ; code = LEU ; case LEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; case LTU : code = GEU ; case GEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; default : break ; } emit_insn ( gen_rtx_SET ( VOIDmode , cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return cc_reg ; } </s>


"%qs attribute only applies to functions"

Handle a `` naked '' attribute ; arguments as in struct attribute_spec.handler .


<s> static int mcore_ior_cost ( rtx x ) { int val ; if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) return 2 ; val = INTVAL ( XEXP ( x , 1 ) ) ; if ( CONST_OK_FOR_M ( val ) ) return 2 ; else if ( const_ok_for_mcore ( val ) ) return 3 ; else if ( TARGET_HARDLIT && mcore_const_ok_for_inline ( val ) ) return 4 ; return 5 ; } </s>

What does an or cost - see and_cost ( ) .


<s> int mcore_is_dead ( rtx first , rtx reg ) { rtx insn ; if ( GET_CODE ( reg ) == SUBREG ) reg = SUBREG_REG ( reg ) ; if ( dead_or_set_p ( first , reg ) ) return 1 ; for ( insn = NEXT_INSN ( first ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( GET_CODE ( insn ) == JUMP_INSN ) return 0 ; else if ( GET_CODE ( insn ) == CALL_INSN ) { if ( reg_referenced_p ( reg , PATTERN ( insn ) ) || find_reg_fusage ( insn , USE , reg ) ) return 0 ; else if ( dead_or_set_p ( insn , reg ) ) return 1 ; } else if ( GET_CODE ( insn ) == INSN ) { if ( reg_referenced_p ( reg , PATTERN ( insn ) ) ) return 0 ; else if ( dead_or_set_p ( insn , reg ) ) return 1 ; } } return 0 ; } </s>

Check whether reg is dead at first . This is done by searching ahead for either the next use ( i.e. , reg is live ) , a death note , or a set of reg . Do n't just use dead_or_set_p ( ) since reload does not always mark deaths ( especially if PRESERVE_DEATH_NOTES_REGNO_P is not defined ) . We can ignore subregs by extracting the actual register . BRC


<s> static void mcore_mark_dllexport ( tree decl ) { const char * oldname ; char * newname ; rtx rtlname ; tree idp ; rtlname = XEXP ( DECL_RTL ( decl ) , 0 ) ; if ( GET_CODE ( rtlname ) == MEM ) rtlname = XEXP ( rtlname , 0 ) ; gcc_assert ( GET_CODE ( rtlname ) == SYMBOL_REF ) ; oldname = XSTR ( rtlname , 0 ) ; if ( mcore_dllexport_name_p ( oldname ) ) return ; newname = alloca ( strlen ( oldname ) + 4 ) ; sprintf ( newname , "@e.%s" , oldname ) ; idp = get_identifier ( newname ) ; XEXP ( DECL_RTL ( decl ) , 0 ) = gen_rtx_SYMBOL_REF ( Pmode , IDENTIFIER_POINTER ( idp ) ) ; } </s>


"initialized variable %q+D is marked dllimport"


<s> int mcore_modify_comparison ( enum rtx_code code ) { rtx op1 = arch_compare_op1 ; if ( GET_CODE ( op1 ) == CONST_INT ) { int val = INTVAL ( op1 ) ; switch ( code ) { case LE : if ( CONST_OK_FOR_J ( val + 1 ) ) { arch_compare_op1 = GEN_INT ( val + 1 ) ; return 1 ; } break ; default : break ; } } return 0 ; } </s>

Check to see if a comparison against a constant can be made more efficient by incrementing/decrementing the constant to get one that is more efficient to load .


<s> int mcore_num_arg_regs ( enum machine_mode mode , tree type ) { int size ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; if ( type && mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; return ROUND_ADVANCE ( size ) ; } </s>

Compute the number of word sized registers needed to hold a function argument of mode MODE and type TYPE .


<s> int mcore_num_zeros ( int mask ) { return 32 - mcore_num_ones ( mask ) ; } </s>


<s> const char * mcore_output_andn ( rtx insn ATTRIBUTE_UNUSED , rtx operands [ ] ) { int x , y ; rtx out_operands [ 3 ] ; const char * load_op ; char buf [ 256 ] ; int trick_no ; trick_no = try_constant_tricks ( INTVAL ( operands [ 1 ] ) , & x , & y ) ; gcc_assert ( trick_no == 2 ) ; out_operands [ 0 ] = operands [ 0 ] ; out_operands [ 1 ] = GEN_INT ( x ) ; out_operands [ 2 ] = operands [ 2 ] ; if ( x >= 0 && x <= 127 ) load_op = "movi\t%0,%1" ; else if ( ( x & ( x - 1 ) ) == 0 ) load_op = "bgeni\t%0,%P1" ; else if ( ( x & ( x + 1 ) ) == 0 ) load_op = "bmaski\t%0,%N1" ; else load_op = "BADMOVI\t%0,%1" ; sprintf ( buf , "%s\n\tandn\t%%2,%%0" , load_op ) ; output_asm_insn ( buf , out_operands ) ; return "" ; } </s>

Outputs the peephole for moving a constant that gets not'ed followed by an and ( i.e . combine the not and the and into andn ) . BRC


<s> const char * mcore_output_cmov ( rtx operands [ ] , int cmp_t , const char * test ) { int load_value ; int adjust_value ; rtx out_operands [ 4 ] ; out_operands [ 0 ] = operands [ 0 ] ; if ( const_ok_for_mcore ( INTVAL ( operands [ 1 ] ) ) ) { out_operands [ 1 ] = operands [ 1 ] ; out_operands [ 2 ] = operands [ 2 ] ; } else if ( const_ok_for_mcore ( INTVAL ( operands [ 2 ] ) ) ) { out_operands [ 1 ] = operands [ 2 ] ; out_operands [ 2 ] = operands [ 1 ] ; cmp_t = ( cmp_t == 0 ) ; } load_value = INTVAL ( out_operands [ 1 ] ) ; adjust_value = INTVAL ( out_operands [ 2 ] ) ; if ( test ) output_asm_insn ( test , operands ) ; if ( load_value >= 0 && load_value <= 127 ) output_asm_insn ( "movi\t%0,%1" , out_operands ) ; else if ( ( load_value & ( load_value - 1 ) ) == 0 ) output_asm_insn ( "bgeni\t%0,%P1" , out_operands ) ; else if ( ( load_value & ( load_value + 1 ) ) == 0 ) output_asm_insn ( "bmaski\t%0,%N1" , out_operands ) ; if ( load_value > adjust_value ) { if ( cmp_t ) output_asm_insn ( "decf\t%0" , out_operands ) ; else output_asm_insn ( "dect\t%0" , out_operands ) ; } else { if ( cmp_t ) output_asm_insn ( "incf\t%0" , out_operands ) ; else output_asm_insn ( "inct\t%0" , out_operands ) ; } return "" ; } </s>

Output a conditional move of two constants that are +/- 1 within each other . See the `` movtK '' patterns in mcore.md . I 'm not sure this is really worth the effort .


<s>
const
char
*
mcore_output_move
(
rtx
insn
ATTRIBUTE_UNUSED
,
rtx
operands
[
]
,
enum
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
if
(
GET_CODE
(
dst
)
==
REG
)
{
if
(
GET_CODE
(
src
)
==
REG
)
{
if
(
REGNO
(
src
)
==
CC_REG
)
return
"mvc\t%0"
;
else
return
"mov\t%0,%1"
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
if
(
GET_CODE
(
XEXP
(
src
,
0
)
)
==
LABEL_REF
)
return
"lrw\t%0,[%1]"
;
else
switch
(
GET_MODE
(
src
)
)
{
case
SImode
:
return
"ldw\t%0,%1"
;
case
HImode
:
return
"ld.h\t%0,%1"
;
case
QImode
:
return
"ld.b\t%0,%1"
;
default
:
gcc_unreachable
(
)
;
}
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
int
x
,
y
;
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
return
"movi\t%0,%1"
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
return
"bgeni\t%0,%P1\t// %1 %x1"
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
return
"bmaski\t%0,%N1\t// %1 %x1"
;
else
if
(
try_constant_tricks
(
INTVAL
(
src
)
,
&
x
,
&
y
)
)
return
output_inline_const
(
SImode
,
operands
)
;
else
return
"lrw\t%0,%x1\t// %1"
;
}
else
return
"lrw\t%0, %1"
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
)
switch
(
GET_MODE
(
dst
)
)
{
case
SImode
:
return
"stw\t%1,%0"
;
case
HImode
:
return
"st.h\t%1,%0"
;
case
QImode
:
return
"st.b\t%1,%0"
;
default
:
gcc_unreachable
(
)
;
}
gcc_unreachable
(
)
;
}
</s>


<s>
const
char
*
mcore_output_movedouble
(
rtx
operands
[
]
,
enum
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
if
(
GET_CODE
(
dst
)
==
REG
)
{
if
(
GET_CODE
(
src
)
==
REG
)
{
int
dstreg
=
REGNO
(
dst
)
;
int
srcreg
=
REGNO
(
src
)
;
if
(
srcreg
+
1
==
dstreg
)
return
"mov	%R0,%R1\n\tmov	%0,%1"
;
else
return
"mov	%0,%1\n\tmov	%R0,%R1"
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
rtx
memexp
=
memexp
=
XEXP
(
src
,
0
)
;
int
dstreg
=
REGNO
(
dst
)
;
int
basereg
=
1
;
if
(
GET_CODE
(
memexp
)
==
LABEL_REF
)
return
"lrw\t%0,[%1]\n\tlrw\t%R0,[%R1]"
;
else
if
(
GET_CODE
(
memexp
)
==
REG
)
basereg
=
REGNO
(
memexp
)
;
else
if
(
GET_CODE
(
memexp
)
==
PLUS
)
{
if
(
GET_CODE
(
XEXP
(
memexp
,
0
)
)
==
REG
)
basereg
=
REGNO
(
XEXP
(
memexp
,
0
)
)
;
else
if
(
GET_CODE
(
XEXP
(
memexp
,
1
)
)
==
REG
)
basereg
=
REGNO
(
XEXP
(
memexp
,
1
)
)
;
else
gcc_unreachable
(
)
;
}
else
gcc_unreachable
(
)
;
if
(
dstreg
==
basereg
)
{
return
"ldw\t%R0,%R1\n\tldw\t%0,%1"
;
}
else
return
"ldw\t%0,%1\n\tldw\t%R0,%R1"
;
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
if
(
TARGET_LITTLE_END
)
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"movi	%0,%1"
,
operands
)
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bgeni	%0,%P1"
,
operands
)
;
else
if
(
INTVAL
(
src
)
==
1
)
output_asm_insn
(
"bmaski	%0,32"
,
operands
)
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bmaski	%0,%N1"
,
operands
)
;
else
gcc_unreachable
(
)
;
if
(
INTVAL
(
src
)
<
0
)
return
"bmaski	%R0,32"
;
else
return
"movi	%R0,0"
;
}
else
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"movi	%R0,%1"
,
operands
)
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bgeni	%R0,%P1"
,
operands
)
;
else
if
(
INTVAL
(
src
)
==
1
)
output_asm_insn
(
"bmaski	%R0,32"
,
operands
)
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bmaski	%R0,%N1"
,
operands
)
;
else
gcc_unreachable
(
)
;
if
(
INTVAL
(
src
)
<
0
)
return
"bmaski	%0,32"
;
else
return
"movi	%0,0"
;
}
}
else
gcc_unreachable
(
)
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
&&
GET_CODE
(
src
)
==
REG
)
return
"stw\t%1,%0\n\tstw\t%R1,%R0"
;
else
gcc_unreachable
(
)
;
}
</s>

Return a sequence of instructions to perform DI or DF move . Since the MCORE can not move a DI or DF in one instruction , we have to take care when we see overlapping source and dest registers .


<s> void mcore_print_operand ( FILE * stream , rtx x , int code ) { switch ( code ) { case 'N' : if ( INTVAL ( x ) == - 1 ) fprintf ( asm_out_file , "32" ) ; else fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) + 1 ) ) ; break ; case 'P' : fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) ) ) ; break ; case 'Q' : fprintf ( asm_out_file , "%d" , exact_log2 ( ~ INTVAL ( x ) ) ) ; break ; case 'O' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , INTVAL ( x ) ) ; break ; case 'M' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , - INTVAL ( x ) ) ; break ; case 'R' : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) + 1 ] , ( stream ) ) ; break ; case MEM : mcore_print_operand_address ( stream , XEXP ( adjust_address ( x , SImode , 4 ) , 0 ) ) ; break ; default : gcc_unreachable ( ) ; } break ; case 'U' : fprintf ( asm_out_file , "%s-%s" , reg_names [ REGNO ( x ) ] , reg_names [ REGNO ( x ) + 3 ] ) ; break ; case 'x' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_HEX , INTVAL ( x ) ) ; break ; case 'X' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , 3 - INTVAL ( x ) / 8 ) ; break ; default : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) ] , ( stream ) ) ; break ; case MEM : output_address ( XEXP ( x , 0 ) ) ; break ; default : output_addr_const ( stream , x ) ; break ; } break ; } } </s>

Print operand x ( an rtx ) in assembler syntax to file stream according to modifier code . ' R ' print the next register or memory location along , ie the lsw in a double word value ' O ' print a constant without the # 'M ' print a constant as its negative ' P ' print log2 of a power of two ' Q ' print log2 of an inverse of a power of two ' U ' print register for ldm/stm instruction ' X ' print byte number for xtrbN instruction .


<s> void mcore_print_operand_address ( FILE * stream , rtx x ) { switch ( GET_CODE ( x ) ) { case REG : fprintf ( stream , "(%s)" , reg_names [ REGNO ( x ) ] ) ; break ; case PLUS : { rtx base = XEXP ( x , 0 ) ; rtx index = XEXP ( x , 1 ) ; if ( GET_CODE ( base ) != REG ) { rtx temp = base ; base = index ; index = temp ; } switch ( GET_CODE ( index ) ) { case CONST_INT : fprintf ( stream , "(%s," HOST_WIDE_INT_PRINT_DEC ")" , reg_names [ REGNO ( base ) ] , INTVAL ( index ) ) ; break ; default : gcc_unreachable ( ) ; } } break ; default : output_addr_const ( stream , x ) ; break ; } } </s>

Print the operand address in x to the stream .


<s> enum reg_class mcore_reload_class ( rtx x , enum reg_class class ) { if ( reg_class_subset_p ( LRW_REGS , class ) && ! mcore_r15_operand_p ( x ) ) return LRW_REGS ; return class ; } </s>

Return the reg_class to use when reloading the rtx X into the class CLASS . If X is too complex to move directly into r15 , prefer to use LRW_REGS instead .


<s> static void mcore_reorg ( void ) { current_function_anonymous_args = 0 ; if ( saved_warn_return_type != - 1 ) { if ( -- saved_warn_return_type_count == 0 ) { warn_return_type = saved_warn_return_type ; saved_warn_return_type = - 1 ; } } if ( optimize == 0 ) return ; conditionalize_optimization ( ) ; } </s>

This is to handle loads from the constant pool .


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

Worker function for TARGET_RETURN_IN_MEMORY .


<s> enum reg_class mcore_secondary_reload_class ( enum reg_class class , enum machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { if ( TEST_HARD_REG_BIT ( reg_class_contents [ class ] , 15 ) && ! mcore_r15_operand_p ( x ) ) return LRW_REGS ; return NO_REGS ; } </s>

Implement SECONDARY_RELOAD_CLASS . If CLASS contains r15 , and we ca n't directly move X into it , use r1-r14 as a temporary .


<s> static void mcore_setup_incoming_varargs ( CUMULATIVE_ARGS * args_so_far , enum machine_mode mode , tree type , int * ptr_pretend_size ATTRIBUTE_UNUSED , int second_time ATTRIBUTE_UNUSED ) { current_function_anonymous_args = 1 ; number_of_regs_before_varargs = * args_so_far + mcore_num_arg_regs ( mode , type ) ; number_of_regs_before_varargs = * args_so_far ; if ( number_of_regs_before_varargs > NPARM_REGS ) number_of_regs_before_varargs = NPARM_REGS ; } </s>

Keep track of some information about varargs for the prolog .


<s> static void mcore_unique_section ( tree decl , int reloc ATTRIBUTE_UNUSED ) { int len ; const char * name ; char * string ; const char * prefix ; name = IDENTIFIER_POINTER ( DECL_ASSEMBLER_NAME ( decl ) ) ; name = ( * targetm . strip_name_encoding ) ( name ) ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) prefix = ".text$" ; else if ( decl_readonly_section ( decl , 0 ) ) prefix = ".rdata$" ; else prefix = ".data$" ; len = strlen ( name ) + strlen ( prefix ) ; string = alloca ( len + 1 ) ; sprintf ( string , "%s%s" , prefix , name ) ; DECL_SECTION_NAME ( decl ) = build_string ( len , string ) ; } </s>


<s>
static
const
char
*
output_inline_const
(
enum
machine_mode
mode
,
rtx
operands
[
]
)
{
int
x
=
0
,
y
=
0
;
int
trick_no
;
rtx
out_operands
[
3
]
;
char
buf
[
256
]
;
char
load_op
[
256
]
;
const
char
*
dst_fmt
;
int
value
;
value
=
INTVAL
(
operands
[
1
]
)
;
trick_no
=
try_constant_tricks
(
value
,
&
x
,
&
y
)
;
gcc_assert
(
trick_no
!=
0
)
;
if
(
trick_no
==
1
)
x
=
value
;
out_operands
[
0
]
=
operands
[
0
]
;
out_operands
[
1
]
=
GEN_INT
(
x
)
;
if
(
trick_no
>
2
)
out_operands
[
2
]
=
GEN_INT
(
y
)
;
if
(
mode
==
DImode
&&
(
!
TARGET_LITTLE_END
)
)
dst_fmt
=
"%R0"
;
else
dst_fmt
=
"%0"
;
if
(
x
>=
0
&&
x
<=
127
)
sprintf
(
load_op
,
"movi\t%s,%%1"
,
dst_fmt
)
;
else
if
(
(
x
&
(
x
1
)
)
==
0
)
sprintf
(
load_op
,
"bgeni\t%s,%%P1"
,
dst_fmt
)
;
else
if
(
(
x
&
(
x
+
1
)
)
==
0
)
sprintf
(
load_op
,
"bmaski\t%s,%%N1"
,
dst_fmt
)
;
else
sprintf
(
load_op
,
"BADMOVI\t%s,%%1"
,
dst_fmt
)
;
switch
(
trick_no
)
{
case
1
:
strcpy
(
buf
,
load_op
)
;
break
;
case
2
:
sprintf
(
buf
,
"%s\n\tnot\t%s\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
3
:
sprintf
(
buf
,
"%s\n\taddi\t%s,%%2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
4
:
sprintf
(
buf
,
"%s\n\tsubi\t%s,%%2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
5
:
sprintf
(
buf
,
"%s\n\trsubi\t%s,%%2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
6
:
sprintf
(
buf
,
"%s\n\tbseti\t%s,%%P2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
7
:
sprintf
(
buf
,
"%s\n\tbclri\t%s,%%Q2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
8
:
sprintf
(
buf
,
"%s\n\trotli\t%s,%%2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
9
:
sprintf
(
buf
,
"%s\n\tlsli\t%s,%%2\t// %d 0x%x"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
10
:
sprintf
(
buf
,
"%s\n\tixh\t%s,%s\t// %d 0x%x"
,
load_op
,
dst_fmt
,
dst_fmt
,
value
,
value
)
;
break
;
case
11
:
sprintf
(
buf
,
"%s\n\tixw\t%s,%s\t// %d 0x%x"
,
load_op
,
dst_fmt
,
dst_fmt
,
value
,
value
)
;
break
;
default
:
return
""
;
}
output_asm_insn
(
buf
,
out_operands
)
;
return
""
;
}
</s>


<s> static int try_constant_tricks ( long value , int * x , int * y ) { int i ; unsigned bit , shf , rot ; if ( const_ok_for_mcore ( value ) ) return 1 ; if ( TARGET_HARDLIT ) { if ( const_ok_for_mcore ( ~ value ) ) { * x = ~ value ; return 2 ; } for ( i = 1 ; i <= 32 ; i ++ ) { if ( const_ok_for_mcore ( value - i ) ) { * x = value - i ; * y = i ; return 3 ; } if ( const_ok_for_mcore ( value + i ) ) { * x = value + i ; * y = i ; return 4 ; } } bit = 0x80000000L ; for ( i = 0 ; i <= 31 ; i ++ ) { if ( const_ok_for_mcore ( i - value ) ) { * x = i - value ; * y = i ; return 5 ; } if ( const_ok_for_mcore ( value & ~ bit ) ) { * y = bit ; * x = value & ~ bit ; return 6 ; } if ( const_ok_for_mcore ( value | bit ) ) { * y = ~ bit ; * x = value | bit ; return 7 ; } bit >>= 1 ; } shf = value ; rot = value ; for ( i = 1 ; i < 31 ; i ++ ) { int c ; c = rot << 31 ; rot >>= 1 ; rot &= 0x7FFFFFFF ; rot |= c ; if ( const_ok_for_mcore ( rot ) ) { * y = i ; * x = rot ; return 8 ; } if ( shf & 1 ) shf = 0 ; shf >>= 1 ; if ( shf != 0 && const_ok_for_mcore ( shf ) ) { * y = i ; * x = shf ; return 9 ; } } if ( ( value % 3 ) == 0 && const_ok_for_mcore ( value / 3 ) ) { * x = value / 3 ; return 10 ; } if ( ( value % 5 ) == 0 && const_ok_for_mcore ( value / 5 ) ) { * x = value / 5 ; return 11 ; } } return 0 ; } </s>

Try tricks to load a constant inline and return the trick number if success ( 0 is non-inlinable ) . 0 : not inlinable 1 : single instruction ( do the usual thing ) 2 : single insn followed by a 'not ' 3 : single insn followed by a subi 4 : single insn followed by an addi 5 : single insn followed by rsubi 6 : single insn followed by bseti 7 : single insn followed by bclri 8 : single insn followed by rotli 9 : single insn followed by lsli 10 : single insn followed by ixh 11 : single insn followed by ixw .


<s> static void block_move_sequence ( rtx dst_mem , rtx src_mem , int size , int align ) { rtx temp [ 2 ] ; machine_mode mode [ 2 ] ; int amount [ 2 ] ; bool active [ 2 ] ; int phase = 0 ; int next ; int offset_ld = 0 ; int offset_st = 0 ; rtx x ; x = XEXP ( dst_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; dst_mem = replace_equiv_address ( dst_mem , x ) ; } x = XEXP ( src_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; src_mem = replace_equiv_address ( src_mem , x ) ; } active [ 0 ] = active [ 1 ] = false ; do { next = phase ; phase ^= 1 ; if ( size > 0 ) { int next_amount ; next_amount = ( size >= 4 ? 4 : ( size >= 2 ? 2 : 1 ) ) ; next_amount = MIN ( next_amount , align ) ; amount [ next ] = next_amount ; mode [ next ] = mode_from_align [ next_amount ] ; temp [ next ] = gen_reg_rtx ( mode [ next ] ) ; x = adjust_address ( src_mem , mode [ next ] , offset_ld ) ; emit_insn ( gen_rtx_SET ( VOIDmode , temp [ next ] , x ) ) ; offset_ld += next_amount ; size -= next_amount ; active [ next ] = true ; } if ( active [ phase ] ) { active [ phase ] = false ; x = adjust_address ( dst_mem , mode [ phase ] , offset_st ) ; emit_insn ( gen_rtx_SET ( VOIDmode , x , temp [ phase ] ) ) ; offset_st += amount [ phase ] ; } } while ( active [ next ] ) ; } </s>

Emit code to perform a block move with an offset sequence of ld/st instructions ( ... , ld 0 , st 1 , ld 1 , st 0 , ... ) . SIZE and ALIGN are known constants . DEST and SRC are registers . OFFSET is the known starting point for the output pattern .


<s> static int calc_live_regs ( int * count ) { int reg ; int live_regs_mask = 0 ; * count = 0 ; for ( reg = 0 ; reg < FIRST_PSEUDO_REGISTER ; reg ++ ) { if ( df_regs_ever_live_p ( reg ) && ! call_used_regs [ reg ] ) { ( * count ) ++ ; live_regs_mask |= ( 1 << reg ) ; } } return live_regs_mask ; } </s>

Work out the registers which need to be saved , both as a mask and a count


<s> static rtx_insn * emit_new_cond_insn ( rtx insn , int cond ) { rtx c_insn = 0 ; rtx pat , dst , src ; cond_type num ; if ( ( num = is_cond_candidate ( insn ) ) == COND_NO ) return NULL ; pat = PATTERN ( insn ) ; if ( NONJUMP_INSN_P ( insn ) ) { dst = SET_DEST ( pat ) ; src = SET_SRC ( pat ) ; } else { dst = JUMP_LABEL ( insn ) ; src = NULL_RTX ; } switch ( num ) { case COND_MOV_INSN : case COND_CLR_INSN : if ( cond ) c_insn = gen_movt0 ( dst , src , dst ) ; else c_insn = gen_movt0 ( dst , dst , src ) ; break ; case COND_INC_INSN : if ( cond ) c_insn = gen_incscc ( dst , dst ) ; else c_insn = gen_incscc_false ( dst , dst ) ; break ; case COND_DEC_INSN : if ( cond ) c_insn = gen_decscc ( dst , dst ) ; else c_insn = gen_decscc_false ( dst , dst ) ; break ; case COND_BRANCH_INSN : if ( cond ) c_insn = gen_branch_true ( dst ) ; else c_insn = gen_branch_false ( dst ) ; break ; default : return NULL ; } if ( rtx_length [ GET_CODE ( c_insn ) ] >= 7 && rtx_length [ GET_CODE ( insn ) ] >= 7 ) { REG_NOTES ( c_insn ) = REG_NOTES ( insn ) ; } if ( num == COND_BRANCH_INSN ) { c_insn = emit_jump_insn_before ( c_insn , insn ) ; ++ LABEL_NUSES ( dst ) ; JUMP_LABEL ( c_insn ) = dst ; } else c_insn = emit_insn_after ( c_insn , insn ) ; delete_insn ( insn ) ; return as_a < rtx_insn * > ( c_insn ) ; } </s>

Emit a conditional version of insn and replace the old insn with the new one . Return the new insn if emitted .


<s> static int mcore_arg_partial_bytes ( cumulative_args_t cum , machine_mode mode , tree type , bool named ) { int reg = ROUND_REG ( * get_cumulative_args ( cum ) , mode ) ; if ( named == 0 ) return 0 ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; if ( reg >= NPARM_REGS ) return 0 ; if ( reg + mcore_num_arg_regs ( mode , type ) <= NPARM_REGS ) return 0 ; reg = NPARM_REGS - reg ; return reg * UNITS_PER_WORD ; } </s>

Returns the number of bytes of argument registers required to hold * part * of a parameter of machine mode MODE and type TYPE ( which may be NULL if the type is not known ) . If the argument fits entirely in the argument registers , or entirely on the stack , then 0 is returned . CUM is the number of argument registers already used by earlier parameters to the function .


<s> int mcore_expand_insv ( rtx operands [ ] ) { int width = INTVAL ( operands [ 1 ] ) ; int posn = INTVAL ( operands [ 2 ] ) ; int mask ; rtx mreg , sreg , ereg ; if ( width == 1 && GET_CODE ( operands [ 3 ] ) == CONST_INT ) { if ( ( INTVAL ( operands [ 3 ] ) & 1 ) == 0 ) { mask = ~ ( 1 << posn ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } else { mask = 1 << posn ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } return 1 ; } if ( ! TARGET_W_FIELD ) return 0 ; if ( width == 8 && posn % 8 == 0 ) return 0 ; if ( width == 16 && posn % 16 == 0 ) return 0 ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == ( ( 1 << width ) - 1 ) ) { mreg = force_reg ( SImode , GEN_INT ( INTVAL ( operands [ 3 ] ) << posn ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , mreg ) ) ) ; return 1 ; } mreg = force_reg ( SImode , GEN_INT ( ~ ( ( ( 1 << width ) - 1 ) << posn ) ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , mreg ) ) ) ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == 0 ) return 1 ; sreg = copy_to_mode_reg ( SImode , operands [ 3 ] ) ; if ( width + posn != ( int ) GET_MODE_SIZE ( SImode ) ) { ereg = force_reg ( SImode , GEN_INT ( ( 1 << width ) - 1 ) ) ; emit_insn ( gen_rtx_SET ( SImode , sreg , gen_rtx_AND ( SImode , sreg , ereg ) ) ) ; } if ( posn != 0 ) emit_insn ( gen_rtx_SET ( SImode , sreg , gen_rtx_ASHIFT ( SImode , sreg , GEN_INT ( posn ) ) ) ) ; emit_insn ( gen_rtx_SET ( SImode , operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , sreg ) ) ) ; return 1 ; } </s>


<s> static rtx mcore_function_arg ( cumulative_args_t cum , machine_mode mode , const_tree type , bool named ) { int arg_reg ; if ( ! named || mode == VOIDmode ) return 0 ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; arg_reg = ROUND_REG ( * get_cumulative_args ( cum ) , mode ) ; if ( arg_reg < NPARM_REGS ) return handle_structs_in_regs ( mode , type , FIRST_PARM_REG + arg_reg ) ; return 0 ; } </s>

Define where to put the arguments to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) . On MCore the first args are normally in registers and the rest are pushed . Any arg that starts within the first NPARM_REGS words is at least partially passed in a register unless its data type forbids .


<s> bool mcore_gen_compare ( enum rtx_code code , rtx op0 , rtx op1 ) { rtx cc_reg = gen_rtx_REG ( CCmode , CC_REG ) ; bool invert ; if ( GET_CODE ( op1 ) == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( op1 ) ; switch ( code ) { case GTU : if ( val == 0 ) code = NE ; break ; case GT : case LE : if ( CONST_OK_FOR_J ( val + 1 ) ) { op1 = GEN_INT ( val + 1 ) ; code = code == LE ? LT : GE ; } break ; default : break ; } } if ( CONSTANT_P ( op1 ) && GET_CODE ( op1 ) != CONST_INT ) op1 = force_reg ( SImode , op1 ) ; invert = false ; switch ( code ) { case EQ : code = NE ; invert = true ; case NE : if ( GET_CODE ( op1 ) == CONST_INT && ! CONST_OK_FOR_K ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case LE : code = GT ; invert = true ; case GT : if ( GET_CODE ( op1 ) == CONST_INT ) op1 = force_reg ( SImode , op1 ) ; break ; case GE : code = LT ; invert = true ; case LT : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 && ! CONST_OK_FOR_J ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case GTU : gcc_assert ( GET_CODE ( op1 ) != CONST_INT || INTVAL ( op1 ) != 0 ) ; code = LEU ; invert = true ; case LEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; case LTU : code = GEU ; invert = true ; case GEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; default : break ; } emit_insn ( gen_rtx_SET ( VOIDmode , cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return invert ; } </s>

Prepare the operands for a comparison . Return whether the branch/setcc should reverse the operands .


<s> int mcore_num_arg_regs ( machine_mode mode , const_tree type ) { int size ; if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return 0 ; if ( type && mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; return ROUND_ADVANCE ( size ) ; } </s>

Compute the number of word sized registers needed to hold a function argument of mode MODE and type TYPE .


<s>
const
char
*
mcore_output_move
(
rtx
insn
ATTRIBUTE_UNUSED
,
rtx
operands
[
]
,
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
if
(
GET_CODE
(
dst
)
==
REG
)
{
if
(
GET_CODE
(
src
)
==
REG
)
{
if
(
REGNO
(
src
)
==
CC_REG
)
return
"mvc\t%0"
;
else
return
"mov\t%0,%1"
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
if
(
GET_CODE
(
XEXP
(
src
,
0
)
)
==
LABEL_REF
)
return
"lrw\t%0,[%1]"
;
else
switch
(
GET_MODE
(
src
)
)
{
case
SImode
:
return
"ldw\t%0,%1"
;
case
HImode
:
return
"ld.h\t%0,%1"
;
case
QImode
:
return
"ld.b\t%0,%1"
;
default
:
gcc_unreachable
(
)
;
}
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
HOST_WIDE_INT
x
,
y
;
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
return
"movi\t%0,%1"
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
return
"bgeni\t%0,%P1\t// %1 %x1"
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
return
"bmaski\t%0,%N1\t// %1 %x1"
;
else
if
(
try_constant_tricks
(
INTVAL
(
src
)
,
&
x
,
&
y
)
)
return
output_inline_const
(
SImode
,
operands
)
;
else
return
"lrw\t%0,%x1\t// %1"
;
}
else
return
"lrw\t%0, %1"
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
)
switch
(
GET_MODE
(
dst
)
)
{
case
SImode
:
return
"stw\t%1,%0"
;
case
HImode
:
return
"st.h\t%1,%0"
;
case
QImode
:
return
"st.b\t%1,%0"
;
default
:
gcc_unreachable
(
)
;
}
gcc_unreachable
(
)
;
}
</s>


<s> static void mcore_print_operand ( FILE * stream , rtx x , int code ) { switch ( code ) { case 'N' : if ( INTVAL ( x ) == - 1 ) fprintf ( asm_out_file , "32" ) ; else fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) + 1 ) ) ; break ; case 'P' : fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) & 0xffffffff ) ) ; break ; case 'Q' : fprintf ( asm_out_file , "%d" , exact_log2 ( ~ INTVAL ( x ) ) ) ; break ; case 'O' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , INTVAL ( x ) ) ; break ; case 'M' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , - INTVAL ( x ) ) ; break ; case 'R' : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) + 1 ] , ( stream ) ) ; break ; case MEM : mcore_print_operand_address ( stream , XEXP ( adjust_address ( x , SImode , 4 ) , 0 ) ) ; break ; default : gcc_unreachable ( ) ; } break ; case 'U' : fprintf ( asm_out_file , "%s-%s" , reg_names [ REGNO ( x ) ] , reg_names [ REGNO ( x ) + 3 ] ) ; break ; case 'x' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_HEX , INTVAL ( x ) ) ; break ; case 'X' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , 3 - INTVAL ( x ) / 8 ) ; break ; default : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) ] , ( stream ) ) ; break ; case MEM : output_address ( XEXP ( x , 0 ) ) ; break ; default : output_addr_const ( stream , x ) ; break ; } break ; } } </s>


<s> static void mcore_print_operand_address ( FILE * stream , rtx x ) { switch ( GET_CODE ( x ) ) { case REG : fprintf ( stream , "(%s)" , reg_names [ REGNO ( x ) ] ) ; break ; case PLUS : { rtx base = XEXP ( x , 0 ) ; rtx index = XEXP ( x , 1 ) ; if ( GET_CODE ( base ) != REG ) { rtx temp = base ; base = index ; index = temp ; } switch ( GET_CODE ( index ) ) { case CONST_INT : fprintf ( stream , "(%s," HOST_WIDE_INT_PRINT_DEC ")" , reg_names [ REGNO ( base ) ] , INTVAL ( index ) ) ; break ; default : gcc_unreachable ( ) ; } } break ; default : output_addr_const ( stream , x ) ; break ; } } </s>


<s> static void block_move_sequence ( rtx dst_mem , rtx src_mem , int size , int align ) { rtx temp [ 2 ] ; machine_mode mode [ 2 ] ; int amount [ 2 ] ; bool active [ 2 ] ; int phase = 0 ; int next ; int offset_ld = 0 ; int offset_st = 0 ; rtx x ; x = XEXP ( dst_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; dst_mem = replace_equiv_address ( dst_mem , x ) ; } x = XEXP ( src_mem , 0 ) ; if ( ! REG_P ( x ) ) { x = force_reg ( Pmode , x ) ; src_mem = replace_equiv_address ( src_mem , x ) ; } active [ 0 ] = active [ 1 ] = false ; do { next = phase ; phase ^= 1 ; if ( size > 0 ) { int next_amount ; next_amount = ( size >= 4 ? 4 : ( size >= 2 ? 2 : 1 ) ) ; next_amount = MIN ( next_amount , align ) ; amount [ next ] = next_amount ; mode [ next ] = mode_from_align [ next_amount ] ; temp [ next ] = gen_reg_rtx ( mode [ next ] ) ; x = adjust_address ( src_mem , mode [ next ] , offset_ld ) ; emit_insn ( gen_rtx_SET ( temp [ next ] , x ) ) ; offset_ld += next_amount ; size -= next_amount ; active [ next ] = true ; } if ( active [ phase ] ) { active [ phase ] = false ; x = adjust_address ( dst_mem , mode [ phase ] , offset_st ) ; emit_insn ( gen_rtx_SET ( x , temp [ phase ] ) ) ; offset_st += amount [ phase ] ; } } while ( active [ next ] ) ; } </s>


<s> static int calc_live_regs ( int * count ) { int reg ; int live_regs_mask = 0 ; * count = 0 ; for ( reg = 0 ; reg < FIRST_PSEUDO_REGISTER ; reg ++ ) { if ( df_regs_ever_live_p ( reg ) && ! call_used_or_fixed_reg_p ( reg ) ) { ( * count ) ++ ; live_regs_mask |= ( 1 << reg ) ; } } return live_regs_mask ; } </s>


<s> static rtx_insn * conditionalize_block ( rtx_insn * first ) { rtx_insn * insn ; rtx br_pat ; rtx_insn * end_blk_1_br = 0 ; rtx_insn * end_blk_2_insn = 0 ; rtx_insn * start_blk_3_lab = 0 ; int cond ; int br_lab_num ; int blk_size = 0 ; if ( ! JUMP_P ( first ) || GET_CODE ( PATTERN ( first ) ) != SET || GET_CODE ( XEXP ( PATTERN ( first ) , 1 ) ) != IF_THEN_ELSE ) return NEXT_INSN ( first ) ; end_blk_1_br = first ; br_pat = PATTERN ( end_blk_1_br ) ; cond = ( GET_CODE ( XEXP ( XEXP ( br_pat , 1 ) , 0 ) ) == EQ ) ; if ( GET_CODE ( XEXP ( XEXP ( br_pat , 1 ) , 1 ) ) == LABEL_REF ) { br_lab_num = CODE_LABEL_NUMBER ( XEXP ( XEXP ( XEXP ( br_pat , 1 ) , 1 ) , 0 ) ) ; } else { cond = ( cond == 0 ) ; br_lab_num = CODE_LABEL_NUMBER ( XEXP ( XEXP ( XEXP ( br_pat , 1 ) , 2 ) , 0 ) ) ; } for ( insn = NEXT_INSN ( first ) ; insn ; insn = NEXT_INSN ( insn ) ) { enum rtx_code code ; code = GET_CODE ( insn ) ; if ( code == CODE_LABEL && CODE_LABEL_NUMBER ( insn ) == br_lab_num ) break ; if ( code != BARRIER && code != NOTE && ! is_cond_candidate ( insn ) ) return NEXT_INSN ( insn ) ; if ( code == JUMP_INSN || code == INSN ) { blk_size ++ ; end_blk_2_insn = insn ; } } if ( ! insn ) return insn ; if ( optimize > 1 && blk_size > 2 ) return insn ; start_blk_3_lab = insn ; for ( insn = NEXT_INSN ( end_blk_1_br ) ; insn != start_blk_3_lab ; insn = NEXT_INSN ( insn ) ) { rtx_insn * newinsn ; if ( insn -> deleted ( ) ) continue ; if ( ( newinsn = emit_new_cond_insn ( insn , cond ) ) ) { if ( end_blk_2_insn == insn ) end_blk_2_insn = newinsn ; insn = newinsn ; } } if ( LABEL_NUSES ( start_blk_3_lab ) == 1 ) { start_blk_3_lab = 0 ; } delete_insn ( end_blk_1_br ) ; if ( ! start_blk_3_lab ) return end_blk_2_insn ; return NEXT_INSN ( start_blk_3_lab ) ; } </s>

Attempt to change a basic block into a series of conditional insns . This works by taking the branch at the end of the 1st block and scanning for the end of the 2nd block . If all instructions in the 2nd block have cond . versions and the label at the start of block 3 is the same as the target from the branch at block 1 , then conditionalize all insn in block 2 using the inverse condition of the branch at block 1 . ( Note I 'm bending the definition of basic block here . ) e.g. , change : bt L2 < -- end of block 1 ( delete ) mov r7 , r8 addu r7,1 br L3 < -- end of block 2 L2 : ... < -- start of block 3 ( NUSES==1 ) L3 : ... to : movf r7 , r8 incf r7 bf L3 L3 : ... we can delete the L2 label if NUSES==1 and re-apply the optimization starting at the last instruction of block 2 . This may allow an entire if-then-else statement to be conditionalized . BRC


<s> static void conditionalize_optimization ( void ) { rtx_insn * insn ; for ( insn = get_insns ( ) ; insn ; insn = conditionalize_block ( insn ) ) continue ; } </s>

Apply the conditionalization of blocks optimization . This is the outer loop that traverses through the insns scanning for a branch that signifies an opportunity to apply the optimization . Note that this optimization is applied late . If we could apply it earlier , say before cse 2 , it may expose more optimization opportunities . but , the pay back probably is n't really worth the effort ( we 'd have to update all reg/flow/notes/links/etc to make it work - and stick it in before cse 2 ) .


<s> static rtx_insn * emit_new_cond_insn ( rtx_insn * insn , int cond ) { rtx c_insn = 0 ; rtx pat , dst , src ; cond_type num ; if ( ( num = is_cond_candidate ( insn ) ) == COND_NO ) return NULL ; pat = PATTERN ( insn ) ; if ( NONJUMP_INSN_P ( insn ) ) { dst = SET_DEST ( pat ) ; src = SET_SRC ( pat ) ; } else { dst = JUMP_LABEL ( insn ) ; src = NULL_RTX ; } switch ( num ) { case COND_MOV_INSN : case COND_CLR_INSN : if ( cond ) c_insn = gen_movt0 ( dst , src , dst ) ; else c_insn = gen_movt0 ( dst , dst , src ) ; break ; case COND_INC_INSN : if ( cond ) c_insn = gen_incscc ( dst , dst ) ; else c_insn = gen_incscc_false ( dst , dst ) ; break ; case COND_DEC_INSN : if ( cond ) c_insn = gen_decscc ( dst , dst ) ; else c_insn = gen_decscc_false ( dst , dst ) ; break ; case COND_BRANCH_INSN : if ( cond ) c_insn = gen_branch_true ( dst ) ; else c_insn = gen_branch_false ( dst ) ; break ; default : return NULL ; } if ( rtx_length [ GET_CODE ( c_insn ) ] >= 7 && rtx_length [ GET_CODE ( insn ) ] >= 7 ) { REG_NOTES ( c_insn ) = REG_NOTES ( insn ) ; } if ( num == COND_BRANCH_INSN ) { c_insn = emit_jump_insn_before ( c_insn , insn ) ; ++ LABEL_NUSES ( dst ) ; JUMP_LABEL ( c_insn ) = dst ; } else c_insn = emit_insn_after ( c_insn , insn ) ; delete_insn ( insn ) ; return as_a < rtx_insn * > ( c_insn ) ; } </s>


<s> static cond_type is_cond_candidate ( rtx insn ) { if ( NONJUMP_INSN_P ( insn ) ) { rtx pat = PATTERN ( insn ) ; rtx src , dst ; if ( GET_CODE ( pat ) != SET ) return COND_NO ; dst = XEXP ( pat , 0 ) ; if ( ( GET_CODE ( dst ) != REG && GET_CODE ( dst ) != SUBREG ) || GET_MODE ( dst ) != SImode ) return COND_NO ; src = XEXP ( pat , 1 ) ; if ( ( GET_CODE ( src ) == REG || ( GET_CODE ( src ) == SUBREG && GET_CODE ( SUBREG_REG ( src ) ) == REG ) ) && GET_MODE ( src ) == SImode ) return COND_MOV_INSN ; else if ( GET_CODE ( src ) == CONST_INT && INTVAL ( src ) == 0 ) return COND_CLR_INSN ; else if ( GET_CODE ( src ) == PLUS && ( GET_CODE ( XEXP ( src , 0 ) ) == REG || ( GET_CODE ( XEXP ( src , 0 ) ) == SUBREG && GET_CODE ( SUBREG_REG ( XEXP ( src , 0 ) ) ) == REG ) ) && GET_MODE ( XEXP ( src , 0 ) ) == SImode && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == 1 ) return COND_INC_INSN ; else if ( ( ( GET_CODE ( src ) == MINUS && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == 1 ) || ( GET_CODE ( src ) == PLUS && GET_CODE ( XEXP ( src , 1 ) ) == CONST_INT && INTVAL ( XEXP ( src , 1 ) ) == - 1 ) ) && ( GET_CODE ( XEXP ( src , 0 ) ) == REG || ( GET_CODE ( XEXP ( src , 0 ) ) == SUBREG && GET_CODE ( SUBREG_REG ( XEXP ( src , 0 ) ) ) == REG ) ) && GET_MODE ( XEXP ( src , 0 ) ) == SImode ) return COND_DEC_INSN ; } else if ( JUMP_P ( insn ) && GET_CODE ( PATTERN ( insn ) ) == SET && GET_CODE ( XEXP ( PATTERN ( insn ) , 1 ) ) == LABEL_REF ) return COND_BRANCH_INSN ; return COND_NO ; } </s>

Check whether insn is a candidate for a conditional .


<s> static int mcore_and_cost ( rtx x ) { HOST_WIDE_INT val ; if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) return 2 ; val = INTVAL ( XEXP ( x , 1 ) ) ; if ( CONST_OK_FOR_K ( val ) || CONST_OK_FOR_M ( ~ val ) ) return 2 ; else if ( const_ok_for_mcore ( val ) ) return 3 ; else if ( TARGET_HARDLIT && mcore_const_ok_for_inline ( val ) ) return 4 ; return 5 ; } </s>

What does an and instruction cost - we do this b/c immediates may have been relaxed . We want to ensure that cse will cse relaxed immeds out . Otherwise we 'll get bad code ( multiple reloads of the same const ) .


<s> static int mcore_arg_partial_bytes ( cumulative_args_t cum , const function_arg_info & arg ) { int reg = ROUND_REG ( * get_cumulative_args ( cum ) , arg . mode ) ; if ( ! arg . named ) return 0 ; if ( targetm . calls . must_pass_in_stack ( arg ) ) return 0 ; if ( reg >= NPARM_REGS ) return 0 ; if ( reg + mcore_num_arg_regs ( arg . mode , arg . type ) <= NPARM_REGS ) return 0 ; reg = NPARM_REGS - reg ; return reg * UNITS_PER_WORD ; } </s>


<s> int mcore_arith_S_operand ( rtx op ) { if ( GET_CODE ( op ) == CONST_INT && CONST_OK_FOR_M ( ~ INTVAL ( op ) ) ) return 1 ; return 0 ; } </s>


<s>
static
void
mcore_asm_trampoline_template
(
FILE
*
f
)
{
fprintf
(
f
,
"\t.short	0x7102\n"
)
;
fprintf
(
f
,
"\t.short	0x7d02\n"
)
;
fprintf
(
f
,
"\t.short	0x00cd\n"
)
;
fprintf
(
f
,
"\t.short	0x1e00\n"
)
;
fprintf
(
f
,
"\t.long	0\n"
)
;
fprintf
(
f
,
"\t.long	0\n"
)
;
}
</s>

Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE . Output assembler code for a block containing the constant parts of a trampoline , leaving space for the variable parts . On the MCore , the trampoline looks like : lrw r1 , function lrw r13 , area jmp r13 or r0 , r0 .literals

mcore
"\t.short	0x7102\n"
"\t.short	0x7d02\n"
"\t.short	0x00cd\n"
"\t.short	0x1e00\n"
"\t.long	0\n"
"\t.long	0\n"


<s> int mcore_byte_offset ( unsigned int mask ) { if ( mask == 0x00ffffffL ) return 0 ; else if ( mask == 0xff00ffffL ) return 1 ; else if ( mask == 0xffff00ffL ) return 2 ; else if ( mask == 0xffffff00L ) return 3 ; return - 1 ; } </s>


<s> int mcore_dllexport_name_p ( const char * symbol ) { return symbol [ 0 ] == '@' && symbol [ 1 ] == 'e' && symbol [ 2 ] == '.' ; } </s>

Return non-zero if SYMBOL is marked as being dllexport 'd .


<s> int mcore_dllimport_name_p ( const char * symbol ) { return symbol [ 0 ] == '@' && symbol [ 1 ] == 'i' && symbol [ 2 ] == '.' ; } </s>

Return non-zero if SYMBOL is marked as being dllimport 'd .


<s> static void mcore_encode_section_info ( tree decl , rtx rtl ATTRIBUTE_UNUSED , int first ATTRIBUTE_UNUSED ) { if ( mcore_dllexport_p ( decl ) ) mcore_mark_dllexport ( decl ) ; else if ( mcore_dllimport_p ( decl ) ) mcore_mark_dllimport ( decl ) ; else if ( ( TREE_CODE ( decl ) == FUNCTION_DECL || TREE_CODE ( decl ) == VAR_DECL ) && DECL_RTL ( decl ) != NULL_RTX && GET_CODE ( DECL_RTL ( decl ) ) == MEM && GET_CODE ( XEXP ( DECL_RTL ( decl ) , 0 ) ) == MEM && GET_CODE ( XEXP ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) ) == SYMBOL_REF && mcore_dllimport_name_p ( XSTR ( XEXP ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) , 0 ) ) ) { const char * oldname = XSTR ( XEXP ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) , 0 ) ; tree idp = get_identifier ( oldname + 9 ) ; rtx newrtl = gen_rtx_SYMBOL_REF ( Pmode , IDENTIFIER_POINTER ( idp ) ) ; XEXP ( DECL_RTL ( decl ) , 0 ) = newrtl ; } } </s>

Cover function to implement ENCODE_SECTION_INFO .


<s> int mcore_expand_insv ( rtx operands [ ] ) { int width = INTVAL ( operands [ 1 ] ) ; int posn = INTVAL ( operands [ 2 ] ) ; int mask ; rtx mreg , sreg , ereg ; if ( width == 1 && GET_CODE ( operands [ 3 ] ) == CONST_INT ) { if ( ( INTVAL ( operands [ 3 ] ) & 1 ) == 0 ) { mask = ~ ( 1 << posn ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } else { mask = 1 << posn ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , GEN_INT ( mask ) ) ) ) ; } return 1 ; } if ( ! TARGET_W_FIELD ) return 0 ; if ( width == 8 && posn % 8 == 0 ) return 0 ; if ( width == 16 && posn % 16 == 0 ) return 0 ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == ( ( 1 << width ) - 1 ) ) { mreg = force_reg ( SImode , GEN_INT ( INTVAL ( operands [ 3 ] ) << posn ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , mreg ) ) ) ; return 1 ; } mreg = force_reg ( SImode , GEN_INT ( ~ ( ( ( 1 << width ) - 1 ) << posn ) ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_AND ( SImode , operands [ 0 ] , mreg ) ) ) ; if ( GET_CODE ( operands [ 3 ] ) == CONST_INT && INTVAL ( operands [ 3 ] ) == 0 ) return 1 ; sreg = copy_to_mode_reg ( SImode , operands [ 3 ] ) ; if ( width + posn != ( int ) GET_MODE_SIZE ( SImode ) ) { ereg = force_reg ( SImode , GEN_INT ( ( 1 << width ) - 1 ) ) ; emit_insn ( gen_rtx_SET ( sreg , gen_rtx_AND ( SImode , sreg , ereg ) ) ) ; } if ( posn != 0 ) emit_insn ( gen_rtx_SET ( sreg , gen_rtx_ASHIFT ( SImode , sreg , GEN_INT ( posn ) ) ) ) ; emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_IOR ( SImode , operands [ 0 ] , sreg ) ) ) ; return 1 ; } </s>


<s> static void mcore_external_libcall ( rtx fun ) { fprintf ( asm_out_file , "\t.import\t" ) ; assemble_name ( asm_out_file , XSTR ( fun , 0 ) ) ; fprintf ( asm_out_file , "\n" ) ; } </s>

Worker function for TARGET_ASM_EXTERNAL_LIBCALL .


<s> static rtx mcore_function_arg ( cumulative_args_t cum , const function_arg_info & arg ) { int arg_reg ; if ( ! arg . named || arg . end_marker_p ( ) ) return 0 ; if ( targetm . calls . must_pass_in_stack ( arg ) ) return 0 ; arg_reg = ROUND_REG ( * get_cumulative_args ( cum ) , arg . mode ) ; if ( arg_reg < NPARM_REGS ) return handle_structs_in_regs ( arg . mode , arg . type , FIRST_PARM_REG + arg_reg ) ; return 0 ; } </s>


<s> bool mcore_gen_compare ( enum rtx_code code , rtx op0 , rtx op1 ) { rtx cc_reg = gen_rtx_REG ( CCmode , CC_REG ) ; bool invert ; if ( GET_CODE ( op1 ) == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( op1 ) ; switch ( code ) { case GTU : if ( val == 0 ) code = NE ; break ; case GT : case LE : if ( CONST_OK_FOR_J ( val + 1 ) ) { op1 = GEN_INT ( val + 1 ) ; code = code == LE ? LT : GE ; } break ; default : break ; } } if ( CONSTANT_P ( op1 ) && GET_CODE ( op1 ) != CONST_INT ) op1 = force_reg ( SImode , op1 ) ; invert = false ; switch ( code ) { case EQ : code = NE ; invert = true ; case NE : if ( GET_CODE ( op1 ) == CONST_INT && ! CONST_OK_FOR_K ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case LE : code = GT ; invert = true ; case GT : if ( GET_CODE ( op1 ) == CONST_INT ) op1 = force_reg ( SImode , op1 ) ; break ; case GE : code = LT ; invert = true ; case LT : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 && ! CONST_OK_FOR_J ( INTVAL ( op1 ) ) ) op1 = force_reg ( SImode , op1 ) ; break ; case GTU : gcc_assert ( GET_CODE ( op1 ) != CONST_INT || INTVAL ( op1 ) != 0 ) ; code = LEU ; invert = true ; case LEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; case LTU : code = GEU ; invert = true ; case GEU : if ( GET_CODE ( op1 ) == CONST_INT && INTVAL ( op1 ) != 0 ) op1 = force_reg ( SImode , op1 ) ; break ; default : break ; } emit_insn ( gen_rtx_SET ( cc_reg , gen_rtx_fmt_ee ( code , CCmode , op0 , op1 ) ) ) ; return invert ; } </s>


<s> int mcore_halfword_offset ( unsigned int mask ) { if ( mask == 0x0000ffffL ) return 0 ; else if ( mask == 0xffff0000L ) return 1 ; return - 1 ; } </s>


"%qE attribute only applies to functions"

Handle a `` naked '' attribute ; arguments as in struct attribute_spec.handler .


<s> static bool mcore_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( TARGET_8ALIGN && GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return ( regno & 1 ) == 0 ; return regno < 18 ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . We may keep double values in even registers .


<s> int mcore_initial_elimination_offset ( int from , int to ) { int above_frame ; int below_frame ; struct mcore_frame fi ; layout_mcore_frame ( & fi ) ; above_frame = fi . local_size + fi . pad_local + fi . reg_size + fi . pad_reg ; below_frame = fi . outbound_size + fi . pad_outbound ; if ( from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM ) return above_frame ; if ( from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) return above_frame + below_frame ; if ( from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) return below_frame ; gcc_unreachable ( ) ; } </s>

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


<s> static int mcore_ior_cost ( rtx x ) { HOST_WIDE_INT val ; if ( GET_CODE ( XEXP ( x , 1 ) ) != CONST_INT ) return 2 ; val = INTVAL ( XEXP ( x , 1 ) ) ; if ( CONST_OK_FOR_M ( val ) ) return 2 ; else if ( const_ok_for_mcore ( val ) ) return 3 ; else if ( TARGET_HARDLIT && mcore_const_ok_for_inline ( val ) ) return 4 ; return 5 ; } </s>

What does an or cost - see and_cost ( ) .


<s> int mcore_is_dead ( rtx_insn * first , rtx reg ) { rtx_insn * insn ; if ( GET_CODE ( reg ) == SUBREG ) reg = SUBREG_REG ( reg ) ; if ( dead_or_set_p ( first , reg ) ) return 1 ; for ( insn = NEXT_INSN ( first ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) ) return 0 ; else if ( CALL_P ( insn ) ) { if ( reg_referenced_p ( reg , PATTERN ( insn ) ) || find_reg_fusage ( insn , USE , reg ) ) return 0 ; else if ( dead_or_set_p ( insn , reg ) ) return 1 ; } else if ( NONJUMP_INSN_P ( insn ) ) { if ( reg_referenced_p ( reg , PATTERN ( insn ) ) ) return 0 ; else if ( dead_or_set_p ( insn , reg ) ) return 1 ; } } return 0 ; } </s>

Check whether reg is dead at first . This is done by searching ahead for either the next use ( i.e. , reg is live ) , a death note , or a set of reg . Do n't just use dead_or_set_p ( ) since reload does not always mark deaths ( especially if PRESERVE_DEATH_NOTES_REGNO_P is not defined ) . We can ignore subregs by extracting the actual register . BRC


<s> int mcore_is_same_reg ( rtx x , rtx y ) { while ( GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; while ( GET_CODE ( y ) == SUBREG ) y = SUBREG_REG ( y ) ; if ( GET_CODE ( x ) == REG && GET_CODE ( y ) == REG && REGNO ( x ) == REGNO ( y ) ) return 1 ; return 0 ; } </s>

Tell me if a pair of reg/subreg rtx 's actually refer to the same register . Note that the current version does n't worry about whether they are the same mode or note ( e.g. , a QImode in r2 matches an HImode in r2 matches an SImode in r2 . Might think in the future about whether we want to be able to say something about modes .


<s> static bool mcore_legitimate_address_p ( machine_mode mode , rtx x , bool strict_p , addr_space_t as ) { gcc_assert ( ADDR_SPACE_GENERIC_P ( as ) ) ; if ( mcore_base_register_rtx_p ( x , strict_p ) ) return true ; else if ( GET_CODE ( x ) == PLUS || GET_CODE ( x ) == LO_SUM ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; if ( mcore_base_register_rtx_p ( xop0 , strict_p ) && mcore_legitimate_index_p ( mode , xop1 ) ) return true ; if ( mcore_base_register_rtx_p ( xop1 , strict_p ) && mcore_legitimate_index_p ( mode , xop0 ) ) return true ; } return false ; } </s>

Worker function for TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P . Allow REG REG + disp


<s> static bool mcore_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { return GET_CODE ( x ) != CONST_DOUBLE ; } </s>

Implement TARGET_LEGITIMATE_CONSTANT_P On the MCore , allow anything but a double .


<s> static bool mcore_legitimate_index_p ( machine_mode mode , const_rtx op ) { if ( CONST_INT_P ( op ) ) { if ( GET_MODE_SIZE ( mode ) >= 4 && ( ( ( unsigned HOST_WIDE_INT ) INTVAL ( op ) ) % 4 ) == 0 && ( ( unsigned HOST_WIDE_INT ) INTVAL ( op ) ) <= ( unsigned HOST_WIDE_INT ) 64 - GET_MODE_SIZE ( mode ) ) return true ; if ( GET_MODE_SIZE ( mode ) == 2 && ( ( ( unsigned HOST_WIDE_INT ) INTVAL ( op ) ) % 2 ) == 0 && ( ( unsigned HOST_WIDE_INT ) INTVAL ( op ) ) <= 30 ) return true ; if ( GET_MODE_SIZE ( mode ) == 1 && ( ( unsigned HOST_WIDE_INT ) INTVAL ( op ) ) <= 15 ) return true ; } return false ; } </s>

A legitimate index for a QI is 0 .. 15 , for HI is 0 .. 30 , for SI is 0 .. 60 , and for DI is 0 .. 56 because we use two SI loads , etc .


<s> static void mcore_mark_dllexport ( tree decl ) { const char * oldname ; char * newname ; rtx rtlname ; tree idp ; rtlname = XEXP ( DECL_RTL ( decl ) , 0 ) ; if ( GET_CODE ( rtlname ) == MEM ) rtlname = XEXP ( rtlname , 0 ) ; gcc_assert ( GET_CODE ( rtlname ) == SYMBOL_REF ) ; oldname = XSTR ( rtlname , 0 ) ; if ( mcore_dllexport_name_p ( oldname ) ) return ; newname = XALLOCAVEC ( char , strlen ( oldname ) + 4 ) ; sprintf ( newname , "@e.%s" , oldname ) ; idp = get_identifier ( newname ) ; XEXP ( DECL_RTL ( decl ) , 0 ) = gen_rtx_SYMBOL_REF ( Pmode , IDENTIFIER_POINTER ( idp ) ) ; } </s>


"initialized variable %q+D is marked dllimport"


<s> int mcore_num_arg_regs ( machine_mode mode , const_tree type ) { int size ; function_arg_info arg ( const_cast < tree > ( type ) , mode , true ) ; if ( targetm . calls . must_pass_in_stack ( arg ) ) return 0 ; if ( type && mode == BLKmode ) size = int_size_in_bytes ( type ) ; else size = GET_MODE_SIZE ( mode ) ; return ROUND_ADVANCE ( size ) ; } </s>

Compute the number of word sized registers needed to hold a function argument of mode MODE and type TYPE .


<s> int mcore_num_zeros ( HOST_WIDE_INT mask ) { return 32 - mcore_num_ones ( mask ) ; } </s>


<s>
const
char
*
mcore_output_andn
(
rtx
insn
ATTRIBUTE_UNUSED
,
rtx
operands
[
]
)
{
HOST_WIDE_INT
x
,
y
;
rtx
out_operands
[
3
]
;
const
char
*
load_op
;
char
buf
[
256
]
;
int
trick_no
;
trick_no
=
try_constant_tricks
(
INTVAL
(
operands
[
1
]
)
,
&
x
,
&
y
)
;
gcc_assert
(
trick_no
==
2
)
;
out_operands
[
0
]
=
operands
[
0
]
;
out_operands
[
1
]
=
GEN_INT
(
x
)
;
out_operands
[
2
]
=
operands
[
2
]
;
if
(
x
>=
0
&&
x
<=
127
)
load_op
=
"movi\t%0,%1"
;
else
if
(
CONST_OK_FOR_M
(
x
)
)
load_op
=
"bgeni\t%0,%P1"
;
else
if
(
CONST_OK_FOR_N
(
x
)
)
load_op
=
"bmaski\t%0,%N1"
;
else
{
load_op
=
"BADMOVI-andn\t%0, %1"
;
gcc_unreachable
(
)
;
}
sprintf
(
buf
,
"%s\n\tandn\t%%2,%%0"
,
load_op
)
;
output_asm_insn
(
buf
,
out_operands
)
;
return
""
;
}
</s>

Outputs the peephole for moving a constant that gets not'ed followed by an and ( i.e . combine the not and the and into andn ) . BRC


<s> const char * mcore_output_bclri ( rtx dst , int mask ) { rtx out_operands [ 2 ] ; int bit ; out_operands [ 0 ] = dst ; for ( bit = 0 ; bit < 32 ; bit ++ ) { if ( ( mask & 0x1 ) == 0x0 ) { out_operands [ 1 ] = GEN_INT ( bit ) ; output_asm_insn ( "bclri\t%0,%1" , out_operands ) ; } mask >>= 1 ; } return "" ; } </s>

Output a series of bclri 's corresponding to mask .


<s> const char * mcore_output_bseti ( rtx dst , int mask ) { rtx out_operands [ 2 ] ; int bit ; out_operands [ 0 ] = dst ; for ( bit = 0 ; bit < 32 ; bit ++ ) { if ( ( mask & 0x1 ) == 0x1 ) { out_operands [ 1 ] = GEN_INT ( bit ) ; output_asm_insn ( "bseti\t%0,%1" , out_operands ) ; } mask >>= 1 ; } return "" ; } </s>

Output a series of bseti 's corresponding to mask .


<s> char * mcore_output_call ( rtx operands [ ] , int index ) { static char buffer [ 20 ] ; rtx addr = operands [ index ] ; if ( REG_P ( addr ) ) { if ( TARGET_CG_DATA ) { gcc_assert ( mcore_current_function_name ) ; ASM_OUTPUT_CG_EDGE ( asm_out_file , mcore_current_function_name , "unknown" , 1 ) ; } sprintf ( buffer , "jsr\t%%%d" , index ) ; } else { if ( TARGET_CG_DATA ) { gcc_assert ( mcore_current_function_name ) ; gcc_assert ( GET_CODE ( addr ) == SYMBOL_REF ) ; ASM_OUTPUT_CG_EDGE ( asm_out_file , mcore_current_function_name , XSTR ( addr , 0 ) , 0 ) ; } sprintf ( buffer , "jbsr\t%%%d" , index ) ; } return buffer ; } </s>

Functions to output assembly code for a function call .


<s> const char * mcore_output_cmov ( rtx operands [ ] , int cmp_t , const char * test ) { HOST_WIDE_INT load_value ; HOST_WIDE_INT adjust_value ; rtx out_operands [ 4 ] ; out_operands [ 0 ] = operands [ 0 ] ; if ( const_ok_for_mcore ( INTVAL ( operands [ 1 ] ) ) ) { out_operands [ 1 ] = operands [ 1 ] ; out_operands [ 2 ] = operands [ 2 ] ; } else if ( const_ok_for_mcore ( INTVAL ( operands [ 2 ] ) ) ) { out_operands [ 1 ] = operands [ 2 ] ; out_operands [ 2 ] = operands [ 1 ] ; cmp_t = ( cmp_t == 0 ) ; } load_value = INTVAL ( out_operands [ 1 ] ) ; adjust_value = INTVAL ( out_operands [ 2 ] ) ; if ( test ) output_asm_insn ( test , operands ) ; if ( load_value >= 0 && load_value <= 127 ) output_asm_insn ( "movi\t%0,%1" , out_operands ) ; else if ( CONST_OK_FOR_M ( load_value ) ) output_asm_insn ( "bgeni\t%0,%P1" , out_operands ) ; else if ( CONST_OK_FOR_N ( load_value ) ) output_asm_insn ( "bmaski\t%0,%N1" , out_operands ) ; if ( load_value > adjust_value ) { if ( cmp_t ) output_asm_insn ( "decf\t%0" , out_operands ) ; else output_asm_insn ( "dect\t%0" , out_operands ) ; } else { if ( cmp_t ) output_asm_insn ( "incf\t%0" , out_operands ) ; else output_asm_insn ( "inct\t%0" , out_operands ) ; } return "" ; } </s>

Output a conditional move of two constants that are +/- 1 within each other . See the `` movtK '' patterns in mcore.md . I 'm not sure this is really worth the effort .


<s>
const
char
*
mcore_output_jump_label_table
(
void
)
{
int
i
;
if
(
pool_size
)
{
fprintf
(
asm_out_file
,
"\t.align 2\n"
)
;
for
(
i
=
0
;
i
<
pool_size
;
i
++
)
{
pool_node
*
p
=
pool_vector
+
i
;
(
*
targetm
.
asm_out
.
internal_label
)
(
asm_out_file
,
"L"
,
CODE_LABEL_NUMBER
(
p
->
label
)
)
;
output_asm_insn
(
".long	%0"
,
&
p
->
value
)
;
}
pool_size
=
0
;
}
return
""
;
}
</s>

Dump out any constants accumulated in the final pass . These will only be labels .


<s>
const
char
*
mcore_output_move
(
rtx
insn
ATTRIBUTE_UNUSED
,
rtx
operands
[
]
,
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
if
(
GET_CODE
(
dst
)
==
REG
)
{
if
(
GET_CODE
(
src
)
==
REG
)
{
if
(
REGNO
(
src
)
==
CC_REG
)
return
"mvc\t%0"
;
else
return
"mov\t%0,%1"
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
if
(
GET_CODE
(
XEXP
(
src
,
0
)
)
==
LABEL_REF
)
return
"lrw\t%0,[%1]"
;
else
switch
(
GET_MODE
(
src
)
)
{
case
E_SImode
:
return
"ldw\t%0,%1"
;
case
E_HImode
:
return
"ld.h\t%0,%1"
;
case
E_QImode
:
return
"ld.b\t%0,%1"
;
default
:
gcc_unreachable
(
)
;
}
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
HOST_WIDE_INT
x
,
y
;
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
return
"movi\t%0,%1"
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
return
"bgeni\t%0,%P1\t// %1 %x1"
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
return
"bmaski\t%0,%N1\t// %1 %x1"
;
else
if
(
try_constant_tricks
(
INTVAL
(
src
)
,
&
x
,
&
y
)
)
return
output_inline_const
(
SImode
,
operands
)
;
else
return
"lrw\t%0,%x1\t// %1"
;
}
else
return
"lrw\t%0, %1"
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
)
switch
(
GET_MODE
(
dst
)
)
{
case
E_SImode
:
return
"stw\t%1,%0"
;
case
E_HImode
:
return
"st.h\t%1,%0"
;
case
E_QImode
:
return
"st.b\t%1,%0"
;
default
:
gcc_unreachable
(
)
;
}
gcc_unreachable
(
)
;
}
</s>


<s>
const
char
*
mcore_output_movedouble
(
rtx
operands
[
]
,
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
rtx
dst
=
operands
[
0
]
;
rtx
src
=
operands
[
1
]
;
if
(
GET_CODE
(
dst
)
==
REG
)
{
if
(
GET_CODE
(
src
)
==
REG
)
{
int
dstreg
=
REGNO
(
dst
)
;
int
srcreg
=
REGNO
(
src
)
;
if
(
srcreg
+
1
==
dstreg
)
return
"mov	%R0,%R1\n\tmov	%0,%1"
;
else
return
"mov	%0,%1\n\tmov	%R0,%R1"
;
}
else
if
(
GET_CODE
(
src
)
==
MEM
)
{
rtx
memexp
=
XEXP
(
src
,
0
)
;
int
dstreg
=
REGNO
(
dst
)
;
int
basereg
=
1
;
if
(
GET_CODE
(
memexp
)
==
LABEL_REF
)
return
"lrw\t%0,[%1]\n\tlrw\t%R0,[%R1]"
;
else
if
(
GET_CODE
(
memexp
)
==
REG
)
basereg
=
REGNO
(
memexp
)
;
else
if
(
GET_CODE
(
memexp
)
==
PLUS
)
{
if
(
GET_CODE
(
XEXP
(
memexp
,
0
)
)
==
REG
)
basereg
=
REGNO
(
XEXP
(
memexp
,
0
)
)
;
else
if
(
GET_CODE
(
XEXP
(
memexp
,
1
)
)
==
REG
)
basereg
=
REGNO
(
XEXP
(
memexp
,
1
)
)
;
else
gcc_unreachable
(
)
;
}
else
gcc_unreachable
(
)
;
if
(
dstreg
==
basereg
)
{
return
"ldw\t%R0,%R1\n\tldw\t%0,%1"
;
}
else
return
"ldw\t%0,%1\n\tldw\t%R0,%R1"
;
}
else
if
(
GET_CODE
(
src
)
==
CONST_INT
)
{
if
(
TARGET_LITTLE_END
)
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"movi	%0,%1"
,
operands
)
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bgeni	%0,%P1"
,
operands
)
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bmaski	%0,%N1"
,
operands
)
;
else
gcc_unreachable
(
)
;
if
(
INTVAL
(
src
)
<
0
)
return
"bmaski	%R0,32"
;
else
return
"movi	%R0,0"
;
}
else
{
if
(
CONST_OK_FOR_I
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"movi	%R0,%1"
,
operands
)
;
else
if
(
CONST_OK_FOR_M
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bgeni	%R0,%P1"
,
operands
)
;
else
if
(
CONST_OK_FOR_N
(
INTVAL
(
src
)
)
)
output_asm_insn
(
"bmaski	%R0,%N1"
,
operands
)
;
else
gcc_unreachable
(
)
;
if
(
INTVAL
(
src
)
<
0
)
return
"bmaski	%0,32"
;
else
return
"movi	%0,0"
;
}
}
else
gcc_unreachable
(
)
;
}
else
if
(
GET_CODE
(
dst
)
==
MEM
&&
GET_CODE
(
src
)
==
REG
)
return
"stw\t%1,%0\n\tstw\t%R1,%R0"
;
else
gcc_unreachable
(
)
;
}
</s>

Return a sequence of instructions to perform DI or DF move . Since the MCORE can not move a DI or DF in one instruction , we have to take care when we see overlapping source and dest registers .


<s> static void mcore_print_operand ( FILE * stream , rtx x , int code ) { switch ( code ) { case 'N' : if ( INTVAL ( x ) == - 1 ) fprintf ( asm_out_file , "32" ) ; else fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) + 1 ) ) ; break ; case 'P' : fprintf ( asm_out_file , "%d" , exact_log2 ( INTVAL ( x ) & 0xffffffff ) ) ; break ; case 'Q' : fprintf ( asm_out_file , "%d" , exact_log2 ( ~ INTVAL ( x ) ) ) ; break ; case 'O' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , INTVAL ( x ) ) ; break ; case 'M' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , - INTVAL ( x ) ) ; break ; case 'R' : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) + 1 ] , ( stream ) ) ; break ; case MEM : mcore_print_operand_address ( stream , GET_MODE ( x ) , XEXP ( adjust_address ( x , SImode , 4 ) , 0 ) ) ; break ; default : gcc_unreachable ( ) ; } break ; case 'U' : fprintf ( asm_out_file , "%s-%s" , reg_names [ REGNO ( x ) ] , reg_names [ REGNO ( x ) + 3 ] ) ; break ; case 'x' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_HEX , INTVAL ( x ) ) ; break ; case 'X' : fprintf ( asm_out_file , HOST_WIDE_INT_PRINT_DEC , 3 - INTVAL ( x ) / 8 ) ; break ; default : switch ( GET_CODE ( x ) ) { case REG : fputs ( reg_names [ REGNO ( x ) ] , ( stream ) ) ; break ; case MEM : output_address ( GET_MODE ( x ) , XEXP ( x , 0 ) ) ; break ; default : output_addr_const ( stream , x ) ; break ; } break ; } } </s>

Print operand x ( an rtx ) in assembler syntax to file stream according to modifier code . ' R ' print the next register or memory location along , ie the lsw in a double word value ' O ' print a constant without the # 'M ' print a constant as its negative ' P ' print log2 of a power of two ' Q ' print log2 of an inverse of a power of two ' U ' print register for ldm/stm instruction ' X ' print byte number for xtrbN instruction .


<s> static void mcore_print_operand_address ( FILE * stream , machine_mode , rtx x ) { switch ( GET_CODE ( x ) ) { case REG : fprintf ( stream , "(%s)" , reg_names [ REGNO ( x ) ] ) ; break ; case PLUS : { rtx base = XEXP ( x , 0 ) ; rtx index = XEXP ( x , 1 ) ; if ( GET_CODE ( base ) != REG ) { rtx temp = base ; base = index ; index = temp ; } switch ( GET_CODE ( index ) ) { case CONST_INT : fprintf ( stream , "(%s," HOST_WIDE_INT_PRINT_DEC ")" , reg_names [ REGNO ( base ) ] , INTVAL ( index ) ) ; break ; default : gcc_unreachable ( ) ; } } break ; default : output_addr_const ( stream , x ) ; break ; } } </s>

Print the operand address in x to the stream .


<s> bool mcore_r15_operand_p ( rtx x ) { switch ( GET_CODE ( x ) ) { case CONST_INT : return mcore_const_ok_for_inline ( INTVAL ( x ) ) ; case REG : case SUBREG : case MEM : return 1 ; default : return 0 ; } } </s>

Return true if X is something that can be moved directly into r15 .


<s> static bool mcore_reg_ok_for_base_p ( const_rtx reg , bool strict_p ) { if ( strict_p ) return REGNO_OK_FOR_BASE_P ( REGNO ( reg ) ) ; else return ( REGNO ( reg ) <= 16 || ! HARD_REGISTER_P ( reg ) ) ; } </s>

Helper function for ` mcore_legitimate_address_p ' .


<s> enum reg_class mcore_reload_class ( rtx x , enum reg_class rclass ) { if ( reg_class_subset_p ( LRW_REGS , rclass ) && ! mcore_r15_operand_p ( x ) ) return LRW_REGS ; return rclass ; } </s>

Return the reg_class to use when reloading the rtx X into the class CLASS . If X is too complex to move directly into r15 , prefer to use LRW_REGS instead .


<s> static void mcore_reorg ( void ) { current_function_anonymous_args = 0 ; if ( optimize == 0 ) return ; conditionalize_optimization ( ) ; } </s>

This is to handle loads from the constant pool .


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

Worker function for TARGET_RETURN_IN_MEMORY .


<s> enum reg_class mcore_secondary_reload_class ( enum reg_class rclass , machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { if ( TEST_HARD_REG_BIT ( reg_class_contents [ rclass ] , 15 ) && ! mcore_r15_operand_p ( x ) ) return LRW_REGS ; return NO_REGS ; } </s>

Implement SECONDARY_RELOAD_CLASS . If CLASS contains r15 , and we ca n't directly move X into it , use r1-r14 as a temporary .


<s> static void mcore_setup_incoming_varargs ( cumulative_args_t args_so_far_v , const function_arg_info & arg , int * ptr_pretend_size ATTRIBUTE_UNUSED , int second_time ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * args_so_far = get_cumulative_args ( args_so_far_v ) ; current_function_anonymous_args = 1 ; number_of_regs_before_varargs = * args_so_far + mcore_num_arg_regs ( arg . mode , arg . type ) ; number_of_regs_before_varargs = * args_so_far ; if ( number_of_regs_before_varargs > NPARM_REGS ) number_of_regs_before_varargs = NPARM_REGS ; } </s>

Keep track of some information about varargs for the prolog .


<s> static const char * mcore_strip_name_encoding ( const char * str ) { return str + ( str [ 0 ] == '@' ? 3 : 0 ) ; } </s>


<s> static void mcore_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx mem ; emit_block_move ( m_tramp , assemble_trampoline_template ( ) , GEN_INT ( 2 * UNITS_PER_WORD ) , BLOCK_OP_NORMAL ) ; mem = adjust_address ( m_tramp , SImode , 8 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , 12 ) ; emit_move_insn ( mem , fnaddr ) ; } </s>

Worker function for TARGET_TRAMPOLINE_INIT .


<s> static void mcore_unique_section ( tree decl , int reloc ATTRIBUTE_UNUSED ) { int len ; const char * name ; char * string ; const char * prefix ; name = IDENTIFIER_POINTER ( DECL_ASSEMBLER_NAME ( decl ) ) ; name = ( * targetm . strip_name_encoding ) ( name ) ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) prefix = ".text$" ; else if ( decl_readonly_section ( decl , 0 ) ) prefix = ".rdata$" ; else prefix = ".data$" ; len = strlen ( name ) + strlen ( prefix ) ; string = XALLOCAVEC ( char , len + 1 ) ; sprintf ( string , "%s%s" , prefix , name ) ; set_decl_section_name ( decl , string ) ; } </s>


<s>
static
const
char
*
output_inline_const
(
machine_mode
mode
,
rtx
operands
[
]
)
{
HOST_WIDE_INT
x
=
0
,
y
=
0
;
int
trick_no
;
rtx
out_operands
[
3
]
;
char
buf
[
256
]
;
char
load_op
[
256
]
;
const
char
*
dst_fmt
;
HOST_WIDE_INT
value
;
value
=
INTVAL
(
operands
[
1
]
)
;
trick_no
=
try_constant_tricks
(
value
,
&
x
,
&
y
)
;
gcc_assert
(
trick_no
!=
0
)
;
if
(
trick_no
==
1
)
x
=
value
;
out_operands
[
0
]
=
operands
[
0
]
;
out_operands
[
1
]
=
GEN_INT
(
x
)
;
if
(
trick_no
>
2
)
out_operands
[
2
]
=
GEN_INT
(
y
)
;
if
(
mode
==
DImode
&&
(
!
TARGET_LITTLE_END
)
)
dst_fmt
=
"%R0"
;
else
dst_fmt
=
"%0"
;
if
(
x
>=
0
&&
x
<=
127
)
sprintf
(
load_op
,
"movi\t%s,%%1"
,
dst_fmt
)
;
else
if
(
CONST_OK_FOR_M
(
x
)
)
sprintf
(
load_op
,
"bgeni\t%s,%%P1"
,
dst_fmt
)
;
else
if
(
CONST_OK_FOR_N
(
x
)
)
sprintf
(
load_op
,
"bmaski\t%s,%%N1"
,
dst_fmt
)
;
else
{
sprintf
(
load_op
,
"BADMOVI-inline_const %s, %%1"
,
dst_fmt
)
;
gcc_unreachable
(
)
;
}
switch
(
trick_no
)
{
case
1
:
strcpy
(
buf
,
load_op
)
;
break
;
case
2
:
sprintf
(
buf
,
"%s\n\tnot\t%s\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
3
:
sprintf
(
buf
,
"%s\n\taddi\t%s,%%2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
4
:
sprintf
(
buf
,
"%s\n\tsubi\t%s,%%2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
5
:
sprintf
(
buf
,
"%s\n\trsubi\t%s,%%2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
6
:
sprintf
(
buf
,
"%s\n\tbseti\t%s,%%P2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
7
:
sprintf
(
buf
,
"%s\n\tbclri\t%s,%%Q2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
8
:
sprintf
(
buf
,
"%s\n\trotli\t%s,%%2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
9
:
sprintf
(
buf
,
"%s\n\tlsli\t%s,%%2\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
value
,
value
)
;
break
;
case
10
:
sprintf
(
buf
,
"%s\n\tixh\t%s,%s\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
dst_fmt
,
value
,
value
)
;
break
;
case
11
:
sprintf
(
buf
,
"%s\n\tixw\t%s,%s\t// %ld 0x%lx"
,
load_op
,
dst_fmt
,
dst_fmt
,
value
,
value
)
;
break
;
default
:
return
""
;
}
output_asm_insn
(
buf
,
out_operands
)
;
return
""
;
}
</s>


<s> static void output_stack_adjust ( int direction , int size ) { if ( direction < 0 && size > mcore_stack_increment && mcore_stack_increment > 0 ) { rtx tmp = gen_rtx_REG ( SImode , 1 ) ; rtx memref ; emit_insn ( gen_movsi ( tmp , GEN_INT ( mcore_stack_increment ) ) ) ; do { emit_insn ( gen_subsi3 ( stack_pointer_rtx , stack_pointer_rtx , tmp ) ) ; memref = gen_rtx_MEM ( SImode , stack_pointer_rtx ) ; MEM_VOLATILE_P ( memref ) = 1 ; emit_insn ( gen_movsi ( memref , stack_pointer_rtx ) ) ; size -= mcore_stack_increment ; } while ( size > mcore_stack_increment ) ; } if ( size ) { rtx insn ; rtx val = GEN_INT ( size ) ; if ( size > 32 ) { rtx nval = gen_rtx_REG ( SImode , 1 ) ; emit_insn ( gen_movsi ( nval , val ) ) ; val = nval ; } if ( direction > 0 ) insn = gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , val ) ; else insn = gen_subsi3 ( stack_pointer_rtx , stack_pointer_rtx , val ) ; emit_insn ( insn ) ; } } </s>

Adjust the stack and return the number of bytes taken to do it


<s> static int try_constant_tricks ( HOST_WIDE_INT value , HOST_WIDE_INT * x , HOST_WIDE_INT * y ) { HOST_WIDE_INT i ; unsigned HOST_WIDE_INT bit , shf , rot ; if ( const_ok_for_mcore ( value ) ) return 1 ; if ( ! TARGET_HARDLIT ) return 0 ; if ( const_ok_for_mcore ( ~ value ) ) { * x = ~ value ; return 2 ; } for ( i = 1 ; i <= 32 ; i ++ ) { if ( const_ok_for_mcore ( value - i ) ) { * x = value - i ; * y = i ; return 3 ; } if ( const_ok_for_mcore ( value + i ) ) { * x = value + i ; * y = i ; return 4 ; } } bit = 0x80000000ULL ; for ( i = 0 ; i <= 31 ; i ++ ) { if ( const_ok_for_mcore ( i - value ) ) { * x = i - value ; * y = i ; return 5 ; } if ( const_ok_for_mcore ( value & ~ bit ) ) { * y = bit ; * x = value & ~ bit ; return 6 ; } if ( const_ok_for_mcore ( value | bit ) ) { * y = ~ bit ; * x = value | bit ; return 7 ; } bit >>= 1 ; } shf = value ; rot = value ; for ( i = 1 ; i < 31 ; i ++ ) { int c ; c = rot << 31 ; rot >>= 1 ; rot &= 0x7FFFFFFF ; rot |= c ; if ( const_ok_for_mcore ( rot ) ) { * y = i ; * x = rot ; return 8 ; } if ( shf & 1 ) shf = 0 ; shf >>= 1 ; if ( shf != 0 && const_ok_for_mcore ( shf ) ) { * y = i ; * x = shf ; return 9 ; } } if ( ( value % 3 ) == 0 && const_ok_for_mcore ( value / 3 ) ) { * x = value / 3 ; return 10 ; } if ( ( value % 5 ) == 0 && const_ok_for_mcore ( value / 5 ) ) { * x = value / 5 ; return 11 ; } return 0 ; } </s>

Try tricks to load a constant inline and return the trick number if success ( 0 is non-inlinable ) . 0 : not inlinable 1 : single instruction ( do the usual thing ) 2 : single insn followed by a 'not ' 3 : single insn followed by a subi 4 : single insn followed by an addi 5 : single insn followed by rsubi 6 : single insn followed by bseti 7 : single insn followed by bclri 8 : single insn followed by rotli 9 : single insn followed by lsli 10 : single insn followed by ixh 11 : single insn followed by ixw .