<s> static void add_constant ( int dest , int src , int value , int mark_frame ) { rtx_insn * insn ; int hi , lo ; if ( src == dest && value == 0 ) return ; if ( value == 0 ) { insn = emit_move_insn ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) ) ; if ( mark_frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; return ; } if ( value >= - 32768 && value <= 32767 ) { insn = emit_insn ( gen_addsi3 ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) , GEN_INT ( value ) ) ) ; if ( mark_frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; return ; } hi = trunc_int_for_mode ( value & 0xffff0000 , SImode ) ; lo = value & 0xffff ; insn = emit_move_insn ( gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , GEN_INT ( hi ) ) ; if ( lo ) { insn = emit_insn ( gen_iorsi3 ( gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , GEN_INT ( lo ) ) ) ; } insn = emit_insn ( gen_addsi3 ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) , gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) ) ) ; if ( mark_frame ) { RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , gen_rtx_SET ( gen_rtx_REG ( SImode , dest ) , gen_rtx_PLUS ( SImode , gen_rtx_REG ( SImode , dest ) , GEN_INT ( value ) ) ) ) ; } } </s>

Add a constant to the pool and return its label .


<s> static bool mep_expand_setcc_1 ( enum rtx_code code , rtx dest , rtx op1 , rtx op2 ) { rtx tmp ; switch ( code ) { case GT : case GTU : tmp = op1 , op1 = op2 , op2 = tmp ; code = swap_condition ( code ) ; case LT : case LTU : op1 = force_reg ( SImode , op1 ) ; emit_insn ( gen_rtx_SET ( dest , gen_rtx_fmt_ee ( code , SImode , op1 , op2 ) ) ) ; return true ; case EQ : if ( op2 != const0_rtx ) op1 = expand_binop ( SImode , sub_optab , op1 , op2 , NULL , 1 , OPTAB_WIDEN ) ; mep_expand_setcc_1 ( LTU , dest , op1 , const1_rtx ) ; return true ; case NE : if ( optimize_size && op2 != const0_rtx ) return false ; if ( op2 != const0_rtx ) op1 = expand_binop ( SImode , sub_optab , op1 , op2 , NULL , 1 , OPTAB_WIDEN ) ; op2 = gen_reg_rtx ( SImode ) ; mep_expand_setcc_1 ( LTU , op2 , op1 , const1_rtx ) ; emit_insn ( gen_rtx_SET ( dest , gen_rtx_XOR ( SImode , op2 , const1_rtx ) ) ) ; return true ; case LE : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == 0x7ffffff ) return false ; op2 = GEN_INT ( INTVAL ( op2 ) + 1 ) ; return mep_expand_setcc_1 ( LT , dest , op1 , op2 ) ; case LEU : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == - 1 ) return false ; op2 = GEN_INT ( trunc_int_for_mode ( INTVAL ( op2 ) + 1 , SImode ) ) ; return mep_expand_setcc_1 ( LTU , dest , op1 , op2 ) ; case GE : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == trunc_int_for_mode ( 0x80000000 , SImode ) ) return false ; op2 = GEN_INT ( INTVAL ( op2 ) - 1 ) ; return mep_expand_setcc_1 ( GT , dest , op1 , op2 ) ; case GEU : if ( GET_CODE ( op2 ) != CONST_INT || op2 == const0_rtx ) return false ; op2 = GEN_INT ( trunc_int_for_mode ( INTVAL ( op2 ) - 1 , SImode ) ) ; return mep_expand_setcc_1 ( GTU , dest , op1 , op2 ) ; default : gcc_unreachable ( ) ; } } </s>

Emit a setcc instruction in its entirity .


<s> static void add_constant ( int dest , int src , int value , int mark_frame ) { rtx_insn * insn ; int hi , lo ; if ( src == dest && value == 0 ) return ; if ( value == 0 ) { insn = emit_move_insn ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) ) ; if ( mark_frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; return ; } if ( value >= - 32768 && value <= 32767 ) { insn = emit_insn ( gen_addsi3 ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) , GEN_INT ( value ) ) ) ; if ( mark_frame ) RTX_FRAME_RELATED_P ( insn ) = 1 ; return ; } hi = trunc_int_for_mode ( value & 0xffff0000 , SImode ) ; lo = value & 0xffff ; insn = emit_move_insn ( gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , GEN_INT ( hi ) ) ; if ( lo ) { insn = emit_insn ( gen_iorsi3 ( gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) , GEN_INT ( lo ) ) ) ; } insn = emit_insn ( gen_addsi3 ( gen_rtx_REG ( SImode , dest ) , gen_rtx_REG ( SImode , src ) , gen_rtx_REG ( SImode , REGSAVE_CONTROL_TEMP ) ) ) ; if ( mark_frame ) { RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , gen_rtx_SET ( SImode , gen_rtx_REG ( SImode , dest ) , gen_rtx_PLUS ( SImode , gen_rtx_REG ( SImode , dest ) , GEN_INT ( value ) ) ) ) ; } } </s>


<s> static int add_sp_insn_p ( rtx_insn * insn ) { rtx pat ; if ( ! single_set ( insn ) ) return 0 ; pat = PATTERN ( insn ) ; if ( GET_CODE ( SET_DEST ( pat ) ) != REG ) return 0 ; if ( REGNO ( SET_DEST ( pat ) ) != SP_REGNO ) return 0 ; if ( GET_CODE ( SET_SRC ( pat ) ) != PLUS ) return 0 ; if ( GET_CODE ( XEXP ( SET_SRC ( pat ) , 0 ) ) != REG ) return 0 ; if ( REGNO ( XEXP ( SET_SRC ( pat ) , 0 ) ) != SP_REGNO ) return 0 ; if ( GET_CODE ( XEXP ( SET_SRC ( pat ) , 1 ) ) != CONST_INT ) return 0 ; return INTVAL ( XEXP ( SET_SRC ( pat ) , 1 ) ) ; } </s>

If this insn adjusts the stack , return the adjustment , else return zero .


<s> static rtx_insn * F ( rtx_insn * x ) { RTX_FRAME_RELATED_P ( x ) = 1 ; return x ; } </s>

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


<s> static bool global_reg_mentioned_p ( rtx x ) { if ( INSN_P ( x ) ) { if ( CALL_P ( x ) ) { if ( ! RTL_CONST_OR_PURE_CALL_P ( x ) ) return true ; x = CALL_INSN_FUNCTION_USAGE ( x ) ; if ( x == 0 ) return false ; } else x = PATTERN ( x ) ; } subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , NONCONST ) if ( global_reg_mentioned_p_1 ( * iter ) ) return true ; return false ; } </s>

Returns nonzero if X mentions a global register .


<s> static bool global_reg_mentioned_p_1 ( const_rtx x ) { int regno ; switch ( GET_CODE ( x ) ) { case SUBREG : if ( REG_P ( SUBREG_REG ( x ) ) ) { if ( REGNO ( SUBREG_REG ( x ) ) < FIRST_PSEUDO_REGISTER && global_regs [ subreg_regno ( x ) ] ) return true ; return false ; } break ; case REG : regno = REGNO ( x ) ; if ( regno < FIRST_PSEUDO_REGISTER && global_regs [ regno ] ) return true ; return false ; case CALL : return true ; default : break ; } return false ; } </s>

A subroutine of global_reg_mentioned_p , returns 1 if * LOC mentions a global register .


<s> static hashval_t hash ( const char * s ) { return htab_hash_string ( s ) ; } </s>

Hash function for builtin functions with up to 3 arguments and a return type .


<s> static rtx_insn * maybe_dead_move ( rtx dest , rtx src , bool ATTRIBUTE_UNUSED maybe_dead_p ) { rtx_insn * insn = emit_move_insn ( dest , src ) ; if ( maybe_dead_p ) REG_NOTES ( insn ) = gen_rtx_EXPR_LIST ( REG_MAYBE_DEAD , const0_rtx , NULL ) ; return insn ; } </s>

Move SRC to DEST . Mark the move as being potentially dead if MAYBE_DEAD_P .


<s> static int mep_adjust_cost ( rtx_insn * insn , rtx link , rtx_insn * dep_insn , int cost ) { int cost_specified ; if ( REG_NOTE_KIND ( link ) != 0 ) { if ( REG_NOTE_KIND ( link ) == REG_DEP_OUTPUT && global_reg_mentioned_p ( PATTERN ( insn ) ) && global_reg_mentioned_p ( PATTERN ( dep_insn ) ) ) return 1 ; return 0 ; } if ( recog_memoized ( dep_insn ) < 0 ) return cost ; if ( ! TARGET_H1 ) { cost_specified = get_attr_latency ( dep_insn ) ; if ( cost_specified != 0 ) return cost_specified ; } return cost ; } </s>

Scheduling hooks for VLIW mode . Conceptually this is very simple : we have a two-pack architecture that takes one core insn and one coprocessor insn to make up either a 32- or 64-bit instruction word ( depending on the option bit set in the chip ) . I.e . in VL32 mode , we can pack one 16-bit core insn and one 16-bit cop insn ; in VL64 mode we can pack one 16-bit core insn and one 48-bit cop insn or two 32-bit core/cop insns . In practice , instruction selection will be a bear . Consider in VL64 mode the following insns add $ 1 , 1 cmov $ cr0 , $ 0 these can not pack , since the add is a 16-bit core insn and cmov is a 32-bit cop insn . However , add3 $ 1 , $ 1 , 1 cmov $ cr0 , $ 0 packs just fine . For good VLIW code generation in VL64 mode , we will have to have 32-bit alternatives for many of the common core insns . Not implemented .


<s> static void mep_asm_named_section ( const char * name , unsigned int flags , tree decl ATTRIBUTE_UNUSED ) { char flagchars [ 8 ] , * f = flagchars ; const char * type ; if ( ! ( flags & SECTION_DEBUG ) ) * f ++ = 'a' ; if ( flags & SECTION_WRITE ) * f ++ = 'w' ; if ( flags & SECTION_CODE ) * f ++ = 'x' ; if ( flags & SECTION_SMALL ) * f ++ = 's' ; if ( flags & SECTION_MEP_VLIW ) * f ++ = 'v' ; * f = '\0' ; if ( flags & SECTION_BSS ) type = "nobits" ; else type = "progbits" ; fprintf ( asm_out_file , "\t.section\t%s,\"%s\",@%s\n" , name , flagchars , type ) ; if ( flags & SECTION_CODE ) fputs ( ( flags & SECTION_MEP_VLIW ? "\t.vliw\n" : "\t.core\n" ) , asm_out_file ) ; } </s>

Switch to an arbitrary section NAME with attributes as specified by FLAGS . ALIGN specifies any known alignment requirements for the section ; 0 if the default should be used . Differs from the standard ELF version only in support of VLIW mode .


<s>
void
mep_asm_output_opcode
(
FILE
*
file
,
const
char
*
ptr
)
{
int
this_opcode
=
op_none
;
const
char
*
hazard
=
0
;
switch
(
*
ptr
)
{
case
'f'
:
if
(
strncmp
(
ptr
,
"fsft"
,
4
)
==
0
&&
!
ISGRAPH
(
ptr
[
4
]
)
)
this_opcode
=
op_fsft
;
break
;
case
'r'
:
if
(
strncmp
(
ptr
,
"ret"
,
3
)
==
0
&&
!
ISGRAPH
(
ptr
[
3
]
)
)
this_opcode
=
op_ret
;
break
;
case
's'
:
if
(
strncmp
(
ptr
,
"stc"
,
3
)
==
0
&&
!
ISGRAPH
(
ptr
[
3
]
)
)
this_opcode
=
op_stc
;
break
;
}
if
(
prev_opcode
==
op_stc
&&
this_opcode
==
op_fsft
)
hazard
=
"nop"
;
if
(
prev_opcode
==
op_stc
&&
this_opcode
==
op_ret
)
hazard
=
"nop"
;
if
(
hazard
)
fprintf
(
file
,
"%s\t# %s-%s hazard\n\t"
,
hazard
,
opnames
[
prev_opcode
]
,
opnames
[
this_opcode
]
)
;
prev_opcode
=
this_opcode
;
}
</s>

This is n't as optimal as it could be , because we do n't know what control register the STC opcode is storing in . We only need to add the nop if it 's the relevant register , but we add it for irrelevant registers also .


<s> static bool mep_assign_save_slots ( int reg_save_size ) { bool really_need_stack_frame = false ; int di_ofs = 0 ; int i ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( mep_call_saves_register ( i ) ) { int regsize = mep_reg_size ( i ) ; if ( ( i != TP_REGNO && i != GP_REGNO && i != LP_REGNO ) || mep_reg_set_in_function ( i ) ) really_need_stack_frame = true ; if ( cfun -> machine -> reg_save_slot [ i ] ) continue ; if ( regsize < 8 ) { cfun -> machine -> reg_save_size += regsize ; cfun -> machine -> reg_save_slot [ i ] = cfun -> machine -> reg_save_size ; } else { cfun -> machine -> reg_save_slot [ i ] = reg_save_size - di_ofs ; di_ofs += 8 ; } } cfun -> machine -> frame_locked = 1 ; return really_need_stack_frame ; } </s>

Assign save slots for any register not already saved . DImode registers go at the end of the reg save area ; the rest go at the beginning . This is for alignment purposes . Returns true if a frame is really needed .


<s> bool mep_cannot_change_mode_class ( machine_mode from , machine_mode to , enum reg_class regclass ) { if ( from == to ) return false ; if ( TARGET_64BIT_CR_REGS && ( regclass == CR_REGS || regclass == LOADABLE_CR_REGS ) && ( GET_MODE_SIZE ( to ) < 8 || GET_MODE_SIZE ( from ) < 8 ) ) return true ; return false ; } </s>

Return true if the registers in CLASS can not represent the change from modes FROM to TO .


<s> bool mep_can_eliminate ( const int from , const int to ) { return ( from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true ) ; } </s>

Worker function for TARGET_CAN_ELIMINATE .


<s> static rtx mep_convert_arg ( machine_mode mode , rtx arg ) { if ( GET_MODE ( arg ) != mode && register_operand ( arg , VOIDmode ) && GET_MODE_SIZE ( GET_MODE ( arg ) ) == GET_MODE_SIZE ( mode ) ) return simplify_gen_subreg ( mode , arg , GET_MODE ( arg ) , 0 ) ; return arg ; } </s>

If ARG is a register operand that is the same size as MODE , convert it to MODE using a subreg . Otherwise return ARG as-is .


<s> static rtx mep_convert_regnum ( const struct cgen_regnum_operand * regnum , rtx arg ) { if ( regnum -> count == 0 ) return arg ; if ( GET_CODE ( arg ) != CONST_INT || INTVAL ( arg ) < 0 || INTVAL ( arg ) >= regnum -> count ) return 0 ; return gen_rtx_REG ( SImode , INTVAL ( arg ) + regnum -> base ) ; } </s>

Apply regnum conversions to ARG using the description given by REGNUM . Return the new argument on success and null on failure .


<s> bool mep_emit_intrinsic ( int intrinsic , const rtx * operands ) { const struct cgen_insn * cgen_insn ; const struct insn_data_d * idata ; rtx newop [ 10 ] ; int i ; if ( ! mep_get_intrinsic_insn ( intrinsic , & cgen_insn ) ) return false ; idata = & insn_data [ cgen_insn -> icode ] ; for ( i = 0 ; i < idata -> n_operands ; i ++ ) { newop [ i ] = mep_convert_arg ( idata -> operand [ i ] . mode , operands [ i ] ) ; if ( ! idata -> operand [ i ] . predicate ( newop [ i ] , idata -> operand [ i ] . mode ) ) return false ; } emit_insn ( idata -> genfun ( newop [ 0 ] , newop [ 1 ] , newop [ 2 ] , newop [ 3 ] , newop [ 4 ] , newop [ 5 ] , newop [ 6 ] , newop [ 7 ] , newop [ 8 ] ) ) ; return true ; } </s>

Try to instantiate INTRINSIC with the operands given in OPERANDS . Return true on success . This function can fail if the intrinsic is unavailable or if the operands do n't satisfy their predicates .


<s> bool mep_epilogue_uses ( int regno ) { if ( regno == LP_REGNO && ( profile_arc_flag > 0 || profile_flag > 0 ) ) return true ; return ( reload_completed && mep_interrupt_saved_reg ( regno ) ) ; } </s>

Return true if epilogue uses register REGNO .


<s> bool mep_expand_binary_intrinsic ( int ATTRIBUTE_UNUSED immediate , int ATTRIBUTE_UNUSED immediate3 , int ATTRIBUTE_UNUSED reg , int ATTRIBUTE_UNUSED reg3 , rtx * operands ATTRIBUTE_UNUSED ) { return false ; } </s>

Likewise , but apply a binary operation to OPERANDS [ 1 ] and OPERANDS [ 2 ] . OPERANDS [ 1 ] is a register_operand , OPERANDS [ 2 ] can be a general_operand . IMMEDIATE and IMMEDIATE3 are intrinsics that take an immediate third operand . REG and REG3 take register operands only .


<s> static bool mep_expand_setcc_1 ( enum rtx_code code , rtx dest , rtx op1 , rtx op2 ) { rtx tmp ; switch ( code ) { case GT : case GTU : tmp = op1 , op1 = op2 , op2 = tmp ; code = swap_condition ( code ) ; case LT : case LTU : op1 = force_reg ( SImode , op1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , dest , gen_rtx_fmt_ee ( code , SImode , op1 , op2 ) ) ) ; return true ; case EQ : if ( op2 != const0_rtx ) op1 = expand_binop ( SImode , sub_optab , op1 , op2 , NULL , 1 , OPTAB_WIDEN ) ; mep_expand_setcc_1 ( LTU , dest , op1 , const1_rtx ) ; return true ; case NE : if ( optimize_size && op2 != const0_rtx ) return false ; if ( op2 != const0_rtx ) op1 = expand_binop ( SImode , sub_optab , op1 , op2 , NULL , 1 , OPTAB_WIDEN ) ; op2 = gen_reg_rtx ( SImode ) ; mep_expand_setcc_1 ( LTU , op2 , op1 , const1_rtx ) ; emit_insn ( gen_rtx_SET ( VOIDmode , dest , gen_rtx_XOR ( SImode , op2 , const1_rtx ) ) ) ; return true ; case LE : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == 0x7ffffff ) return false ; op2 = GEN_INT ( INTVAL ( op2 ) + 1 ) ; return mep_expand_setcc_1 ( LT , dest , op1 , op2 ) ; case LEU : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == - 1 ) return false ; op2 = GEN_INT ( trunc_int_for_mode ( INTVAL ( op2 ) + 1 , SImode ) ) ; return mep_expand_setcc_1 ( LTU , dest , op1 , op2 ) ; case GE : if ( GET_CODE ( op2 ) != CONST_INT || INTVAL ( op2 ) == trunc_int_for_mode ( 0x80000000 , SImode ) ) return false ; op2 = GEN_INT ( INTVAL ( op2 ) - 1 ) ; return mep_expand_setcc_1 ( GT , dest , op1 , op2 ) ; case GEU : if ( GET_CODE ( op2 ) != CONST_INT || op2 == const0_rtx ) return false ; op2 = GEN_INT ( trunc_int_for_mode ( INTVAL ( op2 ) - 1 , SImode ) ) ; return mep_expand_setcc_1 ( GTU , dest , op1 , op2 ) ; default : gcc_unreachable ( ) ; } } </s>

Emit a setcc instruction in its entirity .


<s> bool mep_expand_unary_intrinsic ( int ATTRIBUTE_UNUSED intrinsic , rtx * operands ATTRIBUTE_UNUSED ) { return false ; } </s>

Apply the given unary intrinsic to OPERANDS [ 1 ] and store it on OPERANDS [ 0 ] . Report an error if the instruction could not be synthesized . OPERANDS [ 1 ] is a register_operand . For sign and zero extensions , it may be smaller than SImode .


<s> rtx mep_find_base_term ( rtx x ) { rtx base , term ; int unspec ; if ( GET_CODE ( x ) != PLUS ) return x ; base = XEXP ( x , 0 ) ; term = XEXP ( x , 1 ) ; if ( has_hard_reg_initial_val ( Pmode , TP_REGNO ) && base == mep_tp_rtx ( ) ) unspec = UNS_TPREL ; else if ( has_hard_reg_initial_val ( Pmode , GP_REGNO ) && base == mep_gp_rtx ( ) ) unspec = UNS_GPREL ; else return x ; if ( GET_CODE ( term ) != CONST ) return x ; term = XEXP ( term , 0 ) ; if ( GET_CODE ( term ) != UNSPEC || XINT ( term , 1 ) != unspec ) return x ; return XVECEXP ( term , 0 , 0 ) ; } </s>

If X is a machine specific address ( i.e . a symbol or label being referenced as a displacement from the GOT implemented using an UNSPEC ) , then return the base term . Otherwise return X .


<s> static rtx mep_frame_expr ( rtx_insn * insn ) { rtx note , expr ; note = find_reg_note ( insn , REG_FRAME_RELATED_EXPR , 0 ) ; expr = ( note != 0 ? XEXP ( note , 0 ) : copy_rtx ( PATTERN ( insn ) ) ) ; RTX_FRAME_RELATED_P ( expr ) = 1 ; return expr ; } </s>

Return the effect of frame-related instruction INSN .


<s> static rtx mep_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; if ( mode == VOIDmode ) return GEN_INT ( cum -> vliw ) ; if ( cum -> nregs < 4 ) { if ( type && TARGET_IVC2 && VECTOR_TYPE_P ( type ) ) return gen_rtx_REG ( mode , cum -> nregs + 49 ) ; else return gen_rtx_REG ( mode , cum -> nregs + 1 ) ; } return NULL_RTX ; } </s>

The ABI is thus : Arguments are in $ 1 , $ 2 , $ 3 , $ 4 , stack . Arguments larger than 4 bytes are passed indirectly . Return value in 0 , unless bigger than 4 bytes , then the caller passes a pointer as the first arg . For varargs , we copy $ 1 .. $ 4 to the stack .


<s> rtx mep_function_value ( const_tree type , const_tree func ATTRIBUTE_UNUSED ) { if ( TARGET_IVC2 && VECTOR_TYPE_P ( type ) ) return gen_rtx_REG ( TYPE_MODE ( type ) , 48 ) ; return gen_rtx_REG ( TYPE_MODE ( type ) , RETURN_VALUE_REGNUM ) ; } </s>

Implement FUNCTION_VALUE . All values are returned in $ 0 .


<s> static bool mep_get_intrinsic_insn ( int intrinsic ATTRIBUTE_UNUSED , const struct cgen_insn * * insn_ptr ATTRIBUTE_UNUSED ) { int i ; i = mep_intrinsic_insn [ intrinsic ] ; while ( i >= 0 && ! CGEN_ENABLE_INSN_P ( i ) ) i = mep_intrinsic_chain [ i ] ; if ( i >= 0 ) { * insn_ptr = & cgen_insns [ i ] ; return true ; } return false ; } </s>

See if any implementation of INTRINSIC is available to the current function . If so , store the most general implementation in * INSN_PTR and return true . Return false otherwise .


<s> static bool mep_get_move_insn ( int intrinsic , const struct cgen_insn * * cgen_insn ) { size_t i ; if ( intrinsic == mep_cmov ) { for ( i = 0 ; i < ARRAY_SIZE ( mep_cmov_insns ) ; i ++ ) if ( mep_get_intrinsic_insn ( mep_cmov_insns [ i ] , cgen_insn ) ) return true ; return false ; } return mep_get_intrinsic_insn ( intrinsic , cgen_insn ) ; } </s>

Like mep_get_intrinsic_insn , but with extra handling for moves . If INTRINSIC is mep_cmov , but there is no pure CR < - CR move insn , try using a work-alike instead . In this case , the returned insn may have three operands rather than two .


"argument %d of %qE must be in the range %d...%d"

"argument %d of %qE must be a multiple of %d"

"incompatible type for argument %d of %qE"

Report that ARG can not be passed to argument ARGNUM of intrinsic function FNNAME . OPERAND describes the operand to which ARGNUM is mapped .


<s> static void mep_init_intrinsics ( void ) { size_t i ; mep_selected_isa = mep_configs [ 0 ] . isa ; if ( mep_config_string != 0 ) for ( i = 0 ; mep_configs [ i ] . config_name ; i ++ ) if ( strcmp ( mep_config_string , mep_configs [ i ] . config_name ) == 0 ) { mep_selected_isa = mep_configs [ i ] . isa ; break ; } for ( i = 0 ; i < ARRAY_SIZE ( mep_intrinsic_insn ) ; i ++ ) mep_intrinsic_insn [ i ] = - 1 ; for ( i = 0 ; i < ARRAY_SIZE ( cgen_insns ) ; i ++ ) if ( ( cgen_insns [ i ] . isas & mep_selected_isa ) != 0 ) { mep_intrinsic_chain [ i ] = mep_intrinsic_insn [ cgen_insns [ i ] . intrinsic ] ; mep_intrinsic_insn [ cgen_insns [ i ] . intrinsic ] = i ; } for ( i = 0 ; i < ARRAY_SIZE ( mep_cmov_insns ) ; i ++ ) if ( MEP_INTRINSIC_AVAILABLE_P ( mep_cmov_insns [ i ] ) ) mep_have_copro_copro_moves_p = true ; mep_have_core_copro_moves_p = ( MEP_INTRINSIC_AVAILABLE_P ( mep_cmov1 ) && MEP_INTRINSIC_AVAILABLE_P ( mep_cmov2 ) ) ; mep_have_core_copro_moves_p = 1 ; } </s>

Initialize the global intrinsics variables above .


<s> static struct machine_function * mep_init_machine_status ( void ) { return ggc_cleared_alloc < machine_function > ( ) ; } </s>

Functions to save and restore machine-specific function data .


"considering end of repeat loop at insn %d\n"

Figure out where to put LABEL , which is the label for a repeat loop . If INCLUDING , LAST_INSN is the last instruction in the loop , otherwise the loop ends just before LAST_INSN . If SHARED , insns other than the `` repeat '' might use LABEL to jump to the loop 's continuation point . Return the last instruction in the adjusted loop .


<s> static int mep_insn_dependent_p ( rtx x , rtx y ) { rtx tmp ; gcc_assert ( INSN_P ( x ) ) ; gcc_assert ( INSN_P ( y ) ) ; tmp = PATTERN ( y ) ; note_stores ( PATTERN ( x ) , mep_insn_dependent_p_1 , & tmp ) ; if ( tmp == NULL_RTX ) return 1 ; tmp = PATTERN ( x ) ; note_stores ( PATTERN ( y ) , mep_insn_dependent_p_1 , & tmp ) ; if ( tmp == NULL_RTX ) return 1 ; return 0 ; } </s>

Return true if anything in insn X is ( anti , output , true ) dependent on anything in insn Y .


<s> static void mep_insn_dependent_p_1 ( rtx x , const_rtx pat ATTRIBUTE_UNUSED , void * data ) { rtx * pinsn = ( rtx * ) data ; if ( * pinsn && reg_mentioned_p ( x , * pinsn ) ) * pinsn = NULL_RTX ; } </s>

A helper routine for ms1_insn_dependent_p called through note_stores .


<s> bool mep_ipipe_ldc_p ( rtx_insn * insn ) { rtx pat , src ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET ) { src = SET_SRC ( pat ) ; if ( GET_CODE ( src ) == UNSPEC || GET_CODE ( src ) == UNSPEC_VOLATILE ) src = XVECEXP ( src , 0 , 0 ) ; if ( REG_P ( src ) ) switch ( REGNO ( src ) ) { case PSW_REGNO : case LP_REGNO : case SAR_REGNO : case HI_REGNO : case LO_REGNO : return true ; } } return false ; } </s>

Return true if INSN is an ldc instruction that issues to the MeP-h1 integer pipeline . This is true for instructions that read from PSW , LP , SAR , HI and LO .


<s> static void mep_jmp_return_reorg ( rtx_insn * insns ) { rtx_insn * insn , * label , * ret ; int ret_code ; for ( insn = insns ; insn ; insn = NEXT_INSN ( insn ) ) if ( simplejump_p ( insn ) ) { label = ret = safe_as_a < rtx_insn * > ( JUMP_LABEL ( insn ) ) ; while ( ret && ( NOTE_P ( ret ) || LABEL_P ( ret ) || GET_CODE ( PATTERN ( ret ) ) == USE ) ) ret = NEXT_INSN ( ret ) ; if ( ret ) { ret_code = recog_memoized ( ret ) ; if ( ret_code == CODE_FOR_return_internal || ret_code == CODE_FOR_eh_return_internal ) { LABEL_NUSES ( label ) -- ; if ( LABEL_NUSES ( label ) == 0 ) delete_insn ( label ) ; PATTERN ( insn ) = copy_rtx ( PATTERN ( ret ) ) ; INSN_CODE ( insn ) = - 1 ; } } } } </s>

Replace a jump to a return , with a copy of the return . GCC does n't always do this on its own .


" - nope, %%lo(sym)[reg] not splittable\n"

Be careful not to use macros that need to be compiled one way for strict , and another way for not-strict , like REG_OK_FOR_BASE_P .


<s> static bool mep_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { if ( GET_CODE ( x ) == SYMBOL_REF && ( reload_in_progress || reload_completed ) ) { char e = mep_section_tag ( x ) ; return ( e != 't' && e != 'b' ) ; } return 1 ; } </s>


<s> static rtx mep_legitimize_arg ( const struct insn_operand_data * operand , rtx arg , int unsigned_p ) { if ( GET_CODE ( arg ) == CONST_INT ) { if ( GET_MODE_CLASS ( operand -> mode ) != MODE_INT ) return 0 ; } else if ( GET_CODE ( arg ) == CONST_DOUBLE ) ; else if ( GET_MODE_SIZE ( GET_MODE ( arg ) ) != GET_MODE_SIZE ( operand -> mode ) ) { if ( GET_MODE_CLASS ( operand -> mode ) != GET_MODE_CLASS ( GET_MODE ( arg ) ) ) return 0 ; if ( operand -> constraint [ 0 ] != '=' ) arg = convert_to_mode ( operand -> mode , arg , unsigned_p ) ; } if ( operand -> constraint [ 0 ] == '=' && ( ! REG_P ( arg ) || ! ( CONTROL_REGNO_P ( REGNO ( arg ) ) || CCR_REGNO_P ( REGNO ( arg ) ) || CR_REGNO_P ( REGNO ( arg ) ) ) ) ) return gen_reg_rtx ( operand -> mode ) ; arg = mep_convert_arg ( operand -> mode , arg ) ; if ( operand -> predicate ( arg , operand -> mode ) ) return arg ; if ( GET_CODE ( arg ) == CONST_INT || GET_CODE ( arg ) == CONST_DOUBLE ) arg = force_reg ( operand -> mode , arg ) ; else arg = mep_convert_arg ( operand -> mode , force_reg ( GET_MODE ( arg ) , arg ) ) ; if ( operand -> predicate ( arg , operand -> mode ) ) return arg ; return 0 ; } </s>

Try to make intrinsic argument ARG match the given operand . UNSIGNED_P is true if the argument has an unsigned type .


<s> rtx mep_libcall_value ( machine_mode mode ) { return gen_rtx_REG ( mode , RETURN_VALUE_REGNUM ) ; } </s>

Implement LIBCALL_VALUE , using the same rules as mep_function_value .


<s> static rtx_insn * mep_make_bundle ( rtx core_insn_or_pat , rtx_insn * cop ) { rtx seq ; rtx_insn * core_insn ; rtx_insn * insn ; if ( INSN_P ( core_insn_or_pat ) ) { core_insn = as_a < rtx_insn * > ( core_insn_or_pat ) ; remove_insn ( core_insn ) ; } else core_insn = make_insn_raw ( core_insn_or_pat ) ; seq = gen_rtx_SEQUENCE ( VOIDmode , gen_rtvec ( 2 , core_insn , cop ) ) ; insn = emit_insn_after ( seq , cop ) ; remove_insn ( cop ) ; SET_PREV_INSN ( core_insn ) = PREV_INSN ( insn ) ; SET_NEXT_INSN ( core_insn ) = cop ; SET_PREV_INSN ( cop ) = core_insn ; SET_NEXT_INSN ( cop ) = NEXT_INSN ( insn ) ; PUT_MODE ( core_insn , VOIDmode ) ; PUT_MODE ( cop , BImode ) ; INSN_LOCATION ( insn ) = INSN_LOCATION ( INSN_LOCATION ( core_insn ) ? core_insn : cop ) ; INSN_LOCATION ( core_insn ) = 0 ; INSN_LOCATION ( cop ) = 0 ; return insn ; } </s>

Create a VLIW bundle from core instruction CORE and coprocessor instruction COP . COP always satisfies INSN_P , but CORE can be either a new pattern or an existing instruction . Emit the bundle in place of COP and return it .


<s> static void mep_make_parallel ( rtx_insn * insn1 , rtx_insn * insn2 ) { rtx expr ; if ( RTX_FRAME_RELATED_P ( insn2 ) ) { expr = mep_frame_expr ( insn2 ) ; if ( RTX_FRAME_RELATED_P ( insn1 ) ) expr = gen_rtx_SEQUENCE ( VOIDmode , gen_rtvec ( 2 , mep_frame_expr ( insn1 ) , expr ) ) ; set_unique_reg_note ( insn1 , REG_FRAME_RELATED_EXPR , expr ) ; RTX_FRAME_RELATED_P ( insn1 ) = 1 ; } PATTERN ( insn1 ) = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , PATTERN ( insn1 ) , PATTERN ( insn2 ) ) ) ; INSN_CODE ( insn1 ) = - 1 ; } </s>

Merge instructions INSN1 and INSN2 using a PARALLEL . Store the new pattern in INSN1 ; INSN2 will be deleted by the caller .


<s> static bool mep_mentioned_p ( rtx in , rtx reg , int modes_too ) { const char * fmt ; int i ; enum rtx_code code ; if ( in == 0 ) return false ; if ( reg && GET_CODE ( reg ) != REG ) return false ; if ( GET_CODE ( in ) == LABEL_REF ) return ( reg == 0 ) ; code = GET_CODE ( in ) ; switch ( code ) { case MEM : if ( reg ) return mep_mentioned_p ( XEXP ( in , 0 ) , reg , modes_too ) ; return true ; case REG : if ( ! reg ) return false ; if ( modes_too && ( GET_MODE ( in ) != GET_MODE ( reg ) ) ) return false ; return ( REGNO ( in ) == REGNO ( reg ) ) ; case SCRATCH : case CC0 : case PC : case CONST_INT : case CONST_DOUBLE : return false ; default : break ; } if ( code == SET && ! reg ) return mep_mentioned_p ( SET_DEST ( in ) , reg , modes_too ) ; fmt = GET_RTX_FORMAT ( code ) ; for ( i = GET_RTX_LENGTH ( code ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { register int j ; for ( j = XVECLEN ( in , i ) - 1 ; j >= 0 ; j -- ) if ( mep_mentioned_p ( XVECEXP ( in , i , j ) , reg , modes_too ) ) return true ; } else if ( fmt [ i ] == 'e' && mep_mentioned_p ( XEXP ( in , i ) , reg , modes_too ) ) return true ; } return false ; } </s>


<s>
bool
mep_mov_ok
(
rtx
*
operands
,
machine_mode
mode
ATTRIBUTE_UNUSED
)
{
int
i
;
fprintf
(
stderr
,
"mep_mov_ok %s %c=%c\n"
,
mode_name
[
mode
]
,
mep_section_tag
(
operands
[
0
]
)
,
mep_section_tag
(
operands
[
1
]
)
)
;
debug_rtx
(
operands
[
0
]
)
;
debug_rtx
(
operands
[
1
]
)
;
if
(
GET_CODE
(
operands
[
1
]
)
==
HIGH
)
return
false
;
if
(
mep_section_tag
(
operands
[
0
]
)
==
'f'
||
mep_section_tag
(
operands
[
1
]
)
==
'f'
)
{
fprintf
(
stderr
,
" - no, f\n"
)
;
return
false
;
}
i
=
mep_section_tag
(
operands
[
1
]
)
;
if
(
(
i
==
'b'
||
i
==
't'
)
&&
!
reload_completed
&&
!
reload_in_progress
)
{
fprintf
(
stderr
,
" - no, bt\n"
)
;
return
false
;
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
rtx
x
=
operands
[
i
]
;
if
(
GET_CODE
(
x
)
==
SUBREG
)
x
=
XEXP
(
x
,
0
)
;
if
(
GET_CODE
(
x
)
==
REG
&&
!
MEP_CONTROL_REG
(
x
)
)
{
fprintf
(
stderr
,
" - ok\n"
)
;
return
true
;
}
}
fprintf
(
stderr
,
" - no, no gen reg\n"
)
;
return
false
;
}
</s>

Cases where the pattern ca n't be made to use at all .


<s> rtx mep_mulr_source ( rtx_insn * insn , rtx dest , rtx src1 , rtx src2 ) { if ( rtx_equal_p ( dest , src1 ) ) return src2 ; else if ( rtx_equal_p ( dest , src2 ) ) return src1 ; else { if ( insn == 0 ) emit_insn ( gen_movsi ( copy_rtx ( dest ) , src1 ) ) ; else emit_insn_before ( gen_movsi ( copy_rtx ( dest ) , src1 ) , insn ) ; return src2 ; } } </s>

Given three integer registers DEST , SRC1 and SRC2 , return an rtx X such that `` mulr DEST , X '' will calculate DEST = SRC1 * SRC2 . If a move is needed , emit it before INSN if INSN is nonnull , otherwise emit it at the end of the insn stream .


<s> bool mep_mul_hilo_bypass_p ( rtx_insn * prev , rtx_insn * insn ) { rtx pat ; pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == PARALLEL ) pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) != SET ) return false ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , SET_SRC ( pat ) , NONCONST ) { const_rtx x = * iter ; if ( REG_P ( x ) && REGNO ( x ) != LO_REGNO && REGNO ( x ) != HI_REGNO && reg_set_p ( x , prev ) ) return false ; } return true ; } </s>

Return true if , apart from HI/LO , there are no true dependencies between multiplication instructions PREV and INSN .


<s> enum reg_class mep_preferred_reload_class ( rtx x , enum reg_class rclass ) { switch ( GET_CODE ( x ) ) { case CONST_INT : if ( INTVAL ( x ) >= 0x10000 && INTVAL ( x ) < 0x01000000 && ( INTVAL ( x ) & 0xffff ) != 0 && reg_class_subset_p ( TPREL_REGS , rclass ) ) rclass = TPREL_REGS ; break ; case CONST : case SYMBOL_REF : case LABEL_REF : if ( mep_section_tag ( x ) != 'f' && reg_class_subset_p ( TPREL_REGS , rclass ) ) rclass = TPREL_REGS ; break ; default : break ; } return rclass ; } </s>

Implement PREFERRED_RELOAD_CLASS . See whether X is a constant that can be moved directly into registers 0 to 7 , but not into the rest . If so , and if the required class includes registers 0 to 7 , restrict it to those registers .


<s> void mep_print_operand_address ( FILE * stream , rtx address ) { if ( GET_CODE ( address ) == MEM ) address = XEXP ( address , 0 ) ; else gcc_assert ( GET_CODE ( address ) == REG ) ; mep_print_operand ( stream , address , 0 ) ; } </s>


<s> int mep_register_move_cost ( machine_mode mode , enum reg_class from , enum reg_class to ) { if ( mep_have_copro_copro_moves_p && reg_class_subset_p ( from , CR_REGS ) && reg_class_subset_p ( to , CR_REGS ) ) { if ( TARGET_32BIT_CR_REGS && GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return 4 ; return 2 ; } if ( reg_class_subset_p ( from , CR_REGS ) && reg_class_subset_p ( to , CR_REGS ) ) { if ( TARGET_32BIT_CR_REGS && GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return 8 ; return 4 ; } if ( reg_class_subset_p ( from , CR_REGS ) || reg_class_subset_p ( to , CR_REGS ) ) { if ( GET_MODE_SIZE ( mode ) > UNITS_PER_WORD ) return 4 ; return 2 ; } if ( mep_secondary_memory_needed ( from , to , mode ) ) return 1000 ; if ( MEP_NONGENERAL_CLASS ( from ) && MEP_NONGENERAL_CLASS ( to ) ) return 1000 ; if ( GET_MODE_SIZE ( mode ) > 4 ) return 4 ; return 2 ; } </s>

Implement REGISTER_MOVE_COST . Return 2 for direct single-register moves , 4 for direct double-register moves , and 1000 for anything that requires a temporary register or temporary stack slot .


<s> static bool mep_reg_set_p ( rtx reg , rtx insn ) { if ( INSN_P ( insn ) ) { if ( FIND_REG_INC_NOTE ( insn , reg ) ) return true ; insn = PATTERN ( insn ) ; } if ( GET_CODE ( insn ) == SET && GET_CODE ( XEXP ( insn , 0 ) ) == REG && GET_CODE ( XEXP ( insn , 1 ) ) == REG && REGNO ( XEXP ( insn , 0 ) ) == REGNO ( XEXP ( insn , 1 ) ) ) return false ; return set_of ( reg , insn ) != NULL_RTX ; } </s>


<s> static void mep_reload_pointer ( int regno , const char * symbol ) { rtx reg , sym ; if ( ! df_regs_ever_live_p ( regno ) && crtl -> is_leaf ) return ; reg = gen_rtx_REG ( SImode , regno ) ; sym = gen_rtx_SYMBOL_REF ( SImode , symbol ) ; emit_insn ( gen_movsi_topsym_s ( reg , sym ) ) ; emit_insn ( gen_movsi_botsym_s ( reg , reg , sym ) ) ; } </s>

Used for interrupt functions , which ca n't assume that $ tp and $ gp contain the correct pointers .


<s> static void mep_reorg_noframe ( rtx_insn * insns ) { rtx_insn * start_frame_insn ; rtx_insn * end_frame_insn = 0 ; int sp_adjust , sp2 ; rtx sp ; while ( insns && ! INSN_P ( insns ) ) insns = NEXT_INSN ( insns ) ; if ( ! insns ) return ; sp_adjust = add_sp_insn_p ( insns ) ; if ( sp_adjust == 0 ) return ; start_frame_insn = insns ; sp = SET_DEST ( PATTERN ( start_frame_insn ) ) ; insns = next_real_insn ( insns ) ; while ( insns ) { rtx_insn * next = next_real_insn ( insns ) ; if ( ! next ) break ; sp2 = add_sp_insn_p ( insns ) ; if ( sp2 ) { if ( end_frame_insn ) return ; end_frame_insn = insns ; if ( sp2 != - sp_adjust ) return ; } else if ( mep_mentioned_p ( insns , sp , 0 ) ) return ; else if ( CALL_P ( insns ) ) return ; insns = next ; } if ( end_frame_insn ) { delete_insn ( start_frame_insn ) ; delete_insn ( end_frame_insn ) ; } } </s>

Check for trivial functions that set up an unneeded stack frame .


<s> static bool mep_repeat_loop_p ( struct mep_doloop * loop ) { struct mep_doloop_end * end ; rtx fallthrough ; if ( loop -> begin == 0 || loop -> end == 0 || loop -> begin -> next != 0 ) return false ; if ( prev_real_insn ( loop -> end -> label ) != loop -> begin -> insn ) return false ; fallthrough = loop -> end -> fallthrough ; for ( end = loop -> end -> next ; end != 0 ; end = end -> next ) if ( end -> label != loop -> end -> label || ! simplejump_p ( end -> fallthrough ) || next_real_insn ( JUMP_LABEL ( end -> fallthrough ) ) != fallthrough ) return false ; return true ; } </s>

Return true if LOOP can be converted into repeat/repeat_end form ( that is , if it matches cases ( 1 ) or ( 2 ) above ) .


<s> bool mep_reuse_lo_p ( rtx lo , rtx gpr , rtx_insn * insn , bool gpr_dead_p ) { bool result = mep_reuse_lo_p_1 ( lo , gpr , insn , gpr_dead_p ) ; extract_insn ( insn ) ; return result ; } </s>

A wrapper around mep_reuse_lo_p_1 that preserves recog_data .


<s> static bool mep_reuse_lo_p_1 ( rtx lo , rtx gpr , rtx_insn * insn , bool gpr_dead_p ) { do { insn = PREV_INSN ( insn ) ; if ( INSN_P ( insn ) ) switch ( recog_memoized ( insn ) ) { case CODE_FOR_mulsi3_1 : extract_insn ( insn ) ; if ( rtx_equal_p ( recog_data . operand [ 0 ] , gpr ) ) { mep_rewrite_mulsi3 ( insn , gpr_dead_p ? NULL : recog_data . operand [ 0 ] , recog_data . operand [ 1 ] , recog_data . operand [ 2 ] ) ; return true ; } return false ; case CODE_FOR_maddsi3 : extract_insn ( insn ) ; if ( rtx_equal_p ( recog_data . operand [ 0 ] , gpr ) ) { mep_rewrite_maddsi3 ( insn , gpr_dead_p ? NULL : recog_data . operand [ 0 ] , recog_data . operand [ 1 ] , recog_data . operand [ 2 ] , recog_data . operand [ 3 ] ) ; return true ; } return false ; case CODE_FOR_mulsi3r : case CODE_FOR_maddsi3r : extract_insn ( insn ) ; return rtx_equal_p ( recog_data . operand [ 1 ] , gpr ) ; default : if ( reg_set_p ( lo , insn ) || reg_set_p ( gpr , insn ) || volatile_insn_p ( PATTERN ( insn ) ) ) return false ; if ( gpr_dead_p && reg_referenced_p ( gpr , PATTERN ( insn ) ) ) gpr_dead_p = false ; break ; } } while ( ! NOTE_INSN_BASIC_BLOCK_P ( insn ) ) ; return false ; } </s>

Return true if $ lo has the same value as integer register GPR when instruction INSN is reached . If necessary , rewrite the instruction that sets $ lo so that it uses a proper SET , not a CLOBBER . LO is an rtx for ( reg : SI LO_REGNO ) . This function is intended to be used by the peephole2 pass . Since that pass goes from the end of a basic block to the beginning , and propagates liveness information on the way , there is no need to update register notes here . If GPR_DEAD_P is true on entry , and this function returns true , then the caller will replace _every_ use of GPR in and after INSN with LO . This means that if the instruction that sets $ lo is a mulr- or maddr-type instruction , we can rewrite it to use mul or madd instead . In combination with the copy progagation pass , this allows us to replace sequences like : mov GPR , R1 mulr GPR , R2 with : mul R1 , R2 if GPR is no longer used .


<s> static void mep_rewrite_maddsi3 ( rtx_insn * insn , rtx dest , rtx src1 , rtx src2 , rtx src3 ) { rtx lo , pattern ; lo = gen_rtx_REG ( SImode , LO_REGNO ) ; emit_insn_before ( gen_movsi ( copy_rtx ( lo ) , src3 ) , insn ) ; if ( dest ) pattern = gen_maddsi3r ( lo , dest , copy_rtx ( dest ) , mep_mulr_source ( insn , dest , src1 , src2 ) , copy_rtx ( lo ) ) ; else pattern = gen_maddsi3_lo ( lo , src1 , src2 , copy_rtx ( lo ) ) ; mep_rewrite_mult ( insn , pattern ) ; } </s>

Like mep_rewrite_mulsi3 , but calculate SRC1 * SRC2 + SRC3 . First copy SRC3 into $ lo , then use either madd or maddr . The move into $ lo will be deleted by a peephole2 if SRC3 is already in $ lo .


<s> static void mep_rewrite_mulsi3 ( rtx_insn * insn , rtx dest , rtx src1 , rtx src2 ) { rtx lo , pattern ; lo = gen_rtx_REG ( SImode , LO_REGNO ) ; if ( dest ) pattern = gen_mulsi3r ( lo , dest , copy_rtx ( dest ) , mep_mulr_source ( insn , dest , src1 , src2 ) ) ; else pattern = gen_mulsi3_lo ( lo , src1 , src2 ) ; mep_rewrite_mult ( insn , pattern ) ; } </s>

Subroutine of mep_reuse_lo_p . Rewrite instruction INSN so that it calculates SRC1 * SRC2 and stores the result in $ lo . Also make it store the result in DEST if nonnull .


<s> static void mep_rewrite_mult ( rtx_insn * insn , rtx pattern ) { rtx hi_clobber ; hi_clobber = XVECEXP ( pattern , 0 , XVECLEN ( pattern , 0 ) - 1 ) ; XEXP ( hi_clobber , 0 ) = gen_rtx_REG ( SImode , HI_REGNO ) ; PATTERN ( insn ) = pattern ; INSN_CODE ( insn ) = - 1 ; } </s>

Replace INSN 's pattern with PATTERN , a multiplication PARALLEL . Change the last element of PATTERN from ( clobber ( scratch : SI ) ) to ( clobber ( reg : SI HI_REGNO ) ) .


<s> void mep_save_register_info ( void ) { save_register_info ( ) ; } </s>

These three functions provide a bridge between the pramgas that affect register classes , and the functions that maintain them . We ca n't call those functions directly as pragma handling is part of the front end and does n't have direct access to them .


<s> static enum reg_class mep_secondary_copro_reload_class ( enum reg_class rclass , rtx x ) { if ( mep_general_reg ( x ) ) return NO_REGS ; if ( mep_general_copro_reg ( x ) ) { if ( mep_have_copro_copro_moves_p ) return NO_REGS ; if ( mep_have_core_copro_moves_p ) return GENERAL_REGS ; return NO_REGS ; } if ( reg_class_subset_p ( rclass , LOADABLE_CR_REGS ) && constraint_satisfied_p ( x , CONSTRAINT_U ) ) return NO_REGS ; return GENERAL_REGS ; } </s>

Return the secondary reload class needed for moving value X to or from a register in coprocessor register class CLASS .


"secondary input reload copy to %s %s from "


<s> bool mep_secondary_memory_needed ( enum reg_class rclass1 , enum reg_class rclass2 , machine_mode mode ATTRIBUTE_UNUSED ) { if ( ! mep_have_core_copro_moves_p ) { if ( reg_classes_intersect_p ( rclass1 , CR_REGS ) && reg_classes_intersect_p ( rclass2 , GENERAL_REGS ) ) return true ; if ( reg_classes_intersect_p ( rclass2 , CR_REGS ) && reg_classes_intersect_p ( rclass1 , GENERAL_REGS ) ) return true ; if ( ! mep_have_copro_copro_moves_p && reg_classes_intersect_p ( rclass1 , CR_REGS ) && reg_classes_intersect_p ( rclass2 , CR_REGS ) ) return true ; } return false ; } </s>


"secondary output reload copy from %s %s to "


<s> static void mep_setup_incoming_varargs ( cumulative_args_t cum , machine_mode mode ATTRIBUTE_UNUSED , tree type ATTRIBUTE_UNUSED , int * pretend_size , int second_time ATTRIBUTE_UNUSED ) { int nsave = 4 - ( get_cumulative_args ( cum ) -> nregs + 1 ) ; if ( nsave > 0 ) cfun -> machine -> arg_regs_to_save = nsave ; * pretend_size = nsave * 4 ; } </s>


<s> static bool mep_store_data_bypass_1 ( rtx_insn * prev , rtx pat ) { if ( GET_CODE ( pat ) == PARALLEL ) { int i ; for ( i = 0 ; i < XVECLEN ( pat , 0 ) ; i ++ ) if ( mep_store_data_bypass_p ( prev , as_a < rtx_insn * > ( XVECEXP ( pat , 0 , i ) ) ) ) return true ; return false ; } if ( GET_CODE ( pat ) != SET || GET_CODE ( SET_DEST ( pat ) ) != MEM ) return false ; if ( GET_CODE ( SET_SRC ( pat ) ) == UNSPEC ) { rtx src ; int i ; src = SET_SRC ( pat ) ; for ( i = 1 ; i < XVECLEN ( src , 0 ) ; i ++ ) if ( mep_store_find_set ( XVECEXP ( src , 0 , i ) , prev ) ) return false ; return true ; } return ! mep_store_find_set ( SET_DEST ( pat ) , prev ) ; } </s>

Like mep_store_bypass_p , but takes a pattern as the second argument , not the containing insn .


<s> bool mep_store_data_bypass_p ( rtx_insn * prev , rtx_insn * insn ) { return INSN_P ( insn ) ? mep_store_data_bypass_1 ( prev , PATTERN ( insn ) ) : false ; } </s>

Return true if INSN is a store instruction and if the store address has no true dependence on PREV .


<s> static bool mep_store_find_set ( const_rtx x , const rtx_insn * prev ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , NONCONST ) if ( REG_P ( x ) && reg_set_p ( x , prev ) ) return true ; return false ; } </s>

Return true if X contains a register that is set by insn PREV .


<s> static void mep_trampoline_init ( rtx m_tramp , tree fndecl , rtx static_chain ) { rtx addr = XEXP ( m_tramp , 0 ) ; rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; emit_library_call ( gen_rtx_SYMBOL_REF ( Pmode , "__mep_trampoline_helper" ) , LCT_NORMAL , VOIDmode , 3 , addr , Pmode , fnaddr , Pmode , static_chain , Pmode ) ; } </s>


<s> static bool mep_use_post_modify_for_set_p ( rtx set , rtx gpr , rtx offset ) { rtx * reg , * mem ; unsigned int reg_bytes , mem_bytes ; machine_mode reg_mode , mem_mode ; if ( GET_CODE ( set ) != SET ) return false ; if ( GET_CODE ( SET_DEST ( set ) ) == MEM ) { mem = & SET_DEST ( set ) ; reg = & SET_SRC ( set ) ; } else { reg = & SET_DEST ( set ) ; mem = & SET_SRC ( set ) ; if ( GET_CODE ( * mem ) == SIGN_EXTEND ) mem = & XEXP ( * mem , 0 ) ; } if ( GET_CODE ( * reg ) != REG || ! LOADABLE_CR_REGNO_P ( REGNO ( * reg ) ) ) return false ; if ( GET_CODE ( * mem ) != MEM || ! rtx_equal_p ( XEXP ( * mem , 0 ) , gpr ) ) return false ; mem_bytes = GET_MODE_SIZE ( GET_MODE ( * mem ) ) ; reg_bytes = GET_MODE_SIZE ( GET_MODE ( * reg ) ) ; if ( INTVAL ( offset ) & ( mem_bytes - 1 ) ) return false ; mem_mode = mode_for_size ( mem_bytes * BITS_PER_UNIT , MODE_INT , 0 ) ; * mem = change_address ( * mem , mem_mode , NULL ) ; * reg = shallow_copy_rtx ( * reg ) ; if ( reg == & SET_DEST ( set ) && reg_bytes < UNITS_PER_WORD ) { PUT_MODE ( * reg , SImode ) ; * mem = gen_rtx_SIGN_EXTEND ( SImode , * mem ) ; } else { reg_mode = mode_for_size ( reg_bytes * BITS_PER_UNIT , MODE_INT , 0 ) ; PUT_MODE ( * reg , reg_mode ) ; } return true ; } </s>

Return true if SET can be turned into a post-modify load or store that adds OFFSET to GPR . In other words , return true if SET can be changed into : ( parallel [ SET ( set GPR ( plus : SI GPR OFFSET ) ) ] ) . It 's OK to change SET to an equivalent operation in order to make it match .


<s> bool mep_use_post_modify_p ( rtx_insn * insn , rtx reg , rtx offset ) { bool result = mep_use_post_modify_p_1 ( insn , reg , offset ) ; extract_insn ( insn ) ; return result ; } </s>

A wrapper around mep_use_post_modify_p_1 that preserves recog_data .


<s> static bool mep_use_post_modify_p_1 ( rtx_insn * set_insn , rtx reg , rtx offset ) { rtx_insn * insn ; insn = set_insn ; do { insn = PREV_INSN ( insn ) ; if ( INSN_P ( insn ) ) { if ( mep_use_post_modify_for_set_p ( PATTERN ( insn ) , reg , offset ) ) { mep_make_parallel ( insn , set_insn ) ; return true ; } if ( reg_set_p ( reg , insn ) || reg_referenced_p ( reg , PATTERN ( insn ) ) || volatile_insn_p ( PATTERN ( insn ) ) ) return false ; } } while ( ! NOTE_INSN_BASIC_BLOCK_P ( insn ) ) ; return false ; } </s>

SET_INSN is an instruction that adds OFFSET to REG . Go back through the basic block to see if any previous load or store instruction can be persuaded to do SET_INSN as a side-effect . Return true if so .


"%qE attribute only applies to variables"

"address region attributes not allowed with auto storage class"

"address region attributes on pointed-to types ignored"


<s> bool mep_vliw_function_p ( tree decl ) { return lookup_attribute ( "vliw" , TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ) != 0 ; } </s>

Return true if function DECL was declared with the vliw attribute .


<s> bool mep_vliw_jmp_match ( rtx tgt ) { bool src_vliw = mep_vliw_function_p ( cfun -> decl ) ; bool tgt_vliw = INTVAL ( tgt ) ; if ( mep_section_tag ( DECL_RTL ( cfun -> decl ) ) == 'f' ) return false ; return src_vliw == tgt_vliw ; } </s>

Like the above , but also test for near/far mismatches .


<s> bool mep_vliw_mode_match ( rtx tgt ) { bool src_vliw = mep_vliw_function_p ( cfun -> decl ) ; bool tgt_vliw = INTVAL ( tgt ) ; return src_vliw == tgt_vliw ; } </s>

Irritatingly , the `` jsrv '' insn * toggles * PSW.OM rather than set it to one specific value . So the insn chosen depends on whether the source and destination modes match .


<s> static bool symbol_p ( rtx x ) { int c = GET_CODE ( x ) ; return ( c == CONST_INT || c == CONST || c == SYMBOL_REF ) ; } </s>

MEP has very few instructions that can refer to the span of addresses used by symbols , so it 's common to check for them .