<s> static void aarch64_pushwb_single_reg ( machine_mode mode , unsigned regno , HOST_WIDE_INT adjustment ) { rtx base_rtx = stack_pointer_rtx ; rtx insn , reg , mem ; reg = gen_rtx_REG ( mode , regno ) ; mem = gen_rtx_PRE_MODIFY ( Pmode , base_rtx , plus_constant ( Pmode , base_rtx , - adjustment ) ) ; mem = gen_rtx_MEM ( mode , mem ) ; insn = emit_move_insn ( mem , reg ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Push the register number REGNO of mode MODE to the stack with write-back adjusting the stack by ADJUSTMENT .


<s> static int aarch64_reassociation_width ( unsigned opc ATTRIBUTE_UNUSED , enum machine_mode mode ) { if ( VECTOR_MODE_P ( mode ) ) return aarch64_tune_params -> vec_reassoc_width ; if ( INTEGRAL_MODE_P ( mode ) ) return aarch64_tune_params -> int_reassoc_width ; if ( FLOAT_MODE_P ( mode ) ) return aarch64_tune_params -> fp_reassoc_width ; return 1 ; } </s>

Return the reassociation width of treeop OPC with mode MODE .


<s> static bool aarch64_register_saved_on_entry ( int regno ) { return cfun -> machine -> frame . reg_offset [ regno ] >= 0 ; } </s>

Return true if the register REGNO is saved on entry to the current function .


<s> enum reg_class aarch64_regno_regclass ( unsigned regno ) { if ( GP_REGNUM_P ( regno ) ) return GENERAL_REGS ; if ( regno == SP_REGNUM ) return STACK_REG ; if ( regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM ) return POINTER_REGS ; if ( FP_REGNUM_P ( regno ) ) return FP_LO_REGNUM_P ( regno ) ? FP_LO_REGS : FP_REGS ; return NO_REGS ; } </s>


<s> static void aarch64_restore_callee_saves ( machine_mode mode , HOST_WIDE_INT start_offset , unsigned start , unsigned limit , bool skip_wb , rtx * cfi_ops ) { rtx base_rtx = stack_pointer_rtx ; rtx ( * gen_mem_ref ) ( machine_mode , rtx ) = ( frame_pointer_needed ? gen_frame_mem : gen_rtx_MEM ) ; unsigned regno ; unsigned regno2 ; HOST_WIDE_INT offset ; for ( regno = aarch64_next_callee_save ( start , limit ) ; regno <= limit ; regno = aarch64_next_callee_save ( regno + 1 , limit ) ) { rtx reg , mem ; if ( skip_wb && ( regno == cfun -> machine -> frame . wb_candidate1 || regno == cfun -> machine -> frame . wb_candidate2 ) ) continue ; reg = gen_rtx_REG ( mode , regno ) ; offset = start_offset + cfun -> machine -> frame . reg_offset [ regno ] ; mem = gen_mem_ref ( mode , plus_constant ( Pmode , base_rtx , offset ) ) ; regno2 = aarch64_next_callee_save ( regno + 1 , limit ) ; if ( regno2 <= limit && ( ( cfun -> machine -> frame . reg_offset [ regno ] + UNITS_PER_WORD ) == cfun -> machine -> frame . reg_offset [ regno2 ] ) ) { rtx reg2 = gen_rtx_REG ( mode , regno2 ) ; rtx mem2 ; offset = start_offset + cfun -> machine -> frame . reg_offset [ regno2 ] ; mem2 = gen_mem_ref ( mode , plus_constant ( Pmode , base_rtx , offset ) ) ; emit_insn ( aarch64_gen_load_pair ( mode , reg , mem , reg2 , mem2 ) ) ; * cfi_ops = alloc_reg_note ( REG_CFA_RESTORE , reg2 , * cfi_ops ) ; regno = regno2 ; } else emit_move_insn ( reg , mem ) ; * cfi_ops = alloc_reg_note ( REG_CFA_RESTORE , reg , * cfi_ops ) ; } } </s>

Emit code to restore the callee registers of mode MODE from register number START up to and including LIMIT . Restore from the stack offset START_OFFSET , skipping any write-back candidates if SKIP_WB is true . Write the appropriate REG_CFA_RESTORE notes into CFI_OPS .


<s> static bool aarch64_return_in_memory ( const_tree type , const_tree fndecl ATTRIBUTE_UNUSED ) { HOST_WIDE_INT size ; machine_mode ag_mode ; int count ; if ( ! AGGREGATE_TYPE_P ( type ) && TREE_CODE ( type ) != COMPLEX_TYPE && TREE_CODE ( type ) != VECTOR_TYPE ) return false ; if ( aarch64_vfp_is_call_or_return_candidate ( TYPE_MODE ( type ) , type , & ag_mode , & count , NULL ) ) return false ; size = int_size_in_bytes ( type ) ; return ( size < 0 || size > 2 * UNITS_PER_WORD ) ; } </s>

Implement TARGET_RETURN_IN_MEMORY . If the type T of the result of a function is such that void func ( T arg ) would require that arg be passed as a value in a register ( or set of registers ) according to the parameter passing rules , then the result is returned in the same registers as would be used for such an argument .


<s> static bool aarch64_return_in_msb ( const_tree valtype ) { machine_mode dummy_mode ; int dummy_int ; if ( ! BYTES_BIG_ENDIAN ) return false ; if ( ! aarch64_composite_type_p ( valtype , TYPE_MODE ( valtype ) ) || int_size_in_bytes ( valtype ) <= 0 || int_size_in_bytes ( valtype ) > 16 ) return false ; if ( aarch64_vfp_is_call_or_return_candidate ( TYPE_MODE ( valtype ) , valtype , & dummy_mode , & dummy_int , NULL ) ) return false ; return true ; } </s>

Return TRUE if VALTYPE is padded to its least significant bits .


<s> rtx aarch64_reverse_mask ( enum machine_mode mode ) { rtx mask ; rtvec v = rtvec_alloc ( 16 ) ; int i , j ; int nunits = GET_MODE_NUNITS ( mode ) ; int usize = GET_MODE_UNIT_SIZE ( mode ) ; gcc_assert ( BYTES_BIG_ENDIAN ) ; gcc_assert ( AARCH64_VALID_SIMD_QREG_MODE ( mode ) ) ; for ( i = 0 ; i < nunits ; i ++ ) for ( j = 0 ; j < usize ; j ++ ) RTVEC_ELT ( v , i * usize + j ) = GEN_INT ( ( i + 1 ) * usize - 1 - j ) ; mask = gen_rtx_CONST_VECTOR ( V16QImode , v ) ; return force_reg ( V16QImode , mask ) ; } </s>

Generate a byte permute mask for a register of mode MODE , which has NUNITS units .


<s> static bool aarch64_rtx_arith_op_extract_p ( rtx x , machine_mode mode ) { if ( GET_CODE ( x ) == SIGN_EXTRACT || GET_CODE ( x ) == ZERO_EXTRACT ) { rtx op0 = XEXP ( x , 0 ) ; rtx op1 = XEXP ( x , 1 ) ; rtx op2 = XEXP ( x , 2 ) ; if ( GET_CODE ( op0 ) == MULT && CONST_INT_P ( op1 ) && op2 == const0_rtx && CONST_INT_P ( XEXP ( op0 , 1 ) ) && aarch64_is_extend_from_extract ( mode , XEXP ( op0 , 1 ) , op1 ) ) { return true ; } } return false ; } </s>

Return true if X is a zero or sign extract usable in an ADD or SUB ( extended register ) instruction .


<s>
static
bool
aarch64_rtx_costs_wrapper
(
rtx
x
,
int
code
,
int
outer
,
int
param
,
int
*
cost
,
bool
speed
)
{
bool
result
=
aarch64_rtx_costs
(
x
,
code
,
outer
,
param
,
cost
,
speed
)
;
if
(
dump_file
&&
(
dump_flags
&
TDF_DETAILS
)
)
{
print_rtl_single
(
dump_file
,
x
)
;
fprintf
(
dump_file
,
"\n%s cost: %d (%s)\n"
,
speed
"Hot"
:
"Cold"
,
*
cost
,
result
"final"
:
"partial"
)
;
}
return
result
;
}
</s>

Wrapper around aarch64_rtx_costs , dumps the partial , or total cost calculated for X . This cost is stored in * COST . Returns true if the total cost of X was calculated .

aarch64
"\n%s cost: %d (%s)\n"
"Hot"
"Cold"
"final"
"partial"


<s> static int aarch64_rtx_mult_cost ( rtx x , int code , int outer , bool speed ) { rtx op0 , op1 ; const struct cpu_cost_table * extra_cost = aarch64_tune_params -> insn_extra_cost ; int cost = 0 ; bool maybe_fma = ( outer == PLUS || outer == MINUS ) ; machine_mode mode = GET_MODE ( x ) ; gcc_checking_assert ( code == MULT ) ; op0 = XEXP ( x , 0 ) ; op1 = XEXP ( x , 1 ) ; if ( VECTOR_MODE_P ( mode ) ) mode = GET_MODE_INNER ( mode ) ; if ( GET_MODE_CLASS ( mode ) == MODE_INT ) { if ( CONST_INT_P ( op1 ) && exact_log2 ( INTVAL ( op1 ) ) > 0 ) { if ( speed ) { if ( maybe_fma ) cost += extra_cost -> alu . arith_shift ; else cost += extra_cost -> alu . shift ; } cost += rtx_cost ( op0 , GET_CODE ( op0 ) , 0 , speed ) ; return cost ; } if ( ( GET_CODE ( op0 ) == ZERO_EXTEND && GET_CODE ( op1 ) == ZERO_EXTEND ) || ( GET_CODE ( op0 ) == SIGN_EXTEND && GET_CODE ( op1 ) == SIGN_EXTEND ) ) { cost += rtx_cost ( XEXP ( op0 , 0 ) , MULT , 0 , speed ) + rtx_cost ( XEXP ( op1 , 0 ) , MULT , 1 , speed ) ; if ( speed ) { if ( maybe_fma ) cost += extra_cost -> mult [ 0 ] . extend_add ; else cost += extra_cost -> mult [ 0 ] . extend ; } return cost ; } cost += rtx_cost ( op0 , MULT , 0 , speed ) + rtx_cost ( op1 , MULT , 1 , speed ) ; if ( speed ) { if ( maybe_fma ) cost += extra_cost -> mult [ mode == DImode ] . add ; else cost += extra_cost -> mult [ mode == DImode ] . simple ; } return cost ; } else { if ( speed ) { if ( GET_CODE ( op0 ) == NEG ) op0 = XEXP ( op0 , 0 ) ; if ( GET_CODE ( op1 ) == NEG ) op1 = XEXP ( op1 , 0 ) ; if ( maybe_fma ) cost += extra_cost -> fp [ mode == DFmode ] . fma ; else cost += extra_cost -> fp [ mode == DFmode ] . mult ; } cost += rtx_cost ( op0 , MULT , 0 , speed ) + rtx_cost ( op1 , MULT , 1 , speed ) ; return cost ; } } </s>

Helper function for rtx cost calculation . Calculate the cost of a MULT , which may be part of a multiply-accumulate rtx . Return the calculated cost of the expression , recursing manually in to operands where needed .


<s> static void aarch64_save_callee_saves ( machine_mode mode , HOST_WIDE_INT start_offset , unsigned start , unsigned limit , bool skip_wb ) { rtx_insn * insn ; rtx ( * gen_mem_ref ) ( machine_mode , rtx ) = ( frame_pointer_needed ? gen_frame_mem : gen_rtx_MEM ) ; unsigned regno ; unsigned regno2 ; for ( regno = aarch64_next_callee_save ( start , limit ) ; regno <= limit ; regno = aarch64_next_callee_save ( regno + 1 , limit ) ) { rtx reg , mem ; HOST_WIDE_INT offset ; if ( skip_wb && ( regno == cfun -> machine -> frame . wb_candidate1 || regno == cfun -> machine -> frame . wb_candidate2 ) ) continue ; reg = gen_rtx_REG ( mode , regno ) ; offset = start_offset + cfun -> machine -> frame . reg_offset [ regno ] ; mem = gen_mem_ref ( mode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; regno2 = aarch64_next_callee_save ( regno + 1 , limit ) ; if ( regno2 <= limit && ( ( cfun -> machine -> frame . reg_offset [ regno ] + UNITS_PER_WORD ) == cfun -> machine -> frame . reg_offset [ regno2 ] ) ) { rtx reg2 = gen_rtx_REG ( mode , regno2 ) ; rtx mem2 ; offset = start_offset + cfun -> machine -> frame . reg_offset [ regno2 ] ; mem2 = gen_mem_ref ( mode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; insn = emit_insn ( aarch64_gen_store_pair ( mode , mem , reg , mem2 , reg2 ) ) ; RTX_FRAME_RELATED_P ( XVECEXP ( PATTERN ( insn ) , 0 , 1 ) ) = 1 ; regno = regno2 ; } else insn = emit_move_insn ( mem , reg ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } } </s>

Emit code to save the callee-saved registers from register number START to LIMIT to the stack at the location starting at offset START_OFFSET , skipping any write-back candidates if SKIP_WB is true .


<s> static int aarch64_sched_issue_rate ( void ) { return aarch64_tune_params -> issue_rate ; } </s>

Return the number of instructions that can be issued per cycle .


<s> static section * aarch64_select_rtx_section ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ATTRIBUTE_UNUSED , unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED ) { return function_section ( current_function_decl ) ; } </s>

Select appropriate section for constants depending on where we place literal pools .


"%qs and floating point or vector arguments"


<s> static bool aarch64_short_vector_p ( const_tree type , machine_mode mode ) { HOST_WIDE_INT size = - 1 ; if ( type && TREE_CODE ( type ) == VECTOR_TYPE ) size = int_size_in_bytes ( type ) ; else if ( ! aarch64_composite_type_p ( type , mode ) && ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) ) size = GET_MODE_SIZE ( mode ) ; return ( size == 8 || size == 16 ) ? true : false ; } </s>

Return TRUE if the type , as described by TYPE and MODE , is a short vector type as described in AAPCS64 \S 4.1.2 . See the comment above aarch64_composite_type_p for the notes on MODE .


<s> int aarch64_simd_attr_length_move ( rtx_insn * insn ) { machine_mode mode ; extract_insn_cached ( insn ) ; if ( REG_P ( recog_data . operand [ 0 ] ) && REG_P ( recog_data . operand [ 1 ] ) ) { mode = GET_MODE ( recog_data . operand [ 0 ] ) ; switch ( mode ) { case OImode : return 8 ; case CImode : return 12 ; case XImode : return 16 ; default : gcc_unreachable ( ) ; } } return 4 ; } </s>

Compute and return the length of aarch64_simd_mov < mode > , where < mode > is one of VSTRUCT modes : OI , CI or XI .


<s> int aarch64_simd_attr_length_rglist ( enum machine_mode mode ) { return ( GET_MODE_SIZE ( mode ) / UNITS_PER_VREG ) * 4 ; } </s>

Compute and return the length of aarch64_simd_reglist < mode > , where < mode > is one of VSTRUCT modes : OI , CI , EI , or XI .


<s> bool aarch64_simd_check_vect_par_cnst_half ( rtx op , machine_mode mode , bool high ) { rtx ideal = aarch64_simd_vect_par_cnst_half ( mode , high ) ; HOST_WIDE_INT count_op = XVECLEN ( op , 0 ) ; HOST_WIDE_INT count_ideal = XVECLEN ( ideal , 0 ) ; int i = 0 ; if ( ! VECTOR_MODE_P ( mode ) ) return false ; if ( count_op != count_ideal ) return false ; for ( i = 0 ; i < count_ideal ; i ++ ) { rtx elt_op = XVECEXP ( op , 0 , i ) ; rtx elt_ideal = XVECEXP ( ideal , 0 , i ) ; if ( ! CONST_INT_P ( elt_op ) || INTVAL ( elt_ideal ) != INTVAL ( elt_op ) ) return false ; } return true ; } </s>

Check OP for validity as a PARALLEL RTX vector with elements numbering the lanes of either the high ( HIGH == TRUE ) or low lanes , from the perspective of the architecture . See the diagram above aarch64_simd_vect_par_cnst_half for more details .


<s> static machine_mode aarch64_simd_container_mode ( machine_mode mode , unsigned width ) { gcc_assert ( width == 64 || width == 128 ) ; if ( TARGET_SIMD ) { if ( width == 128 ) switch ( mode ) { case DFmode : return V2DFmode ; case SFmode : return V4SFmode ; case SImode : return V4SImode ; case HImode : return V8HImode ; case QImode : return V16QImode ; case DImode : return V2DImode ; default : break ; } else switch ( mode ) { case SFmode : return V2SFmode ; case SImode : return V2SImode ; case HImode : return V4HImode ; case QImode : return V8QImode ; default : break ; } } return word_mode ; } </s>

Return appropriate SIMD container for MODE within a vector of WIDTH bits .


<s> static rtx aarch64_simd_dup_constant ( rtx vals ) { machine_mode mode = GET_MODE ( vals ) ; machine_mode inner_mode = GET_MODE_INNER ( mode ) ; int n_elts = GET_MODE_NUNITS ( mode ) ; bool all_same = true ; rtx x ; int i ; if ( GET_CODE ( vals ) != CONST_VECTOR ) return NULL_RTX ; for ( i = 1 ; i < n_elts ; ++ i ) { x = CONST_VECTOR_ELT ( vals , i ) ; if ( ! rtx_equal_p ( x , CONST_VECTOR_ELT ( vals , 0 ) ) ) all_same = false ; } if ( ! all_same ) return NULL_RTX ; x = copy_to_mode_reg ( inner_mode , CONST_VECTOR_ELT ( vals , 0 ) ) ; return gen_rtx_VEC_DUPLICATE ( mode , x ) ; } </s>

If VALS is a vector constant that can be loaded into a register using DUP , generate instructions to do so and return an RTX to assign to the register . Otherwise return NULL_RTX .


<s> void aarch64_simd_emit_pair_result_insn ( machine_mode mode , rtx ( * intfn ) ( rtx , rtx , rtx ) , rtx destaddr , rtx op1 ) { rtx mem = gen_rtx_MEM ( mode , destaddr ) ; rtx tmp1 = gen_reg_rtx ( mode ) ; rtx tmp2 = gen_reg_rtx ( mode ) ; emit_insn ( intfn ( tmp1 , op1 , tmp2 ) ) ; emit_move_insn ( mem , tmp1 ) ; mem = adjust_address ( mem , mode , GET_MODE_SIZE ( mode ) ) ; emit_move_insn ( mem , tmp2 ) ; } </s>

Emit code to place a AdvSIMD pair result in memory locations ( with equal registers ) .


<s> void aarch64_simd_emit_reg_reg_move ( rtx * operands , enum machine_mode mode , unsigned int count ) { unsigned int i ; int rdest = REGNO ( operands [ 0 ] ) ; int rsrc = REGNO ( operands [ 1 ] ) ; if ( ! reg_overlap_mentioned_p ( operands [ 0 ] , operands [ 1 ] ) || rdest < rsrc ) for ( i = 0 ; i < count ; i ++ ) emit_move_insn ( gen_rtx_REG ( mode , rdest + i ) , gen_rtx_REG ( mode , rsrc + i ) ) ; else for ( i = 0 ; i < count ; i ++ ) emit_move_insn ( gen_rtx_REG ( mode , rdest + count - i - 1 ) , gen_rtx_REG ( mode , rsrc + count - i - 1 ) ) ; } </s>

Emit a register copy from operand to operand , taking care not to early-clobber source registers in the process . COUNT is the number of components into which the copy needs to be decomposed .


<s> rtx aarch64_simd_gen_const_vector_dup ( machine_mode mode , int val ) { int nunits = GET_MODE_NUNITS ( mode ) ; rtvec v = rtvec_alloc ( nunits ) ; int i ; for ( i = 0 ; i < nunits ; i ++ ) RTVEC_ELT ( v , i ) = GEN_INT ( val ) ; return gen_rtx_CONST_VECTOR ( mode , v ) ; } </s>


<s> bool aarch64_simd_imm_zero_p ( rtx x , machine_mode mode ) { return x == CONST0_RTX ( mode ) ; } </s>

Return true if X is a uniform vector where all elements are either the floating-point constant 0.0 or the integer constant 0 .


<s>
void
aarch64_simd_lane_bounds
(
rtx
operand
,
HOST_WIDE_INT
low
,
HOST_WIDE_INT
high
,
const_tree
exp
)
{
HOST_WIDE_INT
lane
;
gcc_assert
(
CONST_INT_P
(
operand
)
)
;
lane
=
INTVAL
(
operand
)
;
if
(
lane
<
low
||
lane
>=
high
)
{
if
(
exp
)
error
(
"%Klane %ld out of range %ld - %ld"
,
exp
,
lane
,
low
,
high
1
)
;
else
error
(
"lane %ld out of range %ld - %ld"
,
lane
,
low
,
high
1
)
;
}
}
</s>

Bounds-check lanes . Ensure OPERAND lies between LOW ( inclusive ) and HIGH ( exclusive ) .


<s> static rtx aarch64_simd_make_constant ( rtx vals ) { machine_mode mode = GET_MODE ( vals ) ; rtx const_dup ; 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_RTX && aarch64_simd_valid_immediate ( const_vec , mode , false , NULL ) ) return const_vec ; else if ( ( const_dup = aarch64_simd_dup_constant ( vals ) ) != NULL_RTX ) return const_dup ; else if ( const_vec != NULL_RTX ) return 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 .


Check OP is a legal scalar immediate for the MOVI instruction .


<s> bool aarch64_simd_shift_imm_p ( rtx x , machine_mode mode , bool left ) { int bit_width = GET_MODE_UNIT_SIZE ( mode ) * BITS_PER_UNIT ; if ( left ) return aarch64_const_vec_all_same_in_range_p ( x , 0 , bit_width - 1 ) ; else return aarch64_const_vec_all_same_in_range_p ( x , 1 , bit_width ) ; } </s>

Check of immediate shift constants are within range .


<s> static HOST_WIDE_INT aarch64_simd_vector_alignment ( const_tree type ) { HOST_WIDE_INT align = tree_to_shwi ( TYPE_SIZE ( type ) ) ; return MIN ( align , 128 ) ; } </s>

Implement target hook TARGET_VECTOR_ALIGNMENT . The AAPCS64 sets the maximum alignment of a vector to 128 bits .


<s> static bool aarch64_simd_vector_alignment_reachable ( const_tree type , bool is_packed ) { if ( is_packed ) return false ; if ( tree_int_cst_compare ( TYPE_SIZE ( type ) , bitsize_int ( BIGGEST_ALIGNMENT ) ) > 0 ) return false ; return true ; } </s>


<s> rtx aarch64_simd_vect_par_cnst_half ( machine_mode mode , bool high ) { int nunits = GET_MODE_NUNITS ( mode ) ; rtvec v = rtvec_alloc ( nunits / 2 ) ; int high_base = nunits / 2 ; int low_base = 0 ; int base ; rtx t1 ; int i ; if ( BYTES_BIG_ENDIAN ) base = high ? low_base : high_base ; else base = high ? high_base : low_base ; for ( i = 0 ; i < nunits / 2 ; i ++ ) RTVEC_ELT ( v , i ) = GEN_INT ( base + i ) ; t1 = gen_rtx_PARALLEL ( mode , v ) ; return t1 ; } </s>

Construct and return a PARALLEL RTX vector with elements numbering the lanes of either the high ( HIGH == TRUE ) or low ( HIGH == FALSE ) half of the vector - from the perspective of the architecture . This does not line up with GCC 's perspective on lane numbers , so we end up with different masks depending on our target endian-ness . The diagram below may help . We must draw the distinction when building masks which select one half of the vector . An instruction selecting architectural low-lanes for a big-endian target , must be described using a mask selecting GCC high-lanes . Big-Endian Little-EndianGCC 0 1 2 3 3 2 1 0 | x | x | x | x | | x | x | x | x |Architecture 3 2 1 0 3 2 1 0Low Mask : { 2 , 3 } { 0 , 1 } High Mask : { 0 , 1 } { 2 , 3 }


<s> void aarch64_split_128bit_move ( rtx dst , rtx src ) { rtx dst_lo , dst_hi ; rtx src_lo , src_hi ; machine_mode mode = GET_MODE ( dst ) ; gcc_assert ( mode == TImode || mode == TFmode ) ; gcc_assert ( ! ( side_effects_p ( src ) || side_effects_p ( dst ) ) ) ; gcc_assert ( mode == GET_MODE ( src ) || GET_MODE ( src ) == VOIDmode ) ; if ( REG_P ( dst ) && REG_P ( src ) ) { int src_regno = REGNO ( src ) ; int dst_regno = REGNO ( dst ) ; if ( FP_REGNUM_P ( dst_regno ) && GP_REGNUM_P ( src_regno ) ) { src_lo = gen_lowpart ( word_mode , src ) ; src_hi = gen_highpart ( word_mode , src ) ; if ( mode == TImode ) { emit_insn ( gen_aarch64_movtilow_di ( dst , src_lo ) ) ; emit_insn ( gen_aarch64_movtihigh_di ( dst , src_hi ) ) ; } else { emit_insn ( gen_aarch64_movtflow_di ( dst , src_lo ) ) ; emit_insn ( gen_aarch64_movtfhigh_di ( dst , src_hi ) ) ; } return ; } else if ( GP_REGNUM_P ( dst_regno ) && FP_REGNUM_P ( src_regno ) ) { dst_lo = gen_lowpart ( word_mode , dst ) ; dst_hi = gen_highpart ( word_mode , dst ) ; if ( mode == TImode ) { emit_insn ( gen_aarch64_movdi_tilow ( dst_lo , src ) ) ; emit_insn ( gen_aarch64_movdi_tihigh ( dst_hi , src ) ) ; } else { emit_insn ( gen_aarch64_movdi_tflow ( dst_lo , src ) ) ; emit_insn ( gen_aarch64_movdi_tfhigh ( dst_hi , src ) ) ; } return ; } } dst_lo = gen_lowpart ( word_mode , dst ) ; dst_hi = gen_highpart ( word_mode , dst ) ; src_lo = gen_lowpart ( word_mode , src ) ; src_hi = gen_highpart_mode ( word_mode , mode , src ) ; if ( reg_overlap_mentioned_p ( dst_lo , src_hi ) ) { aarch64_emit_move ( dst_hi , src_hi ) ; aarch64_emit_move ( dst_lo , src_lo ) ; } else { aarch64_emit_move ( dst_lo , src_lo ) ; aarch64_emit_move ( dst_hi , src_hi ) ; } } </s>

Split a 128-bit move operation into two 64-bit move operations , taking care to handle partial overlap of register to register copies . Special cases are needed when moving between GP regs and FP regs . SRC can be a register , constant or memory ; DST a register or memory . If either operand is memory it must not have any side effects .


<s> void aarch64_split_atomic_op ( enum rtx_code code , rtx old_out , rtx new_out , rtx mem , rtx value , rtx model_rtx , rtx cond ) { machine_mode mode = GET_MODE ( mem ) ; machine_mode wmode = ( mode == DImode ? DImode : SImode ) ; rtx_code_label * label ; rtx x ; label = gen_label_rtx ( ) ; emit_label ( label ) ; if ( new_out ) new_out = gen_lowpart ( wmode , new_out ) ; if ( old_out ) old_out = gen_lowpart ( wmode , old_out ) ; else old_out = new_out ; value = simplify_gen_subreg ( wmode , value , mode , 0 ) ; aarch64_emit_load_exclusive ( mode , old_out , mem , model_rtx ) ; switch ( code ) { case SET : new_out = value ; break ; case NOT : x = gen_rtx_AND ( wmode , old_out , value ) ; emit_insn ( gen_rtx_SET ( VOIDmode , new_out , x ) ) ; x = gen_rtx_NOT ( wmode , new_out ) ; emit_insn ( gen_rtx_SET ( VOIDmode , new_out , x ) ) ; break ; case MINUS : if ( CONST_INT_P ( value ) ) { value = GEN_INT ( - INTVAL ( value ) ) ; code = PLUS ; } default : x = gen_rtx_fmt_ee ( code , wmode , old_out , value ) ; emit_insn ( gen_rtx_SET ( VOIDmode , new_out , x ) ) ; break ; } aarch64_emit_store_exclusive ( mode , cond , mem , gen_lowpart ( mode , new_out ) , model_rtx ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( VOIDmode , pc_rtx , x ) ) ; } </s>


<s> void aarch64_split_combinev16qi ( 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 = HARD_REGNO_NREGS ( src1 , halfmode ) ; rtx destlo , desthi ; gcc_assert ( halfmode == V16QImode ) ; 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 ( reg_overlap_mentioned_p ( operands [ 2 ] , destlo ) && reg_overlap_mentioned_p ( operands [ 1 ] , desthi ) ) { emit_insn ( gen_xorv16qi3 ( operands [ 1 ] , operands [ 1 ] , operands [ 2 ] ) ) ; emit_insn ( gen_xorv16qi3 ( operands [ 2 ] , operands [ 1 ] , operands [ 2 ] ) ) ; emit_insn ( gen_xorv16qi3 ( operands [ 1 ] , operands [ 1 ] , operands [ 2 ] ) ) ; } else 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> void aarch64_split_compare_and_swap ( rtx operands [ ] ) { rtx rval , mem , oldval , newval , scratch ; machine_mode mode ; bool is_weak ; rtx_code_label * label1 , * label2 ; rtx x , cond ; rval = operands [ 0 ] ; mem = operands [ 1 ] ; oldval = operands [ 2 ] ; newval = operands [ 3 ] ; is_weak = ( operands [ 4 ] != const0_rtx ) ; scratch = operands [ 7 ] ; mode = GET_MODE ( mem ) ; label1 = NULL ; if ( ! is_weak ) { label1 = gen_label_rtx ( ) ; emit_label ( label1 ) ; } label2 = gen_label_rtx ( ) ; aarch64_emit_load_exclusive ( mode , rval , mem , operands [ 5 ] ) ; cond = aarch64_gen_compare_reg ( NE , rval , oldval ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label2 ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( VOIDmode , pc_rtx , x ) ) ; aarch64_emit_store_exclusive ( mode , scratch , mem , newval , operands [ 5 ] ) ; if ( ! is_weak ) { x = gen_rtx_NE ( VOIDmode , scratch , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label1 ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( VOIDmode , pc_rtx , x ) ) ; } else { cond = gen_rtx_REG ( CCmode , CC_REGNUM ) ; x = gen_rtx_COMPARE ( CCmode , scratch , const0_rtx ) ; emit_insn ( gen_rtx_SET ( VOIDmode , cond , x ) ) ; } emit_label ( label2 ) ; } </s>


<s> void aarch64_split_simd_combine ( rtx dst , rtx src1 , rtx src2 ) { machine_mode src_mode = GET_MODE ( src1 ) ; machine_mode dst_mode = GET_MODE ( dst ) ; gcc_assert ( VECTOR_MODE_P ( dst_mode ) ) ; if ( REG_P ( dst ) && REG_P ( src1 ) && REG_P ( src2 ) ) { rtx ( * gen ) ( rtx , rtx , rtx ) ; switch ( src_mode ) { case V8QImode : gen = gen_aarch64_simd_combinev8qi ; break ; case V4HImode : gen = gen_aarch64_simd_combinev4hi ; break ; case V2SImode : gen = gen_aarch64_simd_combinev2si ; break ; case V2SFmode : gen = gen_aarch64_simd_combinev2sf ; break ; case DImode : gen = gen_aarch64_simd_combinedi ; break ; case DFmode : gen = gen_aarch64_simd_combinedf ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , src1 , src2 ) ) ; return ; } } </s>


<s> void aarch64_split_simd_move ( rtx dst , rtx src ) { machine_mode src_mode = GET_MODE ( src ) ; machine_mode dst_mode = GET_MODE ( dst ) ; gcc_assert ( VECTOR_MODE_P ( dst_mode ) ) ; if ( REG_P ( dst ) && REG_P ( src ) ) { rtx ( * gen ) ( rtx , rtx ) ; gcc_assert ( VECTOR_MODE_P ( src_mode ) ) ; switch ( src_mode ) { case V16QImode : gen = gen_aarch64_split_simd_movv16qi ; break ; case V8HImode : gen = gen_aarch64_split_simd_movv8hi ; break ; case V4SImode : gen = gen_aarch64_split_simd_movv4si ; break ; case V2DImode : gen = gen_aarch64_split_simd_movv2di ; break ; case V4SFmode : gen = gen_aarch64_split_simd_movv4sf ; break ; case V2DFmode : gen = gen_aarch64_split_simd_movv2df ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , src ) ) ; return ; } } </s>


<s>
static
void
aarch64_start_file
(
void
)
{
if
(
selected_arch
)
{
asm_fprintf
(
asm_out_file
,
"\t.arch %s"
,
selected_arch
->
name
)
;
aarch64_print_extension
(
)
;
}
else
if
(
selected_cpu
)
{
const
char
*
truncated_name
=
aarch64_rewrite_selected_cpu
(
selected_cpu
->
name
)
;
asm_fprintf
(
asm_out_file
,
"\t.cpu %s"
,
truncated_name
)
;
aarch64_print_extension
(
)
;
}
default_file_start
(
)
;
}
</s>

Implements TARGET_ASM_FILE_START . Output the assembly header .


<s> static rtx aarch64_strip_extend ( rtx x ) { rtx op = x ; if ( ( GET_CODE ( op ) == ZERO_EXTRACT || GET_CODE ( op ) == SIGN_EXTRACT ) && XEXP ( op , 2 ) == const0_rtx && GET_CODE ( XEXP ( op , 0 ) ) == MULT && aarch64_is_extend_from_extract ( GET_MODE ( op ) , XEXP ( XEXP ( op , 0 ) , 1 ) , XEXP ( op , 1 ) ) ) return XEXP ( XEXP ( op , 0 ) , 0 ) ; if ( GET_CODE ( op ) == AND && GET_CODE ( XEXP ( op , 0 ) ) == MULT && CONST_INT_P ( XEXP ( XEXP ( op , 0 ) , 1 ) ) && CONST_INT_P ( XEXP ( op , 1 ) ) && aarch64_uxt_size ( exact_log2 ( INTVAL ( XEXP ( XEXP ( op , 0 ) , 1 ) ) ) , INTVAL ( XEXP ( op , 1 ) ) ) != 0 ) return XEXP ( XEXP ( op , 0 ) , 0 ) ; if ( GET_CODE ( op ) == ASHIFT && CONST_INT_P ( XEXP ( op , 1 ) ) && ( ( unsigned HOST_WIDE_INT ) INTVAL ( XEXP ( op , 1 ) ) ) <= 4 ) op = XEXP ( op , 0 ) ; if ( GET_CODE ( op ) == ZERO_EXTEND || GET_CODE ( op ) == SIGN_EXTEND ) op = XEXP ( op , 0 ) ; if ( op != x ) return op ; return x ; } </s>

Helper function for rtx cost calculation . Strip an extend expression from X . Returns the inner operand if successful , or the original expression on failure . We deal with a number of possible canonicalization variations here .


<s> bool aarch64_use_return_insn_p ( void ) { if ( ! reload_completed ) return false ; if ( crtl -> profile ) return false ; aarch64_layout_frame ( ) ; return cfun -> machine -> frame . frame_size == 0 ; } </s>

Return TRUE if we can use a simple_return insn . This function checks whether the callee saved stack is empty , which means no restore actions are need . The pro_and_epilogue will use this to check whether shrink-wrapping opt is feasible .


<s> static bool aarch64_valid_floating_const ( machine_mode mode , rtx x ) { if ( ! CONST_DOUBLE_P ( x ) ) return false ; if ( ! ( mode == SFmode || mode == DFmode ) ) return false ; if ( aarch64_float_const_zero_rtx_p ( x ) ) return true ; return aarch64_float_const_representable_p ( x ) ; } </s>

Return true if X holds either a quarter-precision or floating-point +0.0 constant .


<s> static bool aarch64_vector_mode_p ( machine_mode mode ) { return aarch64_vector_mode_supported_p ( mode ) || aarch64_vect_struct_mode_p ( mode ) ; } </s>

Return TRUE if MODE is any of the vector modes .


<s> static bool aarch64_vector_mode_supported_p ( machine_mode mode ) { if ( TARGET_SIMD && ( mode == V4SImode || mode == V8HImode || mode == V16QImode || mode == V2DImode || mode == V2SImode || mode == V4HImode || mode == V8QImode || mode == V2SFmode || mode == V4SFmode || mode == V2DFmode || mode == V1DFmode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


Return true iff x is a uniform vector of floating-point constants , and the constant can be represented in quarter-precision form . Note , as aarch64_float_const_representable rejects both +0.0 and -0.0 , we will also reject +0.0 and -0.0 .


<s> static bool aarch64_vect_struct_mode_p ( machine_mode mode ) { return mode == OImode || mode == CImode || mode == XImode ; } </s>

Return TRUE if MODE is any of the large INT modes .


<s> static bool aarch64_vfp_is_call_or_return_candidate ( machine_mode mode , const_tree type , machine_mode * base_mode , int * count , bool * is_ha ) { machine_mode new_mode = VOIDmode ; bool composite_p = aarch64_composite_type_p ( type , mode ) ; if ( is_ha != NULL ) * is_ha = false ; if ( ( ! composite_p && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) || aarch64_short_vector_p ( type , mode ) ) { * count = 1 ; new_mode = mode ; } else if ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) { if ( is_ha != NULL ) * is_ha = true ; * count = 2 ; new_mode = GET_MODE_INNER ( mode ) ; } else if ( type && composite_p ) { int ag_count = aapcs_vfp_sub_candidate ( type , & new_mode ) ; if ( ag_count > 0 && ag_count <= HA_MAX_NUM_FLDS ) { if ( is_ha != NULL ) * is_ha = true ; * count = ag_count ; } else return false ; } else return false ; * base_mode = new_mode ; return true ; } </s>

Return TRUE if an argument , whose type is described by TYPE and MODE , shall be passed or returned in simd/fp register ( s ) ( providing these parameter passing registers are available ) . Upon successful return , * COUNT returns the number of needed registers , * BASE_MODE returns the mode of the individual register and when IS_HAF is not NULL , * IS_HA indicates whether or not the argument is a homogeneous floating-point aggregate or a homogeneous short-vector aggregate .


<s> static unsigned bit_count ( unsigned HOST_WIDE_INT value ) { unsigned 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> inline static rtx emit_set_insn ( rtx x , rtx y ) { return emit_insn ( gen_rtx_SET ( VOIDmode , x , y ) ) ; } </s>

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


<s> static enum sched_fusion_type fusion_load_store ( rtx_insn * insn , rtx * base , rtx * offset ) { rtx x , dest , src ; enum sched_fusion_type fusion = SCHED_FUSION_LD ; gcc_assert ( INSN_P ( insn ) ) ; x = PATTERN ( insn ) ; if ( GET_CODE ( x ) != SET ) return SCHED_FUSION_NONE ; src = SET_SRC ( x ) ; dest = SET_DEST ( x ) ; if ( GET_MODE ( dest ) != SImode && GET_MODE ( dest ) != DImode && GET_MODE ( dest ) != SFmode && GET_MODE ( dest ) != DFmode ) return SCHED_FUSION_NONE ; if ( GET_CODE ( src ) == SIGN_EXTEND ) { fusion = SCHED_FUSION_LD_SIGN_EXTEND ; src = XEXP ( src , 0 ) ; if ( GET_CODE ( src ) != MEM || GET_MODE ( src ) != SImode ) return SCHED_FUSION_NONE ; } else if ( GET_CODE ( src ) == ZERO_EXTEND ) { fusion = SCHED_FUSION_LD_ZERO_EXTEND ; src = XEXP ( src , 0 ) ; if ( GET_CODE ( src ) != MEM || GET_MODE ( src ) != SImode ) return SCHED_FUSION_NONE ; } if ( GET_CODE ( src ) == MEM && REG_P ( dest ) ) extract_base_offset_in_addr ( src , base , offset ) ; else if ( GET_CODE ( dest ) == MEM && ( REG_P ( src ) || src == const0_rtx ) ) { fusion = SCHED_FUSION_ST ; extract_base_offset_in_addr ( dest , base , offset ) ; } else return SCHED_FUSION_NONE ; if ( * base == NULL_RTX || * offset == NULL_RTX ) fusion = SCHED_FUSION_NONE ; return fusion ; } </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> static bool has_memory_op ( rtx_insn * mem_insn ) { subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , PATTERN ( mem_insn ) , ALL ) if ( MEM_P ( * iter ) ) return true ; return false ; } </s>

Return true if the rtx_insn contains a MEM RTX somewhere in it .


<s>
static
void
initialize_aarch64_code_model
(
void
)
{
if
(
flag_pic
)
{
switch
(
aarch64_cmodel_var
)
{
case
AARCH64_CMODEL_TINY
:
aarch64_cmodel
=
AARCH64_CMODEL_TINY_PIC
;
break
;
case
AARCH64_CMODEL_SMALL
:
aarch64_cmodel
=
AARCH64_CMODEL_SMALL_PIC
;
break
;
case
AARCH64_CMODEL_LARGE
:
sorry
(
"code model %qs with -f%s"
,
"large"
,
flag_pic
>
1
"PIC"
:
"pic"
)
;
default
:
gcc_unreachable
(
)
;
}
}
else
aarch64_cmodel
=
aarch64_cmodel_var
;
}
</s>

A checking mechanism for the implementation of the various code models .

aarch64
"code model %qs with -f%s"
"large"
1
"PIC"
"pic"


<s> static inline bool offset_12bit_unsigned_scaled_p ( machine_mode mode , HOST_WIDE_INT offset ) { return ( offset >= 0 && offset < 4096 * GET_MODE_SIZE ( mode ) && offset % GET_MODE_SIZE ( mode ) == 0 ) ; } </s>

Return true if OFFSET is an unsigned 12-bit value multiplied by the size of MODE .


<s> static inline bool offset_9bit_signed_unscaled_p ( machine_mode mode ATTRIBUTE_UNUSED , HOST_WIDE_INT offset ) { return offset >= - 256 && offset < 256 ; } </s>

Return true if OFFSET is a signed 9-bit value .


<s> static enum tls_model tls_symbolic_operand_type ( rtx addr ) { enum tls_model tls_kind = TLS_MODEL_NONE ; rtx sym , addend ; if ( GET_CODE ( addr ) == CONST ) { split_const ( addr , & sym , & addend ) ; if ( GET_CODE ( sym ) == SYMBOL_REF ) tls_kind = SYMBOL_REF_TLS_MODEL ( sym ) ; } else if ( GET_CODE ( addr ) == SYMBOL_REF ) tls_kind = SYMBOL_REF_TLS_MODEL ( addr ) ; return tls_kind ; } </s>

Return the TLS model to use for SYMBOL .


<s> static unsigned aarch64_add_stmt_cost ( void * data , int count , enum vect_cost_for_stmt kind , struct _stmt_vec_info * stmt_info , int misalign , enum vect_cost_model_location where ) { unsigned * cost = ( unsigned * ) data ; unsigned retval = 0 ; if ( flag_vect_cost_model ) { tree vectype = stmt_info ? stmt_vectype ( stmt_info ) : NULL_TREE ; int stmt_cost = aarch64_builtin_vectorization_cost ( kind , vectype , misalign ) ; if ( where == vect_body && stmt_info && stmt_in_inner_loop_p ( stmt_info ) ) count *= 50 ; retval = ( unsigned ) ( count * stmt_cost ) ; cost [ where ] += retval ; } return retval ; } </s>


<s> bool aarch64_atomic_ldop_supported_p ( enum rtx_code code ) { if ( ! TARGET_LSE ) return false ; switch ( code ) { case SET : case AND : case IOR : case XOR : case MINUS : case PLUS : return true ; default : return false ; } } </s>

Test whether the target supports using a atomic load-operate instruction . CODE is the operation and AFTER is TRUE if the data in memory after the operation should be returned and FALSE if the data before the operation should be returned . Returns FALSE if the operation is n't supported by the architecture .


<s> bool aarch64_bitmask_imm ( HOST_WIDE_INT val_in , machine_mode mode ) { unsigned HOST_WIDE_INT val , tmp , mask , first_one , next_one ; int bits ; val = ( unsigned HOST_WIDE_INT ) val_in ; tmp = val + ( val & - val ) ; if ( tmp == ( tmp & - tmp ) ) return ( val + 1 ) > 1 ; if ( mode == SImode ) val = ( val << 32 ) | ( val & 0xffffffff ) ; if ( val & 1 ) val = ~ val ; first_one = val & - val ; tmp = val & ( val + first_one ) ; if ( tmp == 0 ) return true ; next_one = tmp & - tmp ; bits = clz_hwi ( first_one ) - clz_hwi ( next_one ) ; mask = val ^ tmp ; if ( ( mask >> bits ) != 0 || bits != ( bits & - bits ) ) return false ; return val == mask * bitmask_imm_mul [ __builtin_clz ( bits ) - 26 ] ; } </s>

Return true if val is a valid bitmask immediate .


<s> static tree aarch64_builtin_reciprocal ( tree fndecl ) { if ( ! use_rsqrt_p ( ) ) return NULL_TREE ; return aarch64_builtin_rsqrt ( DECL_FUNCTION_CODE ( fndecl ) ) ; } </s>

Function to decide when to use the approximate reciprocal square root builtin .


<s> bool aarch64_cannot_change_mode_class ( machine_mode from , machine_mode to , enum reg_class rclass ) { return ( reg_classes_intersect_p ( FP_REGS , rclass ) && GET_MODE_SIZE ( to ) == UNITS_PER_WORD && GET_MODE_SIZE ( from ) > UNITS_PER_WORD ) ; } </s>

Implement target hook CANNOT_CHANGE_MODE_CLASS .


<s> static bool aarch64_can_inline_p ( tree caller , tree callee ) { tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET ( caller ) ; tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET ( callee ) ; if ( ! callee_tree ) return true ; struct cl_target_option * caller_opts = TREE_TARGET_OPTION ( caller_tree ? caller_tree : target_option_default_node ) ; struct cl_target_option * callee_opts = TREE_TARGET_OPTION ( callee_tree ) ; if ( ( caller_opts -> x_aarch64_isa_flags & callee_opts -> x_aarch64_isa_flags ) != callee_opts -> x_aarch64_isa_flags ) return false ; if ( ( TARGET_STRICT_ALIGN_P ( caller_opts -> x_target_flags ) != TARGET_STRICT_ALIGN_P ( callee_opts -> x_target_flags ) ) && ! ( ! TARGET_STRICT_ALIGN_P ( callee_opts -> x_target_flags ) && TARGET_STRICT_ALIGN_P ( caller_opts -> x_target_flags ) ) ) return false ; bool always_inline = lookup_attribute ( "always_inline" , DECL_ATTRIBUTES ( callee ) ) ; if ( always_inline ) return true ; if ( caller_opts -> x_aarch64_cmodel_var != callee_opts -> x_aarch64_cmodel_var ) return false ; if ( caller_opts -> x_aarch64_tls_dialect != callee_opts -> x_aarch64_tls_dialect ) return false ; if ( ! aarch64_tribools_ok_for_inlining_p ( caller_opts -> x_aarch64_fix_a53_err835769 , callee_opts -> x_aarch64_fix_a53_err835769 , 2 , TARGET_FIX_ERR_A53_835769_DEFAULT ) ) return false ; if ( ! aarch64_tribools_ok_for_inlining_p ( caller_opts -> x_aarch64_fix_a53_err843419 , callee_opts -> x_aarch64_fix_a53_err843419 , 2 , TARGET_FIX_ERR_A53_843419 ) ) return false ; if ( ! aarch64_tribools_ok_for_inlining_p ( caller_opts -> x_flag_omit_leaf_frame_pointer , callee_opts -> x_flag_omit_leaf_frame_pointer , 2 , 1 ) ) return false ; if ( callee_opts -> x_aarch64_override_tune_string != NULL && caller_opts -> x_aarch64_override_tune_string == NULL ) return false ; if ( callee_opts -> x_aarch64_override_tune_string && caller_opts -> x_aarch64_override_tune_string && ( strcmp ( callee_opts -> x_aarch64_override_tune_string , caller_opts -> x_aarch64_override_tune_string ) != 0 ) ) return false ; return true ; } </s>

Implement TARGET_CAN_INLINE_P . Decide whether it is valid to inline CALLEE into CALLER based on target-specific info . Make sure that the caller and callee have compatible architectural features . Then go through the other possible target attributes and see if they can block inlining . Try not to reject always_inline callees unless they are incompatible architecturally .


Constant pools are per function only when PC relative literal loads are true or we are in the large memory model .


<s> static unsigned int aarch64_case_values_threshold ( void ) { if ( optimize > 2 && selected_cpu -> tune -> max_case_values != 0 ) return selected_cpu -> tune -> max_case_values ; else return default_case_values_threshold ( ) ; } </s>


<s> enum aarch64_symbol_type aarch64_classify_symbol ( rtx x , rtx offset ) { if ( GET_CODE ( x ) == LABEL_REF ) { switch ( aarch64_cmodel ) { case AARCH64_CMODEL_LARGE : return SYMBOL_FORCE_TO_MEM ; case AARCH64_CMODEL_TINY_PIC : case AARCH64_CMODEL_TINY : return SYMBOL_TINY_ABSOLUTE ; case AARCH64_CMODEL_SMALL_SPIC : case AARCH64_CMODEL_SMALL_PIC : case AARCH64_CMODEL_SMALL : return SYMBOL_SMALL_ABSOLUTE ; default : gcc_unreachable ( ) ; } } if ( GET_CODE ( x ) == SYMBOL_REF ) { if ( aarch64_cmodel == AARCH64_CMODEL_LARGE ) { if ( nopcrelative_literal_loads && CONSTANT_POOL_ADDRESS_P ( x ) ) return SYMBOL_SMALL_ABSOLUTE ; else return SYMBOL_FORCE_TO_MEM ; } if ( aarch64_tls_symbol_p ( x ) ) return aarch64_classify_tls_symbol ( x ) ; switch ( aarch64_cmodel ) { case AARCH64_CMODEL_TINY : if ( SYMBOL_REF_WEAK ( x ) || INTVAL ( offset ) < - 1048575 || INTVAL ( offset ) > 1048575 ) return SYMBOL_FORCE_TO_MEM ; return SYMBOL_TINY_ABSOLUTE ; case AARCH64_CMODEL_SMALL : if ( SYMBOL_REF_WEAK ( x ) || ! IN_RANGE ( INTVAL ( offset ) , HOST_WIDE_INT_C ( - 4294967263 ) , HOST_WIDE_INT_C ( 4294967264 ) ) ) return SYMBOL_FORCE_TO_MEM ; return SYMBOL_SMALL_ABSOLUTE ; case AARCH64_CMODEL_TINY_PIC : if ( ! aarch64_symbol_binds_local_p ( x ) ) return SYMBOL_TINY_GOT ; return SYMBOL_TINY_ABSOLUTE ; case AARCH64_CMODEL_SMALL_SPIC : case AARCH64_CMODEL_SMALL_PIC : if ( ! aarch64_symbol_binds_local_p ( x ) ) return ( aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC ? SYMBOL_SMALL_GOT_28K : SYMBOL_SMALL_GOT_4G ) ; return SYMBOL_SMALL_ABSOLUTE ; default : gcc_unreachable ( ) ; } } return SYMBOL_FORCE_TO_MEM ; } </s>

Return the method that should be used to access SYMBOL_REF or LABEL_REF X .


<s> enum aarch64_symbol_type aarch64_classify_symbolic_expression ( rtx x ) { rtx offset ; split_const ( x , & x , & offset ) ; return aarch64_classify_symbol ( x , offset ) ; } </s>

Classify the base of symbolic expression X , given that X appears in context CONTEXT .


<s> static enum insn_code aarch64_constant_pool_reload_icode ( machine_mode mode ) { switch ( mode ) { case SFmode : return CODE_FOR_aarch64_reload_movcpsfdi ; case DFmode : return CODE_FOR_aarch64_reload_movcpdfdi ; case TFmode : return CODE_FOR_aarch64_reload_movcptfdi ; case V8QImode : return CODE_FOR_aarch64_reload_movcpv8qidi ; case V16QImode : return CODE_FOR_aarch64_reload_movcpv16qidi ; case V4HImode : return CODE_FOR_aarch64_reload_movcpv4hidi ; case V8HImode : return CODE_FOR_aarch64_reload_movcpv8hidi ; case V2SImode : return CODE_FOR_aarch64_reload_movcpv2sidi ; case V4SImode : return CODE_FOR_aarch64_reload_movcpv4sidi ; case V2DImode : return CODE_FOR_aarch64_reload_movcpv2didi ; case V2DFmode : return CODE_FOR_aarch64_reload_movcpv2dfdi ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; } </s>

Return the reload icode required for a constant pool in mode .


Implement ASM_DECLARE_FUNCTION_NAME . Output the ISA features used by the function fndecl .

aarch64
"\t.arch %s\n"
"\t"
".tune %s\n"
"function"


<s> void aarch64_emit_approx_rsqrt ( rtx dst , rtx src ) { machine_mode mode = GET_MODE ( src ) ; gcc_assert ( mode == SFmode || mode == V2SFmode || mode == V4SFmode || mode == DFmode || mode == V2DFmode ) ; rtx xsrc = gen_reg_rtx ( mode ) ; emit_move_insn ( xsrc , src ) ; rtx x0 = gen_reg_rtx ( mode ) ; emit_insn ( ( * get_rsqrte_type ( mode ) ) ( x0 , xsrc ) ) ; bool double_mode = ( mode == DFmode || mode == V2DFmode ) ; int iterations = double_mode ? 3 : 2 ; if ( flag_mrecip_low_precision_sqrt ) iterations -- ; for ( int i = 0 ; i < iterations ; ++ i ) { rtx x1 = gen_reg_rtx ( mode ) ; rtx x2 = gen_reg_rtx ( mode ) ; rtx x3 = gen_reg_rtx ( mode ) ; emit_set_insn ( x2 , gen_rtx_MULT ( mode , x0 , x0 ) ) ; emit_insn ( ( * get_rsqrts_type ( mode ) ) ( x3 , xsrc , x2 ) ) ; emit_set_insn ( x1 , gen_rtx_MULT ( mode , x0 , x3 ) ) ; x0 = x1 ; } emit_move_insn ( dst , x0 ) ; } </s>

Emit instruction sequence to compute the reciprocal square root using the Newton-Raphson series . Iterate over the series twice for SF and thrice for DF .


<s> static void aarch64_emit_atomic_load_op ( enum aarch64_atomic_load_op_code code , machine_mode mode , rtx dst , rtx src , rtx mem , rtx model ) { typedef rtx ( * aarch64_atomic_load_op_fn ) ( rtx , rtx , rtx , rtx ) ; const aarch64_atomic_load_op_fn plus [ ] = { gen_aarch64_atomic_loadaddqi , gen_aarch64_atomic_loadaddhi , gen_aarch64_atomic_loadaddsi , gen_aarch64_atomic_loadadddi } ; const aarch64_atomic_load_op_fn eor [ ] = { gen_aarch64_atomic_loadeorqi , gen_aarch64_atomic_loadeorhi , gen_aarch64_atomic_loadeorsi , gen_aarch64_atomic_loadeordi } ; const aarch64_atomic_load_op_fn ior [ ] = { gen_aarch64_atomic_loadsetqi , gen_aarch64_atomic_loadsethi , gen_aarch64_atomic_loadsetsi , gen_aarch64_atomic_loadsetdi } ; const aarch64_atomic_load_op_fn bic [ ] = { gen_aarch64_atomic_loadclrqi , gen_aarch64_atomic_loadclrhi , gen_aarch64_atomic_loadclrsi , gen_aarch64_atomic_loadclrdi } ; aarch64_atomic_load_op_fn gen ; int idx = 0 ; switch ( mode ) { case QImode : idx = 0 ; break ; case HImode : idx = 1 ; break ; case SImode : idx = 2 ; break ; case DImode : idx = 3 ; break ; default : gcc_unreachable ( ) ; } switch ( code ) { case AARCH64_LDOP_PLUS : gen = plus [ idx ] ; break ; case AARCH64_LDOP_XOR : gen = eor [ idx ] ; break ; case AARCH64_LDOP_OR : gen = ior [ idx ] ; break ; case AARCH64_LDOP_BIC : gen = bic [ idx ] ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , mem , src , model ) ) ; } </s>


<s> static void aarch64_emit_atomic_swap ( machine_mode mode , rtx dst , rtx value , rtx mem , rtx model ) { rtx ( * gen ) ( rtx , rtx , rtx , rtx ) ; switch ( mode ) { case QImode : gen = gen_aarch64_atomic_swpqi ; break ; case HImode : gen = gen_aarch64_atomic_swphi ; break ; case SImode : gen = gen_aarch64_atomic_swpsi ; break ; case DImode : gen = gen_aarch64_atomic_swpdi ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , mem , value , model ) ) ; } </s>


<s> static void aarch64_emit_bic ( machine_mode mode , rtx dst , rtx s1 , rtx s2 , int shift ) { rtx shift_rtx = GEN_INT ( shift ) ; rtx ( * gen ) ( rtx , rtx , rtx , rtx ) ; switch ( mode ) { case SImode : gen = gen_and_one_cmpl_lshrsi3 ; break ; case DImode : gen = gen_and_one_cmpl_lshrdi3 ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , s2 , shift_rtx , s1 ) ) ; } </s>


<s> static void aarch64_emit_probe_stack_range ( HOST_WIDE_INT first , HOST_WIDE_INT size ) { rtx reg1 = gen_rtx_REG ( ptr_mode , PROBE_STACK_FIRST_REG ) ; gcc_assert ( ( first % ARITH_FACTOR ) == 0 ) ; if ( size <= PROBE_INTERVAL ) { const HOST_WIDE_INT base = ROUND_UP ( size , ARITH_FACTOR ) ; emit_set_insn ( reg1 , plus_constant ( ptr_mode , stack_pointer_rtx , - ( first + base ) ) ) ; emit_stack_probe ( plus_constant ( ptr_mode , reg1 , base - size ) ) ; } else if ( size <= 4 * PROBE_INTERVAL ) { HOST_WIDE_INT i , rem ; emit_set_insn ( reg1 , plus_constant ( ptr_mode , stack_pointer_rtx , - ( first + PROBE_INTERVAL ) ) ) ; emit_stack_probe ( reg1 ) ; for ( i = 2 * PROBE_INTERVAL ; i < size ; i += PROBE_INTERVAL ) { emit_set_insn ( reg1 , plus_constant ( ptr_mode , reg1 , - PROBE_INTERVAL ) ) ; emit_stack_probe ( reg1 ) ; } rem = size - ( i - PROBE_INTERVAL ) ; if ( rem > 256 ) { const HOST_WIDE_INT base = ROUND_UP ( rem , ARITH_FACTOR ) ; emit_set_insn ( reg1 , plus_constant ( ptr_mode , reg1 , - base ) ) ; emit_stack_probe ( plus_constant ( ptr_mode , reg1 , base - rem ) ) ; } else emit_stack_probe ( plus_constant ( ptr_mode , reg1 , - rem ) ) ; } else { rtx reg2 = gen_rtx_REG ( ptr_mode , PROBE_STACK_SECOND_REG ) ; HOST_WIDE_INT rounded_size = size & - PROBE_INTERVAL ; emit_set_insn ( reg1 , plus_constant ( ptr_mode , stack_pointer_rtx , - first ) ) ; emit_set_insn ( reg2 , plus_constant ( ptr_mode , stack_pointer_rtx , - ( first + rounded_size ) ) ) ; if ( ptr_mode == DImode ) emit_insn ( gen_probe_stack_range_di ( reg1 , reg1 , reg2 ) ) ; else emit_insn ( gen_probe_stack_range_si ( reg1 , reg1 , reg2 ) ) ; if ( size != rounded_size ) { HOST_WIDE_INT rem = size - rounded_size ; if ( rem > 256 ) { const HOST_WIDE_INT base = ROUND_UP ( rem , ARITH_FACTOR ) ; emit_set_insn ( reg2 , plus_constant ( ptr_mode , reg2 , - base ) ) ; emit_stack_probe ( plus_constant ( ptr_mode , reg2 , base - rem ) ) ; } else emit_stack_probe ( plus_constant ( ptr_mode , reg2 , - rem ) ) ; } } emit_insn ( gen_blockage ( ) ) ; } </s>

Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE , inclusive . These are offsets from the current stack pointer .


<s> static void aarch64_expand_builtin_va_start ( tree valist , rtx nextarg ATTRIBUTE_UNUSED ) { const CUMULATIVE_ARGS * cum ; tree f_stack , f_grtop , f_vrtop , f_groff , f_vroff ; tree stack , grtop , vrtop , groff , vroff ; tree t ; int gr_save_area_size ; int vr_save_area_size ; int vr_offset ; cum = & crtl -> args . info ; gr_save_area_size = ( NUM_ARG_REGS - cum -> aapcs_ncrn ) * UNITS_PER_WORD ; vr_save_area_size = ( NUM_FP_ARG_REGS - cum -> aapcs_nvrn ) * UNITS_PER_VREG ; if ( ! TARGET_FLOAT ) { gcc_assert ( cum -> aapcs_nvrn == 0 ) ; vr_save_area_size = 0 ; } f_stack = TYPE_FIELDS ( va_list_type_node ) ; f_grtop = DECL_CHAIN ( f_stack ) ; f_vrtop = DECL_CHAIN ( f_grtop ) ; f_groff = DECL_CHAIN ( f_vrtop ) ; f_vroff = DECL_CHAIN ( f_groff ) ; stack = build3 ( COMPONENT_REF , TREE_TYPE ( f_stack ) , valist , f_stack , NULL_TREE ) ; grtop = build3 ( COMPONENT_REF , TREE_TYPE ( f_grtop ) , valist , f_grtop , NULL_TREE ) ; vrtop = build3 ( COMPONENT_REF , TREE_TYPE ( f_vrtop ) , valist , f_vrtop , NULL_TREE ) ; groff = build3 ( COMPONENT_REF , TREE_TYPE ( f_groff ) , valist , f_groff , NULL_TREE ) ; vroff = build3 ( COMPONENT_REF , TREE_TYPE ( f_vroff ) , valist , f_vroff , NULL_TREE ) ; t = make_tree ( TREE_TYPE ( stack ) , virtual_incoming_args_rtx ) ; if ( cum -> aapcs_stack_size > 0 ) t = fold_build_pointer_plus_hwi ( t , cum -> aapcs_stack_size * UNITS_PER_WORD ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( stack ) , stack , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( grtop ) , virtual_incoming_args_rtx ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( grtop ) , grtop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( vrtop ) , virtual_incoming_args_rtx ) ; vr_offset = ROUND_UP ( gr_save_area_size , STACK_BOUNDARY / BITS_PER_UNIT ) ; if ( vr_offset ) t = fold_build_pointer_plus_hwi ( t , - vr_offset ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( vrtop ) , vrtop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( groff ) , groff , build_int_cst ( TREE_TYPE ( groff ) , - gr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build2 ( MODIFY_EXPR , TREE_TYPE ( vroff ) , vroff , build_int_cst ( TREE_TYPE ( vroff ) , - vr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; } </s>


<s> void aarch64_expand_compare_and_swap ( rtx operands [ ] ) { rtx bval , rval , mem , oldval , newval , is_weak , mod_s , mod_f , x ; machine_mode mode , cmp_mode ; typedef rtx ( * gen_cas_fn ) ( rtx , rtx , rtx , rtx , rtx , rtx , rtx ) ; int idx ; gen_cas_fn gen ; const gen_cas_fn split_cas [ ] = { gen_aarch64_compare_and_swapqi , gen_aarch64_compare_and_swaphi , gen_aarch64_compare_and_swapsi , gen_aarch64_compare_and_swapdi } ; const gen_cas_fn atomic_cas [ ] = { gen_aarch64_compare_and_swapqi_lse , gen_aarch64_compare_and_swaphi_lse , gen_aarch64_compare_and_swapsi_lse , gen_aarch64_compare_and_swapdi_lse } ; bval = operands [ 0 ] ; rval = operands [ 1 ] ; mem = operands [ 2 ] ; oldval = operands [ 3 ] ; newval = operands [ 4 ] ; is_weak = operands [ 5 ] ; mod_s = operands [ 6 ] ; mod_f = operands [ 7 ] ; mode = GET_MODE ( mem ) ; cmp_mode = mode ; if ( is_mm_acquire ( memmodel_from_int ( INTVAL ( mod_f ) ) ) && is_mm_release ( memmodel_from_int ( INTVAL ( mod_s ) ) ) ) mod_s = GEN_INT ( MEMMODEL_ACQ_REL ) ; switch ( mode ) { case QImode : case HImode : cmp_mode = SImode ; rval = gen_reg_rtx ( SImode ) ; oldval = convert_modes ( SImode , mode , oldval , true ) ; case SImode : case DImode : if ( ! aarch64_plus_operand ( oldval , mode ) ) oldval = force_reg ( cmp_mode , oldval ) ; break ; default : gcc_unreachable ( ) ; } switch ( mode ) { case QImode : idx = 0 ; break ; case HImode : idx = 1 ; break ; case SImode : idx = 2 ; break ; case DImode : idx = 3 ; break ; default : gcc_unreachable ( ) ; } if ( TARGET_LSE ) gen = atomic_cas [ idx ] ; else gen = split_cas [ idx ] ; emit_insn ( gen ( rval , mem , oldval , newval , is_weak , mod_s , mod_f ) ) ; if ( mode == QImode || mode == HImode ) emit_move_insn ( operands [ 1 ] , gen_lowpart ( mode , rval ) ) ; x = gen_rtx_REG ( CCmode , CC_REGNUM ) ; x = gen_rtx_EQ ( SImode , x , const0_rtx ) ; emit_insn ( gen_rtx_SET ( bval , x ) ) ; } </s>


<s> void aarch64_expand_mov_immediate ( rtx dest , rtx imm ) { machine_mode mode = GET_MODE ( dest ) ; gcc_assert ( mode == SImode || mode == DImode ) ; if ( GET_CODE ( imm ) == SYMBOL_REF || GET_CODE ( imm ) == LABEL_REF || GET_CODE ( imm ) == CONST ) { rtx mem , base , offset ; enum aarch64_symbol_type sty ; split_const ( imm , & base , & offset ) ; sty = aarch64_classify_symbol ( base , offset ) ; switch ( sty ) { case SYMBOL_FORCE_TO_MEM : if ( offset != const0_rtx && targetm . cannot_force_const_mem ( mode , imm ) ) { gcc_assert ( can_create_pseudo_p ( ) ) ; base = aarch64_force_temporary ( mode , dest , base ) ; base = aarch64_add_offset ( mode , NULL , base , INTVAL ( offset ) ) ; aarch64_emit_move ( dest , base ) ; return ; } mem = force_const_mem ( ptr_mode , imm ) ; gcc_assert ( mem ) ; if ( aarch64_nopcrelative_literal_loads ) { gcc_assert ( can_create_pseudo_p ( ) ) ; base = gen_reg_rtx ( ptr_mode ) ; aarch64_expand_mov_immediate ( base , XEXP ( mem , 0 ) ) ; mem = gen_rtx_MEM ( ptr_mode , base ) ; } if ( mode != ptr_mode ) mem = gen_rtx_ZERO_EXTEND ( mode , mem ) ; emit_insn ( gen_rtx_SET ( dest , mem ) ) ; return ; case SYMBOL_SMALL_TLSGD : case SYMBOL_SMALL_TLSDESC : case SYMBOL_SMALL_TLSIE : case SYMBOL_SMALL_GOT_28K : case SYMBOL_SMALL_GOT_4G : case SYMBOL_TINY_GOT : case SYMBOL_TINY_TLSIE : if ( offset != const0_rtx ) { gcc_assert ( can_create_pseudo_p ( ) ) ; base = aarch64_force_temporary ( mode , dest , base ) ; base = aarch64_add_offset ( mode , NULL , base , INTVAL ( offset ) ) ; aarch64_emit_move ( dest , base ) ; return ; } case SYMBOL_SMALL_ABSOLUTE : case SYMBOL_TINY_ABSOLUTE : case SYMBOL_TLSLE12 : case SYMBOL_TLSLE24 : case SYMBOL_TLSLE32 : case SYMBOL_TLSLE48 : aarch64_load_symref_appropriately ( dest , imm , sty ) ; return ; default : gcc_unreachable ( ) ; } } if ( ! CONST_INT_P ( imm ) ) { if ( GET_CODE ( imm ) == HIGH ) emit_insn ( gen_rtx_SET ( dest , imm ) ) ; else { rtx mem = force_const_mem ( mode , imm ) ; gcc_assert ( mem ) ; emit_insn ( gen_rtx_SET ( dest , mem ) ) ; } return ; } aarch64_internal_mov_immediate ( dest , imm , true , GET_MODE ( dest ) ) ; } </s>

Set DEST to immediate IMM . For SVE vector modes , GEN_VEC_DUPLICATE is a pattern that can be used to set DEST to a replicated scalar element .


<s> void aarch64_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 ; rtx any_const = NULL_RTX ; rtx v0 = XVECEXP ( vals , 0 , 0 ) ; bool all_same = true ; for ( int i = 0 ; i < n_elts ; ++ i ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( ! ( CONST_INT_P ( x ) || CONST_DOUBLE_P ( x ) ) ) ++ n_var ; else any_const = x ; all_same &= rtx_equal_p ( x , v0 ) ; } if ( n_var == 0 ) { rtx constant = aarch64_simd_make_constant ( vals ) ; if ( constant != NULL_RTX ) { emit_move_insn ( target , constant ) ; return ; } } if ( all_same ) { rtx x = copy_to_mode_reg ( inner_mode , v0 ) ; aarch64_emit_move ( target , gen_rtx_VEC_DUPLICATE ( mode , x ) ) ; return ; } if ( n_var != n_elts ) { rtx copy = copy_rtx ( vals ) ; for ( int i = 0 ; i < n_elts ; i ++ ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( CONST_INT_P ( x ) || CONST_DOUBLE_P ( x ) ) continue ; rtx subst = any_const ; for ( int bit = n_elts / 2 ; bit > 0 ; bit /= 2 ) { rtx test = XVECEXP ( copy , 0 , i ^ bit ) ; if ( CONST_INT_P ( test ) || CONST_DOUBLE_P ( test ) ) { subst = test ; break ; } } XVECEXP ( copy , 0 , i ) = subst ; } aarch64_expand_vector_init ( target , copy ) ; } enum insn_code icode = optab_handler ( vec_set_optab , mode ) ; gcc_assert ( icode != CODE_FOR_nothing ) ; for ( int i = 0 ; i < n_elts ; i ++ ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( CONST_INT_P ( x ) || CONST_DOUBLE_P ( x ) ) continue ; x = copy_to_mode_reg ( inner_mode , x ) ; emit_insn ( GEN_FCN ( icode ) ( target , x , GEN_INT ( i ) ) ) ; } } </s>

Expand a vector initialisation sequence , such that TARGET is initialised to contain VALS .


<s> static bool aarch64_extr_rtx_p ( rtx x , rtx * res_op0 , rtx * res_op1 ) { rtx op0 , op1 ; machine_mode mode = GET_MODE ( x ) ; * res_op0 = NULL_RTX ; * res_op1 = NULL_RTX ; if ( GET_CODE ( x ) != IOR ) return false ; op0 = XEXP ( x , 0 ) ; op1 = XEXP ( x , 1 ) ; if ( ( GET_CODE ( op0 ) == ASHIFT && GET_CODE ( op1 ) == LSHIFTRT ) || ( GET_CODE ( op1 ) == ASHIFT && GET_CODE ( op0 ) == LSHIFTRT ) ) { if ( GET_CODE ( op1 ) == ASHIFT ) std :: swap ( op0 , op1 ) ; if ( ! CONST_INT_P ( XEXP ( op0 , 1 ) ) || ! CONST_INT_P ( XEXP ( op1 , 1 ) ) ) return false ; unsigned HOST_WIDE_INT shft_amnt_0 = UINTVAL ( XEXP ( op0 , 1 ) ) ; unsigned HOST_WIDE_INT shft_amnt_1 = UINTVAL ( XEXP ( op1 , 1 ) ) ; if ( shft_amnt_0 < GET_MODE_BITSIZE ( mode ) && shft_amnt_0 + shft_amnt_1 == GET_MODE_BITSIZE ( mode ) ) { * res_op0 = XEXP ( op0 , 0 ) ; * res_op1 = XEXP ( op1 , 0 ) ; return true ; } } return false ; } </s>

Return true iff X is an rtx that will match an extr instruction i.e . as described in the * extr < mode > 5_insn family of patterns . OP0 and OP1 will be set to the operands of the shifts involved on success and will be NULL_RTX otherwise .


<s> bool aarch64_float_const_representable_p ( rtx x ) { int point_pos = 2 * HOST_BITS_PER_WIDE_INT - 1 ; int exponent ; unsigned HOST_WIDE_INT mantissa , mask ; REAL_VALUE_TYPE r , m ; bool fail ; if ( ! CONST_DOUBLE_P ( x ) ) return false ; if ( GET_MODE ( x ) == VOIDmode || GET_MODE ( x ) == HFmode ) return false ; r = * CONST_DOUBLE_REAL_VALUE ( x ) ; if ( REAL_VALUE_ISINF ( r ) || REAL_VALUE_ISNAN ( r ) || REAL_VALUE_MINUS_ZERO ( r ) ) return false ; 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 ) ; if ( w . elt ( 0 ) != 0 ) return false ; mantissa = w . elt ( 1 ) ; point_pos -= HOST_BITS_PER_WIDE_INT ; mask = ( ( unsigned HOST_WIDE_INT ) 1 << ( point_pos - 5 ) ) - 1 ; if ( ( mantissa & mask ) != 0 ) return false ; mantissa >>= point_pos - 5 ; if ( mantissa == 0 ) return false ; mantissa &= ~ ( 1 << 4 ) ; gcc_assert ( mantissa <= 15 ) ; exponent = 5 - exponent ; return ( exponent >= 0 && exponent <= 7 ) ; } </s>

Return true iff X can be represented by a quarter-precision floating point immediate operand X . Note , we can not represent 0.0 .


<s> void aarch64_gen_atomic_cas ( rtx rval , rtx mem , rtx expected , rtx desired , rtx model ) { rtx ( * gen ) ( rtx , rtx , rtx , rtx ) ; machine_mode mode ; mode = GET_MODE ( mem ) ; switch ( mode ) { case QImode : gen = gen_aarch64_atomic_casqi ; break ; case HImode : gen = gen_aarch64_atomic_cashi ; break ; case SImode : gen = gen_aarch64_atomic_cassi ; break ; case DImode : gen = gen_aarch64_atomic_casdi ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen_rtx_SET ( rval , expected ) ) ; emit_insn ( gen ( rval , mem , desired , model ) ) ; aarch64_gen_compare_reg ( EQ , rval , expected ) ; } </s>

Emit an atomic compare-and-swap operation . RVAL is the destination register for the data in memory . EXPECTED is the value expected to be in memory . DESIRED is the value to store to memory . MEM is the memory location . MODEL is the memory ordering to use .


<s> void aarch64_gen_atomic_ldop ( enum rtx_code code , rtx out_data , rtx out_result , rtx mem , rtx value , rtx model_rtx ) { machine_mode mode = GET_MODE ( mem ) ; machine_mode wmode = ( mode == DImode ? DImode : SImode ) ; const bool short_mode = ( mode < SImode ) ; aarch64_atomic_load_op_code ldop_code ; rtx src ; rtx x ; if ( out_data ) out_data = gen_lowpart ( mode , out_data ) ; if ( out_result ) out_result = gen_lowpart ( mode , out_result ) ; if ( ! register_operand ( value , mode ) || code == AND || code == MINUS ) { src = out_result ? out_result : out_data ; emit_move_insn ( src , gen_lowpart ( mode , value ) ) ; } else src = value ; gcc_assert ( register_operand ( src , mode ) ) ; switch ( code ) { case SET : aarch64_emit_atomic_swap ( mode , out_data , src , mem , model_rtx ) ; return ; case MINUS : { rtx neg_src ; if ( short_mode ) src = gen_lowpart ( wmode , src ) ; neg_src = gen_rtx_NEG ( wmode , src ) ; emit_insn ( gen_rtx_SET ( src , neg_src ) ) ; if ( short_mode ) src = gen_lowpart ( mode , src ) ; } case PLUS : ldop_code = AARCH64_LDOP_PLUS ; break ; case IOR : ldop_code = AARCH64_LDOP_OR ; break ; case XOR : ldop_code = AARCH64_LDOP_XOR ; break ; case AND : { rtx not_src ; if ( short_mode ) src = gen_lowpart ( wmode , src ) ; not_src = gen_rtx_NOT ( wmode , src ) ; emit_insn ( gen_rtx_SET ( src , not_src ) ) ; if ( short_mode ) src = gen_lowpart ( mode , src ) ; } ldop_code = AARCH64_LDOP_BIC ; break ; default : gcc_unreachable ( ) ; } aarch64_emit_atomic_load_op ( ldop_code , mode , out_data , src , mem , model_rtx ) ; if ( ! out_result ) return ; if ( short_mode ) { src = gen_lowpart ( wmode , src ) ; out_data = gen_lowpart ( wmode , out_data ) ; out_result = gen_lowpart ( wmode , out_result ) ; } x = NULL_RTX ; switch ( code ) { case MINUS : case PLUS : x = gen_rtx_PLUS ( wmode , out_data , src ) ; break ; case IOR : x = gen_rtx_IOR ( wmode , out_data , src ) ; break ; case XOR : x = gen_rtx_XOR ( wmode , out_data , src ) ; break ; case AND : aarch64_emit_bic ( wmode , out_result , out_data , src , 0 ) ; return ; default : gcc_unreachable ( ) ; } emit_set_insn ( out_result , x ) ; return ; } </s>

Emit an atomic load+operate . CODE is the operation . OUT_DATA is the location to store the data read from memory . OUT_RESULT is the location to store the result of the operation . MEM is the memory location to read and modify . MODEL_RTX is the memory ordering to use . VALUE is the second operand for the operation . Either OUT_DATA or OUT_RESULT , but not both , can be NULL .


"missing architecture name in 'arch' target %s"

"unknown value %qs for 'arch' target %s"

"invalid feature modifier %qs for 'arch' target %s"

Handle the ARCH_STR argument to the arch= target attribute . PRAGMA_OR_ATTR is used in potential error messages .


"invalid feature modifier %qs for 'cpu' target %s"

Handle the argument CPU_STR to the cpu= target attribute . PRAGMA_OR_ATTR is used in potential error messages .


"missing feature modifier in target %s %qs"

"invalid feature modifier in target %s %qs"

Parse an architecture extensions target attribute string specified in STR . For example `` +fp+nosimd '' . Show any errors if needed . Return TRUE if successful . Update aarch64_isa_flags to reflect the ISA features modified . PRAGMA_OR_ATTR is used in potential error messages .


"unknown value %qs for 'tune' target %s"

Handle the argument STR to the tune= target attribute . PRAGMA_OR_ATTR is used in potential error messages .


<s> static bool aarch64_if_then_else_costs ( rtx op0 , rtx op1 , rtx op2 , int * cost , bool speed ) { rtx inner ; rtx comparator ; enum rtx_code cmpcode ; if ( COMPARISON_P ( op0 ) ) { inner = XEXP ( op0 , 0 ) ; comparator = XEXP ( op0 , 1 ) ; cmpcode = GET_CODE ( op0 ) ; } else { inner = op0 ; comparator = const0_rtx ; cmpcode = NE ; } if ( GET_CODE ( op1 ) == PC || GET_CODE ( op2 ) == PC ) { if ( GET_MODE_CLASS ( GET_MODE ( inner ) ) == MODE_CC ) return true ; else { if ( cmpcode == NE || cmpcode == EQ ) { if ( comparator == const0_rtx ) { if ( GET_CODE ( inner ) == ZERO_EXTRACT ) * cost += rtx_cost ( XEXP ( inner , 0 ) , VOIDmode , ZERO_EXTRACT , 0 , speed ) ; else * cost += rtx_cost ( inner , VOIDmode , cmpcode , 0 , speed ) ; return true ; } } else if ( cmpcode == LT || cmpcode == GE ) { if ( comparator == const0_rtx ) return true ; } } } else if ( GET_MODE_CLASS ( GET_MODE ( inner ) ) == MODE_CC ) { if ( GET_CODE ( op1 ) == COMPARE ) { if ( XEXP ( op1 , 1 ) == const0_rtx ) * cost += 1 ; if ( speed ) { machine_mode mode = GET_MODE ( XEXP ( op1 , 0 ) ) ; const struct cpu_cost_table * extra_cost = aarch64_tune_params . insn_extra_cost ; if ( GET_MODE_CLASS ( mode ) == MODE_INT ) * cost += extra_cost -> alu . arith ; else * cost += extra_cost -> fp [ mode == DFmode ] . compare ; } return true ; } if ( GET_CODE ( op1 ) == NEG || GET_CODE ( op1 ) == NOT || ( GET_CODE ( op1 ) == PLUS && XEXP ( op1 , 1 ) == const1_rtx ) ) op1 = XEXP ( op1 , 0 ) ; else if ( GET_CODE ( op1 ) == ZERO_EXTEND && GET_CODE ( op2 ) == ZERO_EXTEND ) { op1 = XEXP ( op1 , 0 ) ; op2 = XEXP ( op2 , 0 ) ; } * cost += rtx_cost ( op1 , VOIDmode , IF_THEN_ELSE , 1 , speed ) ; * cost += rtx_cost ( op2 , VOIDmode , IF_THEN_ELSE , 2 , speed ) ; return true ; } return false ; } </s>

Calculate the cost of calculating ( if_then_else ( OP0 ) ( OP1 ) ( OP2 ) ) , storing it in * COST . Result is true if the total cost of the operation has now been calculated .


<s> static reg_class_t aarch64_ira_change_pseudo_allocno_class ( int regno , reg_class_t allocno_class , reg_class_t best_class ) { enum machine_mode mode ; if ( allocno_class != ALL_REGS ) return allocno_class ; if ( best_class != ALL_REGS ) return best_class ; mode = PSEUDO_REGNO_MODE ( regno ) ; return FLOAT_MODE_P ( mode ) || VECTOR_MODE_P ( mode ) ? FP_REGS : GENERAL_REGS ; } </s>

Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS . The register allocator chooses ALL_REGS if FP_REGS and GENERAL_REGS have the same cost even if ALL_REGS has a much larger cost . ALL_REGS is also used if the cost of both FP_REGS and GENERAL_REGS is lower than the memory cost ( in this case the best class is the lowest cost one ) . Using ALL_REGS irrespectively of its cost results in bad allocations with many redundant int < - > FP moves which are expensive on various cores . To avoid this we do n't allow ALL_REGS as the allocno class , but force a decision between FP_REGS and GENERAL_REGS . We use the allocno class if it is n't ALL_REGS . Similarly , use the best class if it is n't ALL_REGS . Otherwise set the allocno class depending on the mode . The result of this is that it is no longer inefficient to have a higher memory move cost than the register move cost .


<s> bool aarch64_madd_needs_nop ( rtx_insn * insn ) { enum attr_type attr_type ; rtx_insn * prev ; rtx body ; if ( ! TARGET_FIX_ERR_A53_835769 ) return false ; if ( ! INSN_P ( insn ) || recog_memoized ( insn ) < 0 ) return false ; attr_type = get_attr_type ( insn ) ; if ( ! is_madd_op ( attr_type ) ) return false ; prev = aarch64_prev_real_insn ( insn ) ; extract_constrain_insn_cached ( insn ) ; if ( ! prev || ! has_memory_op ( prev ) ) return false ; body = single_set ( prev ) ; if ( GET_MODE ( recog_data . operand [ 0 ] ) == DImode && ( ! body || ! dep_between_memop_and_curr ( body ) ) ) return true ; return false ; } </s>

When working around the Cortex-A53 erratum 835769 , given rtx_insn INSN , return true if it is a 64-bit multiply-accumulate instruction and has a preceding memory instruction such that a NOP should be inserted between them .


<s> static const char * aarch64_mangle_type ( const_tree type ) { if ( lang_hooks . types_compatible_p ( CONST_CAST_TREE ( type ) , va_list_type ) ) return "St9__va_list" ; if ( TREE_CODE ( type ) == REAL_TYPE && TYPE_PRECISION ( type ) == 16 ) return "Dh" ; if ( TYPE_NAME ( type ) != NULL ) return aarch64_mangle_builtin_type ( type ) ; return NULL ; } </s>


<s> static bool aarch64_mode_valid_for_sched_fusion_p ( machine_mode mode ) { return mode == SImode || mode == DImode || mode == SFmode || mode == DFmode || ( aarch64_vector_mode_supported_p ( mode ) && GET_MODE_SIZE ( mode ) == 8 ) ; } </s>

Return true if MODE is one of the modes for which we support LDP/STP operations .


<s> static bool aarch64_optab_supported_p ( int op , machine_mode , machine_mode , optimization_type opt_type ) { switch ( op ) { case rsqrt_optab : return opt_type == OPTIMIZE_FOR_SPEED && use_rsqrt_p ( ) ; default : return true ; } } </s>

Implement the TARGET_OPTAB_SUPPORTED_P hook .


aarch64
"%*sselected tune = %s\n"
""
"%*sselected arch = %s%s\n"
""


<s> static void aarch64_option_restore ( struct gcc_options * opts , struct cl_target_option * ptr ) { opts -> x_explicit_tune_core = ptr -> x_explicit_tune_core ; selected_tune = aarch64_get_tune_cpu ( ptr -> x_explicit_tune_core ) ; opts -> x_explicit_arch = ptr -> x_explicit_arch ; selected_arch = aarch64_get_arch ( ptr -> x_explicit_arch ) ; opts -> x_aarch64_override_tune_string = ptr -> x_aarch64_override_tune_string ; aarch64_override_options_internal ( opts ) ; } </s>

Implements TARGET_OPTION_RESTORE . Restore the backend codegen decisions using the information saved in PTR .


<s> static void aarch64_option_save ( struct cl_target_option * ptr , struct gcc_options * opts ) { ptr -> x_aarch64_override_tune_string = opts -> x_aarch64_override_tune_string ; } </s>


<s> static bool aarch64_option_valid_attribute_p ( tree fndecl , tree , tree args , int ) { struct cl_target_option cur_target ; bool ret ; tree old_optimize ; tree new_target , new_optimize ; tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) ; if ( ! existing_target && args == current_target_pragma ) { DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) = target_option_current_node ; return true ; } tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION ( fndecl ) ; old_optimize = build_optimization_node ( & global_options ) ; func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION ( fndecl ) ; if ( func_optimize && func_optimize != old_optimize ) cl_optimization_restore ( & global_options , TREE_OPTIMIZATION ( func_optimize ) ) ; cl_target_option_save ( & cur_target , & global_options ) ; if ( existing_target ) { struct cl_target_option * existing_options = TREE_TARGET_OPTION ( existing_target ) ; if ( existing_options ) cl_target_option_restore ( & global_options , existing_options ) ; } else cl_target_option_restore ( & global_options , TREE_TARGET_OPTION ( target_option_current_node ) ) ; ret = aarch64_process_target_attr ( args , "attribute" ) ; if ( ret ) { aarch64_override_options_internal ( & global_options ) ; if ( TARGET_SIMD ) { tree saved_current_target_pragma = current_target_pragma ; current_target_pragma = NULL ; aarch64_init_simd_builtins ( ) ; current_target_pragma = saved_current_target_pragma ; } new_target = build_target_option_node ( & global_options ) ; } else new_target = NULL ; new_optimize = build_optimization_node ( & global_options ) ; if ( fndecl && ret ) { DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) = new_target ; if ( old_optimize != new_optimize ) DECL_FUNCTION_SPECIFIC_OPTIMIZATION ( fndecl ) = new_optimize ; } cl_target_option_restore ( & global_options , & cur_target ) ; if ( old_optimize != new_optimize ) cl_optimization_restore ( & global_options , TREE_OPTIMIZATION ( old_optimize ) ) ; return ret ; } </s>

Implement TARGET_OPTION_VALID_ATTRIBUTE_P . This is used to process attribute ( ( target ( `` ... '' ) ) ) .


<s>
const
char
*
aarch64_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\txzr, [%0]"
,
xops
)
;
xops
[
1
]
=
reg2
;
output_asm_insn
(
"cmp\t%0, %1"
,
xops
)
;
fputs
(
"\tb.ne\t"
,
asm_out_file
)
;
assemble_name_raw
(
asm_out_file
,
loop_lab
)
;
fputc
(
'\n'
,
asm_out_file
)
;
return
""
;
}
</s>

Probe a range of stack addresses from REG1 to REG2 inclusive . These are absolute addresses .


<s>
char
*
aarch64_output_simd_mov_immediate
(
rtx
const_vector
,
machine_mode
mode
,
unsigned
width
)
{
bool
is_valid
;
static
char
templ
[
40
]
;
const
char
*
mnemonic
;
const
char
*
shift_op
;
unsigned
int
lane_count
=
0
;
char
element_char
;
struct
simd_immediate_info
info
=
{
NULL_RTX
,
0
,
0
,
false
,
false
}
;
is_valid
=
aarch64_simd_valid_immediate
(
const_vector
,
mode
,
false
,
&
info
)
;
gcc_assert
(
is_valid
)
;
element_char
=
sizetochar
(
info
.
element_width
)
;
lane_count
=
width
/
info
.
element_width
;
mode
=
GET_MODE_INNER
(
mode
)
;
if
(
GET_MODE_CLASS
(
mode
)
==
MODE_FLOAT
)
{
gcc_assert
(
info
.
shift
==
0
&&
!
info
.
mvn
)
;
if
(
aarch64_float_const_zero_rtx_p
(
info
.
value
)
)
info
.
value
=
GEN_INT
(
0
)
;
else
{
char
float_buf
[
buf_size
]
=
{
'\0'
}
;
real_to_decimal_for_mode
(
float_buf
,
CONST_DOUBLE_REAL_VALUE
(
info
.
value
)
,
buf_size
,
buf_size
,
1
,
mode
)
;
if
(
lane_count
==
1
)
snprintf
(
templ
,
sizeof
(
templ
)
,
"fmov\t%%d0, %s"
,
float_buf
)
;
else
snprintf
(
templ
,
sizeof
(
templ
)
,
"fmov\t%%0.%d%c, %s"
,
lane_count
,
element_char
,
float_buf
)
;
return
templ
;
}
}
mnemonic
=
info
.
mvn
"mvni"
:
"movi"
;
shift_op
=
info
.
msl
"msl"
:
"lsl"
;
gcc_assert
(
CONST_INT_P
(
info
.
value
)
)
;
if
(
lane_count
==
1
)
snprintf
(
templ
,
sizeof
(
templ
)
,
"%s\t%%d0, "
HOST_WIDE_INT_PRINT_HEX
,
mnemonic
,
UINTVAL
(
info
.
value
)
)
;
else
if
(
info
.
shift
)
snprintf
(
templ
,
sizeof
(
templ
)
,
"%s\t%%0.%d%c, "
HOST_WIDE_INT_PRINT_HEX
", %s %d"
,
mnemonic
,
lane_count
,
element_char
,
UINTVAL
(
info
.
value
)
,
shift_op
,
info
.
shift
)
;
else
snprintf
(
templ
,
sizeof
(
templ
)
,
"%s\t%%0.%d%c, "
HOST_WIDE_INT_PRINT_HEX
,
mnemonic
,
lane_count
,
element_char
,
UINTVAL
(
info
.
value
)
)
;
return
templ
;
}
</s>

Returns the string with the instruction for AdvSIMD MOVI , MVNI , ORR or BIC immediate with a CONST_VECTOR of MODE and WIDTH . WHICH selects whether to output MOVI/MVNI , ORR or BIC immediate .


"switch -mcpu=%s conflicts with -march=%s switch"

"Assembler does not support -mabi=ilp32"


<s> void aarch64_override_options_internal ( struct gcc_options * opts ) { aarch64_tune_flags = selected_tune -> flags ; aarch64_tune = selected_tune -> sched_core ; aarch64_tune_params = * ( selected_tune -> tune ) ; aarch64_architecture_version = selected_arch -> architecture_version ; if ( opts -> x_aarch64_override_tune_string ) aarch64_parse_override_string ( opts -> x_aarch64_override_tune_string , & aarch64_tune_params ) ; if ( opts -> x_flag_strict_volatile_bitfields < 0 && abi_version_at_least ( 2 ) ) opts -> x_flag_strict_volatile_bitfields = 1 ; initialize_aarch64_code_model ( opts ) ; initialize_aarch64_tls_size ( opts ) ; int queue_depth = 0 ; switch ( aarch64_tune_params . autoprefetcher_model ) { case tune_params :: AUTOPREFETCHER_OFF : queue_depth = - 1 ; break ; case tune_params :: AUTOPREFETCHER_WEAK : queue_depth = 0 ; break ; case tune_params :: AUTOPREFETCHER_STRONG : queue_depth = max_insn_queue_index + 1 ; break ; default : gcc_unreachable ( ) ; } maybe_set_param_value ( PARAM_SCHED_AUTOPREF_QUEUE_DEPTH , queue_depth , opts -> x_param_values , global_options_set . x_param_values ) ; if ( selected_cpu -> tune -> cache_line_size != 0 ) maybe_set_param_value ( PARAM_L1_CACHE_LINE_SIZE , selected_cpu -> tune -> cache_line_size , opts -> x_param_values , global_options_set . x_param_values ) ; aarch64_override_options_after_change_1 ( opts ) ; } </s>

'Unpack ' up the internal tuning structs and update the options in OPTS . The caller must have set up selected_tune and selected_arch as all the other target-specific codegen decisions are derived from them .


<s> static enum aarch64_parse_opt_result aarch64_parse_arch ( const char * to_parse , const struct processor * * res , unsigned long * isa_flags ) { char * ext ; const struct processor * arch ; char * str = ( char * ) alloca ( strlen ( to_parse ) + 1 ) ; size_t len ; strcpy ( str , to_parse ) ; ext = strchr ( str , '+' ) ; if ( ext != NULL ) len = ext - str ; else len = strlen ( str ) ; if ( len == 0 ) return AARCH64_PARSE_MISSING_ARG ; for ( arch = all_architectures ; arch -> name != NULL ; arch ++ ) { if ( strlen ( arch -> name ) == len && strncmp ( arch -> name , str , len ) == 0 ) { unsigned long isa_temp = arch -> flags ; if ( ext != NULL ) { enum aarch64_parse_opt_result ext_res = aarch64_parse_extension ( ext , & isa_temp ) ; if ( ext_res != AARCH64_PARSE_OK ) return ext_res ; } * res = arch ; * isa_flags = isa_temp ; return AARCH64_PARSE_OK ; } } return AARCH64_PARSE_INVALID_ARG ; } </s>

Parse the TO_PARSE string and put the architecture struct that it selects into RES and the architectural features into ISA_FLAGS . Return an aarch64_parse_opt_result describing the parse result . If there is an error parsing , RES and ISA_FLAGS are left unchanged .


<s> static enum aarch64_parse_opt_result aarch64_parse_cpu ( const char * to_parse , const struct processor * * res , unsigned long * isa_flags ) { char * ext ; const struct processor * cpu ; char * str = ( char * ) alloca ( strlen ( to_parse ) + 1 ) ; size_t len ; strcpy ( str , to_parse ) ; ext = strchr ( str , '+' ) ; if ( ext != NULL ) len = ext - str ; else len = strlen ( str ) ; if ( len == 0 ) return AARCH64_PARSE_MISSING_ARG ; for ( cpu = all_cores ; cpu -> name != NULL ; cpu ++ ) { if ( strlen ( cpu -> name ) == len && strncmp ( cpu -> name , str , len ) == 0 ) { unsigned long isa_temp = cpu -> flags ; if ( ext != NULL ) { enum aarch64_parse_opt_result ext_res = aarch64_parse_extension ( ext , & isa_temp ) ; if ( ext_res != AARCH64_PARSE_OK ) return ext_res ; } * res = cpu ; * isa_flags = isa_temp ; return AARCH64_PARSE_OK ; } } return AARCH64_PARSE_INVALID_ARG ; } </s>

Parse the TO_PARSE string and put the result tuning in RES and the architecture flags in ISA_FLAGS . Return an aarch64_parse_opt_result describing the parse result . If there is an error parsing , RES and ISA_FLAGS are left unchanged .


"unknown flag passed in -moverride=%s (%s)"

Parse TOKEN , which has length LENGTH to see if it is an option described in FLAG . If it is , return the index bit for that fusion type . If not , error ( printing OPTION_NAME ) and return zero .


<s> static enum aarch64_parse_opt_result aarch64_parse_tune ( const char * to_parse , const struct processor * * res ) { const struct processor * cpu ; char * str = ( char * ) alloca ( strlen ( to_parse ) + 1 ) ; strcpy ( str , to_parse ) ; for ( cpu = all_cores ; cpu -> name != NULL ; cpu ++ ) { if ( strcmp ( cpu -> name , str ) == 0 ) { * res = cpu ; return AARCH64_PARSE_OK ; } } return AARCH64_PARSE_INVALID_ARG ; } </s>


"target %s %qs does not accept an argument"

"target %s %qs does not allow a negated form"

Parse ARG_STR which contains the definition of one target attribute . Show appropriate errors if any or return true if the attribute is valid . PRAGMA_OR_ATTR holds the string to use in error messages about whether we 're processing a target attribute or pragma .


<s>
bool
aarch64_process_target_attr
(
tree
args
,
const
char
*
pragma_or_attr
)
{
if
(
TREE_CODE
(
args
)
==
TREE_LIST
)
{
do
{
tree
head
=
TREE_VALUE
(
args
)
;
if
(
head
)
{
if
(
!
aarch64_process_target_attr
(
head
,
pragma_or_attr
)
)
return
false
;
}
args
=
TREE_CHAIN
(
args
)
;
}
while
(
args
)
;
return
true
;
}
gcc_assert
(
TREE_CODE
(
args
)
==
STRING_CST
)
;
size_t
len
=
strlen
(
TREE_STRING_POINTER
(
args
)
)
;
char
*
str_to_check
=
(
char
*
)
alloca
(
len
+
1
)
;
strcpy
(
str_to_check
,
TREE_STRING_POINTER
(
args
)
)
;
if
(
len
==
0
)
{
error
(
"malformed target %s value"
,
pragma_or_attr
)
;
return
false
;
}
unsigned
int
num_commas
=
num_occurences_in_str
(
','
,
str_to_check
)
;
char
*
token
=
strtok
(
str_to_check
,
","
)
;
unsigned
int
num_attrs
=
0
;
while
(
token
)
{
num_attrs
++
;
if
(
!
aarch64_process_one_target_attr
(
token
,
pragma_or_attr
)
)
{
error
(
"target %s %qs is invalid"
,
pragma_or_attr
,
token
)
;
return
false
;
}
token
=
strtok
(
,
","
)
;
}
if
(
num_attrs
!=
num_commas
+
1
)
{
error
(
"malformed target %s list %qs"
,
pragma_or_attr
,
TREE_STRING_POINTER
(
args
)
)
;
return
false
;
}
return
true
;
}
</s>

Parse the tree in ARGS that contains the target attribute information and update the global target options space . PRAGMA_OR_ATTR is a string to be used in error messages , specifying whether this is processing a target attribute or a target pragma .


<s> static tree aarch64_promoted_type ( const_tree t ) { if ( SCALAR_FLOAT_TYPE_P ( t ) && TYPE_PRECISION ( t ) == 16 ) return float_type_node ; return NULL_TREE ; } </s>

Implement TARGET_PROMOTED_TYPE to promote __fp16 to float .


<s> static int aarch64_reassociation_width ( unsigned opc ATTRIBUTE_UNUSED , enum machine_mode mode ) { if ( VECTOR_MODE_P ( mode ) ) return aarch64_tune_params . vec_reassoc_width ; if ( INTEGRAL_MODE_P ( mode ) ) return aarch64_tune_params . int_reassoc_width ; if ( FLOAT_MODE_P ( mode ) ) return aarch64_tune_params . fp_reassoc_width ; return 1 ; } </s>

Return the reassociation width of treeop OPC with mode MODE .


<s> static bool aarch64_rtx_arith_op_extract_p ( rtx x , machine_mode mode ) { if ( GET_CODE ( x ) == SIGN_EXTRACT || GET_CODE ( x ) == ZERO_EXTRACT ) { rtx op0 = XEXP ( x , 0 ) ; rtx op1 = XEXP ( x , 1 ) ; rtx op2 = XEXP ( x , 2 ) ; if ( GET_CODE ( op0 ) == MULT && CONST_INT_P ( op1 ) && op2 == const0_rtx && CONST_INT_P ( XEXP ( op0 , 1 ) ) && aarch64_is_extend_from_extract ( mode , XEXP ( op0 , 1 ) , op1 ) ) { return true ; } } else if ( GET_CODE ( x ) == SIGN_EXTEND || GET_CODE ( x ) == ZERO_EXTEND ) return REG_P ( XEXP ( x , 0 ) ) ; return false ; } </s>

Return true if X is a zero or sign extract usable in an ADD or SUB ( extended register ) instruction .


<s>
static
bool
aarch64_rtx_costs_wrapper
(
rtx
x
,
machine_mode
mode
,
int
outer
,
int
param
,
int
*
cost
,
bool
speed
)
{
bool
result
=
aarch64_rtx_costs
(
x
,
mode
,
outer
,
param
,
cost
,
speed
)
;
if
(
dump_file
&&
(
dump_flags
&
TDF_DETAILS
)
)
{
print_rtl_single
(
dump_file
,
x
)
;
fprintf
(
dump_file
,
"\n%s cost: %d (%s)\n"
,
speed
"Hot"
:
"Cold"
,
*
cost
,
result
"final"
:
"partial"
)
;
}
return
result
;
}
</s>

Wrapper around aarch64_rtx_costs , dumps the partial , or total cost calculated for X . This cost is stored in * COST . Returns true if the total cost of X was calculated .

aarch64
"\n%s cost: %d (%s)\n"
"Hot"
"Cold"
"final"
"partial"


<s> static void aarch64_setup_incoming_varargs ( cumulative_args_t cum_v , machine_mode mode , tree type , int * pretend_size ATTRIBUTE_UNUSED , int no_rtl ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; CUMULATIVE_ARGS local_cum ; int gr_saved , vr_saved ; local_cum = * cum ; aarch64_function_arg_advance ( pack_cumulative_args ( & local_cum ) , mode , type , true ) ; gr_saved = NUM_ARG_REGS - local_cum . aapcs_ncrn ; vr_saved = NUM_FP_ARG_REGS - local_cum . aapcs_nvrn ; if ( ! TARGET_FLOAT ) { gcc_assert ( local_cum . aapcs_nvrn == 0 ) ; vr_saved = 0 ; } if ( ! no_rtl ) { if ( gr_saved > 0 ) { rtx ptr , mem ; ptr = plus_constant ( Pmode , virtual_incoming_args_rtx , - gr_saved * UNITS_PER_WORD ) ; mem = gen_frame_mem ( BLKmode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; move_block_from_reg ( local_cum . aapcs_ncrn + R0_REGNUM , mem , gr_saved ) ; } if ( vr_saved > 0 ) { machine_mode mode = TImode ; int off , i ; off = - ROUND_UP ( gr_saved * UNITS_PER_WORD , STACK_BOUNDARY / BITS_PER_UNIT ) ; off -= vr_saved * UNITS_PER_VREG ; for ( i = local_cum . aapcs_nvrn ; i < NUM_FP_ARG_REGS ; ++ i ) { rtx ptr , mem ; ptr = plus_constant ( Pmode , virtual_incoming_args_rtx , off ) ; mem = gen_frame_mem ( mode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; aarch64_emit_move ( mem , gen_rtx_REG ( mode , V0_REGNUM + i ) ) ; off += UNITS_PER_VREG ; } } } cfun -> machine -> frame . saved_varargs_size = ( ROUND_UP ( gr_saved * UNITS_PER_WORD , STACK_BOUNDARY / BITS_PER_UNIT ) + vr_saved * UNITS_PER_VREG ) ; } </s>


<s> static bool aarch64_short_vector_p ( const_tree type , machine_mode mode ) { HOST_WIDE_INT size = - 1 ; if ( type && TREE_CODE ( type ) == VECTOR_TYPE ) size = int_size_in_bytes ( type ) ; else if ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT || GET_MODE_CLASS ( mode ) == MODE_VECTOR_FLOAT ) size = GET_MODE_SIZE ( mode ) ; return ( size == 8 || size == 16 ) ; } </s>

Return TRUE if the type , as described by TYPE and MODE , is a short vector type as described in AAPCS64 \S 4.1.2 . See the comment above aarch64_composite_type_p for the notes on MODE .


<s> static rtx aarch64_simd_dup_constant ( rtx vals ) { machine_mode mode = GET_MODE ( vals ) ; machine_mode inner_mode = GET_MODE_INNER ( mode ) ; rtx x ; if ( ! const_vec_duplicate_p ( vals , & x ) ) return NULL_RTX ; x = copy_to_mode_reg ( inner_mode , x ) ; return gen_rtx_VEC_DUPLICATE ( mode , x ) ; } </s>

If VALS is a vector constant that can be loaded into a register using DUP , generate instructions to do so and return an RTX to assign to the register . Otherwise return NULL_RTX .


<s> void aarch64_split_atomic_op ( enum rtx_code code , rtx old_out , rtx new_out , rtx mem , rtx value , rtx model_rtx , rtx cond ) { machine_mode mode = GET_MODE ( mem ) ; machine_mode wmode = ( mode == DImode ? DImode : SImode ) ; const enum memmodel model = memmodel_from_int ( INTVAL ( model_rtx ) ) ; const bool is_sync = is_mm_sync ( model ) ; rtx_code_label * label ; rtx x ; label = gen_label_rtx ( ) ; emit_label ( label ) ; if ( new_out ) new_out = gen_lowpart ( wmode , new_out ) ; if ( old_out ) old_out = gen_lowpart ( wmode , old_out ) ; else old_out = new_out ; value = simplify_gen_subreg ( wmode , value , mode , 0 ) ; if ( is_sync ) aarch64_emit_load_exclusive ( mode , old_out , mem , GEN_INT ( MEMMODEL_RELAXED ) ) ; else aarch64_emit_load_exclusive ( mode , old_out , mem , model_rtx ) ; switch ( code ) { case SET : new_out = value ; break ; case NOT : x = gen_rtx_AND ( wmode , old_out , value ) ; emit_insn ( gen_rtx_SET ( new_out , x ) ) ; x = gen_rtx_NOT ( wmode , new_out ) ; emit_insn ( gen_rtx_SET ( new_out , x ) ) ; break ; case MINUS : if ( CONST_INT_P ( value ) ) { value = GEN_INT ( - INTVAL ( value ) ) ; code = PLUS ; } default : x = gen_rtx_fmt_ee ( code , wmode , old_out , value ) ; emit_insn ( gen_rtx_SET ( new_out , x ) ) ; break ; } aarch64_emit_store_exclusive ( mode , cond , mem , gen_lowpart ( mode , new_out ) , model_rtx ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; if ( is_sync ) aarch64_emit_post_barrier ( model ) ; } </s>


<s> void aarch64_split_compare_and_swap ( rtx operands [ ] ) { rtx rval , mem , oldval , newval , scratch ; machine_mode mode ; bool is_weak ; rtx_code_label * label1 , * label2 ; rtx x , cond ; enum memmodel model ; rtx model_rtx ; rval = operands [ 0 ] ; mem = operands [ 1 ] ; oldval = operands [ 2 ] ; newval = operands [ 3 ] ; is_weak = ( operands [ 4 ] != const0_rtx ) ; model_rtx = operands [ 5 ] ; scratch = operands [ 7 ] ; mode = GET_MODE ( mem ) ; model = memmodel_from_int ( INTVAL ( model_rtx ) ) ; label1 = NULL ; if ( ! is_weak ) { label1 = gen_label_rtx ( ) ; emit_label ( label1 ) ; } label2 = gen_label_rtx ( ) ; if ( is_mm_sync ( model ) ) aarch64_emit_load_exclusive ( mode , rval , mem , GEN_INT ( MEMMODEL_RELAXED ) ) ; else aarch64_emit_load_exclusive ( mode , rval , mem , model_rtx ) ; cond = aarch64_gen_compare_reg ( NE , rval , oldval ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label2 ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; aarch64_emit_store_exclusive ( mode , scratch , mem , newval , model_rtx ) ; if ( ! is_weak ) { x = gen_rtx_NE ( VOIDmode , scratch , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label1 ) , pc_rtx ) ; aarch64_emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; } else { cond = gen_rtx_REG ( CCmode , CC_REGNUM ) ; x = gen_rtx_COMPARE ( CCmode , scratch , const0_rtx ) ; emit_insn ( gen_rtx_SET ( cond , x ) ) ; } emit_label ( label2 ) ; if ( is_mm_sync ( model ) ) aarch64_emit_post_barrier ( model ) ; } </s>


<s> void aarch64_split_simd_combine ( rtx dst , rtx src1 , rtx src2 ) { machine_mode src_mode = GET_MODE ( src1 ) ; machine_mode dst_mode = GET_MODE ( dst ) ; gcc_assert ( VECTOR_MODE_P ( dst_mode ) ) ; if ( REG_P ( dst ) && REG_P ( src1 ) && REG_P ( src2 ) ) { rtx ( * gen ) ( rtx , rtx , rtx ) ; switch ( src_mode ) { case V8QImode : gen = gen_aarch64_simd_combinev8qi ; break ; case V4HImode : gen = gen_aarch64_simd_combinev4hi ; break ; case V2SImode : gen = gen_aarch64_simd_combinev2si ; break ; case V4HFmode : gen = gen_aarch64_simd_combinev4hf ; break ; case V2SFmode : gen = gen_aarch64_simd_combinev2sf ; break ; case DImode : gen = gen_aarch64_simd_combinedi ; break ; case DFmode : gen = gen_aarch64_simd_combinedf ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , src1 , src2 ) ) ; return ; } } </s>


<s> void aarch64_split_simd_move ( rtx dst , rtx src ) { machine_mode src_mode = GET_MODE ( src ) ; machine_mode dst_mode = GET_MODE ( dst ) ; gcc_assert ( VECTOR_MODE_P ( dst_mode ) ) ; if ( REG_P ( dst ) && REG_P ( src ) ) { rtx ( * gen ) ( rtx , rtx ) ; gcc_assert ( VECTOR_MODE_P ( src_mode ) ) ; switch ( src_mode ) { case V16QImode : gen = gen_aarch64_split_simd_movv16qi ; break ; case V8HImode : gen = gen_aarch64_split_simd_movv8hi ; break ; case V4SImode : gen = gen_aarch64_split_simd_movv4si ; break ; case V2DImode : gen = gen_aarch64_split_simd_movv2di ; break ; case V8HFmode : gen = gen_aarch64_split_simd_movv8hf ; break ; case V4SFmode : gen = gen_aarch64_split_simd_movv4sf ; break ; case V2DFmode : gen = gen_aarch64_split_simd_movv2df ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( dst , src ) ) ; return ; } } </s>


Implements TARGET_ASM_FILE_START . Output the assembly header .


"invalid feature modifier in -march=%qs"

Validate a command-line -march option . Parse the arch and extensions ( if any ) specified in STR and throw errors if appropriate . Put the results , if they are valid , in RES and ISA_FLAGS . Return whether the option is valid .


<s>
static
bool
aarch64_validate_mcpu
(
const
char
*
str
,
const
struct
processor
*
*
res
,
unsigned
long
*
isa_flags
)
{
enum
aarch64_parse_opt_result
parse_res
=
aarch64_parse_cpu
(
str
,
res
,
isa_flags
)
;
if
(
parse_res
==
AARCH64_PARSE_OK
)
return
true
;
switch
(
parse_res
)
{
case
AARCH64_PARSE_MISSING_ARG
:
error
(
"missing cpu name in -mcpu=%qs"
,
str
)
;
break
;
case
AARCH64_PARSE_INVALID_ARG
:
error
(
"unknown value %qs for -mcpu"
,
str
)
;
break
;
case
AARCH64_PARSE_INVALID_FEATURE
:
error
(
"invalid feature modifier in -mcpu=%qs"
,
str
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
return
false
;
}
</s>

Validate a command-line -mcpu option . Parse the cpu and extensions ( if any ) specified in STR and throw errors if appropriate . Put the results if they are valid in RES and ISA_FLAGS . Return whether the option is valid .

aarch64
"missing cpu name in -mcpu=%qs"
"unknown value %qs for -mcpu"
"invalid feature modifier in -mcpu=%qs"


<s>
static
bool
aarch64_validate_mtune
(
const
char
*
str
,
const
struct
processor
*
*
res
)
{
enum
aarch64_parse_opt_result
parse_res
=
aarch64_parse_tune
(
str
,
res
)
;
if
(
parse_res
==
AARCH64_PARSE_OK
)
return
true
;
switch
(
parse_res
)
{
case
AARCH64_PARSE_MISSING_ARG
:
error
(
"missing cpu name in -mtune=%qs"
,
str
)
;
break
;
case
AARCH64_PARSE_INVALID_ARG
:
error
(
"unknown value %qs for -mtune"
,
str
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
return
false
;
}
</s>

Validate a command-line -mtune option . Parse the cpu specified in STR and throw errors if appropriate . Put the result , if it is valid , in RES . Return whether the option is valid .

aarch64
"missing cpu name in -mtune=%qs"
"unknown value %qs for -mtune"


<s> static bool aarch64_valid_floating_const ( machine_mode mode , rtx x ) { if ( ! CONST_DOUBLE_P ( x ) ) return false ; if ( aarch64_float_const_zero_rtx_p ( x ) ) return true ; if ( ! ( mode == SFmode || mode == DFmode ) ) return false ; return aarch64_float_const_representable_p ( x ) ; } </s>

Return true if X holds either a quarter-precision or floating-point +0.0 constant .


<s> static bool aarch64_vector_mode_supported_p ( machine_mode mode ) { if ( TARGET_SIMD && ( mode == V4SImode || mode == V8HImode || mode == V16QImode || mode == V2DImode || mode == V2SImode || mode == V4HImode || mode == V8QImode || mode == V2SFmode || mode == V4SFmode || mode == V2DFmode || mode == V4HFmode || mode == V8HFmode || mode == V1DFmode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


Return true iff x is a uniform vector of floating-point constants , and the constant can be represented in quarter-precision form . Note , as aarch64_float_const_representable rejects both +0.0 and -0.0 , we will also reject +0.0 and -0.0 .


<s> int aarch64_vec_fpconst_pow_of_2 ( rtx x ) { if ( GET_CODE ( x ) != CONST_VECTOR ) return - 1 ; if ( GET_MODE_CLASS ( GET_MODE ( x ) ) != MODE_VECTOR_FLOAT ) return - 1 ; int firstval = aarch64_fpconst_pow_of_2 ( CONST_VECTOR_ELT ( x , 0 ) ) ; if ( firstval <= 0 ) return - 1 ; for ( int i = 1 ; i < CONST_VECTOR_NUNITS ( x ) ; i ++ ) if ( aarch64_fpconst_pow_of_2 ( CONST_VECTOR_ELT ( x , i ) ) != firstval ) return - 1 ; return firstval ; } </s>

If X is a vector of equal CONST_DOUBLE values and that value is Y , return the aarch64_fpconst_pow_of_2 of Y . Otherwise return -1 .


<s> inline static rtx 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> rsqrte_type get_rsqrte_type ( machine_mode mode ) { switch ( mode ) { case DFmode : return gen_aarch64_rsqrte_df2 ; case SFmode : return gen_aarch64_rsqrte_sf2 ; case V2DFmode : return gen_aarch64_rsqrte_v2df2 ; case V2SFmode : return gen_aarch64_rsqrte_v2sf2 ; case V4SFmode : return gen_aarch64_rsqrte_v4sf2 ; default : gcc_unreachable ( ) ; } } </s>

Select reciprocal square root initial estimate insn depending on machine mode .


<s> rsqrts_type get_rsqrts_type ( machine_mode mode ) { switch ( mode ) { case DFmode : return gen_aarch64_rsqrts_df3 ; case SFmode : return gen_aarch64_rsqrts_sf3 ; case V2DFmode : return gen_aarch64_rsqrts_v2df3 ; case V2SFmode : return gen_aarch64_rsqrts_v2sf3 ; case V4SFmode : return gen_aarch64_rsqrts_v4sf3 ; default : gcc_unreachable ( ) ; } } </s>

Select reciprocal square root series step insn depending on machine mode .


<s>
static
void
initialize_aarch64_code_model
(
struct
gcc_options
*
opts
)
{
if
(
opts
->
x_flag_pic
)
{
switch
(
opts
->
x_aarch64_cmodel_var
)
{
case
AARCH64_CMODEL_TINY
:
aarch64_cmodel
=
AARCH64_CMODEL_TINY_PIC
;
break
;
case
AARCH64_CMODEL_SMALL
:
aarch64_cmodel
=
(
flag_pic
==
2
AARCH64_CMODEL_SMALL_PIC
:
AARCH64_CMODEL_SMALL_SPIC
)
;
aarch64_cmodel
=
AARCH64_CMODEL_SMALL_PIC
;
break
;
case
AARCH64_CMODEL_LARGE
:
sorry
(
"code model %qs with -f%s"
,
"large"
,
opts
->
x_flag_pic
>
1
"PIC"
:
"pic"
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
}
else
aarch64_cmodel
=
opts
->
x_aarch64_cmodel_var
;
}
</s>

A checking mechanism for the implementation of the various code models .


<s> static bool use_rsqrt_p ( void ) { return ( ! flag_trapping_math && flag_unsafe_math_optimizations && ( ( aarch64_tune_params . extra_tuning_flags & AARCH64_EXTRA_TUNE_APPROX_RSQRT ) || flag_mrecip_low_precision_sqrt ) ) ; } </s>

Return true if it is safe to use the rsqrt optabs to optimize 1.0/sqrt .