<s> bool gen_operands_ldd_std ( rtx * operands , bool load , bool commute ) { int i , gap ; HOST_WIDE_INT offsets [ 2 ] , offset ; int nops = 2 ; rtx cur_base , cur_offset , tmp ; rtx base = NULL_RTX ; for ( i = 0 ; i < nops ; i ++ ) { if ( ! mem_ok_for_ldd_std ( operands [ nops + i ] , & cur_base , & cur_offset ) ) return false ; if ( i == 0 ) base = cur_base ; else if ( REGNO ( base ) != REGNO ( cur_base ) ) return false ; offsets [ i ] = INTVAL ( cur_offset ) ; if ( GET_CODE ( operands [ i ] ) == SUBREG ) { tmp = SUBREG_REG ( operands [ i ] ) ; gcc_assert ( GET_MODE ( operands [ i ] ) == GET_MODE ( tmp ) ) ; operands [ i ] = tmp ; } } if ( load && REGNO ( operands [ 0 ] ) == REGNO ( base ) ) return false ; if ( load && REGNO ( operands [ 0 ] ) == REGNO ( operands [ 1 ] ) ) return false ; if ( offsets [ 0 ] > offsets [ 1 ] ) { gap = offsets [ 0 ] - offsets [ 1 ] ; offset = offsets [ 1 ] ; std :: swap ( operands [ 0 ] , operands [ 1 ] ) ; std :: swap ( operands [ 2 ] , operands [ 3 ] ) ; } else { gap = offsets [ 1 ] - offsets [ 0 ] ; offset = offsets [ 0 ] ; } if ( gap != 4 ) return false ; if ( operands_ok_ldd_std ( operands [ 0 ] , operands [ 1 ] , offset ) ) return true ; if ( load && commute ) { std :: swap ( operands [ 0 ] , operands [ 1 ] ) ; if ( operands_ok_ldd_std ( operands [ 0 ] , operands [ 1 ] , offset ) ) return true ; } return false ; } </s>

Called from peephole2 to replace two word-size accesses with a single LDD/STD instruction . Returns true iff we can generate a new instruction sequence . That is , both accesses use the same base register and the gap between constant offsets is 4 . OPERANDS are the operands found by the peephole matcher ; OPERANDS [ 0,1 ] are register operands , and OPERANDS [ 2,3 ] are the corresponding memory operands . LOAD indicates whether the access is load or store .


<s> static int get_symbol_alignment ( rtx x ) { tree decl = NULL_TREE ; int align = 0 ; switch ( GET_CODE ( x ) ) { case SYMBOL_REF : decl = SYMBOL_REF_DECL ( x ) ; break ; case CONST : return get_symbol_alignment ( XEXP ( x , 0 ) ) ; case PLUS : gcc_assert ( CONST_INT_P ( XEXP ( x , 1 ) ) ) ; return get_symbol_alignment ( XEXP ( x , 0 ) ) ; default : return 0 ; } if ( decl ) align = DECL_ALIGN ( decl ) ; align = align / BITS_PER_UNIT ; return align ; } </s>

Given a symbol RTX ( const ( symb < + const_int > ) , returns its alignment .


<s> static void hwloop_fail ( hwloop_info loop ) { rtx test ; rtx insn = loop -> loop_end ; if ( TARGET_DBNZ && ( loop -> length && ( loop -> length <= ARC_MAX_LOOP_LENGTH ) ) && REG_P ( loop -> iter_reg ) ) { test = gen_dbnz ( loop -> iter_reg , loop -> start_label ) ; insn = emit_jump_insn_before ( test , loop -> loop_end ) ; } else if ( REG_P ( loop -> iter_reg ) && ( REGNO ( loop -> iter_reg ) == LP_COUNT ) ) { emit_insn_before ( gen_loop_fail ( ) , loop -> loop_end ) ; test = gen_rtx_NE ( VOIDmode , gen_rtx_REG ( CC_ZNmode , CC_REG ) , const0_rtx ) ; test = gen_rtx_IF_THEN_ELSE ( VOIDmode , test , gen_rtx_LABEL_REF ( Pmode , loop -> start_label ) , pc_rtx ) ; insn = emit_jump_insn_before ( gen_rtx_SET ( pc_rtx , test ) , loop -> loop_end ) ; } else { emit_insn_before ( gen_addsi3 ( loop -> iter_reg , loop -> iter_reg , constm1_rtx ) , loop -> loop_end ) ; test = gen_rtx_NE ( VOIDmode , loop -> iter_reg , const0_rtx ) ; insn = emit_jump_insn_before ( gen_cbranchsi4 ( test , loop -> iter_reg , const0_rtx , loop -> start_label ) , loop -> loop_end ) ; } JUMP_LABEL ( insn ) = loop -> start_label ; LABEL_NUSES ( loop -> start_label ) ++ ; delete_insn ( loop -> loop_end ) ; } </s>

A callback for the hw-doloop pass . Called when a loop we have discovered turns out not to be optimizable ; we have to split the doloop_end pattern into a subtract and a test .


<s> static rtx hwloop_pattern_reg ( rtx_insn * insn ) { rtx reg ; if ( ! JUMP_P ( insn ) || recog_memoized ( insn ) != CODE_FOR_loop_end ) return NULL_RTX ; reg = SET_DEST ( XVECEXP ( PATTERN ( insn ) , 0 , 1 ) ) ; if ( ! REG_P ( reg ) ) return NULL_RTX ; return reg ; } </s>

A callback for the hw-doloop pass . This function examines INSN ; if it is a doloop_end pattern we recognize , return the reg rtx for the loop counter . Otherwise , return NULL_RTX .


"last register name %s must be an odd register"

Parse -mirq-ctrl-saved=RegisterRange , blink , lp_copunt . The register range is specified as two registers separated by a dash . It always starts with r0 , and its upper limit is fp register . blink and lp_count registers are optional .


<s> static void jli_call_scan ( void ) { rtx_insn * insn ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( ! CALL_P ( insn ) ) continue ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == COND_EXEC ) pat = COND_EXEC_CODE ( pat ) ; pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET ) pat = SET_SRC ( pat ) ; pat = XEXP ( XEXP ( pat , 0 ) , 0 ) ; if ( GET_CODE ( pat ) == SYMBOL_REF && arc_is_jli_call_p ( pat ) ) arc_add_jli_section ( pat ) ; } } </s>

Scan all calls and add symbols to be emitted in the jli section if needed .


<s> static bool legitimate_offset_address_p ( machine_mode mode , rtx x , bool index , bool strict ) { if ( GET_CODE ( x ) != PLUS ) return false ; if ( ! RTX_OK_FOR_BASE_P ( XEXP ( x , 0 ) , ( strict ) ) ) return false ; if ( ( ( index && RTX_OK_FOR_INDEX_P ( XEXP ( x , 1 ) , ( strict ) ) && GET_MODE_SIZE ( ( mode ) ) <= 4 ) || RTX_OK_FOR_OFFSET_P ( mode , XEXP ( x , 1 ) ) ) ) return true ; if ( ! flag_pic && ( GET_CODE ( XEXP ( x , 1 ) ) == SYMBOL_REF ) && ( GET_MODE_SIZE ( mode ) <= 4 ) && ( ! SYMBOL_REF_SMALL_P ( XEXP ( x , 1 ) ) ) ) return true ; return false ; } </s>

Check for constructions like REG + OFFS , where OFFS can be a register , an immediate or an long immediate .


<s> static bool legitimate_scaled_address_p ( machine_mode mode , rtx op , bool strict ) { if ( GET_CODE ( op ) != PLUS ) return false ; if ( GET_CODE ( XEXP ( op , 0 ) ) != MULT ) return false ; if ( ! RTX_OK_FOR_INDEX_P ( XEXP ( XEXP ( op , 0 ) , 0 ) , strict ) ) return false ; if ( ! CONST_INT_P ( XEXP ( XEXP ( op , 0 ) , 1 ) ) ) return false ; switch ( GET_MODE_SIZE ( mode ) ) { case 2 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 2 ) return false ; break ; case 8 : if ( ! TARGET_LL64 ) return false ; case 4 : if ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) != 4 ) return false ; default : return false ; } if ( RTX_OK_FOR_BASE_P ( XEXP ( op , 1 ) , ( strict ) ) ) return true ; if ( flag_pic ) { if ( CONST_INT_P ( XEXP ( op , 1 ) ) ) return true ; return false ; } if ( legitimate_small_data_address_p ( op , mode ) ) return false ; if ( CONSTANT_P ( XEXP ( op , 1 ) ) ) return true ; return false ; } </s>


<s> static bool legitimate_small_data_address_p ( rtx x , machine_mode mode ) { switch ( GET_CODE ( x ) ) { case CONST : return legitimate_small_data_address_p ( XEXP ( x , 0 ) , mode ) ; case SYMBOL_REF : return SYMBOL_REF_SMALL_P ( x ) ; case PLUS : { bool p0 = ( GET_CODE ( XEXP ( x , 0 ) ) == SYMBOL_REF ) && SYMBOL_REF_SMALL_P ( XEXP ( x , 0 ) ) ; if ( ! CONST_INT_P ( XEXP ( x , 1 ) ) ) return false ; switch ( GET_MODE_SIZE ( mode ) ) { case 1 : return p0 ; case 2 : return p0 && ( ( INTVAL ( XEXP ( x , 1 ) ) & 0x1 ) == 0 ) ; case 4 : case 8 : return p0 && ( ( INTVAL ( XEXP ( x , 1 ) ) & 0x3 ) == 0 ) ; default : return false ; } } default : return false ; } } </s>

Return true if x is ok to be used as a small data address .


<s> static bool mem_ok_for_ldd_std ( rtx mem , rtx * base , rtx * offset ) { rtx addr ; gcc_assert ( base != NULL && offset != NULL ) ; if ( side_effects_p ( mem ) ) return false ; if ( GET_CODE ( mem ) == SUBREG ) return false ; gcc_assert ( MEM_P ( mem ) ) ; * offset = const0_rtx ; addr = XEXP ( mem , 0 ) ; if ( ! arc_legitimate_address_p ( DImode , addr , reload_in_progress || reload_completed ) ) return false ; if ( REG_P ( addr ) ) { * base = addr ; return true ; } else if ( GET_CODE ( addr ) == PLUS || GET_CODE ( addr ) == MINUS ) { * base = XEXP ( addr , 0 ) ; * offset = XEXP ( addr , 1 ) ; return ( REG_P ( * base ) && CONST_INT_P ( * offset ) ) ; } return false ; } </s>

Helper for gen_operands_ldd_std . Returns true iff the memory operand MEM 's address contains an immediate offset from the base register and has no side effects , in which case it sets BASE and OFFSET accordingly .


<s> static rtx_insn * next_nonnote_insn_bb ( rtx_insn * insn ) { while ( insn ) { insn = NEXT_INSN ( insn ) ; if ( insn == 0 || ! NOTE_P ( insn ) ) break ; if ( NOTE_INSN_BASIC_BLOCK_P ( insn ) ) return NULL ; } return insn ; } </s>

Return the next insn after INSN that is not a NOTE , but stop the search before we enter another basic block . This routine does not look inside SEQUENCEs .


<s> static bool operands_ok_ldd_std ( rtx rt , rtx rt2 , HOST_WIDE_INT offset ) { unsigned int t , t2 ; if ( ! reload_completed ) return true ; if ( ! ( SMALL_INT_RANGE ( offset , ( GET_MODE_SIZE ( DImode ) - 1 ) & ( ~ 0x03 ) , ( offset & ( GET_MODE_SIZE ( DImode ) - 1 ) & 3 ? 0 : - ( - GET_MODE_SIZE ( DImode ) | ( ~ 0x03 ) ) >> 1 ) ) ) ) return false ; t = REGNO ( rt ) ; t2 = REGNO ( rt2 ) ; if ( ( t2 == PCL_REG ) || ( t % 2 != 0 ) || ( t2 != t + 1 ) ) return false ; return true ; } </s>

Checks whether the operands are valid for use in an LDD/STD instruction . Assumes that RT , and RT2 are REG . This is guaranteed by the patterns . Assumes that the address in the base register RN is word aligned . Pattern guarantees that both memory accesses use the same base register , the offsets are constants within the range , and the gap between the offsets is 4 . If reload complete then check that registers are legal .


FIXME : This probably can be done using a define_split in arc.md . Alternately , generate rtx rather than output instructions .


<s> static void output_short_suffix ( FILE * file ) { rtx_insn * insn = current_output_insn ; if ( ! insn ) return ; if ( arc_verify_short ( insn , cfun -> machine -> unalign , 1 ) ) { fprintf ( file , "_s" ) ; cfun -> machine -> unalign ^= 2 ; } extract_insn_cached ( insn ) ; } </s>

When outputting an instruction ( alternative ) that can potentially be short , output the short suffix if the insn is in fact short , and update cfun- > machine- > unalign accordingly .


<s> static void pad_return ( void ) { rtx_insn * insn ; long offset ; if ( ! TARGET_PAD_RETURN ) return ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { rtx_insn * prev0 = prev_active_insn ( insn ) ; bool wantlong = false ; if ( ! INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) != SIMPLE_RETURN ) continue ; if ( ! prev0 ) { prev0 = emit_insn_before ( gen_nopv ( ) , insn ) ; add_reg_note ( prev0 , REG_SAVE_NOTE , GEN_INT ( 1 ) ) ; emit_insn_before ( gen_nopv ( ) , insn ) ; continue ; } offset = get_attr_length ( prev0 ) ; if ( get_attr_length ( prev0 ) == 2 && get_attr_iscompact ( prev0 ) != ISCOMPACT_TRUE ) { wantlong = true ; offset += 2 ; } rtx_insn * prev = prev_active_insn ( prev0 ) ; if ( prev ) offset += get_attr_length ( prev ) ; prev = prev_active_insn ( prev ) ; if ( prev ) offset += get_attr_length ( prev ) ; switch ( offset ) { case 2 : prev = emit_insn_before ( gen_nopv ( ) , insn ) ; add_reg_note ( prev , REG_SAVE_NOTE , GEN_INT ( 1 ) ) ; break ; case 4 : emit_insn_before ( gen_nopv ( ) , insn ) ; break ; default : continue ; } if ( wantlong ) add_reg_note ( prev0 , REG_SAVE_NOTE , GEN_INT ( 1 ) ) ; emit_insn_before ( gen_blockage ( ) , insn ) ; } } </s>

Add padding if necessary to avoid a mispredict . A return could happen immediately after the function start . A call/return and return/return must be 6 bytes apart to avoid mispredict .


"invalid number in %<-mrgf-banked-regs=%s%> "

Parse -mrgf-banked-regs=NUM option string . Valid values for NUM are 4 , 8 , 16 , or 32 .


<s> static int pop_reg ( rtx reg ) { rtx stkslot = gen_rtx_MEM ( GET_MODE ( reg ) , gen_rtx_POST_INC ( Pmode , stack_pointer_rtx ) ) ; rtx insn = emit_move_insn ( reg , stkslot ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , GET_MODE_SIZE ( GET_MODE ( reg ) ) ) ) ) ; return GET_MODE_SIZE ( GET_MODE ( reg ) ) ; } </s>

Helper used when restoring AUX regs during ISR .


<s> static int push_reg ( rtx reg ) { rtx stkslot = gen_rtx_MEM ( GET_MODE ( reg ) , gen_rtx_PRE_DEC ( Pmode , stack_pointer_rtx ) ) ; rtx insn = emit_move_insn ( stkslot , reg ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - GET_MODE_SIZE ( GET_MODE ( reg ) ) ) ) ) ; return GET_MODE_SIZE ( GET_MODE ( reg ) ) ; } </s>

Helper used when saving AUX regs during ISR .


<s> void split_addsi ( rtx * operands ) { int val = INTVAL ( operands [ 2 ] ) ; if ( val > 127 && val <= 255 && satisfies_constraint_Rcq ( operands [ 0 ] ) ) { operands [ 3 ] = operands [ 2 ] ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 1 ] ) ; } else { operands [ 3 ] = operands [ 1 ] ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 2 ] ) ; } } </s>

Operands 0 .. 2 are the operands of a addsi which uses a 12 bit constant in operand 2 , but which would require a LIMM because of operand mismatch . operands 3 and 4 are new SET_SRCs for operands 0 .


<s> void split_subsi ( rtx * operands ) { int val = INTVAL ( operands [ 1 ] ) ; if ( satisfies_constraint_Rcq ( operands [ 0 ] ) && satisfies_constraint_Rcq ( operands [ 2 ] ) ) { if ( val >= - 31 && val <= 127 ) { operands [ 3 ] = gen_rtx_NEG ( SImode , operands [ 2 ] ) ; operands [ 4 ] = gen_rtx_PLUS ( SImode , operands [ 0 ] , operands [ 1 ] ) ; return ; } else if ( val >= 0 && val < 255 ) { operands [ 3 ] = operands [ 1 ] ; operands [ 4 ] = gen_rtx_MINUS ( SImode , operands [ 0 ] , operands [ 2 ] ) ; return ; } } operands [ 3 ] = operands [ 2 ] ; operands [ 4 ] = gen_rtx_MINUS ( SImode , operands [ 1 ] , operands [ 0 ] ) ; } </s>

Operands 0 .. 2 are the operands of a subsi which uses a 12 bit constant in operand 1 , but which would require a LIMM because of operand mismatch . operands 3 and 4 are new SET_SRCs for operands 0 .


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

Return true if OP contains a symbol reference


<s> static void workaround_arc_anomaly ( void ) { rtx_insn * insn , * succ0 ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { succ0 = next_real_insn ( insn ) ; if ( arc_hazard ( insn , succ0 ) ) { emit_insn_before ( gen_nopv ( ) , succ0 ) ; } } if ( ! TARGET_ARC700 ) return ; if ( arc_tune != ARC_TUNE_ARC7XX ) check_store_cacheline_hazard ( ) ; } </s>

The same functionality as arc_hazard . It is called in machine reorg before any other optimization . Hence , the NOP size is taken into account when doing branch shortening .


<s>
const
char
*
arc_cpu_to_as
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
name
=
;
const
arc_cpu_t
*
arc_selected_cpu
;
if
(
argc
==
0
)
{
arc_selected_cpu
=
&
arc_cpu_types
[
(
int
)
TARGET_CPU_DEFAULT
]
;
}
else
{
name
=
argv
[
0
]
;
for
(
arc_selected_cpu
=
arc_cpu_types
;
arc_selected_cpu
->
name
;
arc_selected_cpu
++
)
{
if
(
strcmp
(
arc_selected_cpu
->
name
,
name
)
==
0
)
break
;
}
}
switch
(
arc_selected_cpu
->
arch_info
->
arch_id
)
{
case
BASE_ARCH_em
:
if
(
arc_selected_cpu
->
flags
&
FL_CD
)
name
=
"-mcode-density"
;
else
name
=
""
;
if
(
arc_selected_cpu
->
flags
&
FL_FPUDA
)
name
=
concat
(
"-mfpuda "
,
name
,
)
;
if
(
arc_selected_cpu
->
flags
&
FL_SPFP
)
name
=
concat
(
"-mspfp "
,
name
,
)
;
if
(
arc_selected_cpu
->
flags
&
FL_DPFP
)
name
=
concat
(
"-mdpfp "
,
name
,
)
;
return
concat
(
"-mcpu=arcem "
,
name
,
)
;
case
BASE_ARCH_hs
:
return
"-mcpu=archs"
;
case
BASE_ARCH_700
:
if
(
arc_selected_cpu
->
processor
==
PROCESSOR_nps400
)
return
"-mcpu=nps400 -mEA"
;
else
return
"-mcpu=arc700 -mEA"
;
case
BASE_ARCH_6xx
:
if
(
arc_selected_cpu
->
flags
&
FL_MUL64
)
return
"-mcpu=arc600 -mmul64 -mnorm"
;
if
(
arc_selected_cpu
->
flags
&
FL_MUL32x16
)
return
"-mcpu=arc600 -mdsp-packa -mnorm"
;
return
"-mcpu=arc600 -mnorm"
;
default
:
gcc_unreachable
(
)
;
}
return
;
}
</s>

Returns command line parameters to pass to as .

arc
0
0
0
"-mcode-density"
""
"-mfpuda "
"-mspfp "
"-mdpfp "
"-mcpu=arcem "
"-mcpu=archs"
"-mcpu=nps400 -mEA"
"-mcpu=arc700 -mEA"
"-mcpu=arc600 -mmul64 -mnorm"
"-mcpu=arc600 -mdsp-packa -mnorm"
"-mcpu=arc600 -mnorm"