<s> static int thumb_far_jump_used_p ( void ) { rtx_insn * insn ; bool far_jump = false ; unsigned int func_size = 0 ; if ( cfun -> machine -> far_jump_used ) return 1 ; if ( ! ( ARM_DOUBLEWORD_ALIGN || reload_completed ) ) { if ( df_regs_ever_live_p ( ARG_POINTER_REGNUM ) ) cfun -> machine -> arg_pointer_live = 1 ; else if ( ! cfun -> machine -> arg_pointer_live ) return 0 ; } if ( reload_in_progress || reload_completed ) return 0 ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( JUMP_P ( insn ) && get_attr_far_jump ( insn ) == FAR_JUMP_YES ) { far_jump = true ; } func_size += get_attr_length ( insn ) ; } if ( far_jump ) { if ( ( func_size * 3 ) >= 2048 ) { cfun -> machine -> far_jump_used = 1 ; return 1 ; } } return 0 ; } </s>

Returns non-zero if the current function contains , or might contain a far jump .


Find a spare low register to use during the prolog of a function .


<s> static bool thumb_force_lr_save ( void ) { return ! cfun -> machine -> lr_save_eliminated && ( ! crtl -> is_leaf || thumb_far_jump_used_p ( ) || df_regs_ever_live_p ( LR_REGNUM ) ) ; } </s>

Return true if the current function needs to save/restore LR .


<s> int thumb_legitimate_offset_p ( machine_mode mode , HOST_WIDE_INT val ) { switch ( GET_MODE_SIZE ( mode ) ) { case 1 : return val >= 0 && val < 32 ; case 2 : return val >= 0 && val < 64 && ( val & 1 ) == 0 ; default : return ( val >= 0 && ( val + GET_MODE_SIZE ( mode ) ) <= 128 && ( val & 3 ) == 0 ) ; } } </s>

Return nonzero if VAL can be used as an offset in a Thumb-state address instruction of mode MODE .


<s> rtx thumb_legitimize_address ( rtx x , rtx orig_x , machine_mode mode ) { if ( GET_CODE ( x ) == PLUS && CONST_INT_P ( XEXP ( x , 1 ) ) && ( INTVAL ( XEXP ( x , 1 ) ) >= 32 * GET_MODE_SIZE ( mode ) || INTVAL ( XEXP ( x , 1 ) ) < 0 ) ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; HOST_WIDE_INT offset = INTVAL ( xop1 ) ; if ( optimize_size && offset >= 0 && offset < 256 + 31 * GET_MODE_SIZE ( mode ) ) { HOST_WIDE_INT delta ; if ( offset >= 256 ) delta = offset - ( 256 - GET_MODE_SIZE ( mode ) ) ; else if ( offset < 32 * GET_MODE_SIZE ( mode ) + 8 ) delta = 31 * GET_MODE_SIZE ( mode ) ; else delta = offset & ( ~ 31 * GET_MODE_SIZE ( mode ) ) ; xop0 = force_operand ( plus_constant ( Pmode , xop0 , offset - delta ) , NULL_RTX ) ; x = plus_constant ( Pmode , xop0 , delta ) ; } else if ( offset < 0 && offset > - 256 ) x = force_operand ( x , NULL_RTX ) ; else { xop1 = force_reg ( SImode , xop1 ) ; x = gen_rtx_PLUS ( SImode , xop0 , xop1 ) ; } } else if ( GET_CODE ( x ) == PLUS && s_register_operand ( XEXP ( x , 1 ) , SImode ) && ! s_register_operand ( XEXP ( x , 0 ) , SImode ) ) { rtx xop0 = force_operand ( XEXP ( x , 0 ) , NULL_RTX ) ; x = gen_rtx_PLUS ( SImode , xop0 , XEXP ( x , 1 ) ) ; } if ( flag_pic ) { rtx new_x = legitimize_pic_address ( orig_x , mode , NULL_RTX , NULL_RTX , false ) ; if ( new_x != orig_x ) x = new_x ; } return x ; } </s>

Try machine-dependent ways of modifying an illegitimate Thumb address to be legitimate . If we find one , return the new , valid address .


<s>
const
char
*
thumb_load_double_from_address
(
rtx
*
operands
)
{
rtx
addr
;
rtx
base
;
rtx
offset
;
rtx
arg1
;
rtx
arg2
;
gcc_assert
(
REG_P
(
operands
[
0
]
)
)
;
gcc_assert
(
MEM_P
(
operands
[
1
]
)
)
;
addr
=
XEXP
(
operands
[
1
]
,
0
)
;
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
operands
[
2
]
=
adjust_address
(
operands
[
1
]
,
SImode
,
4
)
;
if
(
REGNO
(
operands
[
0
]
)
==
REGNO
(
addr
)
)
{
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
}
else
{
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
}
break
;
case
CONST
:
operands
[
2
]
=
adjust_address
(
operands
[
1
]
,
SImode
,
4
)
;
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
break
;
case
PLUS
:
arg1
=
XEXP
(
addr
,
0
)
;
arg2
=
XEXP
(
addr
,
1
)
;
if
(
CONSTANT_P
(
arg1
)
)
base
=
arg2
,
offset
=
arg1
;
else
base
=
arg1
,
offset
=
arg2
;
gcc_assert
(
REG_P
(
base
)
)
;
if
(
REG_P
(
offset
)
)
{
int
reg_offset
=
REGNO
(
offset
)
;
int
reg_base
=
REGNO
(
base
)
;
int
reg_dest
=
REGNO
(
operands
[
0
]
)
;
asm_fprintf
(
asm_out_file
,
"\tadd\t%r, %r, %r"
,
reg_dest
+
1
,
reg_base
,
reg_offset
)
;
asm_fprintf
(
asm_out_file
,
"\tldr\t%r, [%r, #0]"
,
reg_dest
,
reg_dest
+
1
)
;
asm_fprintf
(
asm_out_file
,
"\tldr\t%r, [%r, #4]"
,
reg_dest
+
1
,
reg_dest
+
1
)
;
}
else
{
operands
[
2
]
=
adjust_address
(
operands
[
1
]
,
SImode
,
4
)
;
if
(
REGNO
(
operands
[
0
]
)
==
REGNO
(
base
)
)
{
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
}
else
{
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
}
}
break
;
case
LABEL_REF
:
operands
[
2
]
=
adjust_address
(
operands
[
1
]
,
SImode
,
4
)
;
output_asm_insn
(
"ldr\t%H0, %2"
,
operands
)
;
output_asm_insn
(
"ldr\t%0, %1"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
return
""
;
}
</s>

Handle the case of a double word load into a low register from a computed memory address . The computed address may involve a register which is overwritten by the load .


<s>
static
void
thumb_pop
(
FILE
*
f
,
unsigned
long
mask
)
{
int
regno
;
int
lo_mask
=
mask
&
0xFF
;
gcc_assert
(
mask
)
;
if
(
lo_mask
==
0
&&
(
mask
&
(
1
<<
PC_REGNUM
)
)
)
{
thumb_exit
(
f
,
1
)
;
return
;
}
fprintf
(
f
,
"\tpop\t{"
)
;
for
(
regno
=
0
;
regno
<=
LAST_LO_REGNUM
;
regno
++
,
lo_mask
>>=
1
)
{
if
(
lo_mask
&
1
)
{
asm_fprintf
(
f
,
"%r"
,
regno
)
;
if
(
(
lo_mask
&
~
1
)
!=
0
)
fprintf
(
f
,
", "
)
;
}
}
if
(
mask
&
(
1
<<
PC_REGNUM
)
)
{
if
(
TARGET_INTERWORK
||
TARGET_BACKTRACE
||
crtl
->
calls_eh_return
||
IS_CMSE_ENTRY
(
arm_current_func_type
(
)
)
)
{
fprintf
(
f
,
"}\n"
)
;
thumb_exit
(
f
,
1
)
;
return
;
}
else
{
if
(
mask
&
0xFF
)
fprintf
(
f
,
", "
)
;
asm_fprintf
(
f
,
"%r"
,
PC_REGNUM
)
;
}
}
fprintf
(
f
,
"}\n"
)
;
}
</s>

Emit code to push or pop registers to or from the stack . F is the assembly file . MASK is the registers to pop .


<s> void thumb_reload_out_hi ( rtx * operands ) { emit_insn ( gen_thumb_movhi_clobber ( operands [ 0 ] , operands [ 1 ] , operands [ 2 ] ) ) ; } </s>

Handle storing a half-word to memory during reload .


<s> static void thumb_set_frame_pointer ( arm_stack_offsets * offsets ) { HOST_WIDE_INT amount ; rtx insn , dwarf ; amount = offsets -> outgoing_args - offsets -> locals_base ; if ( amount < 1024 ) insn = emit_insn ( gen_addsi3 ( hard_frame_pointer_rtx , stack_pointer_rtx , GEN_INT ( amount ) ) ) ; else { emit_insn ( gen_movsi ( hard_frame_pointer_rtx , GEN_INT ( amount ) ) ) ; if ( TARGET_THUMB2 ) { insn = emit_insn ( gen_addsi3 ( hard_frame_pointer_rtx , stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; } else { insn = emit_insn ( gen_addsi3 ( hard_frame_pointer_rtx , hard_frame_pointer_rtx , stack_pointer_rtx ) ) ; } dwarf = gen_rtx_SET ( hard_frame_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , amount ) ) ; RTX_FRAME_RELATED_P ( dwarf ) = 1 ; add_reg_note ( insn , REG_FRAME_RELATED_EXPR , dwarf ) ; } RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Set the Thumb frame pointer from the stack pointer .


<s> int use_return_insn ( int iscond , rtx sibling ) { int regno ; unsigned int func_type ; unsigned long saved_int_regs ; unsigned HOST_WIDE_INT stack_adjust ; arm_stack_offsets * offsets ; if ( ! reload_completed ) return 0 ; func_type = arm_current_func_type ( ) ; if ( func_type & ( ARM_FT_VOLATILE | ARM_FT_NAKED | ARM_FT_STACKALIGN ) ) return 0 ; if ( IS_INTERRUPT ( func_type ) && ( frame_pointer_needed || TARGET_THUMB ) ) return 0 ; if ( TARGET_LDRD && current_tune -> prefer_ldrd_strd && ! optimize_function_for_size_p ( cfun ) ) return 0 ; offsets = arm_get_frame_offsets ( ) ; stack_adjust = offsets -> outgoing_args - offsets -> saved_regs ; if ( crtl -> args . pretend_args_size || cfun -> machine -> uses_anonymous_args || crtl -> calls_eh_return || cfun -> calls_alloca || ! ( stack_adjust == 0 || ( TARGET_APCS_FRAME && frame_pointer_needed && stack_adjust == 4 ) ) || ( ! ( TARGET_APCS_FRAME && frame_pointer_needed ) && arm_compute_static_chain_stack_bytes ( ) != 0 ) ) return 0 ; saved_int_regs = offsets -> saved_regs_mask ; if ( stack_adjust == 4 && ! arm_arch5t && TARGET_ARM ) { if ( ! call_used_or_fixed_reg_p ( 3 ) ) return 0 ; if ( arm_size_return_regs ( ) >= ( 4 * UNITS_PER_WORD ) ) return 0 ; if ( sibling ) { gcc_assert ( CALL_P ( sibling ) ) ; if ( find_regno_fusage ( sibling , USE , 3 ) ) return 0 ; } if ( saved_int_regs & 0x7 ) return 0 ; } if ( TARGET_INTERWORK && saved_int_regs != 0 && ! IS_INTERRUPT ( func_type ) ) return 0 ; if ( iscond && arm_tune_strongarm ) { if ( saved_int_regs != 0 && saved_int_regs != ( 1 << LR_REGNUM ) ) return 0 ; if ( flag_pic && arm_pic_register != INVALID_REGNUM && df_regs_ever_live_p ( PIC_OFFSET_TABLE_REGNUM ) ) return 0 ; } if ( IS_CMSE_ENTRY ( func_type ) && ( saved_int_regs || TARGET_HAVE_FPCXT_CMSE ) ) return 0 ; if ( saved_int_regs && ! ( saved_int_regs & ( 1 << LR_REGNUM ) ) ) return 0 ; if ( TARGET_VFP_BASE ) for ( regno = FIRST_VFP_REGNUM ; regno <= LAST_VFP_REGNUM ; regno ++ ) if ( reg_needs_saving_p ( regno ) ) return 0 ; if ( TARGET_REALLY_IWMMXT ) for ( regno = FIRST_IWMMXT_REGNUM ; regno <= LAST_IWMMXT_REGNUM ; regno ++ ) if ( reg_needs_saving_p ( regno ) ) return 0 ; return 1 ; } </s>

Return true if this function 's epilogue can be output as RTL .


<s> bool use_simple_return_p ( void ) { arm_stack_offsets * offsets ; if ( ! reload_completed ) arm_compute_frame_layout ( ) ; offsets = arm_get_frame_offsets ( ) ; return offsets -> outgoing_args != 0 ; } </s>

Return TRUE if we should try to use a simple_return insn , i.e . perform shrink-wrapping if possible . This is the case if we need to emit a prologue , which we can test by looking at the offsets .


<s>
static
bool
use_vfp_abi
(
enum
arm_pcs
pcs_variant
,
bool
is_double
)
{
if
(
pcs_variant
==
ARM_PCS_AAPCS_VFP
)
{
static
bool
seen_thumb1_vfp
=
false
;
if
(
TARGET_THUMB1
&&
!
seen_thumb1_vfp
)
{
sorry
(
"Thumb-1 %<hard-float%> VFP ABI"
)
;
seen_thumb1_vfp
=
true
;
}
return
true
;
}
if
(
pcs_variant
!=
ARM_PCS_AAPCS_LOCAL
)
return
false
;
return
(
TARGET_32BIT
&&
TARGET_HARD_FLOAT
&&
(
TARGET_VFP_DOUBLE
||
!
is_double
)
)
;
}
</s>

Return true if PCS_VARIANT should use VFP registers .


<s> bool valid_operands_ldrd_strd ( rtx * operands , bool load ) { int nops = 2 ; HOST_WIDE_INT offsets [ 2 ] , offset , align [ 2 ] ; rtx base = NULL_RTX ; rtx cur_base , cur_offset ; int i , gap ; for ( i = 0 ; i < nops ; i ++ ) { if ( ! mem_ok_for_ldrd_strd ( operands [ nops + i ] , & cur_base , & cur_offset , & align [ i ] ) ) return false ; if ( i == 0 ) base = cur_base ; else if ( REGNO ( base ) != REGNO ( cur_base ) ) return false ; offsets [ i ] = INTVAL ( cur_offset ) ; if ( GET_CODE ( operands [ i ] ) == SUBREG ) return false ; } if ( offsets [ 0 ] > offsets [ 1 ] ) return false ; gap = offsets [ 1 ] - offsets [ 0 ] ; offset = offsets [ 0 ] ; if ( gap != GET_MODE_SIZE ( SImode ) ) return false ; if ( ! align_ok_ldrd_strd ( align [ 0 ] , offset ) ) return false ; return operands_ok_ldrd_strd ( operands [ 0 ] , operands [ 1 ] , base , offset , false , load ) ; } </s>

Return true if parallel execution of the two word-size accesses provided could be satisfied with a single LDRD/STRD instruction . Two word-size accesses are represented by the OPERANDS array , where OPERANDS [ 0,1 ] are register operands and OPERANDS [ 2,3 ] are the corresponding memory operands .


<s> int vfp3_const_double_for_bits ( rtx x ) { const REAL_VALUE_TYPE * r ; if ( ! CONST_DOUBLE_P ( x ) ) return - 1 ; r = CONST_DOUBLE_REAL_VALUE ( x ) ; if ( REAL_VALUE_NEGATIVE ( * r ) || REAL_VALUE_ISNAN ( * r ) || REAL_VALUE_ISINF ( * r ) || ! real_isinteger ( r , SFmode ) ) return - 1 ; HOST_WIDE_INT hwint = exact_log2 ( real_to_integer ( r ) ) ; if ( ! IN_RANGE ( hwint , 1 , 32 ) ) return - 1 ; return hwint ; } </s>

If X is a CONST_DOUBLE with a value that is a power of 2 whose log2 is in [ 1 , 32 ] , return that log2 . Otherwise return -1 . This is used in the patterns for vcvt.s32.f32 floating-point to fixed-point conversions .


<s> static int vfp3_const_double_index ( rtx x ) { REAL_VALUE_TYPE r , m ; int sign , exponent ; unsigned HOST_WIDE_INT mantissa , mant_hi ; unsigned HOST_WIDE_INT mask ; int point_pos = 2 * HOST_BITS_PER_WIDE_INT - 1 ; bool fail ; if ( ! TARGET_VFP3 || ! CONST_DOUBLE_P ( x ) ) return - 1 ; r = * CONST_DOUBLE_REAL_VALUE ( x ) ; if ( REAL_VALUE_ISINF ( r ) || REAL_VALUE_ISNAN ( r ) || REAL_VALUE_MINUS_ZERO ( r ) ) return - 1 ; sign = REAL_VALUE_NEGATIVE ( r ) ? 1 : 0 ; r = real_value_abs ( & r ) ; exponent = REAL_EXP ( & r ) ; real_ldexp ( & m , & r , point_pos - exponent ) ; wide_int w = real_to_integer ( & m , & fail , HOST_BITS_PER_WIDE_INT * 2 ) ; mantissa = w . elt ( 0 ) ; mant_hi = w . elt ( 1 ) ; if ( mantissa != 0 ) return - 1 ; point_pos -= HOST_BITS_PER_WIDE_INT ; mantissa = mant_hi ; mask = ( HOST_WIDE_INT_1U << ( point_pos - 5 ) ) - 1 ; if ( ( mantissa & mask ) != 0 ) return - 1 ; mantissa >>= point_pos - 5 ; if ( mantissa == 0 ) return - 1 ; gcc_assert ( mantissa >= 16 && mantissa <= 31 ) ; exponent = 5 - exponent ; if ( exponent < 0 || exponent > 7 ) return - 1 ; return ( sign << 7 ) | ( ( exponent ^ 3 ) << 4 ) | ( mantissa - 16 ) ; } </s>

Return an integer index for a VFPv3 immediate operand X suitable for the fconst [ sd ] instruction , or -1 if X is n't suitable .


<s> int vfp3_const_double_rtx ( rtx x ) { if ( ! TARGET_VFP3 ) return 0 ; return vfp3_const_double_index ( x ) != - 1 ; } </s>

Return TRUE if rtx X is a valid immediate VFPv3 constant .


<s> static int vfp_emit_fstmd ( int base_reg , int count ) { rtx par ; rtx dwarf ; rtx tmp , reg ; int i ; if ( count == 2 && ! arm_arch6 ) { if ( base_reg == LAST_VFP_REGNUM - 3 ) base_reg -= 2 ; count ++ ; } if ( count > 16 ) { int saved ; saved = vfp_emit_fstmd ( base_reg + 32 , count - 16 ) ; saved += vfp_emit_fstmd ( base_reg , 16 ) ; return saved ; } par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count ) ) ; dwarf = gen_rtx_SEQUENCE ( VOIDmode , rtvec_alloc ( count + 1 ) ) ; reg = gen_rtx_REG ( DFmode , base_reg ) ; base_reg += 2 ; 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 , - ( count * 8 ) ) ) ) , gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSH_MULT ) ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - ( count * 8 ) ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 0 ) = tmp ; tmp = gen_rtx_SET ( gen_frame_mem ( DFmode , stack_pointer_rtx ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 1 ) = tmp ; for ( i = 1 ; i < count ; i ++ ) { reg = gen_rtx_REG ( DFmode , base_reg ) ; base_reg += 2 ; XVECEXP ( par , 0 , i ) = gen_rtx_USE ( VOIDmode , reg ) ; tmp = gen_rtx_SET ( gen_frame_mem ( DFmode , plus_constant ( Pmode , stack_pointer_rtx , i * 8 ) ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , i + 1 ) = tmp ; } par = emit_insn ( par ) ; add_reg_note ( par , REG_FRAME_RELATED_EXPR , dwarf ) ; RTX_FRAME_RELATED_P ( par ) = 1 ; return count * 8 ; } </s>

Emit RTL to save block of VFP register pairs to the stack . Returns the number of bytes pushed .


<s>
const
char
*
vfp_output_vstmd
(
rtx
*
operands
)
{
char
pattern
[
100
]
;
int
p
;
int
base
;
int
i
;
rtx
addr_reg
=
REG_P
(
XEXP
(
operands
[
0
]
,
0
)
)
XEXP
(
operands
[
0
]
,
0
)
:
XEXP
(
XEXP
(
operands
[
0
]
,
0
)
,
0
)
;
bool
push_p
=
REGNO
(
addr_reg
)
==
SP_REGNUM
;
if
(
push_p
)
strcpy
(
pattern
,
"vpush%?.64\t{%P1"
)
;
else
strcpy
(
pattern
,
"vstmdb%?.64\t%m0!, {%P1"
)
;
p
=
strlen
(
pattern
)
;
gcc_assert
(
REG_P
(
operands
[
1
]
)
)
;
base
=
(
REGNO
(
operands
[
1
]
)
FIRST_VFP_REGNUM
)
/
2
;
for
(
i
=
1
;
i
<
XVECLEN
(
operands
[
2
]
,
0
)
;
i
++
)
{
p
+=
sprintf
(
&
pattern
[
p
]
,
", d%d"
,
base
+
i
)
;
}
strcpy
(
&
pattern
[
p
]
,
"}"
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>

Output the assembly for a store multiple .


<s> static bool will_be_in_index_register ( const_rtx x ) { return GET_CODE ( x ) == UNSPEC && ( XINT ( x , 1 ) == UNSPEC_PIC_SYM ) ; } </s>

Return true if X will surely end up in an index register after next splitting pass .


<s> static bool xscale_sched_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int * cost ) { if ( dep_type == 0 && recog_memoized ( insn ) >= 0 && recog_memoized ( dep ) >= 0 ) { int shift_opnum = get_attr_shift ( insn ) ; enum attr_type attr_type = get_attr_type ( dep ) ; if ( shift_opnum != 0 && ( attr_type == TYPE_ALU_SHIFT_IMM_LSL_1TO4 || attr_type == TYPE_ALU_SHIFT_IMM_OTHER || attr_type == TYPE_ALUS_SHIFT_IMM || attr_type == TYPE_LOGIC_SHIFT_IMM || attr_type == TYPE_LOGICS_SHIFT_IMM || attr_type == TYPE_ALU_SHIFT_REG || attr_type == TYPE_ALUS_SHIFT_REG || attr_type == TYPE_LOGIC_SHIFT_REG || attr_type == TYPE_LOGICS_SHIFT_REG || attr_type == TYPE_MOV_SHIFT || attr_type == TYPE_MVN_SHIFT || attr_type == TYPE_MOV_SHIFT_REG || attr_type == TYPE_MVN_SHIFT_REG ) ) { rtx shifted_operand ; int opno ; extract_insn ( insn ) ; shifted_operand = recog_data . operand [ shift_opnum ] ; extract_insn ( dep ) ; preprocess_constraints ( dep ) ; for ( opno = 0 ; opno < recog_data . n_operands ; opno ++ ) { if ( recog_data . operand_type [ opno ] == OP_IN ) continue ; if ( reg_overlap_mentioned_p ( recog_data . operand [ opno ] , shifted_operand ) ) { * cost = 2 ; return false ; } } } } return true ; } </s>


<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
val
=
;
char
buf
[
128
]
;
FILE
*
f
=
;
bool
arch
;
const
struct
vendor_cpu
*
cpu_table
=
;
char
*
fcpu_info
=
;
if
(
argc
<
1
)
goto
not_found
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"cpu"
)
!=
0
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
goto
not_found
;
fcpu_info
=
getenv
(
"GCC_CPUINFO"
)
;
if
(
fcpu_info
)
f
=
fopen
(
fcpu_info
,
"r"
)
;
else
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
goto
not_found
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
{
if
(
strncmp
(
buf
,
"CPU implementer"
,
sizeof
(
"CPU implementer"
)
1
)
==
0
)
{
int
i
;
for
(
i
=
0
;
vendors_table
[
i
]
.
vendor_no
!=
;
i
++
)
if
(
strstr
(
buf
,
vendors_table
[
i
]
.
vendor_no
)
!=
)
{
cpu_table
=
vendors_table
[
i
]
.
vendor_parts
;
break
;
}
}
if
(
strncmp
(
buf
,
"CPU part"
,
sizeof
(
"CPU part"
)
1
)
==
0
)
{
int
i
;
if
(
cpu_table
==
)
goto
not_found
;
for
(
i
=
0
;
cpu_table
[
i
]
.
part_no
!=
;
i
++
)
if
(
strstr
(
buf
,
cpu_table
[
i
]
.
part_no
)
!=
)
{
val
=
arch
cpu_table
[
i
]
.
arch_name
:
cpu_table
[
i
]
.
cpu_name
;
break
;
}
break
;
}
}
if
(
val
)
{
fclose
(
f
)
;
return
concat
(
"-m"
,
argv
[
0
]
,
"="
,
val
,
)
;
}
not_found
:
{
unsigned
int
i
;
unsigned
int
opt
;
const
char
*
search
[
]
=
{
,
"arch"
}
;
if
(
f
)
fclose
(
f
)
;
search
[
0
]
=
argv
[
0
]
;
for
(
opt
=
0
;
opt
<
ARRAY_SIZE
(
search
)
;
opt
++
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
configure_default_options
)
;
i
++
)
if
(
strcmp
(
configure_default_options
[
i
]
.
name
,
search
[
opt
]
)
==
0
)
return
concat
(
"-m"
,
search
[
opt
]
,
"="
,
configure_default_options
[
i
]
.
value
,
)
;
return
;
}
}
</s>

This will be called by the spec parser in gcc.cc when it sees a % : local_cpu_detect ( args ) construct . Currently it will be called with either `` cpu '' or `` tune '' as argument depending on if -mcpu=native or -mtune=native is to be substituted . It returns a string containing new command line parameters to be put at the place of the above two options , depending on what CPU this is executed . E.g . `` -mcpu=ultrasparc3 '' on an UltraSPARC III for -mcpu=native . If the routine ca n't detect a known processor , the -mcpu or -mtune option is discarded . ARGC and ARGV are set depending on the actual arguments given in the spec .


<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
val
=
;
char
buf
[
128
]
;
FILE
*
f
=
;
bool
arch
;
const
struct
vendor_cpu
*
cpu_table
=
;
if
(
argc
<
1
)
goto
not_found
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"cpu"
)
!=
0
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
goto
not_found
;
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
goto
not_found
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
{
if
(
strncmp
(
buf
,
"CPU implementer"
,
sizeof
(
"CPU implementer"
)
1
)
==
0
)
{
int
i
;
for
(
i
=
0
;
vendors
[
i
]
.
vendor_no
!=
;
i
++
)
if
(
strstr
(
buf
,
vendors
[
i
]
.
vendor_no
)
!=
)
{
cpu_table
=
vendors
[
i
]
.
vendor_parts
;
break
;
}
}
if
(
strncmp
(
buf
,
"CPU part"
,
sizeof
(
"CPU part"
)
1
)
==
0
)
{
int
i
;
if
(
cpu_table
==
)
goto
not_found
;
for
(
i
=
0
;
cpu_table
[
i
]
.
part_no
!=
;
i
++
)
if
(
strstr
(
buf
,
cpu_table
[
i
]
.
part_no
)
!=
)
{
val
=
arch
cpu_table
[
i
]
.
arch_name
:
cpu_table
[
i
]
.
cpu_name
;
break
;
}
break
;
}
}
fclose
(
f
)
;
if
(
val
==
)
goto
not_found
;
return
concat
(
"-m"
,
argv
[
0
]
,
"="
,
val
,
)
;
not_found
:
{
unsigned
int
i
;
unsigned
int
opt
;
const
char
*
search
[
]
=
{
,
"arch"
}
;
if
(
f
)
fclose
(
f
)
;
search
[
0
]
=
argv
[
0
]
;
for
(
opt
=
0
;
opt
<
ARRAY_SIZE
(
search
)
;
opt
++
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
configure_default_options
)
;
i
++
)
if
(
strcmp
(
configure_default_options
[
i
]
.
name
,
search
[
opt
]
)
==
0
)
return
concat
(
"-m"
,
search
[
opt
]
,
"="
,
configure_default_options
[
i
]
.
value
,
)
;
return
;
}
}
</s>


<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
val
=
;
char
buf
[
128
]
;
FILE
*
f
=
;
bool
arch
;
const
struct
vendor_cpu
*
cpu_table
=
;
if
(
argc
<
1
)
goto
not_found
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"cpu"
)
!=
0
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
goto
not_found
;
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
goto
not_found
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
{
if
(
strncmp
(
buf
,
"CPU implementer"
,
sizeof
(
"CPU implementer"
)
1
)
==
0
)
{
int
i
;
for
(
i
=
0
;
vendors
[
i
]
.
vendor_no
!=
;
i
++
)
if
(
strstr
(
buf
,
vendors
[
i
]
.
vendor_no
)
!=
)
{
cpu_table
=
vendors
[
i
]
.
vendor_parts
;
break
;
}
}
if
(
strncmp
(
buf
,
"CPU part"
,
sizeof
(
"CPU part"
)
1
)
==
0
)
{
int
i
;
if
(
cpu_table
==
)
goto
not_found
;
for
(
i
=
0
;
cpu_table
[
i
]
.
part_no
!=
;
i
++
)
if
(
strstr
(
buf
,
cpu_table
[
i
]
.
part_no
)
!=
)
{
val
=
arch
cpu_table
[
i
]
.
arch_name
:
cpu_table
[
i
]
.
cpu_name
;
break
;
}
break
;
}
}
if
(
val
)
{
fclose
(
f
)
;
return
concat
(
"-m"
,
argv
[
0
]
,
"="
,
val
,
)
;
}
not_found
:
{
unsigned
int
i
;
unsigned
int
opt
;
const
char
*
search
[
]
=
{
,
"arch"
}
;
if
(
f
)
fclose
(
f
)
;
search
[
0
]
=
argv
[
0
]
;
for
(
opt
=
0
;
opt
<
ARRAY_SIZE
(
search
)
;
opt
++
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
configure_default_options
)
;
i
++
)
if
(
strcmp
(
configure_default_options
[
i
]
.
name
,
search
[
opt
]
)
==
0
)
return
concat
(
"-m"
,
search
[
opt
]
,
"="
,
configure_default_options
[
i
]
.
value
,
)
;
return
;
}
}
</s>


<s>
const
char
*
host_detect_local_cpu
(
int
argc
,
const
char
*
*
argv
)
{
const
char
*
val
=
;
char
buf
[
128
]
;
FILE
*
f
=
;
bool
arch
;
const
struct
vendor_cpu
*
cpu_table
=
;
char
*
fcpu_info
=
;
if
(
argc
<
1
)
goto
not_found
;
arch
=
strcmp
(
argv
[
0
]
,
"arch"
)
==
0
;
if
(
!
arch
&&
strcmp
(
argv
[
0
]
,
"cpu"
)
!=
0
&&
strcmp
(
argv
[
0
]
,
"tune"
)
)
goto
not_found
;
fcpu_info
=
getenv
(
"GCC_CPUINFO"
)
;
if
(
fcpu_info
)
f
=
fopen
(
fcpu_info
,
"r"
)
;
else
f
=
fopen
(
"/proc/cpuinfo"
,
"r"
)
;
if
(
f
==
)
goto
not_found
;
while
(
fgets
(
buf
,
sizeof
(
buf
)
,
f
)
!=
)
{
if
(
startswith
(
buf
,
"CPU implementer"
)
)
{
int
i
;
for
(
i
=
0
;
vendors_table
[
i
]
.
vendor_no
!=
;
i
++
)
if
(
strstr
(
buf
,
vendors_table
[
i
]
.
vendor_no
)
!=
)
{
cpu_table
=
vendors_table
[
i
]
.
vendor_parts
;
break
;
}
}
if
(
startswith
(
buf
,
"CPU part"
)
)
{
int
i
;
if
(
cpu_table
==
)
goto
not_found
;
for
(
i
=
0
;
cpu_table
[
i
]
.
part_no
!=
;
i
++
)
if
(
strstr
(
buf
,
cpu_table
[
i
]
.
part_no
)
!=
)
{
val
=
arch
cpu_table
[
i
]
.
arch_name
:
cpu_table
[
i
]
.
cpu_name
;
break
;
}
break
;
}
}
if
(
val
)
{
fclose
(
f
)
;
return
concat
(
"-m"
,
argv
[
0
]
,
"="
,
val
,
)
;
}
not_found
:
{
unsigned
int
i
;
unsigned
int
opt
;
const
char
*
search
[
]
=
{
,
"arch"
}
;
if
(
f
)
fclose
(
f
)
;
search
[
0
]
=
argv
[
0
]
;
for
(
opt
=
0
;
opt
<
ARRAY_SIZE
(
search
)
;
opt
++
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
configure_default_options
)
;
i
++
)
if
(
strcmp
(
configure_default_options
[
i
]
.
name
,
search
[
opt
]
)
==
0
)
return
concat
(
"-m"
,
search
[
opt
]
,
"="
,
configure_default_options
[
i
]
.
value
,
)
;
return
;
}
}
</s>


<s> static inline _uw8 next_unwind_byte ( __gnu_unwind_state * uws ) { _uw8 b ; if ( uws -> bytes_left == 0 ) { if ( uws -> words_left == 0 ) return CODE_FINISH ; uws -> words_left -- ; uws -> data = * ( uws -> next ++ ) ; uws -> bytes_left = 3 ; } else uws -> bytes_left -- ; b = ( uws -> data >> 24 ) & 0xff ; uws -> data <<= 8 ; return b ; } </s>

Return the next byte of unwinding information , or CODE_FINISH if there is no data remaining .


<s> static inline _uw selfrel_offset31 ( const _uw * p ) { _uw offset ; offset = * p ; if ( offset & ( 1 << 30 ) ) offset |= 1u << 31 ; return offset + ( _uw ) p ; } </s>

Calculate the address encoded by a 31-bit self-relative offset at address P .


<s> static inline _Unwind_Control_Block * unwind_UCB_from_context ( _Unwind_Context * context ) { return ( _Unwind_Control_Block * ) _Unwind_GetGR ( context , R_IP ) ; } </s>

Get the _Unwind_Control_Block from an _Unwind_Context .


<s> static _Unwind_Reason_Code get_eit_entry ( _Unwind_Control_Block * ucbp , _uw return_address ) { const __EIT_entry * eitp ; int nrec ; return_address -= 2 ; if ( __gnu_Unwind_Find_exidx ) { eitp = ( const __EIT_entry * ) __gnu_Unwind_Find_exidx ( return_address , & nrec ) ; if ( ! eitp ) { UCB_PR_ADDR ( ucbp ) = 0 ; return _URC_FAILURE ; } } else { eitp = & __exidx_start ; nrec = & __exidx_end - & __exidx_start ; } eitp = search_EIT_table ( eitp , nrec , return_address ) ; if ( ! eitp ) { UCB_PR_ADDR ( ucbp ) = 0 ; return _URC_FAILURE ; } ucbp -> pr_cache . fnstart = selfrel_offset31 ( & eitp -> fnoffset ) ; if ( eitp -> content == EXIDX_CANTUNWIND ) { UCB_PR_ADDR ( ucbp ) = 0 ; return _URC_END_OF_STACK ; } if ( eitp -> content & uint32_highbit ) { ucbp -> pr_cache . ehtp = ( _Unwind_EHT_Header * ) & eitp -> content ; ucbp -> pr_cache . additional = 1 ; } else { ucbp -> pr_cache . ehtp = ( _Unwind_EHT_Header * ) selfrel_offset31 ( & eitp -> content ) ; ucbp -> pr_cache . additional = 0 ; } if ( * ucbp -> pr_cache . ehtp & ( 1u << 31 ) ) { _uw idx = ( * ( _uw * ) ucbp -> pr_cache . ehtp >> 24 ) & 0xf ; if ( idx == 0 ) UCB_PR_ADDR ( ucbp ) = ( _uw ) & __aeabi_unwind_cpp_pr0 ; else if ( idx == 1 ) UCB_PR_ADDR ( ucbp ) = ( _uw ) & __aeabi_unwind_cpp_pr1 ; else if ( idx == 2 ) UCB_PR_ADDR ( ucbp ) = ( _uw ) & __aeabi_unwind_cpp_pr2 ; else { UCB_PR_ADDR ( ucbp ) = 0 ; return _URC_FAILURE ; } } else { UCB_PR_ADDR ( ucbp ) = selfrel_offset31 ( ucbp -> pr_cache . ehtp ) ; } return _URC_OK ; } </s>

Find the exception index table eintry for the given address . Fill in the relevant fields of the UCB . Returns _URC_FAILURE if an error occurred , _URC_OK on success .


<s> static void restore_non_core_regs ( phase1_vrs * vrs ) { if ( ( vrs -> demand_save_flags & DEMAND_SAVE_VFP ) == 0 ) __gnu_Unwind_Restore_VFP ( & vrs -> vfp ) ; } </s>

Restore coprocessor state after phase1 unwinding .


<s> static const __EIT_entry * search_EIT_table ( const __EIT_entry * table , int nrec , _uw return_address ) { _uw next_fn ; _uw this_fn ; int n , left , right ; if ( nrec == 0 ) return ( __EIT_entry * ) 0 ; left = 0 ; right = nrec - 1 ; while ( 1 ) { n = ( left + right ) / 2 ; this_fn = selfrel_offset31 ( & table [ n ] . fnoffset ) ; if ( n != nrec - 1 ) next_fn = selfrel_offset31 ( & table [ n + 1 ] . fnoffset ) - 1 ; else next_fn = ( _uw ) 0 - 1 ; if ( return_address < this_fn ) { if ( n == left ) return ( __EIT_entry * ) 0 ; right = n - 1 ; } else if ( return_address <= next_fn ) return & table [ n ] ; else left = n + 1 ; } } </s>

Perform a binary search for RETURN_ADDRESS in TABLE . The table contains NREC entries .


<s> static _Unwind_Reason_Code unwind_phase2_forced ( _Unwind_Control_Block * ucbp , phase2_vrs * entry_vrs , int resuming ) { _Unwind_Stop_Fn stop_fn = ( _Unwind_Stop_Fn ) UCB_FORCED_STOP_FN ( ucbp ) ; void * stop_arg = ( void * ) UCB_FORCED_STOP_ARG ( ucbp ) ; _Unwind_Reason_Code pr_result = 0 ; phase1_vrs saved_vrs , next_vrs ; saved_vrs . core = entry_vrs -> core ; saved_vrs . demand_save_flags = 0 ; do { _Unwind_State action ; _Unwind_Reason_Code entry_code ; _Unwind_Reason_Code stop_code ; entry_code = get_eit_entry ( ucbp , saved_vrs . core . r [ R_PC ] ) ; if ( resuming ) { action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND ; resuming = 0 ; } else action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND ; if ( entry_code == _URC_OK ) { UCB_SAVED_CALLSITE_ADDR ( ucbp ) = saved_vrs . core . r [ R_PC ] ; next_vrs = saved_vrs ; pr_result = ( ( personality_routine ) UCB_PR_ADDR ( ucbp ) ) ( action , ucbp , ( void * ) & next_vrs ) ; saved_vrs . prev_sp = next_vrs . core . r [ R_SP ] ; } else { action |= _US_END_OF_STACK ; saved_vrs . prev_sp = saved_vrs . core . r [ R_SP ] ; } stop_code = stop_fn ( 1 , action , ucbp -> exception_class , ucbp , ( void * ) & saved_vrs , stop_arg ) ; if ( stop_code != _URC_NO_REASON ) return _URC_FAILURE ; if ( entry_code != _URC_OK ) return entry_code ; saved_vrs = next_vrs ; } while ( pr_result == _URC_CONTINUE_UNWIND ) ; if ( pr_result != _URC_INSTALL_CONTEXT ) { return _URC_FAILURE ; } restore_core_regs ( & saved_vrs . core ) ; } </s>