<s>
static
void
arm_unwind_emit_set
(
FILE
*
out_file
,
rtx
p
)
{
rtx
e0
;
rtx
e1
;
unsigned
reg
;
e0
=
XEXP
(
p
,
0
)
;
e1
=
XEXP
(
p
,
1
)
;
switch
(
GET_CODE
(
e0
)
)
{
case
MEM
:
if
(
GET_CODE
(
XEXP
(
e0
,
0
)
)
!=
PRE_DEC
||
!
REG_P
(
XEXP
(
XEXP
(
e0
,
0
)
,
0
)
)
||
REGNO
(
XEXP
(
XEXP
(
e0
,
0
)
,
0
)
)
!=
SP_REGNUM
)
abort
(
)
;
asm_fprintf
(
out_file
,
"\t.save "
)
;
if
(
IS_VFP_REGNUM
(
REGNO
(
e1
)
)
)
asm_fprintf
(
out_file
,
"{d%d}\n"
,
(
REGNO
(
e1
)
FIRST_VFP_REGNUM
)
/
2
)
;
else
asm_fprintf
(
out_file
,
"{%r}\n"
,
REGNO
(
e1
)
)
;
break
;
case
REG
:
if
(
REGNO
(
e0
)
==
SP_REGNUM
)
{
if
(
GET_CODE
(
e1
)
!=
PLUS
||
!
REG_P
(
XEXP
(
e1
,
0
)
)
||
REGNO
(
XEXP
(
e1
,
0
)
)
!=
SP_REGNUM
||
!
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
abort
(
)
;
asm_fprintf
(
out_file
,
"\t.pad #%wd\n"
,
INTVAL
(
XEXP
(
e1
,
1
)
)
)
;
}
else
if
(
REGNO
(
e0
)
==
HARD_FRAME_POINTER_REGNUM
)
{
HOST_WIDE_INT
offset
;
if
(
GET_CODE
(
e1
)
==
PLUS
)
{
if
(
!
REG_P
(
XEXP
(
e1
,
0
)
)
||
!
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
abort
(
)
;
reg
=
REGNO
(
XEXP
(
e1
,
0
)
)
;
offset
=
INTVAL
(
XEXP
(
e1
,
1
)
)
;
asm_fprintf
(
out_file
,
"\t.setfp %r, %r, #%wd\n"
,
HARD_FRAME_POINTER_REGNUM
,
reg
,
offset
)
;
}
else
if
(
REG_P
(
e1
)
)
{
reg
=
REGNO
(
e1
)
;
asm_fprintf
(
out_file
,
"\t.setfp %r, %r\n"
,
HARD_FRAME_POINTER_REGNUM
,
reg
)
;
}
else
abort
(
)
;
}
else
if
(
REG_P
(
e1
)
&&
REGNO
(
e1
)
==
SP_REGNUM
)
{
asm_fprintf
(
out_file
,
"\t.movsp %r\n"
,
REGNO
(
e0
)
)
;
}
else
if
(
GET_CODE
(
e1
)
==
PLUS
&&
REG_P
(
XEXP
(
e1
,
0
)
)
&&
REGNO
(
XEXP
(
e1
,
0
)
)
==
SP_REGNUM
&&
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
{
asm_fprintf
(
out_file
,
"\t.movsp %r, #%d\n"
,
REGNO
(
e0
)
,
(
int
)
INTVAL
(
XEXP
(
e1
,
1
)
)
)
;
}
else
abort
(
)
;
break
;
default
:
abort
(
)
;
}
}
</s>


<s> bool arm_validize_comparison ( rtx * comparison , rtx * op1 , rtx * op2 ) { enum rtx_code code = GET_CODE ( * comparison ) ; int code_int ; machine_mode mode = ( GET_MODE ( * op1 ) == VOIDmode ) ? GET_MODE ( * op2 ) : GET_MODE ( * op1 ) ; gcc_assert ( GET_MODE ( * op1 ) != VOIDmode || GET_MODE ( * op2 ) != VOIDmode ) ; if ( code == UNEQ || code == LTGT ) return false ; code_int = ( int ) code ; arm_canonicalize_comparison ( & code_int , op1 , op2 , 0 ) ; PUT_CODE ( * comparison , ( enum rtx_code ) code_int ) ; switch ( mode ) { case E_SImode : if ( ! arm_add_operand ( * op1 , mode ) ) * op1 = force_reg ( mode , * op1 ) ; if ( ! arm_add_operand ( * op2 , mode ) ) * op2 = force_reg ( mode , * op2 ) ; return true ; case E_DImode : return true ; case E_HFmode : if ( ! TARGET_VFP_FP16INST ) break ; mode = SFmode ; * op1 = convert_to_mode ( mode , * op1 , 1 ) ; * op2 = convert_to_mode ( mode , * op2 , 1 ) ; case E_SFmode : case E_DFmode : if ( ! vfp_compare_operand ( * op1 , mode ) ) * op1 = force_reg ( mode , * op1 ) ; if ( ! vfp_compare_operand ( * op2 , mode ) ) * op2 = force_reg ( mode , * op2 ) ; return true ; default : break ; } return false ; } </s>

Returns true if a valid comparison operation and makes the operands in a form that is valid .


<s> bool arm_valid_symbolic_address_p ( rtx addr ) { rtx xop0 , xop1 = NULL_RTX ; rtx tmp = addr ; if ( target_word_relocations ) return false ; if ( SYMBOL_REF_P ( tmp ) || LABEL_REF_P ( tmp ) ) return true ; if ( GET_CODE ( addr ) == CONST ) tmp = XEXP ( addr , 0 ) ; if ( GET_CODE ( tmp ) == PLUS ) { xop0 = XEXP ( tmp , 0 ) ; xop1 = XEXP ( tmp , 1 ) ; if ( GET_CODE ( xop0 ) == SYMBOL_REF && CONST_INT_P ( xop1 ) ) { if ( TARGET_THUMB1 && ! TARGET_HAVE_MOVT ) return IN_RANGE ( INTVAL ( xop1 ) , 0 , 0xff ) ; else return IN_RANGE ( INTVAL ( xop1 ) , - 0x8000 , 0x7fff ) ; } } return false ; } </s>

Returns true if the pattern is a valid symbolic address , which is either a symbol_ref or ( symbol_ref + addend ) . According to the ARM ELF ABI , the initial addend of REL-type relocations processing MOVW and MOVT instructions is formed by interpreting the 16-bit literal field of the instruction as a 16-bit signed value in the range -32768 < = A < 32768 . In Thumb-1 mode , we use upper/lower relocations which have an 8-bit unsigned range of 0 < = A < 256 as described in the AAELF32 relocation handling documentation : REL-type relocations are encoded as unsigned in this case .


<s> static bool arm_valid_target_attribute_p ( tree fndecl , tree ARG_UNUSED ( name ) , tree args , int ARG_UNUSED ( flags ) ) { bool ret = true ; struct gcc_options func_options , func_options_set ; tree cur_tree , new_optimize ; gcc_assert ( ( fndecl != NULL_TREE ) && ( args != NULL_TREE ) ) ; tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION ( fndecl ) ; if ( ! func_optimize ) func_optimize = optimization_default_node ; memset ( & func_options , 0 , sizeof ( func_options ) ) ; init_options_struct ( & func_options , NULL ) ; lang_hooks . init_options_struct ( & func_options ) ; memset ( & func_options_set , 0 , sizeof ( func_options_set ) ) ; cl_optimization_restore ( & func_options , & func_options_set , TREE_OPTIMIZATION ( func_optimize ) ) ; cl_target_option_restore ( & func_options , & func_options_set , TREE_TARGET_OPTION ( target_option_default_node ) ) ; cur_tree = arm_valid_target_attribute_tree ( args , & func_options , & func_options_set ) ; if ( cur_tree == NULL_TREE ) ret = false ; new_optimize = build_optimization_node ( & func_options , & func_options_set ) ; DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) = cur_tree ; DECL_FUNCTION_SPECIFIC_OPTIMIZATION ( fndecl ) = new_optimize ; return ret ; } </s>

Hook to validate attribute ( ( target ( `` string '' ) ) ) .


"attribute %<target%> argument not a string"

"FDPIC mode is not supported in Thumb-1 mode"

"invalid fpu for target attribute or pragma %qs"

"auto fpu selection not currently permitted here"

"invalid architecture for target attribute or pragma %qs"

"unknown target attribute or pragma %qs"

Inner function to process the attribute ( ( target ( ... ) ) ) , take an argument and set the current options from the argument . If we have a list , recursively go over the list .


<s> tree arm_valid_target_attribute_tree ( tree args , struct gcc_options * opts , struct gcc_options * opts_set ) { struct cl_target_option cl_opts ; if ( ! arm_valid_target_attribute_rec ( args , opts ) ) return NULL_TREE ; cl_target_option_save ( & cl_opts , opts , opts_set ) ; arm_configure_build_target ( & arm_active_target , & cl_opts , false ) ; arm_option_check_internal ( opts ) ; arm_option_reconfigure_globals ( ) ; arm_options_perform_arch_sanity_checks ( ) ; arm_option_override_internal ( opts , opts_set ) ; return build_target_option_node ( opts , opts_set ) ; } </s>

Return a TARGET_OPTION_NODE tree of the target options listed or NULL .


<s> static bool arm_vectorize_vec_perm_const ( machine_mode vmode , rtx target , rtx op0 , rtx op1 , const vec_perm_indices & sel ) { struct expand_vec_perm_d d ; int i , nelt , which ; if ( ! VALID_NEON_DREG_MODE ( vmode ) && ! VALID_NEON_QREG_MODE ( vmode ) ) return false ; d . target = target ; if ( op0 ) { rtx nop0 = force_reg ( vmode , op0 ) ; if ( op0 == op1 ) op1 = nop0 ; op0 = nop0 ; } if ( op1 ) op1 = force_reg ( vmode , op1 ) ; d . op0 = op0 ; d . op1 = op1 ; d . vmode = vmode ; gcc_assert ( VECTOR_MODE_P ( d . vmode ) ) ; d . testing_p = ! target ; nelt = GET_MODE_NUNITS ( d . vmode ) ; for ( i = which = 0 ; i < nelt ; ++ i ) { int ei = sel [ i ] & ( 2 * nelt - 1 ) ; which |= ( ei < nelt ? 1 : 2 ) ; } switch ( which ) { default : gcc_unreachable ( ) ; case 3 : d . one_vector_p = false ; if ( d . testing_p || ! rtx_equal_p ( op0 , op1 ) ) break ; case 2 : d . op0 = op1 ; d . one_vector_p = true ; break ; case 1 : d . op1 = op0 ; d . one_vector_p = true ; break ; } d . perm . new_vector ( sel . encoding ( ) , d . one_vector_p ? 1 : 2 , nelt ) ; if ( ! d . testing_p ) return arm_expand_vec_perm_const_1 ( & d ) ; d . target = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 1 ) ; d . op1 = d . op0 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 2 ) ; if ( ! d . one_vector_p ) d . op1 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 3 ) ; start_sequence ( ) ; bool ret = arm_expand_vec_perm_const_1 ( & d ) ; end_sequence ( ) ; return ret ; } </s>


<s> static HOST_WIDE_INT arm_vector_alignment ( const_tree type ) { HOST_WIDE_INT align = tree_to_shwi ( TYPE_SIZE ( type ) ) ; if ( TARGET_AAPCS_BASED ) align = MIN ( align , 64 ) ; return align ; } </s>

The AAPCS sets the maximum alignment of a vector to 64 bits .


<s> bool arm_vector_mode_supported_p ( machine_mode mode ) { if ( TARGET_NEON && ( mode == V2SFmode || mode == V4SImode || mode == V8HImode || mode == V4HFmode || mode == V16QImode || mode == V4SFmode || mode == V2DImode || mode == V8HFmode || mode == V4BFmode || mode == V8BFmode ) ) return true ; if ( ( TARGET_NEON || TARGET_IWMMXT ) && ( ( mode == V2SImode ) || ( mode == V4HImode ) || ( mode == V8QImode ) ) ) return true ; if ( TARGET_INT_SIMD && ( mode == V4UQQmode || mode == V4QQmode || mode == V2UHQmode || mode == V2HQmode || mode == V2UHAmode || mode == V2HAmode ) ) return true ; if ( TARGET_HAVE_MVE && ( mode == V2DImode || mode == V4SImode || mode == V8HImode || mode == V16QImode || mode == V16BImode || mode == V8BImode || mode == V4BImode ) ) return true ; if ( TARGET_HAVE_MVE_FLOAT && ( mode == V2DFmode || mode == V4SFmode || mode == V8HFmode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


<s> static unsigned bitmap_popcount ( const sbitmap bmap ) { unsigned int count = 0 ; unsigned int n = 0 ; sbitmap_iterator sbi ; EXECUTE_IF_SET_IN_BITMAP ( bmap , 0 , n , sbi ) count ++ ; return count ; } </s>


<s> static unsigned bit_count ( unsigned long value ) { unsigned long count = 0 ; while ( value ) { count ++ ; value &= value - 1 ; } return count ; } </s>

Typical stack layout should looks like this after the function 's prologue : | | -- ^ | | \ | | | arguments saved | Increasing | | on the stack | addresses PARENT arg pointer - > | | / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - CHILD |ret | return address -- | | \ | | call saved | | registers | | / -- | | \ | | local | | variables frame pointer - > | | / -- | | \ | | outgoing | Decreasing | | arguments | addresses current stack pointer - > | | / | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- V | |


<s>
static
void
bounds_check
(
rtx
operand
,
HOST_WIDE_INT
low
,
HOST_WIDE_INT
high
,
const_tree
exp
,
const
char
*
desc
)
{
HOST_WIDE_INT
lane
;
gcc_assert
(
CONST_INT_P
(
operand
)
)
;
lane
=
INTVAL
(
operand
)
;
if
(
lane
<
low
||
lane
>=
high
)
{
if
(
exp
)
error_at
(
EXPR_LOCATION
(
exp
)
,
"%s %wd out of range %wd - %wd"
,
desc
,
lane
,
low
,
high
1
)
;
else
error
(
"%s %wd out of range %wd - %wd"
,
desc
,
lane
,
low
,
high
1
)
;
}
}
</s>

Ensure OPERAND lies between LOW ( inclusive ) and HIGH ( exclusive ) . Raise ERR if it does n't . FIXME : NEON bounds checks occur late in compilation , so reported source locations are bogus .


<s> static rtx_insn * calculate_pic_address_constant ( rtx reg , rtx pic_reg , rtx orig ) { rtx pat ; rtx mem ; pat = gen_calculate_pic_address ( reg , pic_reg , orig ) ; mem = SET_SRC ( pat ) ; gcc_assert ( MEM_P ( mem ) && ! MEM_VOLATILE_P ( mem ) ) ; MEM_READONLY_P ( mem ) = 1 ; MEM_NOTRAP_P ( mem ) = 1 ; return emit_insn ( pat ) ; } </s>

Generate insns to calculate the address of ORIG in pic mode .


<s> static bool can_avoid_literal_pool_for_label_p ( rtx x ) { if ( arm_disable_literal_pool && SYMBOL_REF_P ( x ) && CONSTANT_POOL_ADDRESS_P ( x ) ) return 1 ; return 0 ; } </s>

Return true if we can avoid creating a constant pool entry for x .


<s> bool clear_operation_p ( rtx op , bool vfp ) { unsigned regno ; unsigned last_regno = INVALID_REGNUM ; rtx elt , reg , zero ; int count = XVECLEN ( op , 0 ) ; int first_set = vfp ? 1 : 0 ; machine_mode expected_mode = vfp ? E_SFmode : E_SImode ; for ( int i = first_set ; i < count ; i ++ ) { elt = XVECEXP ( op , 0 , i ) ; if ( ! vfp && GET_CODE ( elt ) == UNSPEC_VOLATILE ) { if ( XINT ( elt , 1 ) != VUNSPEC_CLRM_APSR || XVECLEN ( elt , 0 ) != 1 || XVECEXP ( elt , 0 , 0 ) != CONST0_RTX ( SImode ) || i != count - 2 ) return false ; continue ; } if ( GET_CODE ( elt ) == CLOBBER ) continue ; if ( GET_CODE ( elt ) != SET ) return false ; reg = SET_DEST ( elt ) ; zero = SET_SRC ( elt ) ; if ( ! REG_P ( reg ) || GET_MODE ( reg ) != expected_mode || zero != CONST0_RTX ( SImode ) ) return false ; regno = REGNO ( reg ) ; if ( vfp ) { if ( i != first_set && regno != last_regno + 1 ) return false ; } else { if ( regno == SP_REGNUM || regno == PC_REGNUM ) return false ; if ( i != first_set && regno <= last_regno ) return false ; } last_regno = regno ; } return true ; } </s>

Checks whether OP is a valid parallel pattern for a CLRM ( if VFP is false ) or VSCCLRM ( otherwise ) insn . To be a valid CLRM pattern , OP must have the following form : [ ( set ( reg : SI < N > ) ( const_int 0 ) ) ( set ( reg : SI < M > ) ( const_int 0 ) ) ... ( unspec_volatile [ ( const_int 0 ) ] VUNSPEC_CLRM_APSR ) ( clobber ( reg : CC CC_REGNUM ) ) ] Any number ( including 0 ) of set expressions is valid , the volatile unspec is optional . All registers but SP and PC are allowed and registers must be in strict increasing order . To be a valid VSCCLRM pattern , OP must have the following form : [ ( unspec_volatile [ ( const_int 0 ) ] VUNSPEC_VSCCLRM_VPR ) ( set ( reg : SF < N > ) ( const_int 0 ) ) ( set ( reg : SF < M > ) ( const_int 0 ) ) ... ] As with CLRM , any number ( including 0 ) of set expressions is valid , however the volatile unspec is mandatory here . Any VFP single-precision register is accepted but all registers must be consecutive and in increasing order .


"%qE attribute not available to functions with arguments "

"%qE attribute not available to functions with variable number "

"%qE attribute not available to functions that return value on "

This function returns true if a function with declaration FNDECL and type FNTYPE uses the stack to pass arguments or return variables and false otherwise . This is used for functions with the attributes 'cmse_nonsecure_call ' or 'cmse_nonsecure_entry ' and this function will issue diagnostic messages if the stack is used . NAME is the name of the attribute used .


Clear caller saved registers not used to pass return values and leaked condition flags before exiting a cmse_nonsecure_entry function .


<s> static unsigned HOST_WIDE_INT compute_not_to_clear_mask ( tree arg_type , rtx arg_rtx , int regno , uint32_t * padding_bits_to_clear ) { int last_used_bit = 0 ; unsigned HOST_WIDE_INT not_to_clear_mask ; if ( RECORD_OR_UNION_TYPE_P ( arg_type ) ) { not_to_clear_mask = comp_not_to_clear_mask_str_un ( arg_type , & regno , padding_bits_to_clear , 0 , & last_used_bit ) ; if ( last_used_bit != 0 ) padding_bits_to_clear [ regno ] |= ( ( uint32_t ) - 1 ) - ( ( uint32_t ) 1 << last_used_bit ) + 1 ; else not_to_clear_mask &= ~ ( HOST_WIDE_INT_1U << regno ) ; } else { not_to_clear_mask = 0 ; if ( GET_MODE ( arg_rtx ) == BLKmode ) { int i , arg_regs ; rtx reg ; gcc_assert ( TARGET_HARD_FLOAT_ABI ) ; for ( i = 0 ; i < XVECLEN ( arg_rtx , 0 ) ; i ++ ) { reg = XEXP ( XVECEXP ( arg_rtx , 0 , i ) , 0 ) ; gcc_assert ( REG_P ( reg ) ) ; not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO ( reg ) ; arg_regs = ARM_NUM_REGS ( GET_MODE ( reg ) ) ; if ( arg_regs > 1 ) { unsigned HOST_WIDE_INT mask ; mask = HOST_WIDE_INT_1U << ( REGNO ( reg ) + arg_regs ) ; mask -= HOST_WIDE_INT_1U << REGNO ( reg ) ; not_to_clear_mask |= mask ; } } } else { int arg_regs = ARM_NUM_REGS ( GET_MODE ( arg_rtx ) ) ; not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO ( arg_rtx ) ; if ( arg_regs > 1 ) { unsigned HOST_WIDE_INT mask = HOST_WIDE_INT_1U << ( REGNO ( arg_rtx ) + arg_regs ) ; mask -= HOST_WIDE_INT_1U << REGNO ( arg_rtx ) ; not_to_clear_mask |= mask ; } } } return not_to_clear_mask ; } </s>

In the context of ARMv8-M Security Extensions , this function is used for both 'cmse_nonsecure_call ' and 'cmse_nonsecure_entry ' functions to compute what registers are used when returning or passing arguments , which is then returned as a mask . It will also compute a mask to indicate padding/unused bits for each of these registers , and passes this through the PADDING_BITS_TO_CLEAR pointer . The tree of the argument type is passed in ARG_TYPE , the rtl representation of the argument is passed in ARG_RTX and the starting register used to pass this argument or return value is passed in REGNO . It makes use of 'comp_not_to_clear_mask_str_un ' to compute these for struct and union types .


<s> static bool compute_offset_order ( int nops , HOST_WIDE_INT * unsorted_offsets , int * order , int * unsorted_regs ) { int i ; for ( i = 1 ; i < nops ; i ++ ) { int j ; order [ i ] = order [ i - 1 ] ; for ( j = 0 ; j < nops ; j ++ ) if ( unsorted_offsets [ j ] == unsorted_offsets [ order [ i - 1 ] ] + 4 ) { if ( order [ i ] != order [ i - 1 ] ) return false ; order [ i ] = j ; } if ( order [ i ] == order [ i - 1 ] ) return false ; if ( unsorted_regs != NULL && unsorted_regs [ order [ i ] ] <= unsorted_regs [ order [ i - 1 ] ] ) return false ; } return true ; } </s>

Subroutine of load_multiple_sequence and store_multiple_sequence . Given an array of UNSORTED_OFFSETS , of which there are NOPS , compute an array ORDER which describes the sequence to use when accessing the offsets that produces an ascending order . In this sequence , each offset must be larger by exactly 4 than the previous one . ORDER [ 0 ] must have been filled in with the lowest offset by the caller . If UNSORTED_REGS is nonnull , it is an array of register numbers that we use to verify that ORDER produces an ascending order of registers . Return true if it was possible to construct such an order , false if not .


<s> int const_ok_for_arm ( HOST_WIDE_INT i ) { int lowbit ; if ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) != 0 && ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) != ( ( ~ ( unsigned HOST_WIDE_INT ) 0 ) & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) ) ) return FALSE ; i &= ( unsigned HOST_WIDE_INT ) 0xffffffff ; if ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xff ) == 0 ) return TRUE ; lowbit = ffs ( ( int ) i ) - 1 ; if ( TARGET_ARM ) lowbit &= ~ 1 ; if ( ( i & ~ ( ( ( unsigned HOST_WIDE_INT ) 0xff ) << lowbit ) ) == 0 ) return TRUE ; if ( TARGET_ARM ) { if ( lowbit <= 4 && ( ( i & ~ 0xc000003f ) == 0 || ( i & ~ 0xf000000f ) == 0 || ( i & ~ 0xfc000003 ) == 0 ) ) return TRUE ; } else if ( TARGET_THUMB2 ) { HOST_WIDE_INT v ; v = i & 0xff ; v |= v << 16 ; if ( i == v || i == ( v | ( v << 8 ) ) ) return TRUE ; v = i & 0xff00 ; v |= v << 16 ; if ( i == v ) return TRUE ; } else if ( TARGET_HAVE_MOVT ) { if ( i > 0xffff ) return FALSE ; else return TRUE ; } return FALSE ; } </s>

Return TRUE if int I is a valid immediate ARM constant .


<s> int const_ok_for_dimode_op ( HOST_WIDE_INT i , enum rtx_code code ) { HOST_WIDE_INT hi_val = ( i >> 32 ) & 0xFFFFFFFF ; HOST_WIDE_INT lo_val = i & 0xFFFFFFFF ; rtx hi = GEN_INT ( hi_val ) ; rtx lo = GEN_INT ( lo_val ) ; if ( TARGET_THUMB1 ) return 0 ; switch ( code ) { case AND : case IOR : case XOR : return const_ok_for_op ( hi_val , code ) || hi_val == 0xFFFFFFFF || const_ok_for_op ( lo_val , code ) || lo_val == 0xFFFFFFFF ; case PLUS : return arm_not_operand ( hi , SImode ) && arm_add_operand ( lo , SImode ) ; default : return 0 ; } } </s>

Return true if I is a valid di mode constant for the operation CODE .


<s> int const_ok_for_op ( HOST_WIDE_INT i , enum rtx_code code ) { if ( const_ok_for_arm ( i ) ) return 1 ; switch ( code ) { case SET : if ( TARGET_HAVE_MOVT && ( i & 0xffff0000 ) == 0 ) return 1 ; else return const_ok_for_arm ( ARM_SIGN_EXTEND ( ~ i ) ) ; case PLUS : if ( TARGET_THUMB2 && ( ( i & 0xfffff000 ) == 0 || ( ( - i ) & 0xfffff000 ) == 0 ) ) return 1 ; case COMPARE : case EQ : case NE : case GT : case LE : case LT : case GE : case GEU : case LTU : case GTU : case LEU : case UNORDERED : case ORDERED : case UNEQ : case UNGE : case UNLT : case UNGT : case UNLE : return const_ok_for_arm ( ARM_SIGN_EXTEND ( - i ) ) ; case MINUS : case XOR : return 0 ; case IOR : if ( TARGET_THUMB2 ) return const_ok_for_arm ( ARM_SIGN_EXTEND ( ~ i ) ) ; return 0 ; case AND : return const_ok_for_arm ( ARM_SIGN_EXTEND ( ~ i ) ) ; default : gcc_unreachable ( ) ; } } </s>

Return true if I is a valid constant for the operation CODE .


<s> enum reg_class coproc_secondary_reload_class ( machine_mode mode , rtx x , bool wb ) { if ( mode == HFmode ) { if ( ! TARGET_NEON_FP16 && ! TARGET_VFP_FP16INST ) return GENERAL_REGS ; if ( s_register_operand ( x , mode ) || neon_vector_mem_operand ( x , 2 , true ) ) return NO_REGS ; return GENERAL_REGS ; } if ( TARGET_NEON && ( MEM_P ( x ) || GET_CODE ( x ) == CONST_VECTOR ) && ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT || VALID_NEON_STRUCT_MODE ( mode ) ) ) return NO_REGS ; if ( arm_coproc_mem_operand ( x , wb ) || s_register_operand ( x , mode ) ) return NO_REGS ; return GENERAL_REGS ; } </s>

Return GENERAL_REGS if a scratch register required to reload x to/from coprocessor registers . Otherwise return NO_REGS .


<s> static bool cortexa7_older_only ( rtx_insn * insn ) { if ( recog_memoized ( insn ) < 0 ) return false ; switch ( get_attr_type ( insn ) ) { case TYPE_ALU_DSP_REG : case TYPE_ALU_SREG : case TYPE_ALUS_SREG : case TYPE_LOGIC_REG : case TYPE_LOGICS_REG : case TYPE_ADC_REG : case TYPE_ADCS_REG : case TYPE_ADR : case TYPE_BFM : case TYPE_REV : case TYPE_MVN_REG : case TYPE_SHIFT_IMM : case TYPE_SHIFT_REG : case TYPE_LOAD_BYTE : case TYPE_LOAD_4 : case TYPE_STORE_4 : case TYPE_FFARITHS : case TYPE_FADDS : case TYPE_FFARITHD : case TYPE_FADDD : case TYPE_FMOV : case TYPE_F_CVT : case TYPE_FCMPS : case TYPE_FCMPD : case TYPE_FCONSTS : case TYPE_FCONSTD : case TYPE_FMULS : case TYPE_FMACS : case TYPE_FMULD : case TYPE_FMACD : case TYPE_FDIVS : case TYPE_FDIVD : case TYPE_F_MRC : case TYPE_F_MRRC : case TYPE_F_FLAG : case TYPE_F_LOADS : case TYPE_F_STORES : return true ; default : return false ; } } </s>

Return true if and only if this insn can dual-issue only as older .


";; sched_reorder for cycle %d with %d insns in ready list\n"

";; sched_reorder nothing to reorder as no younger\n"

";; sched_reorder nothing to reorder as no older_only\n"

";; cortexa7_sched_reorder insn %d before %d\n"

Look for an instruction that can dual issue only as an older instruction , and move it in front of any instructions that can dual-issue as younger , while preserving the relative order of all other instructions in the ready list . This is a hueuristic to help dual-issue in later cycles , by postponing issue of more flexible instructions . This heuristic may affect dual issue opportunities in the current cycle .


<s>
static
bool
cortexa7_younger
(
FILE
*
file
,
int
verbose
,
rtx_insn
*
insn
)
{
if
(
recog_memoized
(
insn
)
<
0
)
{
if
(
verbose
>
5
)
fprintf
(
file
,
";; not cortexa7_younger %d\n"
,
INSN_UID
(
insn
)
)
;
return
false
;
}
switch
(
get_attr_type
(
insn
)
)
{
case
TYPE_ALU_IMM
:
case
TYPE_ALUS_IMM
:
case
TYPE_LOGIC_IMM
:
case
TYPE_LOGICS_IMM
:
case
TYPE_EXTEND
:
case
TYPE_MVN_IMM
:
case
TYPE_MOV_IMM
:
case
TYPE_MOV_REG
:
case
TYPE_MOV_SHIFT
:
case
TYPE_MOV_SHIFT_REG
:
case
TYPE_BRANCH
:
case
TYPE_CALL
:
return
true
;
default
:
return
false
;
}
}
</s>

Return true if and only if this insn can dual-issue as younger .


<s> static bool cortex_a9_sched_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int * cost ) { switch ( dep_type ) { case REG_DEP_ANTI : * cost = 0 ; return false ; case REG_DEP_TRUE : case REG_DEP_OUTPUT : if ( recog_memoized ( insn ) >= 0 && recog_memoized ( dep ) >= 0 ) { if ( GET_CODE ( PATTERN ( insn ) ) == SET ) { if ( GET_MODE_CLASS ( GET_MODE ( SET_DEST ( PATTERN ( insn ) ) ) ) == MODE_FLOAT || GET_MODE_CLASS ( GET_MODE ( SET_SRC ( PATTERN ( insn ) ) ) ) == MODE_FLOAT ) { enum attr_type attr_type_insn = get_attr_type ( insn ) ; enum attr_type attr_type_dep = get_attr_type ( dep ) ; if ( REG_P ( SET_DEST ( PATTERN ( insn ) ) ) && reg_set_p ( SET_DEST ( PATTERN ( insn ) ) , dep ) ) { if ( ( attr_type_insn == TYPE_FMACS || attr_type_insn == TYPE_FMACD ) && ( attr_type_dep == TYPE_FMACS || attr_type_dep == TYPE_FMACD ) ) { if ( dep_type == REG_DEP_OUTPUT ) * cost = insn_default_latency ( dep ) - 3 ; else * cost = insn_default_latency ( dep ) ; return false ; } else { if ( dep_type == REG_DEP_OUTPUT ) * cost = insn_default_latency ( dep ) + 1 ; else * cost = insn_default_latency ( dep ) ; } return false ; } } } } break ; default : gcc_unreachable ( ) ; } return true ; } </s>


<s> static Mfix * create_fix_barrier ( Mfix * fix , HOST_WIDE_INT max_address ) { HOST_WIDE_INT count = 0 ; rtx_barrier * barrier ; rtx_insn * from = fix -> insn ; rtx_insn * selected = NULL ; int selected_cost ; HOST_WIDE_INT selected_address ; Mfix * new_fix ; HOST_WIDE_INT max_count = max_address - fix -> address ; rtx_code_label * label = gen_label_rtx ( ) ; selected_cost = arm_barrier_cost ( from ) ; selected_address = fix -> address ; while ( from && count < max_count ) { rtx_jump_table_data * tmp ; int new_cost ; gcc_assert ( ! BARRIER_P ( from ) ) ; if ( LABEL_P ( from ) ) count += get_label_padding ( from ) ; else count += get_attr_length ( from ) ; if ( tablejump_p ( from , NULL , & tmp ) ) { count += get_jump_table_size ( tmp ) ; new_cost = arm_barrier_cost ( from ) ; if ( count < max_count && ( ! selected || new_cost <= selected_cost ) ) { selected = tmp ; selected_cost = new_cost ; selected_address = fix -> address + count ; } from = NEXT_INSN ( tmp ) ; continue ; } new_cost = arm_barrier_cost ( from ) ; if ( count < max_count && ( ! selected || new_cost <= selected_cost ) ) { selected = from ; selected_cost = new_cost ; selected_address = fix -> address + count ; } from = NEXT_INSN ( from ) ; } gcc_assert ( selected ) ; from = emit_jump_insn_after ( gen_jump ( label ) , selected ) ; JUMP_LABEL ( from ) = label ; barrier = emit_barrier_after ( from ) ; emit_label_after ( label , barrier ) ; new_fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * new_fix ) ) ; new_fix -> insn = barrier ; new_fix -> address = selected_address ; new_fix -> next = fix -> next ; fix -> next = new_fix ; return new_fix ; } </s>

Find the best place in the insn stream in the range ( FIX- > address , MAX_ADDRESS ) to forcibly insert a minipool barrier . Create the barrier by inserting a jump and add a new fix entry for it .


<s> bool detect_cmse_nonsecure_call ( tree addr ) { if ( ! addr ) return FALSE ; tree fntype = TREE_TYPE ( addr ) ; if ( use_cmse && lookup_attribute ( "cmse_nonsecure_call" , TYPE_ATTRIBUTES ( fntype ) ) ) return TRUE ; return FALSE ; } </s>

Returns true if -mcmse has been passed and the function pointed to by 'addr ' has the cmse_nonsecure_call attribute and returns false otherwise .


";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n"


<s> static void emit_constant_insn ( rtx cond , rtx pattern ) { if ( cond ) pattern = gen_rtx_COND_EXEC ( VOIDmode , copy_rtx ( cond ) , pattern ) ; emit_insn ( pattern ) ; } </s>

Emit an instruction with the indicated PATTERN . If COND is non-NULL , conditionalize the execution of the instruction on COND being true .


<s> static rtx emit_multi_reg_push ( unsigned long mask , unsigned long dwarf_regs_mask ) { int num_regs = 0 ; int num_dwarf_regs = 0 ; int i , j ; rtx par ; rtx dwarf ; int dwarf_par_index ; rtx tmp , reg ; dwarf_regs_mask &= ~ ( 1 << PC_REGNUM ) ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) { if ( mask & ( 1 << i ) ) num_regs ++ ; if ( dwarf_regs_mask & ( 1 << i ) ) num_dwarf_regs ++ ; } gcc_assert ( num_regs && num_regs <= 16 ) ; gcc_assert ( ( dwarf_regs_mask & ~ mask ) == 0 ) ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs ) ) ; dwarf = gen_rtx_SEQUENCE ( VOIDmode , rtvec_alloc ( num_dwarf_regs + 1 ) ) ; dwarf_par_index = 1 ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) { if ( mask & ( 1 << i ) ) { reg = gen_rtx_REG ( SImode , i ) ; XVECEXP ( par , 0 , 0 ) = gen_rtx_SET ( gen_frame_mem ( BLKmode , gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ) ) , gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSH_MULT ) ) ; if ( dwarf_regs_mask & ( 1 << i ) ) { tmp = gen_rtx_SET ( gen_frame_mem ( SImode , stack_pointer_rtx ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; } break ; } } for ( j = 1 , i ++ ; j < num_regs ; i ++ ) { if ( mask & ( 1 << i ) ) { reg = gen_rtx_REG ( SImode , i ) ; XVECEXP ( par , 0 , j ) = gen_rtx_USE ( VOIDmode , reg ) ; if ( dwarf_regs_mask & ( 1 << i ) ) { tmp = gen_rtx_SET ( gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , 4 * j ) ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; } j ++ ; } } par = emit_insn ( par ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 0 ) = tmp ; add_reg_note ( par , REG_FRAME_RELATED_EXPR , dwarf ) ; return par ; } </s>

Generate and emit an insn that we will recognize as a push_multi . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information .


<s> inline static rtx_insn * emit_set_insn ( rtx x , rtx y ) { return emit_insn ( gen_rtx_SET ( x , y ) ) ; } </s>

Emit an insn that 's a simple single-set . Both the operands must be known to be valid .


<s> static void emit_unlikely_jump ( rtx insn ) { rtx_insn * jump = emit_jump_insn ( insn ) ; add_reg_br_prob_note ( jump , profile_probability :: very_unlikely ( ) ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> inline bool libcall_hasher :: equal ( const rtx_def * p1 , const rtx_def * p2 ) { return rtx_equal_p ( p1 , p2 ) ; } </s>


<s> static bool extract_base_offset_in_addr ( rtx mem , rtx * base , rtx * offset ) { rtx addr ; gcc_assert ( MEM_P ( mem ) ) ; addr = XEXP ( mem , 0 ) ; if ( GET_CODE ( addr ) == CONST ) addr = XEXP ( addr , 0 ) ; if ( REG_P ( addr ) ) { * base = addr ; * offset = const0_rtx ; return true ; } if ( GET_CODE ( addr ) == PLUS && GET_CODE ( XEXP ( addr , 0 ) ) == REG && CONST_INT_P ( XEXP ( addr , 1 ) ) ) { * base = XEXP ( addr , 0 ) ; * offset = XEXP ( addr , 1 ) ; return true ; } * base = NULL_RTX ; * offset = NULL_RTX ; return false ; } </s>

If MEM is in the form of `` base+offset '' , extract the two parts of address and set to BASE and OFFSET , otherwise return false after clearing BASE and OFFSET .


<s> static bool fa726te_sched_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int * cost ) { if ( dep_type == REG_DEP_TRUE && recog_memoized ( insn ) >= 0 && recog_memoized ( dep ) >= 0 && get_attr_conds ( dep ) == CONDS_SET ) { if ( get_attr_conds ( insn ) == CONDS_USE && get_attr_type ( insn ) != TYPE_BRANCH ) { * cost = 3 ; return false ; } if ( GET_CODE ( PATTERN ( insn ) ) == COND_EXEC || get_attr_conds ( insn ) == CONDS_USE ) { * cost = 0 ; return false ; } } return true ; } </s>


<s> static const char * fp_const_from_val ( REAL_VALUE_TYPE * r ) { if ( ! fp_consts_inited ) init_fp_table ( ) ; gcc_assert ( real_equal ( r , & value_fp0 ) ) ; return "0" ; } </s>

As for fp_immediate_constant , but value is passed directly , not in rtx .


<s> static bool fusion_load_store ( rtx_insn * insn , rtx * base , rtx * offset , bool * is_load ) { rtx x , dest , src ; gcc_assert ( INSN_P ( insn ) ) ; x = PATTERN ( insn ) ; if ( GET_CODE ( x ) != SET ) return false ; src = SET_SRC ( x ) ; dest = SET_DEST ( x ) ; if ( REG_P ( src ) && MEM_P ( dest ) ) { * is_load = false ; extract_base_offset_in_addr ( dest , base , offset ) ; } else if ( MEM_P ( src ) && REG_P ( dest ) ) { * is_load = true ; extract_base_offset_in_addr ( src , base , offset ) ; } else return false ; return ( * base != NULL_RTX && * offset != NULL_RTX ) ; } </s>

If INSN is a load or store of address in the form of [ base+offset ] , extract the two parts and set to BASE and OFFSET . IS_LOAD is set to TRUE if it 's a load . Return TRUE if INSN is such an instruction , otherwise return FALSE .


<s> bool gen_ldm_seq ( rtx * operands , int nops , bool sort_regs ) { int regs [ MAX_LDM_STM_OPS ] , mem_order [ MAX_LDM_STM_OPS ] ; rtx mems [ MAX_LDM_STM_OPS ] ; int i , j , base_reg ; rtx base_reg_rtx ; HOST_WIDE_INT offset ; int write_back = FALSE ; int ldm_case ; rtx addr ; ldm_case = load_multiple_sequence ( operands , nops , regs , mem_order , & base_reg , & offset , ! sort_regs ) ; if ( ldm_case == 0 ) return false ; if ( sort_regs ) for ( i = 0 ; i < nops - 1 ; i ++ ) for ( j = i + 1 ; j < nops ; j ++ ) if ( regs [ i ] > regs [ j ] ) { int t = regs [ i ] ; regs [ i ] = regs [ j ] ; regs [ j ] = t ; } base_reg_rtx = gen_rtx_REG ( Pmode , base_reg ) ; if ( TARGET_THUMB1 ) { gcc_assert ( ldm_case == 1 || ldm_case == 5 ) ; write_back = true ; for ( i = 0 ; i < nops ; i ++ ) if ( base_reg == regs [ i ] ) write_back = false ; if ( write_back && ! peep2_reg_dead_p ( nops , base_reg_rtx ) ) return false ; } if ( ldm_case == 5 ) { rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG ( SImode , regs [ 0 ] ) ; emit_insn ( gen_addsi3 ( newbase , base_reg_rtx , GEN_INT ( offset ) ) ) ; offset = 0 ; base_reg_rtx = newbase ; } for ( i = 0 ; i < nops ; i ++ ) { addr = plus_constant ( Pmode , base_reg_rtx , offset + i * 4 ) ; mems [ i ] = adjust_automodify_address_nv ( operands [ nops + mem_order [ i ] ] , SImode , addr , 0 ) ; } emit_insn ( arm_gen_load_multiple_1 ( nops , regs , mems , base_reg_rtx , write_back ? offset + i * 4 : 0 ) ) ; return true ; } </s>

Called from a peephole2 expander to turn a sequence of loads into an LDM instruction . OPERANDS are the operands found by the peephole matcher ; NOPS indicates how many separate loads we are trying to combine . SORT_REGS is true if we can reorder the registers because they are used commutatively subsequently . Returns true iff we could generate a new instruction .


<s> bool gen_stm_seq ( rtx * operands , int nops ) { int i ; int regs [ MAX_LDM_STM_OPS ] , mem_order [ MAX_LDM_STM_OPS ] ; rtx mems [ MAX_LDM_STM_OPS ] ; int base_reg ; rtx base_reg_rtx ; HOST_WIDE_INT offset ; int write_back = FALSE ; int stm_case ; rtx addr ; bool base_reg_dies ; stm_case = store_multiple_sequence ( operands , nops , nops , regs , NULL , mem_order , & base_reg , & offset , true ) ; if ( stm_case == 0 ) return false ; base_reg_rtx = gen_rtx_REG ( Pmode , base_reg ) ; base_reg_dies = peep2_reg_dead_p ( nops , base_reg_rtx ) ; if ( TARGET_THUMB1 ) { gcc_assert ( base_reg_dies ) ; write_back = TRUE ; } if ( stm_case == 5 ) { gcc_assert ( base_reg_dies ) ; emit_insn ( gen_addsi3 ( base_reg_rtx , base_reg_rtx , GEN_INT ( offset ) ) ) ; offset = 0 ; } addr = plus_constant ( Pmode , base_reg_rtx , offset ) ; for ( i = 0 ; i < nops ; i ++ ) { addr = plus_constant ( Pmode , base_reg_rtx , offset + i * 4 ) ; mems [ i ] = adjust_automodify_address_nv ( operands [ nops + mem_order [ i ] ] , SImode , addr , 0 ) ; } emit_insn ( arm_gen_store_multiple_1 ( nops , regs , mems , base_reg_rtx , write_back ? offset + i * 4 : 0 ) ) ; return true ; } </s>

Called from a peephole2 expander to turn a sequence of stores into an STM instruction . OPERANDS are the operands found by the peephole matcher ; NOPS indicates how many separate stores we are trying to combine . Returns true iff we could generate a new instruction .


<s> static enum arm_cond_code get_arm_condition_code ( rtx comparison ) { enum arm_cond_code code = maybe_get_arm_condition_code ( comparison ) ; gcc_assert ( code != ARM_NV ) ; return code ; } </s>

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


<s> static HOST_WIDE_INT get_label_padding ( rtx label ) { HOST_WIDE_INT align , min_insn_size ; align = 1 << label_to_alignment ( label ) . levels [ 0 ] . log ; min_insn_size = TARGET_THUMB ? 2 : 4 ; return align > min_insn_size ? align - min_insn_size : 0 ; } </s>

Return the maximum amount of padding that will be inserted before label LABEL .


<s> static void get_scratch_register_on_entry ( struct scratch_reg * sr , unsigned int regno1 , unsigned long live_regs ) { int regno = - 1 ; sr -> saved = false ; if ( regno1 != LR_REGNUM && ( live_regs & ( 1 << LR_REGNUM ) ) != 0 ) regno = LR_REGNUM ; else { unsigned int i ; for ( i = 4 ; i < 11 ; i ++ ) if ( regno1 != i && ( live_regs & ( 1 << i ) ) != 0 ) { regno = i ; break ; } if ( regno < 0 ) { if ( regno1 == IP_REGNUM && IS_NESTED ( arm_current_func_type ( ) ) ) regno1 = 3 ; regno = ( regno1 == 3 ? 2 : 3 ) ; sr -> saved = REGNO_REG_SET_P ( df_get_live_out ( ENTRY_BLOCK_PTR_FOR_FN ( cfun ) ) , regno ) ; } } sr -> reg = gen_rtx_REG ( SImode , regno ) ; if ( sr -> saved ) { rtx addr = gen_rtx_PRE_DEC ( Pmode , stack_pointer_rtx ) ; rtx insn = emit_set_insn ( gen_frame_mem ( SImode , addr ) , sr -> reg ) ; rtx x = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , x ) ; } } </s>

Return a short-lived scratch register for use on function entry . In 32-bit mode , it is valid only after the registers are saved in the prologue . This register must be released by means of release_scratch_register_on_entry once it is dead .


<s> inline hashval_t libcall_hasher :: hash ( const rtx_def * p1 ) { return hash_rtx ( p1 , VOIDmode , NULL , NULL , FALSE ) ; } </s>

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


<s> static bool is_called_in_ARM_mode ( tree func ) { gcc_assert ( TREE_CODE ( func ) == FUNCTION_DECL ) ; if ( TARGET_CALLEE_INTERWORKING && TREE_PUBLIC ( func ) ) return true ; return lookup_attribute ( "interfacearm" , DECL_ATTRIBUTES ( func ) ) != NULL_TREE ; return false ; } </s>

Return non-zero if FUNC must be entered in ARM mode .


<s> static bool is_indirect_tailcall_p ( rtx call ) { rtx pat = PATTERN ( call ) ; pat = XVECEXP ( pat , 0 , 0 ) ; if ( GET_CODE ( pat ) == SET ) pat = SET_SRC ( pat ) ; pat = XEXP ( XEXP ( pat , 0 ) , 0 ) ; return REG_P ( pat ) ; } </s>

We do not know if r3 will be available because we do have an indirect tailcall happening in this particular case .


<s> int label_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( LABEL_REF_P ( x ) ) return 1 ; if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) return 0 ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( label_mentioned_p ( XVECEXP ( x , i , j ) ) ) return 1 ; } else if ( fmt [ i ] == 'e' && label_mentioned_p ( XEXP ( x , i ) ) ) return 1 ; } return 0 ; } </s>

Return TRUE if X references a LABEL_REF .


<s> int legitimate_pic_operand_p ( rtx x ) { if ( SYMBOL_REF_P ( x ) || ( GET_CODE ( x ) == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == SYMBOL_REF ) ) return 0 ; return 1 ; } </s>

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


<s> static bool mem_ok_for_ldrd_strd ( rtx mem , rtx * base , rtx * offset , HOST_WIDE_INT * align ) { rtx addr ; gcc_assert ( base != NULL && offset != NULL ) ; if ( side_effects_p ( mem ) ) return false ; if ( SUBREG_P ( mem ) ) return false ; gcc_assert ( MEM_P ( mem ) ) ; * offset = const0_rtx ; * align = MEM_ALIGN ( mem ) ; addr = XEXP ( mem , 0 ) ; if ( ! arm_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 ) { * base = XEXP ( addr , 0 ) ; * offset = XEXP ( addr , 1 ) ; return ( REG_P ( * base ) && CONST_INT_P ( * offset ) ) ; } return false ; } </s>

Helper for gen_operands_ldrd_strd . 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 Mnode * move_minipool_fix_forward_ref ( Mnode * mp , Mnode * max_mp , HOST_WIDE_INT max_address ) { gcc_assert ( mp != max_mp ) ; if ( max_mp == NULL ) { if ( max_address < mp -> max_address ) mp -> max_address = max_address ; } else { if ( max_address > max_mp -> max_address - mp -> fix_size ) mp -> max_address = max_mp -> max_address - mp -> fix_size ; else mp -> max_address = max_address ; mp -> prev -> next = mp -> next ; if ( mp -> next != NULL ) mp -> next -> prev = mp -> prev ; else minipool_vector_tail = mp -> prev ; mp -> next = max_mp ; mp -> prev = max_mp -> prev ; max_mp -> prev = mp ; if ( mp -> prev != NULL ) mp -> prev -> next = mp ; else minipool_vector_head = mp ; } max_mp = mp ; while ( mp -> prev != NULL && mp -> prev -> max_address > mp -> max_address - mp -> prev -> fix_size ) { mp -> prev -> max_address = mp -> max_address - mp -> prev -> fix_size ; mp = mp -> prev ; } return max_mp ; } </s>

Move a minipool fix MP from its current location to before MAX_MP . If MAX_MP is NULL , then MP does n't need moving , but the addressing contrains may need updating .


<s> static bool multiple_operation_profitable_p ( bool is_store ATTRIBUTE_UNUSED , int nops , HOST_WIDE_INT add_offset ) { if ( nops == 2 && arm_ld_sched && add_offset != 0 ) return false ; if ( nops <= 2 && arm_tune_xscale && ! optimize_size ) return false ; return true ; } </s>

Return true iff it would be profitable to turn a sequence of NOPS loads or stores ( depending on IS_STORE ) into a load-multiple or store-multiple instruction . ADD_OFFSET is nonzero if the base address register needs to be modified with an add instruction before we can use it .


<s> rtx mve_bool_vec_to_const ( rtx const_vec ) { int n_elts = GET_MODE_NUNITS ( GET_MODE ( const_vec ) ) ; int repeat = 16 / n_elts ; int i ; int hi_val = 0 ; for ( i = 0 ; i < n_elts ; i ++ ) { rtx el = CONST_VECTOR_ELT ( const_vec , i ) ; unsigned HOST_WIDE_INT elpart ; gcc_assert ( CONST_INT_P ( el ) ) ; elpart = INTVAL ( el ) ; for ( int j = 0 ; j < repeat ; j ++ ) hi_val |= elpart << ( i * repeat + j ) ; } return gen_int_mode ( hi_val , HImode ) ; } </s>

Return a HI representation of CONST_VEC suitable for MVE predicates .


<s> int mve_vector_mem_operand ( machine_mode mode , rtx op , bool strict ) { enum rtx_code code ; int val , reg_no ; if ( REG_P ( op ) ) { int reg_no = REGNO ( op ) ; return ( ( ( mode == E_V8QImode || mode == E_V4QImode || mode == E_V4HImode ) ? reg_no <= LAST_LO_REGNUM : ( reg_no < LAST_ARM_REGNUM && reg_no != SP_REGNUM ) ) || ( ! strict && reg_no >= FIRST_PSEUDO_REGISTER ) ) ; } code = GET_CODE ( op ) ; if ( code == POST_INC || code == PRE_DEC || code == PRE_INC || code == POST_DEC ) { reg_no = REGNO ( XEXP ( op , 0 ) ) ; return ( ( mode == E_V8QImode || mode == E_V4QImode || mode == E_V4HImode ) ? reg_no <= LAST_LO_REGNUM : ( reg_no < LAST_ARM_REGNUM && reg_no != SP_REGNUM ) ) || reg_no >= FIRST_PSEUDO_REGISTER ; } else if ( ( ( code == POST_MODIFY || code == PRE_MODIFY ) && GET_CODE ( XEXP ( op , 1 ) ) == PLUS && XEXP ( op , 0 ) == XEXP ( XEXP ( op , 1 ) , 0 ) && REG_P ( XEXP ( op , 0 ) ) && GET_CODE ( XEXP ( XEXP ( op , 1 ) , 1 ) ) == CONST_INT ) || ( reload_completed && code == PLUS && REG_P ( XEXP ( op , 0 ) ) && GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT ) ) { reg_no = REGNO ( XEXP ( op , 0 ) ) ; if ( code == PLUS ) val = INTVAL ( XEXP ( op , 1 ) ) ; else val = INTVAL ( XEXP ( XEXP ( op , 1 ) , 1 ) ) ; switch ( mode ) { case E_V16QImode : case E_V8QImode : case E_V4QImode : if ( abs ( val ) > 127 ) return FALSE ; break ; case E_V8HImode : case E_V8HFmode : case E_V4HImode : case E_V4HFmode : if ( val % 2 != 0 || abs ( val ) > 254 ) return FALSE ; break ; case E_V4SImode : case E_V4SFmode : if ( val % 4 != 0 || abs ( val ) > 508 ) return FALSE ; break ; default : return FALSE ; } return reg_no >= FIRST_PSEUDO_REGISTER || ( MVE_STN_LDW_MODE ( mode ) ? reg_no <= LAST_LO_REGNUM : ( reg_no < LAST_ARM_REGNUM && reg_no != SP_REGNUM ) ) ; } return FALSE ; } </s>

This function returns TRUE on matching mode and op.1 . For given modes , check for [ Rn ] , return TRUE for Rn < = LO_REGS.2 . For other modes , check for [ Rn ] , return TRUE for Rn < R15 ( expect R13 ) .


<s> void neon_disambiguate_copy ( rtx * operands , rtx * dest , rtx * src , unsigned int count ) { unsigned int i ; if ( ! reg_overlap_mentioned_p ( operands [ 0 ] , operands [ 1 ] ) || REGNO ( operands [ 0 ] ) < REGNO ( operands [ 1 ] ) ) { for ( i = 0 ; i < count ; i ++ ) { operands [ 2 * i ] = dest [ i ] ; operands [ 2 * i + 1 ] = src [ i ] ; } } else { for ( i = 0 ; i < count ; i ++ ) { operands [ 2 * i ] = dest [ count - i - 1 ] ; operands [ 2 * i + 1 ] = src [ count - i - 1 ] ; } } } </s>

Set up OPERANDS for a register copy from SRC to DEST , taking care not to early-clobber SRC registers in the process . We assume that the operands described by SRC and DEST represent a decomposed copy of OPERANDS [ 1 ] into OPERANDS [ 0 ] . COUNT is the number of components into which the copy has been decomposed .


<s> static int neon_endian_lane_map ( machine_mode mode , int lane ) { if ( BYTES_BIG_ENDIAN ) { int nelems = GET_MODE_NUNITS ( mode ) ; lane = ( nelems - 1 - lane ) ; if ( GET_MODE_SIZE ( mode ) == 16 ) lane = lane ^ ( nelems / 2 ) ; } return lane ; } </s>

Map lane ordering between architectural lane order , and GCC lane order , taking into account ABI . See comment above output_move_neon for details .


<s> void neon_expand_vector_init ( rtx target , rtx vals ) { machine_mode mode = GET_MODE ( target ) ; machine_mode inner_mode = GET_MODE_INNER ( mode ) ; int n_elts = GET_MODE_NUNITS ( mode ) ; int n_var = 0 , one_var = - 1 ; bool all_same = true ; rtx x , mem ; int i ; for ( i = 0 ; i < n_elts ; ++ i ) { x = XVECEXP ( vals , 0 , i ) ; if ( ! CONSTANT_P ( x ) ) ++ n_var , one_var = i ; if ( i > 0 && ! rtx_equal_p ( x , XVECEXP ( vals , 0 , 0 ) ) ) all_same = false ; } if ( n_var == 0 ) { rtx constant = neon_make_constant ( vals ) ; if ( constant != NULL_RTX ) { emit_move_insn ( target , constant ) ; return ; } } if ( all_same && GET_MODE_SIZE ( inner_mode ) <= 4 ) { x = copy_to_mode_reg ( inner_mode , XVECEXP ( vals , 0 , 0 ) ) ; emit_insn ( gen_rtx_SET ( target , gen_vec_duplicate ( mode , x ) ) ) ; return ; } if ( n_var == 1 ) { rtx copy = copy_rtx ( vals ) ; rtx merge_mask = GEN_INT ( 1 << one_var ) ; XVECEXP ( copy , 0 , one_var ) = XVECEXP ( vals , 0 , ( one_var + 1 ) % n_elts ) ; neon_expand_vector_init ( target , copy ) ; x = copy_to_mode_reg ( inner_mode , XVECEXP ( vals , 0 , one_var ) ) ; emit_insn ( gen_vec_set_internal ( mode , target , x , merge_mask , target ) ) ; return ; } mem = assign_stack_temp ( mode , GET_MODE_SIZE ( mode ) ) ; for ( i = 0 ; i < n_elts ; i ++ ) emit_move_insn ( adjust_address_nv ( mem , inner_mode , i * GET_MODE_SIZE ( inner_mode ) ) , XVECEXP ( vals , 0 , i ) ) ; emit_move_insn ( target , mem ) ; } </s>


<s> int neon_immediate_valid_for_logic ( rtx op , machine_mode mode , int inverse , rtx * modconst , int * elementwidth ) { rtx tmpconst ; int tmpwidth ; int retval = simd_valid_immediate ( op , mode , inverse , & tmpconst , & tmpwidth ) ; if ( retval < 0 || retval > 5 ) return 0 ; if ( modconst ) * modconst = tmpconst ; if ( elementwidth ) * elementwidth = tmpwidth ; return 1 ; } </s>

Return TRUE if rtx X is legal for use in a VORR or VBIC instruction . If the immediate is valid , write a constant suitable for using as an operand to VORR/VBIC/VAND/VORN to * MODCONST and the corresponding element width to * ELEMENTWIDTH . See neon_valid_immediate for description of INVERSE .


<s> int neon_immediate_valid_for_shift ( rtx op , machine_mode mode , rtx * modconst , int * elementwidth , bool isleftshift ) { unsigned int innersize = GET_MODE_UNIT_SIZE ( mode ) ; unsigned int n_elts = CONST_VECTOR_NUNITS ( op ) , i ; unsigned HOST_WIDE_INT last_elt = 0 ; unsigned HOST_WIDE_INT maxshift ; for ( i = 0 ; i < n_elts ; i ++ ) { rtx el = CONST_VECTOR_ELT ( op , i ) ; unsigned HOST_WIDE_INT elpart ; if ( CONST_INT_P ( el ) ) elpart = INTVAL ( el ) ; else if ( CONST_DOUBLE_P ( el ) ) return 0 ; else gcc_unreachable ( ) ; if ( i != 0 && elpart != last_elt ) return 0 ; last_elt = elpart ; } maxshift = innersize * 8 ; if ( isleftshift ) { if ( last_elt >= maxshift ) return 0 ; } else { if ( last_elt == 0 || last_elt > maxshift ) return 0 ; } if ( elementwidth ) * elementwidth = innersize * 8 ; if ( modconst ) * modconst = CONST_VECTOR_ELT ( op , 0 ) ; return 1 ; } </s>

Return TRUE if rtx OP is legal for use in a VSHR or VSHL instruction . If the immediate is valid , write a constant suitable for using as an operand to VSHR/VSHL to * MODCONST and the corresponding element width to * ELEMENTWIDTH . ISLEFTSHIFT is for determine left or right shift , because they have different limitations .


<s> void neon_lane_bounds ( rtx operand , HOST_WIDE_INT low , HOST_WIDE_INT high , const_tree exp ) { bounds_check ( operand , low , high , exp , "lane" ) ; } </s>


<s> rtx neon_make_constant ( rtx vals , bool generate ) { machine_mode mode = GET_MODE ( vals ) ; rtx target ; rtx const_vec = NULL_RTX ; int n_elts = GET_MODE_NUNITS ( mode ) ; int n_const = 0 ; int i ; if ( GET_CODE ( vals ) == CONST_VECTOR ) const_vec = vals ; else if ( GET_CODE ( vals ) == PARALLEL ) { for ( i = 0 ; i < n_elts ; ++ i ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( CONST_INT_P ( x ) || CONST_DOUBLE_P ( x ) ) n_const ++ ; } if ( n_const == n_elts ) const_vec = gen_rtx_CONST_VECTOR ( mode , XVEC ( vals , 0 ) ) ; } else gcc_unreachable ( ) ; if ( const_vec != NULL && simd_immediate_valid_for_move ( const_vec , mode , NULL , NULL ) ) return const_vec ; else if ( TARGET_HAVE_MVE && ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_BOOL ) ) return mve_bool_vec_to_const ( const_vec ) ; else if ( ( target = neon_vdup_constant ( vals , generate ) ) != NULL_RTX ) return target ; else if ( const_vec != NULL_RTX ) return arm_disable_literal_pool ? NULL_RTX : const_vec ; else return NULL_RTX ; } </s>

Generate code to load VALS , which is a PARALLEL containing only constants ( for vec_init ) or CONST_VECTOR , efficiently into a register . Returns an RTX to copy into the register , or NULL_RTX for a PARALLEL that can not be converted into a CONST_VECTOR .


<s>
char
*
neon_output_logic_immediate
(
const
char
*
mnem
,
rtx
*
op2
,
machine_mode
mode
,
int
inverse
,
int
quad
)
{
int
width
,
is_valid
;
static
char
templ
[
40
]
;
is_valid
=
neon_immediate_valid_for_logic
(
*
op2
,
mode
,
inverse
,
op2
,
&
width
)
;
gcc_assert
(
is_valid
!=
0
)
;
if
(
quad
)
sprintf
(
templ
,
"%s.i%d\t%%q0, %%2"
,
mnem
,
width
)
;
else
sprintf
(
templ
,
"%s.i%d\t%%P0, %%2"
,
mnem
,
width
)
;
return
templ
;
}
</s>

Return a string suitable for output of Neon immediate logic operation MNEM .


<s>
char
*
neon_output_shift_immediate
(
const
char
*
mnem
,
char
sign
,
rtx
*
op2
,
machine_mode
mode
,
int
quad
,
bool
isleftshift
)
{
int
width
,
is_valid
;
static
char
templ
[
40
]
;
is_valid
=
neon_immediate_valid_for_shift
(
*
op2
,
mode
,
op2
,
&
width
,
isleftshift
)
;
gcc_assert
(
is_valid
!=
0
)
;
if
(
quad
)
sprintf
(
templ
,
"%s.%c%d\t%%q0, %%q1, %%2"
,
mnem
,
sign
,
width
)
;
else
sprintf
(
templ
,
"%s.%c%d\t%%P0, %%P1, %%2"
,
mnem
,
sign
,
width
)
;
return
templ
;
}
</s>

Return a string suitable for output of Neon immediate shift operation ( VSHR or VSHL ) MNEM .


<s> void neon_pairwise_reduce ( rtx op0 , rtx op1 , machine_mode mode , rtx ( * reduc ) ( rtx , rtx , rtx ) ) { unsigned int i , parts = GET_MODE_SIZE ( mode ) / GET_MODE_UNIT_SIZE ( mode ) ; rtx tmpsum = op1 ; for ( i = parts / 2 ; i >= 1 ; i /= 2 ) { rtx dest = ( i == 1 ) ? op0 : gen_reg_rtx ( mode ) ; emit_insn ( reduc ( dest , tmpsum , tmpsum ) ) ; tmpsum = dest ; } } </s>

Output a sequence of pairwise operations to implement a reduction . NOTE : We do `` too much work '' here , because pairwise operations work on two registers-worth of operands in one go . Unfortunately we ca n't exploit those extra calculations to do the full operation in fewer steps , I do n't think . Although all vector elements of the result but the first are ignored , we actually calculate the same result in each of the elements . An alternative such as initially loading a vector with zero to use as each of the second operands would use up an additional register and take an extra instruction , for no particular gain .


<s> static int neon_pair_endian_lane_map ( machine_mode mode , int lane ) { int nelem = GET_MODE_NUNITS ( mode ) ; if ( BYTES_BIG_ENDIAN ) lane = neon_endian_lane_map ( mode , lane & ( nelem - 1 ) ) + ( lane & nelem ) ; return lane ; } </s>

Some permutations index into pairs of vectors , this is a helper function to map indexes into those pairs of vectors .


<s> void neon_split_vcombine ( rtx operands [ 3 ] ) { unsigned int dest = REGNO ( operands [ 0 ] ) ; unsigned int src1 = REGNO ( operands [ 1 ] ) ; unsigned int src2 = REGNO ( operands [ 2 ] ) ; machine_mode halfmode = GET_MODE ( operands [ 1 ] ) ; unsigned int halfregs = REG_NREGS ( operands [ 1 ] ) ; rtx destlo , desthi ; if ( src1 == dest && src2 == dest + halfregs ) { emit_note ( NOTE_INSN_DELETED ) ; return ; } destlo = gen_rtx_REG_offset ( operands [ 0 ] , halfmode , dest , 0 ) ; desthi = gen_rtx_REG_offset ( operands [ 0 ] , halfmode , dest + halfregs , GET_MODE_SIZE ( halfmode ) ) ; if ( src2 == dest && src1 == dest + halfregs ) { rtx x = gen_rtx_SET ( destlo , operands [ 1 ] ) ; rtx y = gen_rtx_SET ( desthi , operands [ 2 ] ) ; emit_insn ( gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , x , y ) ) ) ; return ; } if ( ! reg_overlap_mentioned_p ( operands [ 2 ] , destlo ) ) { if ( src1 != dest ) emit_move_insn ( destlo , operands [ 1 ] ) ; if ( src2 != dest + halfregs ) emit_move_insn ( desthi , operands [ 2 ] ) ; } else { if ( src2 != dest + halfregs ) emit_move_insn ( desthi , operands [ 2 ] ) ; if ( src1 != dest ) emit_move_insn ( destlo , operands [ 1 ] ) ; } } </s>

Split operands into moves from op [ 1 ] + op [ 2 ] into op [ 0 ] .


<s> int neon_struct_mem_operand ( rtx op ) { rtx ind ; if ( ! ( reload_in_progress || reload_completed ) && ( reg_mentioned_p ( frame_pointer_rtx , op ) || reg_mentioned_p ( arg_pointer_rtx , op ) || reg_mentioned_p ( virtual_incoming_args_rtx , op ) || reg_mentioned_p ( virtual_outgoing_args_rtx , op ) || reg_mentioned_p ( virtual_stack_dynamic_rtx , op ) || reg_mentioned_p ( virtual_stack_vars_rtx , op ) ) ) return FALSE ; if ( ! MEM_P ( op ) ) return FALSE ; ind = XEXP ( op , 0 ) ; if ( reload_completed && ( LABEL_REF_P ( ind ) || ( GET_CODE ( ind ) == CONST && GET_CODE ( XEXP ( ind , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( ind , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( ind , 0 ) , 1 ) ) ) ) ) return TRUE ; if ( REG_P ( ind ) ) return arm_address_register_rtx_p ( ind , 0 ) ; if ( GET_CODE ( ind ) == POST_INC || GET_CODE ( ind ) == PRE_DEC ) return arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) ; return FALSE ; } </s>

Return TRUE if OP is a mem suitable for loading/storing a Neon struct type .


<s> rtx * neon_vcmla_lane_prepare_operands ( rtx * operands ) { int lane = INTVAL ( operands [ 4 ] ) ; machine_mode constmode = SImode ; machine_mode mode = GET_MODE ( operands [ 3 ] ) ; int regno = REGNO ( operands [ 3 ] ) ; regno = ( ( regno - FIRST_VFP_REGNUM ) >> 1 ) ; if ( lane > 0 && lane >= GET_MODE_NUNITS ( mode ) / 4 ) { operands [ 3 ] = gen_int_mode ( regno + 1 , constmode ) ; operands [ 4 ] = gen_int_mode ( lane - GET_MODE_NUNITS ( mode ) / 4 , constmode ) ; } else { operands [ 3 ] = gen_int_mode ( regno , constmode ) ; operands [ 4 ] = gen_int_mode ( lane , constmode ) ; } return operands ; } </s>

Prepares the operands for the VCMLA by lane instruction such that the right register number is selected . This instruction is special in that it always requires a D register , however there is a choice to be made between Dn [ 0 ] , Dn [ 1 ] , D ( n+1 ) [ 0 ] , and D ( n+1 ) [ 1 ] depending on the mode of the registers . The VCMLA by lane function always selects two values . For instance given D0 and a V2SF , the only valid index is 0 as the values in S0 and S1 will be used by the instruction . However given V4SF then index 0 and 1 are valid as D0 [ 0 ] or D1 [ 0 ] are both valid . This function centralizes that information based on OPERANDS , OPERANDS [ 3 ] will be changed from a REG into a CONST_INT RTX and OPERANDS [ 4 ] will be updated to contain the right index .


<s> static rtx neon_vdup_constant ( rtx vals , bool generate ) { machine_mode mode = GET_MODE ( vals ) ; machine_mode inner_mode = GET_MODE_INNER ( mode ) ; rtx x ; if ( GET_CODE ( vals ) != CONST_VECTOR || GET_MODE_SIZE ( inner_mode ) > 4 ) return NULL_RTX ; if ( ! const_vec_duplicate_p ( vals , & x ) ) return NULL_RTX ; if ( ! generate ) return x ; x = copy_to_mode_reg ( inner_mode , x ) ; return gen_vec_duplicate ( mode , x ) ; } </s>

Return a non-NULL RTX iff VALS is a vector constant that can be loaded into a register using VDUP . If this is the case , and GENERATE is set , we also generate instructions to do this and return an RTX to assign to the register .


<s> int neon_vector_mem_operand ( rtx op , int type , bool strict ) { rtx ind ; if ( strict && ! ( reload_in_progress || reload_completed ) && ( reg_mentioned_p ( frame_pointer_rtx , op ) || reg_mentioned_p ( arg_pointer_rtx , op ) || reg_mentioned_p ( virtual_incoming_args_rtx , op ) || reg_mentioned_p ( virtual_outgoing_args_rtx , op ) || reg_mentioned_p ( virtual_stack_dynamic_rtx , op ) || reg_mentioned_p ( virtual_stack_vars_rtx , op ) ) ) return FALSE ; if ( ! MEM_P ( op ) ) return FALSE ; ind = XEXP ( op , 0 ) ; if ( reload_completed && ( LABEL_REF_P ( ind ) || ( GET_CODE ( ind ) == CONST && GET_CODE ( XEXP ( ind , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( ind , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( ind , 0 ) , 1 ) ) ) ) ) return TRUE ; if ( REG_P ( ind ) ) return arm_address_register_rtx_p ( ind , 0 ) ; if ( ( type != 1 && GET_CODE ( ind ) == POST_INC ) || ( type == 0 && GET_CODE ( ind ) == PRE_DEC ) ) return arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) ; if ( type == 2 && GET_CODE ( ind ) == POST_MODIFY && GET_CODE ( XEXP ( ind , 1 ) ) == PLUS && REG_P ( XEXP ( XEXP ( ind , 1 ) , 1 ) ) && REG_P ( XEXP ( ind , 0 ) ) && rtx_equal_p ( XEXP ( ind , 0 ) , XEXP ( XEXP ( ind , 1 ) , 0 ) ) ) return true ; if ( type == 0 && GET_CODE ( ind ) == PLUS && REG_P ( XEXP ( ind , 0 ) ) && REG_MODE_OK_FOR_BASE_P ( XEXP ( ind , 0 ) , VOIDmode ) && CONST_INT_P ( XEXP ( ind , 1 ) ) && INTVAL ( XEXP ( ind , 1 ) ) > - 1024 && ( INTVAL ( XEXP ( ind , 1 ) ) < ( VALID_NEON_QREG_MODE ( GET_MODE ( op ) ) ? 1016 : 1024 ) ) && ( INTVAL ( XEXP ( ind , 1 ) ) & 3 ) == 0 ) return TRUE ; return FALSE ; } </s>

Return TRUE if OP is a memory operand which we can load or store a vector to/from . TYPE is one of the following values : 0 - Vector load/stor ( vldr ) 1 - Core registers ( ldm ) 2 - Element/structure loads ( vld1 )


<s> inline static rtx next_consecutive_mem ( rtx mem ) { machine_mode mode = GET_MODE ( mem ) ; HOST_WIDE_INT offset = GET_MODE_SIZE ( mode ) ; rtx addr = plus_constant ( Pmode , XEXP ( mem , 0 ) , offset ) ; return adjust_automodify_address ( mem , mode , addr , offset ) ; } </s>

Helper for gen_movmem_ldrd_strd . Increase the address of memory rtxby mode size .


<s> static void note_invalid_constants ( rtx_insn * insn , HOST_WIDE_INT address , int do_pushes ) { int opno ; extract_constrain_insn ( insn ) ; if ( recog_data . n_alternatives == 0 ) return ; preprocess_constraints ( insn ) ; const operand_alternative * op_alt = which_op_alt ( ) ; for ( opno = 0 ; opno < recog_data . n_operands ; opno ++ ) { if ( recog_data . operand_type [ opno ] != OP_IN ) continue ; if ( op_alt [ opno ] . memory_ok ) { rtx op = recog_data . operand [ opno ] ; if ( CONSTANT_P ( op ) ) { if ( do_pushes ) push_minipool_fix ( insn , address , recog_data . operand_loc [ opno ] , recog_data . operand_mode [ opno ] , op ) ; } else if ( MEM_P ( op ) && GET_CODE ( XEXP ( op , 0 ) ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( XEXP ( op , 0 ) ) ) { if ( do_pushes ) { rtx cop = avoid_constant_pool_reference ( op ) ; if ( op == cop ) cop = get_pool_constant ( XEXP ( op , 0 ) ) ; push_minipool_fix ( insn , address , recog_data . operand_loc [ opno ] , recog_data . operand_mode [ opno ] , cop ) ; } } } } return ; } </s>

Scan INSN and note any of its operands that need fixing . If DO_PUSHES is false we do not actually push any of the fixups needed . The function returns TRUE if any fixups were needed/pushed . This is used by arm_memory_load_p ( ) which needs to know about loads of constants that will be converted into minipool loads .


<s> inline static int number_of_first_bit_set ( unsigned mask ) { return ctz_hwi ( mask ) ; } </s>

Return the number ( counting from 0 ) of the least significant set bit in MASK .


<s> bool offset_ok_for_ldrd_strd ( HOST_WIDE_INT offset ) { HOST_WIDE_INT max_offset ; if ( TARGET_THUMB2 && ( ( offset & 3 ) != 0 ) ) return false ; if ( TARGET_THUMB2 ) max_offset = 1020 ; else if ( TARGET_ARM ) max_offset = 255 ; else return false ; return ( ( offset <= max_offset ) && ( offset >= - max_offset ) ) ; } </s>

Returns true iff OFFSET is valid for use in an LDRD/STRD instruction , assuming that the address in the base register is word aligned .


<s> bool operands_ok_ldrd_strd ( rtx rt , rtx rt2 , rtx rn , HOST_WIDE_INT offset , bool wback , bool load ) { unsigned int t , t2 , n ; if ( ! reload_completed ) return true ; if ( ! offset_ok_for_ldrd_strd ( offset ) ) return false ; t = REGNO ( rt ) ; t2 = REGNO ( rt2 ) ; n = REGNO ( rn ) ; if ( ( TARGET_THUMB2 ) && ( ( wback && ( n == t || n == t2 ) ) || ( t == SP_REGNUM ) || ( t == PC_REGNUM ) || ( t2 == SP_REGNUM ) || ( t2 == PC_REGNUM ) || ( ! load && ( n == PC_REGNUM ) ) || ( load && ( t == t2 ) ) || ( ! wback && load && fix_cm3_ldrd && ( n == t ) ) ) ) return false ; if ( ( TARGET_ARM ) && ( ( wback && ( n == t || n == t2 ) ) || ( t2 == PC_REGNUM ) || ( t % 2 != 0 ) || ( t2 != t + 1 ) || ( n == PC_REGNUM ) ) ) return false ; return true ; } </s>

Checks whether the operands are valid for use in an LDRD/STRD instruction . Assumes that RT , RT2 , and RN 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 preload complete then check that registers are legal . WBACK indicates whether address is updated . LOAD indicates whether memory access is load or store .


<s> static int optimal_immediate_sequence ( enum rtx_code code , unsigned HOST_WIDE_INT val , struct four_ints * return_sequence ) { int best_consecutive_zeros = 0 ; int i ; int best_start = 0 ; int insns1 , insns2 ; struct four_ints tmp_sequence ; if ( TARGET_ARM ) { for ( i = 0 ; i < 32 ; i += 2 ) { int consecutive_zeros = 0 ; if ( ! ( val & ( 3 << i ) ) ) { while ( ( i < 32 ) && ! ( val & ( 3 << i ) ) ) { consecutive_zeros += 2 ; i += 2 ; } if ( consecutive_zeros > best_consecutive_zeros ) { best_consecutive_zeros = consecutive_zeros ; best_start = i - consecutive_zeros ; } i -= 2 ; } } } insns1 = optimal_immediate_sequence_1 ( code , val , return_sequence , best_start ) ; if ( best_start != 0 && ( ( HOST_WIDE_INT_1U << best_start ) < val ) ) { insns2 = optimal_immediate_sequence_1 ( code , val , & tmp_sequence , 0 ) ; if ( insns2 <= insns1 ) { * return_sequence = tmp_sequence ; insns1 = insns2 ; } } return insns1 ; } </s>

Return a sequence of integers , in RETURN_SEQUENCE that fit into ARM/THUMB2 immediates , and add up to VAL . Thr function return value gives the number of insns required .


<s> static int optimal_immediate_sequence_1 ( enum rtx_code code , unsigned HOST_WIDE_INT val , struct four_ints * return_sequence , int i ) { int remainder = val & 0xffffffff ; int insns = 0 ; do { int end ; unsigned int b1 , b2 , b3 , b4 ; unsigned HOST_WIDE_INT result ; int loc ; gcc_assert ( insns < 4 ) ; if ( i <= 0 ) i += 32 ; if ( remainder & ( ( TARGET_ARM ? ( 3 << ( i - 2 ) ) : ( 1 << ( i - 1 ) ) ) ) ) { loc = i ; if ( i <= 12 && TARGET_THUMB2 && code == PLUS ) result = remainder ; else { end = i - 8 ; if ( end < 0 ) end += 32 ; result = remainder & ( ( 0x0ff << end ) | ( ( i < end ) ? ( 0xff >> ( 32 - end ) ) : 0 ) ) ; i -= 8 ; } } else { i -= TARGET_ARM ? 2 : 1 ; continue ; } if ( TARGET_THUMB2 ) { b1 = ( remainder & 0xff000000 ) >> 24 ; b2 = ( remainder & 0x00ff0000 ) >> 16 ; b3 = ( remainder & 0x0000ff00 ) >> 8 ; b4 = remainder & 0xff ; if ( loc > 24 ) { unsigned int tmp = b1 & b2 & b3 & b4 ; unsigned int tmp2 = tmp + ( tmp << 8 ) + ( tmp << 16 ) + ( tmp << 24 ) ; unsigned int matching_bytes = ( tmp == b1 ) + ( tmp == b2 ) + ( tmp == b3 ) + ( tmp == b4 ) ; if ( tmp && ( matching_bytes >= 3 || ( matching_bytes == 2 && const_ok_for_op ( remainder & ~ tmp2 , code ) ) ) ) { result = tmp2 ; i = tmp != b1 ? 32 : tmp != b2 ? 24 : tmp != b3 ? 16 : 8 ; } else if ( b1 == b3 && ( ! b2 || ! b4 || ( remainder & 0x00ff0000 & ~ result ) ) ) { result = remainder & 0xff00ff00 ; i = 24 ; } } else if ( loc > 16 ) { if ( b2 == b4 ) { result = remainder & 0x00ff00ff ; i = 16 ; } } } return_sequence -> i [ insns ++ ] = result ; remainder &= ~ result ; if ( code == SET || code == MINUS ) code = PLUS ; } while ( remainder ) ; return insns ; } </s>

As for optimal_immediate_sequence , but starting at bit-position I .


<s>
const
char
*
output_add_immediate
(
rtx
*
operands
)
{
HOST_WIDE_INT
n
=
INTVAL
(
operands
[
2
]
)
;
if
(
n
!=
0
||
REGNO
(
operands
[
0
]
)
!=
REGNO
(
operands
[
1
]
)
)
{
if
(
n
<
0
)
output_multi_immediate
(
operands
,
"sub%?\t%0, %1, %2"
,
"sub%?\t%0, %0, %2"
,
2
,
n
)
;
else
output_multi_immediate
(
operands
,
"add%?\t%0, %1, %2"
,
"add%?\t%0, %0, %2"
,
2
,
n
)
;
}
return
""
;
}
</s>

Output an ADD r , s , # n where n may be too big for one instruction . If adding zero to one register , output nothing .


<s>
const
char
*
output_call
(
rtx
*
operands
)
{
gcc_assert
(
!
arm_arch5t
)
;
if
(
REGNO
(
operands
[
0
]
)
==
LR_REGNUM
)
{
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
IP_REGNUM
)
;
output_asm_insn
(
"mov%?\t%0, %|lr"
,
operands
)
;
}
output_asm_insn
(
"mov%?\t%|lr, %|pc"
,
operands
)
;
if
(
TARGET_INTERWORK
||
arm_arch4t
)
output_asm_insn
(
"bx%?\t%0"
,
operands
)
;
else
output_asm_insn
(
"mov%?\t%|pc, %0"
,
operands
)
;
return
""
;
}
</s>

INSN is either a function call or a millicode call . It may have an unconditional jump in its delay slot . CALL_DEST is the routine we are calling .


<s>
const
char
*
output_move_quad
(
rtx
*
operands
)
{
if
(
REG_P
(
operands
[
0
]
)
)
{
if
(
MEM_P
(
operands
[
1
]
)
)
{
switch
(
GET_CODE
(
XEXP
(
operands
[
1
]
,
0
)
)
)
{
case
REG
:
output_asm_insn
(
"ldmia%?\t%m1, %M0"
,
operands
)
;
break
;
case
LABEL_REF
:
case
CONST
:
output_asm_insn
(
"adr%?\t%0, %1"
,
operands
)
;
output_asm_insn
(
"ldmia%?\t%0, %M0"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
}
else
{
rtx
ops
[
2
]
;
int
dest
,
src
,
i
;
gcc_assert
(
REG_P
(
operands
[
1
]
)
)
;
dest
=
REGNO
(
operands
[
0
]
)
;
src
=
REGNO
(
operands
[
1
]
)
;
if
(
dest
<
src
)
for
(
i
=
0
;
i
<
4
;
i
++
)
{
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
dest
+
i
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
src
+
i
)
;
output_asm_insn
(
"mov%?\t%0, %1"
,
ops
)
;
}
else
for
(
i
=
3
;
i
>=
0
;
i
)
{
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
dest
+
i
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
src
+
i
)
;
output_asm_insn
(
"mov%?\t%0, %1"
,
ops
)
;
}
}
}
else
{
gcc_assert
(
MEM_P
(
operands
[
0
]
)
)
;
gcc_assert
(
REG_P
(
operands
[
1
]
)
)
;
gcc_assert
(
!
reg_overlap_mentioned_p
(
operands
[
1
]
,
operands
[
0
]
)
)
;
switch
(
GET_CODE
(
XEXP
(
operands
[
0
]
,
0
)
)
)
{
case
REG
:
output_asm_insn
(
"stm%?\t%m0, %M1"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
}
return
""
;
}
</s>

Output assembler code to perform a quadword move insn with operands OPERANDS .


<s>
const
char
*
output_move_vfp
(
rtx
*
operands
)
{
rtx
reg
,
mem
,
addr
,
ops
[
2
]
;
int
load
=
REG_P
(
operands
[
0
]
)
;
int
dp
=
GET_MODE_SIZE
(
GET_MODE
(
operands
[
0
]
)
)
==
8
;
int
sp
=
(
!
TARGET_VFP_FP16INST
||
GET_MODE_SIZE
(
GET_MODE
(
operands
[
0
]
)
)
==
4
)
;
int
integer_p
=
GET_MODE_CLASS
(
GET_MODE
(
operands
[
0
]
)
)
==
MODE_INT
;
const
char
*
templ
;
char
buff
[
50
]
;
machine_mode
mode
;
reg
=
operands
[
!
load
]
;
mem
=
operands
[
load
]
;
mode
=
GET_MODE
(
reg
)
;
gcc_assert
(
REG_P
(
reg
)
)
;
gcc_assert
(
IS_VFP_REGNUM
(
REGNO
(
reg
)
)
)
;
gcc_assert
(
(
mode
==
HFmode
&&
TARGET_HARD_FLOAT
)
||
mode
==
SFmode
||
mode
==
DFmode
||
mode
==
HImode
||
mode
==
SImode
||
mode
==
DImode
||
(
TARGET_NEON
&&
VALID_NEON_DREG_MODE
(
mode
)
)
)
;
gcc_assert
(
MEM_P
(
mem
)
)
;
addr
=
XEXP
(
mem
,
0
)
;
switch
(
GET_CODE
(
addr
)
)
{
case
PRE_DEC
:
templ
=
"v%smdb%%?.%s\t%%0!, {%%%s1}%s"
;
ops
[
0
]
=
XEXP
(
addr
,
0
)
;
ops
[
1
]
=
reg
;
break
;
case
POST_INC
:
templ
=
"v%smia%%?.%s\t%%0!, {%%%s1}%s"
;
ops
[
0
]
=
XEXP
(
addr
,
0
)
;
ops
[
1
]
=
reg
;
break
;
default
:
templ
=
"v%sr%%?.%s\t%%%s0, %%1%s"
;
ops
[
0
]
=
reg
;
ops
[
1
]
=
mem
;
break
;
}
sprintf
(
buff
,
templ
,
load
"ld"
:
"st"
,
dp
"64"
:
sp
"32"
:
"16"
,
dp
"P"
:
""
,
integer_p
"\t%@ int"
:
""
)
;
output_asm_insn
(
buff
,
ops
)
;
return
""
;
}
</s>

Output a VFP load or store instruction .


<s>
const
char
*
output_mov_long_double_arm_from_arm
(
rtx
*
operands
)
{
int
dest_start
=
REGNO
(
operands
[
0
]
)
;
int
src_start
=
REGNO
(
operands
[
1
]
)
;
rtx
ops
[
2
]
;
int
i
;
if
(
dest_start
<
src_start
)
{
for
(
i
=
0
;
i
<
3
;
i
++
)
{
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
dest_start
+
i
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
src_start
+
i
)
;
output_asm_insn
(
"mov%?\t%0, %1"
,
ops
)
;
}
}
else
{
for
(
i
=
2
;
i
>=
0
;
i
)
{
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
dest_start
+
i
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
src_start
+
i
)
;
output_asm_insn
(
"mov%?\t%0, %1"
,
ops
)
;
}
}
return
""
;
}
</s>

Output a move from arm registers to arm registers of a long double OPERANDS [ 0 ] is the destination . OPERANDS [ 1 ] is the source .


<s> static const char * output_multi_immediate ( rtx * operands , const char * instr1 , const char * instr2 , int immed_op , HOST_WIDE_INT n ) { n &= 0xffffffff ; if ( n == 0 ) { operands [ immed_op ] = const0_rtx ; output_asm_insn ( instr1 , operands ) ; } else { int i ; const char * instr = instr1 ; for ( i = 0 ; i < 32 ; i += 2 ) { if ( n & ( 3 << i ) ) { operands [ immed_op ] = GEN_INT ( n & ( 255 << i ) ) ; output_asm_insn ( instr , operands ) ; instr = instr2 ; i += 6 ; } } } return "" ; } </s>

Output a multiple immediate operation . OPERANDS is the vector of operands referred to in the output patterns . INSTR1 is the output pattern to use for the first constant . INSTR2 is the output pattern to use for subsequent constants . IMMED_OP is the index of the constant slot in OPERANDS . N is the constant value .


<s>
const
char
*
output_probe_stack_range
(
rtx
reg1
,
rtx
reg2
)
{
static
int
labelno
=
0
;
char
loop_lab
[
32
]
;
rtx
xops
[
2
]
;
ASM_GENERATE_INTERNAL_LABEL
(
loop_lab
,
"LPSRL"
,
labelno
++
)
;
ASM_OUTPUT_INTERNAL_LABEL
(
asm_out_file
,
loop_lab
)
;
xops
[
0
]
=
reg1
;
xops
[
1
]
=
GEN_INT
(
PROBE_INTERVAL
)
;
output_asm_insn
(
"sub\t%0, %0, %1"
,
xops
)
;
output_asm_insn
(
"str\tr0, [%0, #0]"
,
xops
)
;
xops
[
1
]
=
reg2
;
output_asm_insn
(
"cmp\t%0, %1"
,
xops
)
;
fputs
(
"\tbne\t"
,
asm_out_file
)
;
assemble_name_raw
(
asm_out_file
,
loop_lab
)
;
fputc
(
'\n'
,
asm_out_file
)
;
return
""
;
}
</s>

Wrapper around the output_probe_stack_range routines .


<s> static int pcrel_constant_p ( rtx x ) { if ( GET_CODE ( x ) == MINUS ) return symbol_mentioned_p ( XEXP ( x , 0 ) ) && label_mentioned_p ( XEXP ( x , 1 ) ) ; return FALSE ; } </s>

Return TRUE if this rtx is the difference of a symbol and a label , and will reduce to a PC-relative relocation in the object file . Expressions like this can be left alone when generating PIC , rather than forced through the GOT .


<s> static void push_minipool_barrier ( rtx_insn * insn , HOST_WIDE_INT address ) { Mfix * fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * fix ) ) ; fix -> insn = insn ; fix -> address = address ; fix -> next = NULL ; if ( minipool_fix_head != NULL ) minipool_fix_tail -> next = fix ; else minipool_fix_head = fix ; minipool_fix_tail = fix ; } </s>

Record that there is a natural barrier in the insn stream at ADDRESS .


";; %smode fixup for i%d; addr %lu, range (%ld,%ld): "

Record INSN , which will need fixing up to load a value from the minipool . ADDRESS is the offset of the insn since the start of the function ; LOC is a pointer to the part of the insn which requires fixing ; VALUE is the constant that must be loaded , which is of type MODE .


<s> static void release_scratch_register_on_entry ( struct scratch_reg * sr ) { if ( sr -> saved ) { rtx addr = gen_rtx_POST_INC ( Pmode , stack_pointer_rtx ) ; rtx insn = emit_set_insn ( sr -> reg , gen_frame_mem ( SImode , addr ) ) ; rtx x = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , 4 ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , x ) ; } } </s>

Release a scratch register obtained from the preceding function . If RELEASE_VIA_POP is true , we just pop the register off the stack to release it . This is what non-Linux systems use with -fstack-check . Otherwise we use OFFSET to locate the saved register and the allocated stack space becomes part of the local frame and is deallocated by the epilogue .


<s> static void require_pic_register ( rtx pic_reg , bool compute_now ) { gcc_assert ( compute_now == ( pic_reg != NULL_RTX ) ) ; if ( ! crtl -> uses_pic_offset_table || compute_now ) { gcc_assert ( can_create_pseudo_p ( ) || ( pic_reg != NULL_RTX && REG_P ( pic_reg ) && GET_MODE ( pic_reg ) == Pmode ) ) ; if ( arm_pic_register != INVALID_REGNUM && ! compute_now && ! ( TARGET_THUMB1 && arm_pic_register > LAST_LO_REGNUM ) ) { if ( ! cfun -> machine -> pic_reg ) cfun -> machine -> pic_reg = gen_rtx_REG ( Pmode , arm_pic_register ) ; if ( current_ir_type ( ) != IR_GIMPLE || currently_expanding_to_rtl ) crtl -> uses_pic_offset_table = 1 ; } else { rtx_insn * seq , * insn ; if ( pic_reg == NULL_RTX ) pic_reg = gen_reg_rtx ( Pmode ) ; if ( ! cfun -> machine -> pic_reg ) cfun -> machine -> pic_reg = pic_reg ; if ( current_ir_type ( ) != IR_GIMPLE || currently_expanding_to_rtl ) { crtl -> uses_pic_offset_table = 1 ; start_sequence ( ) ; if ( TARGET_THUMB1 && arm_pic_register != INVALID_REGNUM && arm_pic_register > LAST_LO_REGNUM && ! compute_now ) emit_move_insn ( cfun -> machine -> pic_reg , gen_rtx_REG ( Pmode , arm_pic_register ) ) ; else arm_load_pic_register ( 0UL , pic_reg ) ; seq = get_insns ( ) ; end_sequence ( ) ; for ( insn = seq ; insn ; insn = NEXT_INSN ( insn ) ) if ( INSN_P ( insn ) ) INSN_LOCATION ( insn ) = prologue_location ; if ( currently_expanding_to_rtl ) insert_insn_on_edge ( seq , single_succ_edge ( ENTRY_BLOCK_PTR_FOR_FN ( cfun ) ) ) ; else emit_insn ( seq ) ; } } } } </s>

Record that the current function needs a PIC register . Initialize cfun- > machine- > pic_reg if we have not already done so .


<s> void save_restore_target_globals ( tree new_tree ) { if ( TREE_TARGET_GLOBALS ( new_tree ) ) restore_target_globals ( TREE_TARGET_GLOBALS ( new_tree ) ) ; else if ( new_tree == target_option_default_node ) restore_target_globals ( & default_target_globals ) ; else { TREE_TARGET_GLOBALS ( new_tree ) = save_target_globals_default_opts ( ) ; } arm_option_params_internal ( ) ; } </s>

Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE .


<s> static rtx shifter_op_p ( rtx op , rtx * shift_reg ) { enum rtx_code code = GET_CODE ( op ) ; if ( code == MULT && CONST_INT_P ( XEXP ( op , 1 ) ) && exact_log2 ( INTVAL ( XEXP ( op , 1 ) ) ) > 0 ) return XEXP ( op , 0 ) ; else if ( code == ROTATE && CONST_INT_P ( XEXP ( op , 1 ) ) ) return XEXP ( op , 0 ) ; else if ( code == ROTATERT || code == ASHIFT || code == LSHIFTRT || code == ASHIFTRT ) { if ( ! CONST_INT_P ( XEXP ( op , 1 ) ) ) * shift_reg = XEXP ( op , 1 ) ; return XEXP ( op , 0 ) ; } return NULL ; } </s>

Helper function for arm_rtx_costs . If the operand is a valid shift operand , then return the operand that is being shifted . If the shift is not by a constant , then set SHIFT_REG to point to the operand . Return NULL if OP is not a shifter operand .


<s>
static
const
char
*
shift_op
(
rtx
op
,
HOST_WIDE_INT
*
amountp
)
{
const
char
*
mnem
;
enum
rtx_code
code
=
GET_CODE
(
op
)
;
switch
(
code
)
{
case
ROTATE
:
if
(
!
CONST_INT_P
(
XEXP
(
op
,
1
)
)
)
{
output_operand_lossage
(
"invalid shift operand"
)
;
return
;
}
code
=
ROTATERT
;
*
amountp
=
32
INTVAL
(
XEXP
(
op
,
1
)
)
;
mnem
=
"ror"
;
break
;
case
ASHIFT
:
case
ASHIFTRT
:
case
LSHIFTRT
:
case
ROTATERT
:
mnem
=
arm_shift_nmem
(
code
)
;
if
(
CONST_INT_P
(
XEXP
(
op
,
1
)
)
)
{
*
amountp
=
INTVAL
(
XEXP
(
op
,
1
)
)
;
}
else
if
(
REG_P
(
XEXP
(
op
,
1
)
)
)
{
*
amountp
=
1
;
return
mnem
;
}
else
{
output_operand_lossage
(
"invalid shift operand"
)
;
return
;
}
break
;
case
MULT
:
if
(
!
CONST_INT_P
(
XEXP
(
op
,
1
)
)
)
{
output_operand_lossage
(
"invalid shift operand"
)
;
return
;
}
*
amountp
=
INTVAL
(
XEXP
(
op
,
1
)
)
&
0xFFFFFFFF
;
if
(
*
amountp
&
(
*
amountp
1
)
)
{
output_operand_lossage
(
"invalid shift operand"
)
;
return
;
}
*
amountp
=
exact_log2
(
*
amountp
)
;
gcc_assert
(
IN_RANGE
(
*
amountp
,
0
,
31
)
)
;
return
ARM_LSL_NAME
;
default
:
output_operand_lossage
(
"invalid shift operand"
)
;
return
;
}
if
(
code
==
ROTATERT
)
*
amountp
&=
31
;
else
if
(
*
amountp
!=
(
*
amountp
&
31
)
)
{
if
(
code
==
ASHIFT
)
mnem
=
"lsr"
;
*
amountp
=
32
;
}
if
(
*
amountp
==
0
)
return
;
return
mnem
;
}
</s>

Ensure valid constant shifts and return the appropriate shift mnemonic for the operation code . The returned result should not be overwritten . OP is the rtx code of the shift . On exit , * AMOUNTP will be -1 if the shift is by a register , or a constant shift .


<s> int simd_immediate_valid_for_move ( rtx op , machine_mode mode , rtx * modconst , int * elementwidth ) { rtx tmpconst ; int tmpwidth ; int retval = simd_valid_immediate ( op , mode , 0 , & tmpconst , & tmpwidth ) ; if ( retval == - 1 ) return 0 ; if ( modconst ) * modconst = tmpconst ; if ( elementwidth ) * elementwidth = tmpwidth ; return 1 ; } </s>

Return TRUE if rtx X is legal for use as either a Neon or MVE VMOV ( or , implicitly , VMVN ) immediate . Write back width per element to * ELEMENTWIDTH ( or zero for float elements ) , and a modified constant ( whatever should be output for a VMOV ) in * MODCONST . `` neon_immediate_valid_for_move '' function is modified to `` simd_immediate_valid_for_move '' as this function will be used both by neon and mve .


<s> static rtx strip_carry_operation ( rtx op ) { gcc_assert ( GET_CODE ( op ) == PLUS ) ; if ( arm_carry_operation ( XEXP ( op , 0 ) , GET_MODE ( op ) ) ) return XEXP ( op , 1 ) ; else if ( arm_carry_operation ( XEXP ( op , 1 ) , GET_MODE ( op ) ) ) return XEXP ( op , 0 ) ; return op ; } </s>

Helper function for arm_rtx_costs . If one operand of the OP , a PLUS , adds the carry flag , then return the other operand . If neither is a carry , return OP unchanged .


<s> int symbol_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( SYMBOL_REF_P ( x ) ) return 1 ; if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) return 0 ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( symbol_mentioned_p ( XVECEXP ( x , i , j ) ) ) return 1 ; } else if ( fmt [ i ] == 'e' && symbol_mentioned_p ( XEXP ( x , i ) ) ) return 1 ; } return 0 ; } </s>

Return TRUE if X references a SYMBOL_REF .


<s> static int thumb1_base_register_rtx_p ( rtx x , machine_mode mode , int strict_p ) { int regno ; if ( ! REG_P ( x ) ) return 0 ; regno = REGNO ( x ) ; if ( strict_p ) return THUMB1_REGNO_MODE_OK_FOR_BASE_P ( regno , mode ) ; return ( regno <= LAST_LO_REGNUM || regno > LAST_VIRTUAL_REGISTER || regno == FRAME_POINTER_REGNUM || ( GET_MODE_SIZE ( mode ) >= 4 && ( regno == STACK_POINTER_REGNUM || regno >= FIRST_PSEUDO_REGISTER || x == hard_frame_pointer_rtx || x == arg_pointer_rtx ) ) ) ; } </s>

Return nonzero if X is valid as a 16-bit Thumb state base register .


Compute a bit mask of which core registers need to be saved on the stack for the current function .


<s> static rtx_insn * thumb1_emit_multi_reg_push ( unsigned long mask , unsigned long real_regs ) { unsigned long regno ; rtx par [ 10 ] , tmp , reg ; rtx_insn * insn ; int i , j ; for ( i = 0 ; mask ; ++ i , mask &= mask - 1 ) { regno = ctz_hwi ( mask ) ; reg = gen_rtx_REG ( SImode , regno ) ; if ( i == 0 ) tmp = gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSH_MULT ) ; else tmp = gen_rtx_USE ( VOIDmode , reg ) ; par [ i ] = tmp ; } tmp = plus_constant ( Pmode , stack_pointer_rtx , - 4 * i ) ; tmp = gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , tmp ) ; tmp = gen_frame_mem ( BLKmode , tmp ) ; tmp = gen_rtx_SET ( tmp , par [ 0 ] ) ; par [ 0 ] = tmp ; tmp = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( i , par ) ) ; insn = emit_insn ( tmp ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , - 4 * i ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , tmp ) ; par [ 0 ] = tmp ; for ( j = 0 ; real_regs ; ++ j , real_regs &= real_regs - 1 ) { regno = ctz_hwi ( real_regs ) ; reg = gen_rtx_REG ( SImode , regno ) ; tmp = plus_constant ( Pmode , stack_pointer_rtx , j * 4 ) ; tmp = gen_frame_mem ( SImode , tmp ) ; tmp = gen_rtx_SET ( tmp , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; par [ j + 1 ] = tmp ; } if ( j == 0 ) tmp = par [ 0 ] ; else { RTX_FRAME_RELATED_P ( par [ 0 ] ) = 1 ; tmp = gen_rtx_SEQUENCE ( VOIDmode , gen_rtvec_v ( j + 1 , par ) ) ; } add_reg_note ( insn , REG_FRAME_RELATED_EXPR , tmp ) ; return insn ; } </s>

Like emit_multi_reg_push , but allowing for a different set of registers to be described as saved . MASK is the set of registers to be saved ; REAL_REGS is the set of registers to be described as saved . If REAL_REGS is 0 , only describe the stack adjustment .


Similarly for the start of the epilogue .


<s> static int thumb1_extra_regs_pushed ( arm_stack_offsets * offsets , bool for_prologue ) { HOST_WIDE_INT amount ; unsigned long live_regs_mask = offsets -> saved_regs_mask ; unsigned long l_mask = live_regs_mask & ( for_prologue ? 0x40ff : 0xff ) ; unsigned long high_regs_pushed = bit_count ( live_regs_mask & 0x0f00 ) ; int n_free , reg_base , size ; if ( ! for_prologue && frame_pointer_needed ) amount = offsets -> locals_base - offsets -> saved_regs ; else amount = offsets -> outgoing_args - offsets -> saved_regs ; if ( ! optimize_size && amount != 512 ) return 0 ; if ( high_regs_pushed != 0 ) return 0 ; if ( l_mask == 0 && ( for_prologue || TARGET_BACKTRACE || ( live_regs_mask & 1 << LR_REGNUM ) == 0 || TARGET_INTERWORK || crtl -> args . pretend_args_size != 0 ) ) return 0 ; if ( for_prologue && ( ( flag_pic && arm_pic_register != INVALID_REGNUM ) || ( ! frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0 ) ) ) return 0 ; reg_base = 0 ; n_free = 0 ; if ( ! for_prologue ) { size = arm_size_return_regs ( ) ; reg_base = ARM_NUM_INTS ( size ) ; live_regs_mask >>= reg_base ; } while ( reg_base + n_free < 8 && ! ( live_regs_mask & 1 ) && ( for_prologue || call_used_or_fixed_reg_p ( reg_base + n_free ) ) ) { live_regs_mask >>= 1 ; n_free ++ ; } if ( n_free == 0 ) return 0 ; gcc_assert ( amount / 4 * 4 == amount ) ; if ( amount >= 512 && ( amount - n_free * 4 ) < 512 ) return ( amount - 508 ) / 4 ; if ( amount <= n_free * 4 ) return amount / 4 ; return 0 ; } </s>

Given the stack offsets and register mask in OFFSETS , decide how many additional registers to push instead of subtracting a constant from SP . For epilogues the principle is the same except we use pop . FOR_PROLOGUE indicates which we 're generating .


<s>
void
thumb1_final_prescan_insn
(
rtx_insn
*
insn
)
{
if
(
flag_print_asm_name
)
asm_fprintf
(
asm_out_file
,
"%@ 0x%04x\n"
,
INSN_ADDRESSES
(
INSN_UID
(
insn
)
)
)
;
if
(
INSN_CODE
(
insn
)
!=
CODE_FOR_cbranchsi4_insn
)
{
enum
attr_conds
conds
;
if
(
cfun
->
machine
->
thumb1_cc_insn
)
{
if
(
modified_in_p
(
cfun
->
machine
->
thumb1_cc_op0
,
insn
)
||
modified_in_p
(
cfun
->
machine
->
thumb1_cc_op1
,
insn
)
)
CC_STATUS_INIT
;
}
conds
=
get_attr_conds
(
insn
)
;
if
(
conds
==
CONDS_SET
)
{
rtx
set
=
single_set
(
insn
)
;
cfun
->
machine
->
thumb1_cc_insn
=
insn
;
cfun
->
machine
->
thumb1_cc_op0
=
SET_DEST
(
set
)
;
cfun
->
machine
->
thumb1_cc_op1
=
const0_rtx
;
cfun
->
machine
->
thumb1_cc_mode
=
CC_NZmode
;
if
(
INSN_CODE
(
insn
)
==
CODE_FOR_thumb1_subsi3_insn
)
{
rtx
src1
=
XEXP
(
SET_SRC
(
set
)
,
1
)
;
if
(
src1
==
const0_rtx
)
cfun
->
machine
->
thumb1_cc_mode
=
CCmode
;
}
else
if
(
REG_P
(
SET_DEST
(
set
)
)
&&
REG_P
(
SET_SRC
(
set
)
)
)
{
cfun
->
machine
->
thumb1_cc_op0
=
SET_SRC
(
set
)
;
}
}
else
if
(
conds
!=
CONDS_NOCOND
)
cfun
->
machine
->
thumb1_cc_insn
=
NULL_RTX
;
}
if
(
cfun
->
machine
->
lr_save_eliminated
&&
get_attr_far_jump
(
insn
)
==
FAR_JUMP_YES
)
internal_error
(
"Unexpected thumb1 far jump"
)
;
}
</s>

Scan INSN just before assembler is output for it . For Thumb-1 , we track the status of the condition codes ; this information is used in the cbranchsi4_insn pattern .

arm
"%@ 0x%04x\n"
1
"Unexpected thumb1 far jump"


<s> void thumb1_gen_const_int ( rtx op0 , HOST_WIDE_INT op1 ) { bool mov_done_p = false ; int i ; for ( i = 0 ; i < 3 ; i ++ ) { int byte = ( op1 >> ( 8 * ( 3 - i ) ) ) & 0xff ; if ( byte ) { emit_set_insn ( op0 , mov_done_p ? gen_rtx_PLUS ( SImode , op0 , GEN_INT ( byte ) ) : GEN_INT ( byte ) ) ; mov_done_p = true ; } if ( mov_done_p ) emit_set_insn ( op0 , gen_rtx_ASHIFT ( SImode , op0 , GEN_INT ( 8 ) ) ) ; } if ( ! mov_done_p ) emit_set_insn ( op0 , GEN_INT ( op1 & 0xff ) ) ; else if ( op1 & 0xff ) emit_set_insn ( op0 , gen_rtx_PLUS ( SImode , op0 , GEN_INT ( op1 & 0xff ) ) ) ; } </s>

Emit a sequence of movs/adds/shift to produce a 32-bit constant . Avoid generating useless code when one of the bytes is zero .


<s> void thumb1_gen_const_int_rtl ( rtx dst , HOST_WIDE_INT op1 ) { thumb1_const_rtl t ( dst ) ; thumb1_gen_const_int_1 ( t , op1 ) ; } </s>

Proxies for thumb1.md , since the thumb1_const_print and thumb1_const_rtl classes are not exported .


<s> inline static int thumb1_index_register_rtx_p ( rtx x , int strict_p ) { return thumb1_base_register_rtx_p ( x , QImode , strict_p ) ; } </s>

Return nonzero if x is a legitimate index register . This is the case for any base register that can access a QImode object .


"%<asm%> flags not supported in thumb1 mode"

Worker function for TARGET_MD_ASM_ADJUST , while in thumb1 mode . Unlike the arm version , we do NOT implement asm flag outputs .


<s> const char * thumb1_output_casesi ( rtx * operands ) { rtx diff_vec = PATTERN ( NEXT_INSN ( as_a < rtx_insn * > ( operands [ 0 ] ) ) ) ; gcc_assert ( GET_CODE ( diff_vec ) == ADDR_DIFF_VEC ) ; switch ( GET_MODE ( diff_vec ) ) { case E_QImode : return ( ADDR_DIFF_VEC_FLAGS ( diff_vec ) . offset_unsigned ? "bl\t%___gnu_thumb1_case_uqi" : "bl\t%___gnu_thumb1_case_sqi" ) ; case E_HImode : return ( ADDR_DIFF_VEC_FLAGS ( diff_vec ) . offset_unsigned ? "bl\t%___gnu_thumb1_case_uhi" : "bl\t%___gnu_thumb1_case_shi" ) ; case E_SImode : return "bl\t%___gnu_thumb1_case_si" ; default : gcc_unreachable ( ) ; } } </s>

Output a Thumb-1 casesi dispatch sequence .


<s>
const
char
*
thumb1_output_interwork
(
void
)
{
const
char
*
name
;
FILE
*
f
=
asm_out_file
;
gcc_assert
(
MEM_P
(
DECL_RTL
(
current_function_decl
)
)
)
;
gcc_assert
(
GET_CODE
(
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
)
==
SYMBOL_REF
)
;
name
=
XSTR
(
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
,
0
)
;
asm_fprintf
(
f
,
"\torr\t%r, %r, #1\n"
,
IP_REGNUM
,
PC_REGNUM
)
;
asm_fprintf
(
f
,
"\tbx\t%r\n"
,
IP_REGNUM
)
;
fprintf
(
f
,
"\t.code\t16\n"
)
;
if
(
arm_dllexport_name_p
(
name
)
)
name
=
arm_strip_name_encoding
(
name
)
;
asm_fprintf
(
f
,
"\t.globl %s%U%s\n"
,
STUB_NAME
,
name
)
;
fprintf
(
f
,
"\t.thumb_func\n"
)
;
asm_fprintf
(
f
,
"%s%U%s:\n"
,
STUB_NAME
,
name
)
;
return
""
;
}
</s>

Implementation of insn prologue_thumb1_interwork . This is the first `` instruction '' of a function called in ARM mode . Swap to thumb mode .


Return a mask for the call-clobbered low registers that are unused at the end of the prologue .


<s> static void thumb1_reorg ( void ) { basic_block bb ; FOR_EACH_BB_FN ( bb , cfun ) { rtx dest , src ; rtx cmp , op0 , op1 , set = NULL ; rtx_insn * prev , * insn = BB_END ( bb ) ; bool insn_clobbered = false ; while ( insn != BB_HEAD ( bb ) && ! NONDEBUG_INSN_P ( insn ) ) insn = PREV_INSN ( insn ) ; if ( insn == BB_HEAD ( bb ) || INSN_CODE ( insn ) != CODE_FOR_cbranchsi4_insn ) continue ; cmp = XEXP ( SET_SRC ( PATTERN ( insn ) ) , 0 ) ; op0 = XEXP ( cmp , 0 ) ; op1 = XEXP ( cmp , 1 ) ; if ( ! CONST_INT_P ( op1 ) || INTVAL ( op1 ) != 0 ) continue ; gcc_assert ( insn != BB_HEAD ( bb ) ) ; for ( prev = PREV_INSN ( insn ) ; ( ! insn_clobbered && prev != BB_HEAD ( bb ) && ( NOTE_P ( prev ) || DEBUG_INSN_P ( prev ) || ( ( set = single_set ( prev ) ) != NULL && get_attr_conds ( prev ) == CONDS_NOCOND ) ) ) ; prev = PREV_INSN ( prev ) ) { if ( reg_set_p ( op0 , prev ) ) insn_clobbered = true ; } if ( insn_clobbered ) continue ; if ( ! set ) continue ; dest = SET_DEST ( set ) ; src = SET_SRC ( set ) ; if ( ! low_register_operand ( dest , SImode ) || ! low_register_operand ( src , SImode ) ) continue ; if ( REGNO ( op0 ) == REGNO ( src ) || REGNO ( op0 ) == REGNO ( dest ) ) { dest = copy_rtx ( dest ) ; src = copy_rtx ( src ) ; src = gen_rtx_MINUS ( SImode , src , const0_rtx ) ; PATTERN ( prev ) = gen_rtx_SET ( dest , src ) ; INSN_CODE ( prev ) = - 1 ; XEXP ( cmp , 0 ) = copy_rtx ( dest ) ; INSN_CODE ( insn ) = - 1 ; } } } </s>

Rewrite move insn into subtract of 0 if the condition codes will be useful in next conditional jump insn .


"no low registers available for popping high registers"

The bits which are n't usefully expanded as rtl .


<s> void thumb2_asm_output_opcode ( FILE * stream ) { char buff [ 5 ] ; int n ; if ( arm_condexec_mask ) { for ( n = 0 ; n < arm_condexec_masklen ; n ++ ) buff [ n ] = ( arm_condexec_mask & ( 1 << n ) ) ? 't' : 'e' ; buff [ n ] = 0 ; asm_fprintf ( stream , "i%s\t%s\n\t" , buff , arm_condition_codes [ arm_current_cc ] ) ; arm_condexec_mask = 0 ; } } </s>


<s> void thumb2_final_prescan_insn ( rtx_insn * insn ) { rtx_insn * first_insn = insn ; rtx body = PATTERN ( insn ) ; rtx predicate ; enum arm_cond_code code ; int n ; int mask ; int max ; max = MAX_INSN_PER_IT_BLOCK ; if ( arm_condexec_count ) arm_condexec_count -- ; if ( arm_condexec_count ) return ; if ( GET_CODE ( body ) != COND_EXEC ) return ; if ( JUMP_P ( insn ) ) return ; predicate = COND_EXEC_TEST ( body ) ; arm_current_cc = get_arm_condition_code ( predicate ) ; n = get_attr_ce_count ( insn ) ; arm_condexec_count = 1 ; arm_condexec_mask = ( 1 << n ) - 1 ; arm_condexec_masklen = n ; for ( ; ; ) { insn = next_nonnote_insn ( insn ) ; if ( ! NONJUMP_INSN_P ( insn ) && ! JUMP_P ( insn ) ) break ; body = PATTERN ( insn ) ; if ( GET_CODE ( body ) == USE || GET_CODE ( body ) == CLOBBER ) continue ; if ( GET_CODE ( body ) != COND_EXEC ) break ; n = get_attr_ce_count ( insn ) ; if ( arm_condexec_masklen + n > max ) break ; predicate = COND_EXEC_TEST ( body ) ; code = get_arm_condition_code ( predicate ) ; mask = ( 1 << n ) - 1 ; if ( arm_current_cc == code ) arm_condexec_mask |= ( mask << arm_condexec_masklen ) ; else if ( arm_current_cc != ARM_INVERSE_CONDITION_CODE ( code ) ) break ; arm_condexec_count ++ ; arm_condexec_masklen += n ; if ( JUMP_P ( insn ) ) break ; } extract_constrain_insn_cached ( first_insn ) ; } </s>

Tell arm_asm_output_opcode to output IT blocks for conditionally executed instructions .


<s> static bool thumb2_index_mul_operand ( rtx op ) { HOST_WIDE_INT val ; if ( ! CONST_INT_P ( op ) ) return false ; val = INTVAL ( op ) ; return ( val == 1 || val == 2 || val == 4 || val == 8 ) ; } </s>

Return true if OP is a valid index scaling factor for Thumb-2 address index operand . i.e . 1 , 2 , 4 or 8 .


<s> static int thumb2_legitimate_address_p ( machine_mode mode , rtx x , int strict_p ) { bool use_ldrd ; enum rtx_code code = GET_CODE ( x ) ; if ( TARGET_HAVE_MVE && VALID_MVE_MODE ( mode ) ) return mve_vector_mem_operand ( mode , x , strict_p ) ; if ( arm_address_register_rtx_p ( x , strict_p ) ) return 1 ; use_ldrd = ( TARGET_LDRD && ( mode == DImode || mode == DFmode ) ) ; if ( code == POST_INC || code == PRE_DEC || ( ( code == PRE_INC || code == POST_DEC ) && ( use_ldrd || GET_MODE_SIZE ( mode ) <= 4 ) ) ) return arm_address_register_rtx_p ( XEXP ( x , 0 ) , strict_p ) ; else if ( ( code == POST_MODIFY || code == PRE_MODIFY ) && arm_address_register_rtx_p ( XEXP ( x , 0 ) , strict_p ) && GET_CODE ( XEXP ( x , 1 ) ) == PLUS && rtx_equal_p ( XEXP ( XEXP ( x , 1 ) , 0 ) , XEXP ( x , 0 ) ) ) { rtx addend = XEXP ( XEXP ( x , 1 ) , 1 ) ; HOST_WIDE_INT offset ; if ( ! CONST_INT_P ( addend ) ) return 0 ; offset = INTVAL ( addend ) ; if ( GET_MODE_SIZE ( mode ) <= 4 ) return ( offset > - 256 && offset < 256 ) ; return ( use_ldrd && offset > - 1024 && offset < 1024 && ( offset & 3 ) == 0 ) ; } else if ( reload_completed && ( code == LABEL_REF || ( code == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( x , 0 ) , 1 ) ) ) ) ) return 1 ; else if ( mode == TImode || ( TARGET_NEON && VALID_NEON_STRUCT_MODE ( mode ) ) || ( TARGET_HAVE_MVE && VALID_MVE_STRUCT_MODE ( mode ) ) ) return 0 ; else if ( code == PLUS ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; return ( ( arm_address_register_rtx_p ( xop0 , strict_p ) && ( thumb2_legitimate_index_p ( mode , xop1 , strict_p ) || ( ! strict_p && will_be_in_index_register ( xop1 ) ) ) ) || ( arm_address_register_rtx_p ( xop1 , strict_p ) && thumb2_legitimate_index_p ( mode , xop0 , strict_p ) ) ) ; } else if ( can_avoid_literal_pool_for_label_p ( x ) ) return 0 ; else if ( GET_MODE_CLASS ( mode ) != MODE_FLOAT && code == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( x ) && ! ( flag_pic && symbol_mentioned_p ( get_pool_constant ( x ) ) && ! pcrel_constant_p ( get_pool_constant ( x ) ) ) ) return 1 ; return 0 ; } </s>

Return nonzero if X is a valid Thumb-2 address operand .


<s> static int thumb2_legitimate_index_p ( machine_mode mode , rtx index , int strict_p ) { enum rtx_code code = GET_CODE ( index ) ; if ( TARGET_VFP_BASE && ( mode == SFmode || mode == DFmode ) ) return ( code == CONST_INT && INTVAL ( index ) < 1024 && INTVAL ( index ) > - 256 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE ( mode ) ) { if ( ! TARGET_LDRD || mode != DImode ) return ( code == CONST_INT && INTVAL ( index ) < 1024 && INTVAL ( index ) > - 1024 && ( INTVAL ( index ) & 3 ) == 0 ) ; } if ( TARGET_NEON && VALID_NEON_QREG_MODE ( mode ) ) return ( code == CONST_INT && INTVAL ( index ) < 1016 && INTVAL ( index ) > - 1024 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( TARGET_NEON && VALID_NEON_DREG_MODE ( mode ) ) return ( code == CONST_INT && INTVAL ( index ) < 1024 && INTVAL ( index ) > - 1024 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( arm_address_register_rtx_p ( index , strict_p ) && ( GET_MODE_SIZE ( mode ) <= 4 ) ) return 1 ; if ( mode == DImode || mode == DFmode ) { if ( code == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( index ) ; if ( TARGET_LDRD ) return IN_RANGE ( val , - 1020 , 1020 ) && ( val & 3 ) == 0 ; else return IN_RANGE ( val , - 255 , 4095 - 4 ) ; } else return 0 ; } if ( code == MULT ) { rtx xiop0 = XEXP ( index , 0 ) ; rtx xiop1 = XEXP ( index , 1 ) ; return ( ( arm_address_register_rtx_p ( xiop0 , strict_p ) && thumb2_index_mul_operand ( xiop1 ) ) || ( arm_address_register_rtx_p ( xiop1 , strict_p ) && thumb2_index_mul_operand ( xiop0 ) ) ) ; } else if ( code == ASHIFT ) { rtx op = XEXP ( index , 1 ) ; return ( arm_address_register_rtx_p ( XEXP ( index , 0 ) , strict_p ) && CONST_INT_P ( op ) && INTVAL ( op ) > 0 && INTVAL ( op ) <= 3 ) ; } return ( code == CONST_INT && INTVAL ( index ) < 4096 && INTVAL ( index ) > - 256 ) ; } </s>

Return nonzero if INDEX is a valid Thumb-2 address index operand .


<s>
const
char
*
thumb2_output_casesi
(
rtx
*
operands
)
{
rtx
diff_vec
=
PATTERN
(
NEXT_INSN
(
as_a
<
rtx_insn
*
>
(
operands
[
2
]
)
)
)
;
gcc_assert
(
GET_CODE
(
diff_vec
)
==
ADDR_DIFF_VEC
)
;
output_asm_insn
(
"cmp\t%0, %1"
,
operands
)
;
output_asm_insn
(
"bhi\t%l3"
,
operands
)
;
switch
(
GET_MODE
(
diff_vec
)
)
{
case
E_QImode
:
return
"tbb\t[%|pc, %0]"
;
case
E_HImode
:
return
"tbh\t[%|pc, %0, lsl #1]"
;
case
E_SImode
:
if
(
flag_pic
)
{
output_asm_insn
(
"adr\t%4, %l2"
,
operands
)
;
output_asm_insn
(
"ldr\t%5, [%4, %0, lsl #2]"
,
operands
)
;
output_asm_insn
(
"add\t%4, %4, %5"
,
operands
)
;
return
"bx\t%4"
;
}
else
{
output_asm_insn
(
"adr\t%4, %l2"
,
operands
)
;
return
"ldr\t%|pc, [%4, %0, lsl #2]"
;
}
default
:
gcc_unreachable
(
)
;
}
}
</s>


<s> const char * thumb_call_via_reg ( rtx reg ) { int regno = REGNO ( reg ) ; rtx * labelp ; gcc_assert ( regno < LR_REGNUM ) ; if ( in_section == text_section ) { thumb_call_reg_needed = 1 ; if ( thumb_call_via_label [ regno ] == NULL ) thumb_call_via_label [ regno ] = gen_label_rtx ( ) ; labelp = thumb_call_via_label + regno ; } else { if ( cfun -> machine -> call_via [ regno ] == NULL ) cfun -> machine -> call_via [ regno ] = gen_label_rtx ( ) ; labelp = cfun -> machine -> call_via + regno ; } output_asm_insn ( "bl\t%a0" , labelp ) ; return "" ; } </s>

Output a call-via instruction for thumb state .


Like arm_compute_initial_elimination offset . Simpler because there is n't an ABI specified frame pointer for Thumb . Instead , we set it to point at the base of the local variables after static stack space for a function has been allocated .


<s> void thumb_expand_cpymemqi ( rtx * operands ) { rtx out = copy_to_mode_reg ( SImode , XEXP ( operands [ 0 ] , 0 ) ) ; rtx in = copy_to_mode_reg ( SImode , XEXP ( operands [ 1 ] , 0 ) ) ; HOST_WIDE_INT len = INTVAL ( operands [ 2 ] ) ; HOST_WIDE_INT offset = 0 ; while ( len >= 12 ) { emit_insn ( gen_cpymem12b ( out , in , out , in ) ) ; len -= 12 ; } if ( len >= 8 ) { emit_insn ( gen_cpymem8b ( out , in , out , in ) ) ; len -= 8 ; } if ( len >= 4 ) { rtx reg = gen_reg_rtx ( SImode ) ; emit_insn ( gen_movsi ( reg , gen_rtx_MEM ( SImode , in ) ) ) ; emit_insn ( gen_movsi ( gen_rtx_MEM ( SImode , out ) , reg ) ) ; len -= 4 ; offset += 4 ; } if ( len >= 2 ) { rtx reg = gen_reg_rtx ( HImode ) ; emit_insn ( gen_movhi ( reg , gen_rtx_MEM ( HImode , plus_constant ( Pmode , in , offset ) ) ) ) ; emit_insn ( gen_movhi ( gen_rtx_MEM ( HImode , plus_constant ( Pmode , out , offset ) ) , reg ) ) ; len -= 2 ; offset += 2 ; } if ( len ) { rtx reg = gen_reg_rtx ( QImode ) ; emit_insn ( gen_movqi ( reg , gen_rtx_MEM ( QImode , plus_constant ( Pmode , in , offset ) ) ) ) ; emit_insn ( gen_movqi ( gen_rtx_MEM ( QImode , plus_constant ( Pmode , out , offset ) ) , reg ) ) ; } } </s>