<s> static void aarch64_add_constant_internal ( machine_mode mode , int regnum , int scratchreg , HOST_WIDE_INT delta , bool frame_related_p , bool emit_move_imm ) { HOST_WIDE_INT mdelta = abs_hwi ( delta ) ; rtx this_rtx = gen_rtx_REG ( mode , regnum ) ; rtx_insn * insn ; if ( ! mdelta ) return ; if ( aarch64_uimm12_shift ( mdelta ) ) { insn = emit_insn ( gen_add2_insn ( this_rtx , GEN_INT ( delta ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; return ; } if ( mdelta < 0x1000000 && ! aarch64_move_imm ( mdelta , mode ) ) { HOST_WIDE_INT low_off = mdelta & 0xfff ; low_off = delta < 0 ? - low_off : low_off ; insn = emit_insn ( gen_add2_insn ( this_rtx , GEN_INT ( low_off ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; insn = emit_insn ( gen_add2_insn ( this_rtx , GEN_INT ( delta - low_off ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; return ; } rtx scratch_rtx = gen_rtx_REG ( mode , scratchreg ) ; if ( emit_move_imm ) aarch64_internal_mov_immediate ( scratch_rtx , GEN_INT ( mdelta ) , true , mode ) ; insn = emit_insn ( delta < 0 ? gen_sub2_insn ( this_rtx , scratch_rtx ) : gen_add2_insn ( this_rtx , scratch_rtx ) ) ; if ( frame_related_p ) { RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; rtx adj = plus_constant ( mode , this_rtx , delta ) ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( this_rtx , adj ) ) ; } } </s>

Add DELTA to REGNUM in mode MODE . SCRATCHREG can be used to hold a temporary value if necessary . FRAME_RELATED_P should be true if the RTX_FRAME_RELATED flag should be set and CFA adjustments added to the generated instructions . If SCRATCHREG is known to hold abs ( delta ) , EMIT_MOVE_IMM can be set to false to avoid emitting the immediate again . Since this function may be used to adjust the stack pointer , we must ensure that it can not cause transient stack deallocation ( for example by first incrementing SP and then decrementing when adjusting by a large immediate ) .


<s> static inline void aarch64_add_sp ( int scratchreg , HOST_WIDE_INT delta , bool emit_move_imm ) { aarch64_add_constant_internal ( Pmode , SP_REGNUM , scratchreg , delta , true , emit_move_imm ) ; } </s>

Add DELTA to the stack pointer , marking the instructions frame-related . TEMP1 is available as a temporary if nonnull . EMIT_MOVE_IMM is false if TEMP1 already contains abs ( DELTA ) .


<s> bool aarch64_and_bitmask_imm ( unsigned HOST_WIDE_INT val_in , machine_mode mode ) { if ( aarch64_bitmask_imm ( val_in , mode ) ) return false ; if ( aarch64_move_imm ( val_in , mode ) ) return false ; unsigned HOST_WIDE_INT imm2 = aarch64_and_split_imm2 ( val_in ) ; return aarch64_bitmask_imm ( imm2 , mode ) ; } </s>

Return true if VAL_IN is a valid 'and ' bitmask immediate .


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

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


Return true if the vector misalignment factor is supported by the target .


<s> static int aarch64_builtin_vectorization_cost ( enum vect_cost_for_stmt type_of_cost , tree vectype , int misalign ATTRIBUTE_UNUSED ) { unsigned elements ; const cpu_vector_cost * costs = aarch64_tune_params . vec_costs ; bool fp = false ; if ( vectype != NULL ) fp = FLOAT_TYPE_P ( vectype ) ; switch ( type_of_cost ) { case scalar_stmt : return fp ? costs -> scalar_fp_stmt_cost : costs -> scalar_int_stmt_cost ; case scalar_load : return costs -> scalar_load_cost ; case scalar_store : return costs -> scalar_store_cost ; case vector_stmt : return fp ? costs -> vec_fp_stmt_cost : costs -> vec_int_stmt_cost ; case vector_load : return costs -> vec_align_load_cost ; case vector_store : return costs -> vec_store_cost ; case vec_to_scalar : return costs -> vec_to_scalar_cost ; case scalar_to_vec : return costs -> scalar_to_vec_cost ; case unaligned_load : return costs -> vec_unalign_load_cost ; case unaligned_store : return costs -> vec_unalign_store_cost ; case cond_branch_taken : return costs -> cond_taken_branch_cost ; case cond_branch_not_taken : return costs -> cond_not_taken_branch_cost ; case vec_perm : return costs -> vec_permute_cost ; case vec_promote_demote : return fp ? costs -> vec_fp_stmt_cost : costs -> vec_int_stmt_cost ; case vec_construct : elements = TYPE_VECTOR_SUBPARTS ( vectype ) ; return elements / 2 + 1 ; default : gcc_unreachable ( ) ; } } </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_tls_symbol_p ( x ) ) return aarch64_classify_tls_symbol ( x ) ; switch ( aarch64_cmodel ) { case AARCH64_CMODEL_TINY : if ( ( SYMBOL_REF_WEAK ( x ) && ! aarch64_symbol_binds_local_p ( 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 ) && ! aarch64_symbol_binds_local_p ( 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 ; case AARCH64_CMODEL_LARGE : if ( CONSTANT_POOL_ADDRESS_P ( x ) ) return SYMBOL_SMALL_ABSOLUTE ; else return SYMBOL_FORCE_TO_MEM ; 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> static sbitmap aarch64_components_for_bb ( basic_block bb ) { bitmap in = DF_LIVE_IN ( bb ) ; bitmap gen = & DF_LIVE_BB_INFO ( bb ) -> gen ; bitmap kill = & DF_LIVE_BB_INFO ( bb ) -> kill ; sbitmap components = sbitmap_alloc ( LAST_SAVED_REGNUM + 1 ) ; bitmap_clear ( components ) ; for ( unsigned regno = 0 ; regno <= LAST_SAVED_REGNUM ; regno ++ ) if ( ( ! call_used_regs [ regno ] ) && ( bitmap_bit_p ( in , regno ) || bitmap_bit_p ( gen , regno ) || bitmap_bit_p ( kill , regno ) ) ) bitmap_set_bit ( components , regno ) ; return components ; } </s>


<s> bool aarch64_emit_approx_div ( rtx quo , rtx num , rtx den ) { machine_mode mode = GET_MODE ( quo ) ; if ( GET_MODE_INNER ( mode ) == HFmode ) return false ; bool use_approx_division_p = ( flag_mlow_precision_div || ( aarch64_tune_params . approx_modes -> division & AARCH64_APPROX_MODE ( mode ) ) ) ; if ( ! flag_finite_math_only || flag_trapping_math || ! flag_unsafe_math_optimizations || optimize_function_for_size_p ( cfun ) || ! use_approx_division_p ) return false ; rtx xrcp = gen_reg_rtx ( mode ) ; emit_insn ( ( * get_recpe_type ( mode ) ) ( xrcp , den ) ) ; int iterations = ( GET_MODE_INNER ( mode ) == DFmode ) ? 3 : 2 ; if ( flag_mlow_precision_div ) iterations -- ; rtx xtmp = gen_reg_rtx ( mode ) ; while ( iterations -- ) { emit_insn ( ( * get_recps_type ( mode ) ) ( xtmp , xrcp , den ) ) ; if ( iterations > 0 ) emit_set_insn ( xrcp , gen_rtx_MULT ( mode , xrcp , xtmp ) ) ; } if ( num != CONST1_RTX ( mode ) ) { rtx xnum = force_reg ( mode , num ) ; emit_set_insn ( xrcp , gen_rtx_MULT ( mode , xrcp , xnum ) ) ; } emit_set_insn ( quo , gen_rtx_MULT ( mode , xrcp , xtmp ) ) ; return true ; } </s>

Emit the instruction sequence to compute the approximation for the division of NUM by DEN in QUO and return whether the sequence was emitted or not .


<s> bool aarch64_emit_approx_sqrt ( rtx dst , rtx src , bool recp ) { machine_mode mode = GET_MODE ( dst ) ; if ( GET_MODE_INNER ( mode ) == HFmode ) { gcc_assert ( ! recp ) ; return false ; } machine_mode mmsk = mode_for_vector ( int_mode_for_mode ( GET_MODE_INNER ( mode ) ) , GET_MODE_NUNITS ( mode ) ) ; if ( ! recp ) { if ( ! ( flag_mlow_precision_sqrt || ( aarch64_tune_params . approx_modes -> sqrt & AARCH64_APPROX_MODE ( mode ) ) ) ) return false ; if ( flag_finite_math_only || flag_trapping_math || ! flag_unsafe_math_optimizations || optimize_function_for_size_p ( cfun ) ) return false ; } else gcc_assert ( use_rsqrt_p ( mode ) ) ; rtx xmsk = gen_reg_rtx ( mmsk ) ; if ( ! recp ) emit_insn ( gen_rtx_SET ( xmsk , gen_rtx_NEG ( mmsk , gen_rtx_EQ ( mmsk , src , CONST0_RTX ( mode ) ) ) ) ) ; rtx xdst = gen_reg_rtx ( mode ) ; emit_insn ( ( * get_rsqrte_type ( mode ) ) ( xdst , src ) ) ; int iterations = ( GET_MODE_INNER ( mode ) == DFmode ) ? 3 : 2 ; if ( ( recp && flag_mrecip_low_precision_sqrt ) || ( ! recp && flag_mlow_precision_sqrt ) ) iterations -- ; rtx x1 = gen_reg_rtx ( mode ) ; while ( iterations -- ) { rtx x2 = gen_reg_rtx ( mode ) ; emit_set_insn ( x2 , gen_rtx_MULT ( mode , xdst , xdst ) ) ; emit_insn ( ( * get_rsqrts_type ( mode ) ) ( x1 , src , x2 ) ) ; if ( iterations > 0 ) emit_set_insn ( xdst , gen_rtx_MULT ( mode , xdst , x1 ) ) ; } if ( ! recp ) { rtx xtmp = gen_reg_rtx ( mmsk ) ; emit_set_insn ( xtmp , gen_rtx_AND ( mmsk , gen_rtx_NOT ( mmsk , xmsk ) , gen_rtx_SUBREG ( mmsk , xdst , 0 ) ) ) ; emit_move_insn ( xdst , gen_rtx_SUBREG ( mode , xtmp , 0 ) ) ; emit_set_insn ( xdst , gen_rtx_MULT ( mode , xdst , src ) ) ; } emit_set_insn ( dst , gen_rtx_MULT ( mode , xdst , x1 ) ) ; return true ; } </s>

Emit instruction sequence to compute either the approximate square root or its approximate reciprocal , depending on the flag RECP , and return whether the sequence was emitted or not .


<s> static void aarch64_emit_probe_stack_range ( HOST_WIDE_INT first , HOST_WIDE_INT size ) { rtx reg1 = gen_rtx_REG ( Pmode , 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 ( Pmode , stack_pointer_rtx , - ( first + base ) ) ) ; emit_stack_probe ( plus_constant ( Pmode , reg1 , base - size ) ) ; } else if ( size <= 4 * PROBE_INTERVAL ) { HOST_WIDE_INT i , rem ; emit_set_insn ( reg1 , plus_constant ( Pmode , 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 ( Pmode , 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 ( Pmode , reg1 , - base ) ) ; emit_stack_probe ( plus_constant ( Pmode , reg1 , base - rem ) ) ; } else emit_stack_probe ( plus_constant ( Pmode , reg1 , - rem ) ) ; } else { rtx reg2 = gen_rtx_REG ( Pmode , PROBE_STACK_SECOND_REG ) ; HOST_WIDE_INT rounded_size = size & - PROBE_INTERVAL ; emit_set_insn ( reg1 , plus_constant ( Pmode , stack_pointer_rtx , - first ) ) ; emit_set_insn ( reg2 , plus_constant ( Pmode , stack_pointer_rtx , - ( first + rounded_size ) ) ) ; emit_insn ( gen_probe_stack_range ( 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 ( Pmode , reg2 , - base ) ) ; emit_stack_probe ( plus_constant ( Pmode , reg2 , base - rem ) ) ; } else emit_stack_probe ( plus_constant ( Pmode , 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_emit_unlikely_jump ( rtx insn ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; rtx_insn * jump = emit_jump_insn ( insn ) ; add_int_reg_note ( jump , REG_BR_PROB , very_unlikely ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> static bool aarch64_evpc_ext ( struct expand_vec_perm_d * d ) { unsigned int i , nelt = d -> nelt ; rtx ( * gen ) ( rtx , rtx , rtx , rtx ) ; rtx offset ; unsigned int location = d -> perm [ 0 ] ; for ( i = 1 ; i < nelt ; i ++ ) { unsigned int required = location + i ; if ( d -> one_vector_p ) { required &= ( nelt - 1 ) ; } if ( d -> perm [ i ] != required ) return false ; } switch ( d -> vmode ) { case V16QImode : gen = gen_aarch64_extv16qi ; break ; case V8QImode : gen = gen_aarch64_extv8qi ; break ; case V4HImode : gen = gen_aarch64_extv4hi ; break ; case V8HImode : gen = gen_aarch64_extv8hi ; break ; case V2SImode : gen = gen_aarch64_extv2si ; break ; case V4SImode : gen = gen_aarch64_extv4si ; break ; case V4HFmode : gen = gen_aarch64_extv4hf ; break ; case V8HFmode : gen = gen_aarch64_extv8hf ; break ; case V2SFmode : gen = gen_aarch64_extv2sf ; break ; case V4SFmode : gen = gen_aarch64_extv4sf ; break ; case V2DImode : gen = gen_aarch64_extv2di ; break ; case V2DFmode : gen = gen_aarch64_extv2df ; break ; default : return false ; } if ( d -> testing_p ) return true ; if ( BYTES_BIG_ENDIAN && ( location != 0 ) ) { std :: swap ( d -> op0 , d -> op1 ) ; location = nelt - location ; } offset = GEN_INT ( location ) ; emit_insn ( gen ( d -> target , d -> op0 , d -> op1 , offset ) ) ; return true ; } </s>


<s> static bool aarch64_evpc_rev ( struct expand_vec_perm_d * d ) { unsigned int i , j , diff , nelt = d -> nelt ; rtx ( * gen ) ( rtx , rtx ) ; if ( ! d -> one_vector_p ) return false ; diff = d -> perm [ 0 ] ; switch ( diff ) { case 7 : switch ( d -> vmode ) { case V16QImode : gen = gen_aarch64_rev64v16qi ; break ; case V8QImode : gen = gen_aarch64_rev64v8qi ; break ; default : return false ; } break ; case 3 : switch ( d -> vmode ) { case V16QImode : gen = gen_aarch64_rev32v16qi ; break ; case V8QImode : gen = gen_aarch64_rev32v8qi ; break ; case V8HImode : gen = gen_aarch64_rev64v8hi ; break ; case V4HImode : gen = gen_aarch64_rev64v4hi ; break ; default : return false ; } break ; case 1 : switch ( d -> vmode ) { case V16QImode : gen = gen_aarch64_rev16v16qi ; break ; case V8QImode : gen = gen_aarch64_rev16v8qi ; break ; case V8HImode : gen = gen_aarch64_rev32v8hi ; break ; case V4HImode : gen = gen_aarch64_rev32v4hi ; break ; case V4SImode : gen = gen_aarch64_rev64v4si ; break ; case V2SImode : gen = gen_aarch64_rev64v2si ; break ; case V4SFmode : gen = gen_aarch64_rev64v4sf ; break ; case V2SFmode : gen = gen_aarch64_rev64v2sf ; break ; case V8HFmode : gen = gen_aarch64_rev64v8hf ; break ; case V4HFmode : gen = gen_aarch64_rev64v4hf ; break ; default : return false ; } break ; default : return false ; } for ( i = 0 ; i < nelt ; i += diff + 1 ) for ( j = 0 ; j <= diff ; j += 1 ) { gcc_assert ( i + j < nelt ) ; if ( d -> perm [ i + j ] != i + diff - j ) return false ; } if ( d -> testing_p ) return true ; emit_insn ( gen ( d -> target , d -> op0 ) ) ; return true ; } </s>


<s> static bool aarch64_evpc_trn ( struct expand_vec_perm_d * d ) { unsigned int i , odd , mask , nelt = d -> nelt ; rtx out , in0 , in1 , x ; rtx ( * gen ) ( rtx , rtx , rtx ) ; machine_mode vmode = d -> vmode ; if ( GET_MODE_UNIT_SIZE ( vmode ) > 8 ) return false ; if ( d -> perm [ 0 ] == 0 ) odd = 0 ; else if ( d -> perm [ 0 ] == 1 ) odd = 1 ; else return false ; mask = ( d -> one_vector_p ? nelt - 1 : 2 * nelt - 1 ) ; for ( i = 0 ; i < nelt ; i += 2 ) { if ( d -> perm [ i ] != i + odd ) return false ; if ( d -> perm [ i + 1 ] != ( ( i + nelt + odd ) & mask ) ) return false ; } if ( d -> testing_p ) return true ; in0 = d -> op0 ; in1 = d -> op1 ; if ( BYTES_BIG_ENDIAN ) { x = in0 , in0 = in1 , in1 = x ; odd = ! odd ; } out = d -> target ; if ( odd ) { switch ( vmode ) { case V16QImode : gen = gen_aarch64_trn2v16qi ; break ; case V8QImode : gen = gen_aarch64_trn2v8qi ; break ; case V8HImode : gen = gen_aarch64_trn2v8hi ; break ; case V4HImode : gen = gen_aarch64_trn2v4hi ; break ; case V4SImode : gen = gen_aarch64_trn2v4si ; break ; case V2SImode : gen = gen_aarch64_trn2v2si ; break ; case V2DImode : gen = gen_aarch64_trn2v2di ; break ; case V4HFmode : gen = gen_aarch64_trn2v4hf ; break ; case V8HFmode : gen = gen_aarch64_trn2v8hf ; break ; case V4SFmode : gen = gen_aarch64_trn2v4sf ; break ; case V2SFmode : gen = gen_aarch64_trn2v2sf ; break ; case V2DFmode : gen = gen_aarch64_trn2v2df ; break ; default : return false ; } } else { switch ( vmode ) { case V16QImode : gen = gen_aarch64_trn1v16qi ; break ; case V8QImode : gen = gen_aarch64_trn1v8qi ; break ; case V8HImode : gen = gen_aarch64_trn1v8hi ; break ; case V4HImode : gen = gen_aarch64_trn1v4hi ; break ; case V4SImode : gen = gen_aarch64_trn1v4si ; break ; case V2SImode : gen = gen_aarch64_trn1v2si ; break ; case V2DImode : gen = gen_aarch64_trn1v2di ; break ; case V4HFmode : gen = gen_aarch64_trn1v4hf ; break ; case V8HFmode : gen = gen_aarch64_trn1v8hf ; break ; case V4SFmode : gen = gen_aarch64_trn1v4sf ; break ; case V2SFmode : gen = gen_aarch64_trn1v2sf ; break ; case V2DFmode : gen = gen_aarch64_trn1v2df ; break ; default : return false ; } } emit_insn ( gen ( out , in0 , in1 ) ) ; return true ; } </s>

Recognize patterns suitable for the TRN instructions .


<s> static bool aarch64_evpc_uzp ( struct expand_vec_perm_d * d ) { unsigned int i , odd , mask , nelt = d -> nelt ; rtx out , in0 , in1 , x ; rtx ( * gen ) ( rtx , rtx , rtx ) ; machine_mode vmode = d -> vmode ; if ( GET_MODE_UNIT_SIZE ( vmode ) > 8 ) return false ; if ( d -> perm [ 0 ] == 0 ) odd = 0 ; else if ( d -> perm [ 0 ] == 1 ) odd = 1 ; else return false ; mask = ( d -> one_vector_p ? nelt - 1 : 2 * nelt - 1 ) ; for ( i = 0 ; i < nelt ; i ++ ) { unsigned elt = ( i * 2 + odd ) & mask ; if ( d -> perm [ i ] != elt ) return false ; } if ( d -> testing_p ) return true ; in0 = d -> op0 ; in1 = d -> op1 ; if ( BYTES_BIG_ENDIAN ) { x = in0 , in0 = in1 , in1 = x ; odd = ! odd ; } out = d -> target ; if ( odd ) { switch ( vmode ) { case V16QImode : gen = gen_aarch64_uzp2v16qi ; break ; case V8QImode : gen = gen_aarch64_uzp2v8qi ; break ; case V8HImode : gen = gen_aarch64_uzp2v8hi ; break ; case V4HImode : gen = gen_aarch64_uzp2v4hi ; break ; case V4SImode : gen = gen_aarch64_uzp2v4si ; break ; case V2SImode : gen = gen_aarch64_uzp2v2si ; break ; case V2DImode : gen = gen_aarch64_uzp2v2di ; break ; case V4HFmode : gen = gen_aarch64_uzp2v4hf ; break ; case V8HFmode : gen = gen_aarch64_uzp2v8hf ; break ; case V4SFmode : gen = gen_aarch64_uzp2v4sf ; break ; case V2SFmode : gen = gen_aarch64_uzp2v2sf ; break ; case V2DFmode : gen = gen_aarch64_uzp2v2df ; break ; default : return false ; } } else { switch ( vmode ) { case V16QImode : gen = gen_aarch64_uzp1v16qi ; break ; case V8QImode : gen = gen_aarch64_uzp1v8qi ; break ; case V8HImode : gen = gen_aarch64_uzp1v8hi ; break ; case V4HImode : gen = gen_aarch64_uzp1v4hi ; break ; case V4SImode : gen = gen_aarch64_uzp1v4si ; break ; case V2SImode : gen = gen_aarch64_uzp1v2si ; break ; case V2DImode : gen = gen_aarch64_uzp1v2di ; break ; case V4HFmode : gen = gen_aarch64_uzp1v4hf ; break ; case V8HFmode : gen = gen_aarch64_uzp1v8hf ; break ; case V4SFmode : gen = gen_aarch64_uzp1v4sf ; break ; case V2SFmode : gen = gen_aarch64_uzp1v2sf ; break ; case V2DFmode : gen = gen_aarch64_uzp1v2df ; break ; default : return false ; } } emit_insn ( gen ( out , in0 , in1 ) ) ; return true ; } </s>

Recognize patterns suitable for the UZP instructions .


<s> static bool aarch64_evpc_zip ( struct expand_vec_perm_d * d ) { unsigned int i , high , mask , nelt = d -> nelt ; rtx out , in0 , in1 , x ; rtx ( * gen ) ( rtx , rtx , rtx ) ; machine_mode vmode = d -> vmode ; if ( GET_MODE_UNIT_SIZE ( vmode ) > 8 ) return false ; high = nelt / 2 ; if ( d -> perm [ 0 ] == high ) ; else if ( d -> perm [ 0 ] == 0 ) high = 0 ; else return false ; mask = ( d -> one_vector_p ? nelt - 1 : 2 * nelt - 1 ) ; for ( i = 0 ; i < nelt / 2 ; i ++ ) { unsigned elt = ( i + high ) & mask ; if ( d -> perm [ i * 2 ] != elt ) return false ; elt = ( elt + nelt ) & mask ; if ( d -> perm [ i * 2 + 1 ] != elt ) return false ; } if ( d -> testing_p ) return true ; in0 = d -> op0 ; in1 = d -> op1 ; if ( BYTES_BIG_ENDIAN ) { x = in0 , in0 = in1 , in1 = x ; high = ! high ; } out = d -> target ; if ( high ) { switch ( vmode ) { case V16QImode : gen = gen_aarch64_zip2v16qi ; break ; case V8QImode : gen = gen_aarch64_zip2v8qi ; break ; case V8HImode : gen = gen_aarch64_zip2v8hi ; break ; case V4HImode : gen = gen_aarch64_zip2v4hi ; break ; case V4SImode : gen = gen_aarch64_zip2v4si ; break ; case V2SImode : gen = gen_aarch64_zip2v2si ; break ; case V2DImode : gen = gen_aarch64_zip2v2di ; break ; case V4HFmode : gen = gen_aarch64_zip2v4hf ; break ; case V8HFmode : gen = gen_aarch64_zip2v8hf ; break ; case V4SFmode : gen = gen_aarch64_zip2v4sf ; break ; case V2SFmode : gen = gen_aarch64_zip2v2sf ; break ; case V2DFmode : gen = gen_aarch64_zip2v2df ; break ; default : return false ; } } else { switch ( vmode ) { case V16QImode : gen = gen_aarch64_zip1v16qi ; break ; case V8QImode : gen = gen_aarch64_zip1v8qi ; break ; case V8HImode : gen = gen_aarch64_zip1v8hi ; break ; case V4HImode : gen = gen_aarch64_zip1v4hi ; break ; case V4SImode : gen = gen_aarch64_zip1v4si ; break ; case V2SImode : gen = gen_aarch64_zip1v2si ; break ; case V2DImode : gen = gen_aarch64_zip1v2di ; break ; case V4HFmode : gen = gen_aarch64_zip1v4hf ; break ; case V8HFmode : gen = gen_aarch64_zip1v8hf ; break ; case V4SFmode : gen = gen_aarch64_zip1v4sf ; break ; case V2SFmode : gen = gen_aarch64_zip1v2sf ; break ; case V2DFmode : gen = gen_aarch64_zip1v2df ; break ; default : return false ; } } emit_insn ( gen ( out , in0 , in1 ) ) ; return true ; } </s>

Recognize patterns suitable for the ZIP instructions .


<s> void aarch64_expand_epilogue ( bool for_sibcall ) { aarch64_layout_frame ( ) ; HOST_WIDE_INT initial_adjust = cfun -> machine -> frame . initial_adjust ; HOST_WIDE_INT callee_adjust = cfun -> machine -> frame . callee_adjust ; HOST_WIDE_INT final_adjust = cfun -> machine -> frame . final_adjust ; HOST_WIDE_INT callee_offset = cfun -> machine -> frame . callee_offset ; unsigned reg1 = cfun -> machine -> frame . wb_candidate1 ; unsigned reg2 = cfun -> machine -> frame . wb_candidate2 ; rtx cfi_ops = NULL ; rtx_insn * insn ; bool need_barrier_p = ( get_frame_size ( ) + cfun -> machine -> frame . saved_varargs_size ) != 0 ; if ( final_adjust > crtl -> outgoing_args_size || cfun -> calls_alloca || crtl -> calls_eh_return ) { emit_insn ( gen_stack_tie ( stack_pointer_rtx , stack_pointer_rtx ) ) ; need_barrier_p = false ; } if ( frame_pointer_needed && ( final_adjust || cfun -> calls_alloca ) ) { insn = emit_insn ( gen_add3_insn ( stack_pointer_rtx , hard_frame_pointer_rtx , GEN_INT ( - callee_offset ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = callee_adjust == 0 ; } else aarch64_add_sp ( IP1_REGNUM , final_adjust , df_regs_ever_live_p ( IP1_REGNUM ) ) ; aarch64_restore_callee_saves ( DImode , callee_offset , R0_REGNUM , R30_REGNUM , callee_adjust != 0 , & cfi_ops ) ; aarch64_restore_callee_saves ( DFmode , callee_offset , V0_REGNUM , V31_REGNUM , callee_adjust != 0 , & cfi_ops ) ; if ( need_barrier_p ) emit_insn ( gen_stack_tie ( stack_pointer_rtx , stack_pointer_rtx ) ) ; if ( callee_adjust != 0 ) aarch64_pop_regs ( reg1 , reg2 , callee_adjust , & cfi_ops ) ; if ( callee_adjust != 0 || initial_adjust > 65536 ) { insn = get_last_insn ( ) ; rtx new_cfa = plus_constant ( Pmode , stack_pointer_rtx , initial_adjust ) ; REG_NOTES ( insn ) = alloc_reg_note ( REG_CFA_DEF_CFA , new_cfa , cfi_ops ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; cfi_ops = NULL ; } aarch64_add_sp ( IP0_REGNUM , initial_adjust , df_regs_ever_live_p ( IP0_REGNUM ) ) ; if ( cfi_ops ) { insn = get_last_insn ( ) ; cfi_ops = alloc_reg_note ( REG_CFA_DEF_CFA , stack_pointer_rtx , cfi_ops ) ; REG_NOTES ( insn ) = cfi_ops ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( aarch64_return_address_signing_enabled ( ) && ( for_sibcall || ! TARGET_ARMV8_3 || crtl -> calls_eh_return ) ) { insn = emit_insn ( gen_autisp ( ) ) ; add_reg_note ( insn , REG_CFA_TOGGLE_RA_MANGLE , const0_rtx ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( crtl -> calls_eh_return ) { emit_insn ( gen_add2_insn ( stack_pointer_rtx , EH_RETURN_STACKADJ_RTX ) ) ; } emit_use ( gen_rtx_REG ( DImode , LR_REGNUM ) ) ; if ( ! for_sibcall ) emit_jump_insn ( ret_rtx ) ; } </s>

Generate the epilogue instructions for returning from a function .


<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_pcrelative_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_prologue ( void ) { aarch64_layout_frame ( ) ; HOST_WIDE_INT frame_size = cfun -> machine -> frame . frame_size ; HOST_WIDE_INT initial_adjust = cfun -> machine -> frame . initial_adjust ; HOST_WIDE_INT callee_adjust = cfun -> machine -> frame . callee_adjust ; HOST_WIDE_INT final_adjust = cfun -> machine -> frame . final_adjust ; HOST_WIDE_INT callee_offset = cfun -> machine -> frame . callee_offset ; unsigned reg1 = cfun -> machine -> frame . wb_candidate1 ; unsigned reg2 = cfun -> machine -> frame . wb_candidate2 ; rtx_insn * insn ; if ( aarch64_return_address_signing_enabled ( ) ) { insn = emit_insn ( gen_pacisp ( ) ) ; add_reg_note ( insn , REG_CFA_TOGGLE_RA_MANGLE , const0_rtx ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( flag_stack_usage_info ) current_function_static_stack_size = frame_size ; if ( flag_stack_check == STATIC_BUILTIN_STACK_CHECK ) { if ( crtl -> is_leaf && ! cfun -> calls_alloca ) { if ( frame_size > PROBE_INTERVAL && frame_size > STACK_CHECK_PROTECT ) aarch64_emit_probe_stack_range ( STACK_CHECK_PROTECT , frame_size - STACK_CHECK_PROTECT ) ; } else if ( frame_size > 0 ) aarch64_emit_probe_stack_range ( STACK_CHECK_PROTECT , frame_size ) ; } aarch64_sub_sp ( IP0_REGNUM , initial_adjust , true ) ; if ( callee_adjust != 0 ) aarch64_push_regs ( reg1 , reg2 , callee_adjust ) ; if ( frame_pointer_needed ) { if ( callee_adjust == 0 ) aarch64_save_callee_saves ( DImode , callee_offset , R29_REGNUM , R30_REGNUM , false ) ; insn = emit_insn ( gen_add3_insn ( hard_frame_pointer_rtx , stack_pointer_rtx , GEN_INT ( callee_offset ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; emit_insn ( gen_stack_tie ( stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; } aarch64_save_callee_saves ( DImode , callee_offset , R0_REGNUM , R30_REGNUM , callee_adjust != 0 || frame_pointer_needed ) ; aarch64_save_callee_saves ( DFmode , callee_offset , V0_REGNUM , V31_REGNUM , callee_adjust != 0 || frame_pointer_needed ) ; aarch64_sub_sp ( IP1_REGNUM , final_adjust , ! frame_pointer_needed ) ; } </s>

Generate the prologue instructions for entry into a function . Establish the stack frame by decreasing the stack pointer with a properly calculated size and , if necessary , create a frame record filled with the values of LR and previous frame pointer . The current FP is also set up if it is in use .


<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 . ulow ( ) != 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> static unsigned int aarch64_function_arg_alignment ( machine_mode mode , const_tree type ) { if ( ! type ) return GET_MODE_ALIGNMENT ( mode ) ; if ( integer_zerop ( TYPE_SIZE ( type ) ) ) return 0 ; gcc_assert ( TYPE_MODE ( type ) == mode ) ; if ( ! AGGREGATE_TYPE_P ( type ) ) return TYPE_ALIGN ( TYPE_MAIN_VARIANT ( type ) ) ; if ( TREE_CODE ( type ) == ARRAY_TYPE ) return TYPE_ALIGN ( TREE_TYPE ( type ) ) ; unsigned int alignment = 0 ; for ( tree field = TYPE_FIELDS ( type ) ; field ; field = DECL_CHAIN ( field ) ) if ( TREE_CODE ( field ) == FIELD_DECL ) alignment = std :: max ( alignment , DECL_ALIGN ( field ) ) ; return alignment ; } </s>

Given MODE and TYPE of a function argument , return the alignment in bits . The idea is to suppress any stronger alignment requested by the user and opt for the natural alignment ( specified in AAPCS64 \S 4.1 ) . This is a helper function for local use only .


<s> static unsigned int aarch64_function_arg_boundary ( machine_mode mode , const_tree type ) { unsigned int alignment = aarch64_function_arg_alignment ( mode , type ) ; return MIN ( MAX ( alignment , PARM_BOUNDARY ) , STACK_BOUNDARY ) ; } </s>

Implement FUNCTION_ARG_BOUNDARY . Every parameter gets at least PARM_BOUNDARY bits of alignment , but will be given anything up to STACK_BOUNDARY bits if the type requires it . This makes sure that both before and after the layout of each argument , the Next Stacked Argument Address ( NSAA ) will have a minimum alignment of 8 bytes .


<s> static sbitmap aarch64_get_separate_components ( void ) { aarch64_layout_frame ( ) ; sbitmap components = sbitmap_alloc ( LAST_SAVED_REGNUM + 1 ) ; bitmap_clear ( components ) ; for ( unsigned regno = 0 ; regno <= LAST_SAVED_REGNUM ; regno ++ ) if ( aarch64_register_saved_on_entry ( regno ) ) { HOST_WIDE_INT offset = cfun -> machine -> frame . reg_offset [ regno ] ; if ( ! frame_pointer_needed ) offset += cfun -> machine -> frame . frame_size - cfun -> machine -> frame . hard_fp_offset ; if ( offset_12bit_unsigned_scaled_p ( DImode , offset ) ) bitmap_set_bit ( components , regno ) ; } if ( frame_pointer_needed ) bitmap_clear_bit ( components , HARD_FRAME_POINTER_REGNUM ) ; unsigned reg1 = cfun -> machine -> frame . wb_candidate1 ; unsigned reg2 = cfun -> machine -> frame . wb_candidate2 ; if ( reg2 != INVALID_REGNUM ) bitmap_clear_bit ( components , reg2 ) ; if ( reg1 != INVALID_REGNUM ) bitmap_clear_bit ( components , reg1 ) ; bitmap_clear_bit ( components , LR_REGNUM ) ; bitmap_clear_bit ( components , SP_REGNUM ) ; return components ; } </s>


"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 .


"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_legitimize_address_displacement ( rtx * disp , rtx * off , machine_mode mode ) { HOST_WIDE_INT offset = INTVAL ( * disp ) ; HOST_WIDE_INT base = offset & ~ ( GET_MODE_SIZE ( mode ) < 4 ? 0xfff : 0x3ffc ) ; if ( mode == TImode || mode == TFmode || ( offset & ( GET_MODE_SIZE ( mode ) - 1 ) ) != 0 ) base = ( offset + 0x100 ) & ~ 0x1ff ; * off = GEN_INT ( base ) ; * disp = GEN_INT ( offset - base ) ; return true ; } </s>

Split an out-of-range address displacement into a base and offset . Use 4KB range for 1- and 2-byte accesses and a 16KB range otherwise to increase opportunities for sharing the base address of different sizes . For unaligned accesses and TI/TF mode use the signed 9-bit range .


<s> bool aarch64_mask_and_shift_for_ubfiz_p ( machine_mode mode , rtx mask , rtx shft_amnt ) { return CONST_INT_P ( mask ) && CONST_INT_P ( shft_amnt ) && INTVAL ( shft_amnt ) < GET_MODE_BITSIZE ( mode ) && exact_log2 ( ( INTVAL ( mask ) >> INTVAL ( shft_amnt ) ) + 1 ) >= 0 && ( INTVAL ( mask ) & ( ( 1 << INTVAL ( shft_amnt ) ) - 1 ) ) == 0 ; } </s>

Return true if the mask and a shift amount from an RTX of the form ( x < < SHFT_AMNT ) & MASK are valid to combine into a UBFIZ instruction of mode MODE . See the * andim_ashift < mode > _bfiz pattern .


<s> bool aarch64_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { if ( GET_MODE_CLASS ( mode1 ) == GET_MODE_CLASS ( mode2 ) ) return true ; if ( aarch64_vector_mode_p ( mode1 ) && aarch64_vector_mode_p ( mode2 ) ) return true ; if ( aarch64_vector_mode_supported_p ( mode1 ) || aarch64_vector_mode_supported_p ( mode2 ) ) return true ; return false ; } </s>

Implement MODES_TIEABLE_P . In principle we should always return true . However due to issues with register allocation it is preferable to avoid tieing integer scalar and FP scalar modes . Executing integer operations in general registers is better than treating them as scalar vector operations . This reduces latency and avoids redundant int < - > FP moves . So tie modes if they are either the same class , or vector modes with other vector modes , vector structs or any scalar mode .


<s> bool aarch64_operands_ok_for_ldpstp ( rtx * operands , bool load , enum machine_mode mode ) { HOST_WIDE_INT offval_1 , offval_2 , msize ; enum reg_class rclass_1 , rclass_2 ; rtx mem_1 , mem_2 , reg_1 , reg_2 , base_1 , base_2 , offset_1 , offset_2 ; if ( load ) { mem_1 = operands [ 1 ] ; mem_2 = operands [ 3 ] ; reg_1 = operands [ 0 ] ; reg_2 = operands [ 2 ] ; gcc_assert ( REG_P ( reg_1 ) && REG_P ( reg_2 ) ) ; if ( REGNO ( reg_1 ) == REGNO ( reg_2 ) ) return false ; } else { mem_1 = operands [ 0 ] ; mem_2 = operands [ 2 ] ; reg_1 = operands [ 1 ] ; reg_2 = operands [ 3 ] ; } if ( MEM_VOLATILE_P ( mem_1 ) || MEM_VOLATILE_P ( mem_2 ) ) return false ; if ( mode == SImode && ( aarch64_tune_params . extra_tuning_flags & AARCH64_EXTRA_TUNE_SLOW_UNALIGNED_LDPW ) && ! optimize_size && MEM_ALIGN ( mem_1 ) < 8 * BITS_PER_UNIT ) return false ; extract_base_offset_in_addr ( mem_1 , & base_1 , & offset_1 ) ; if ( base_1 == NULL_RTX || offset_1 == NULL_RTX ) return false ; extract_base_offset_in_addr ( mem_2 , & base_2 , & offset_2 ) ; if ( base_2 == NULL_RTX || offset_2 == NULL_RTX ) return false ; if ( ! rtx_equal_p ( base_1 , base_2 ) ) return false ; offval_1 = INTVAL ( offset_1 ) ; offval_2 = INTVAL ( offset_2 ) ; msize = GET_MODE_SIZE ( mode ) ; if ( offval_1 != ( offval_2 + msize ) && offval_2 != ( offval_1 + msize ) ) return false ; if ( load ) { if ( reg_mentioned_p ( reg_1 , mem_1 ) ) return false ; if ( offval_1 > offval_2 && reg_mentioned_p ( reg_2 , mem_2 ) ) return false ; } if ( REG_P ( reg_1 ) && FP_REGNUM_P ( REGNO ( reg_1 ) ) ) rclass_1 = FP_REGS ; else rclass_1 = GENERAL_REGS ; if ( REG_P ( reg_2 ) && FP_REGNUM_P ( REGNO ( reg_2 ) ) ) rclass_2 = FP_REGS ; else rclass_2 = GENERAL_REGS ; if ( rclass_1 != rclass_2 ) return false ; return true ; } </s>

Given OPERANDS of consecutive load/store , check if we can merge them into ldp/stp . LOAD is true if they are load instructions . MODE is the mode of memory operands .


<s> static void aarch64_output_mi_thunk ( FILE * file , tree thunk ATTRIBUTE_UNUSED , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { int this_regno = R0_REGNUM ; rtx this_rtx , temp0 , temp1 , addr , funexp ; rtx_insn * insn ; reload_completed = 1 ; emit_note ( NOTE_INSN_PROLOGUE_END ) ; if ( vcall_offset == 0 ) aarch64_add_constant ( Pmode , this_regno , IP1_REGNUM , delta ) ; else { gcc_assert ( ( vcall_offset & ( POINTER_BYTES - 1 ) ) == 0 ) ; this_rtx = gen_rtx_REG ( Pmode , this_regno ) ; temp0 = gen_rtx_REG ( Pmode , IP0_REGNUM ) ; temp1 = gen_rtx_REG ( Pmode , IP1_REGNUM ) ; addr = this_rtx ; if ( delta != 0 ) { if ( delta >= - 256 && delta < 256 ) addr = gen_rtx_PRE_MODIFY ( Pmode , this_rtx , plus_constant ( Pmode , this_rtx , delta ) ) ; else aarch64_add_constant ( Pmode , this_regno , IP1_REGNUM , delta ) ; } if ( Pmode == ptr_mode ) aarch64_emit_move ( temp0 , gen_rtx_MEM ( ptr_mode , addr ) ) ; else aarch64_emit_move ( temp0 , gen_rtx_ZERO_EXTEND ( Pmode , gen_rtx_MEM ( ptr_mode , addr ) ) ) ; if ( vcall_offset >= - 256 && vcall_offset < 4096 * POINTER_BYTES ) addr = plus_constant ( Pmode , temp0 , vcall_offset ) ; else { aarch64_internal_mov_immediate ( temp1 , GEN_INT ( vcall_offset ) , true , Pmode ) ; addr = gen_rtx_PLUS ( Pmode , temp0 , temp1 ) ; } if ( Pmode == ptr_mode ) aarch64_emit_move ( temp1 , gen_rtx_MEM ( ptr_mode , addr ) ) ; else aarch64_emit_move ( temp1 , gen_rtx_SIGN_EXTEND ( Pmode , gen_rtx_MEM ( ptr_mode , addr ) ) ) ; emit_insn ( gen_add2_insn ( this_rtx , temp1 ) ) ; } if ( ! TREE_USED ( function ) ) { assemble_external ( function ) ; TREE_USED ( function ) = 1 ; } funexp = XEXP ( DECL_RTL ( function ) , 0 ) ; funexp = gen_rtx_MEM ( FUNCTION_MODE , funexp ) ; insn = emit_call_insn ( gen_sibcall ( funexp , const0_rtx , NULL_RTX ) ) ; SIBLING_CALL_P ( insn ) = 1 ; insn = get_insns ( ) ; shorten_branches ( insn ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; reload_completed = 0 ; } </s>

Output code to add DELTA to the first argument , and then jump to FUNCTION . Used for C++ multiple inheritance .


<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
{
const
unsigned
int
buf_size
=
20
;
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"

"Return address signing is only supported for -mabi=lp64"


<s> static void aarch64_pop_regs ( unsigned regno1 , unsigned regno2 , HOST_WIDE_INT adjustment , rtx * cfi_ops ) { machine_mode mode = ( regno1 <= R30_REGNUM ) ? DImode : DFmode ; rtx reg1 = gen_rtx_REG ( mode , regno1 ) ; * cfi_ops = alloc_reg_note ( REG_CFA_RESTORE , reg1 , * cfi_ops ) ; if ( regno2 == INVALID_REGNUM ) { rtx mem = plus_constant ( Pmode , stack_pointer_rtx , adjustment ) ; mem = gen_rtx_POST_MODIFY ( Pmode , stack_pointer_rtx , mem ) ; emit_move_insn ( reg1 , gen_rtx_MEM ( mode , mem ) ) ; } else { rtx reg2 = gen_rtx_REG ( mode , regno2 ) ; * cfi_ops = alloc_reg_note ( REG_CFA_RESTORE , reg2 , * cfi_ops ) ; emit_insn ( aarch64_gen_loadwb_pair ( mode , stack_pointer_rtx , reg1 , reg2 , adjustment ) ) ; } } </s>

Pop the two registers numbered REGNO1 , REGNO2 from the stack , adjusting it afterwards by ADJUSTMENT and writing the appropriate REG_CFA_RESTORE notes into CFI_OPS .


<s>
static
void
aarch64_print_hint_for_core_or_arch
(
const
char
*
str
,
bool
arch
)
{
auto_vec
<
const
char
*
>
candidates
;
const
struct
processor
*
entry
=
arch
all_architectures
:
all_cores
;
for
(
;
entry
->
name
!=
;
entry
++
)
candidates
.
safe_push
(
entry
->
name
)
;
char
*
s
;
const
char
*
hint
=
candidates_list_and_hint
(
str
,
s
,
candidates
)
;
if
(
hint
)
inform
(
input_location
,
"valid arguments are: %s;"
" did you mean %qs?"
,
s
,
hint
)
;
XDELETEVEC
(
s
)
;
}
</s>

Print a hint with a suggestion for a core or architecture name that most closely resembles what the user passed in STR . ARCH is true if the user is asking for an architecture name . ARCH is false if the user is asking for a core name .

aarch64
"valid arguments are: %s;"
" did you mean %qs?"


<s> static void aarch64_process_components ( sbitmap components , bool prologue_p ) { rtx ptr_reg = gen_rtx_REG ( Pmode , frame_pointer_needed ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ) ; unsigned last_regno = SBITMAP_SIZE ( components ) ; unsigned regno = aarch64_get_next_set_bit ( components , R0_REGNUM ) ; rtx_insn * insn = NULL ; while ( regno != last_regno ) { machine_mode mode = GP_REGNUM_P ( regno ) ? DImode : DFmode ; rtx reg = gen_rtx_REG ( mode , regno ) ; HOST_WIDE_INT offset = cfun -> machine -> frame . reg_offset [ regno ] ; if ( ! frame_pointer_needed ) offset += cfun -> machine -> frame . frame_size - cfun -> machine -> frame . hard_fp_offset ; rtx addr = plus_constant ( Pmode , ptr_reg , offset ) ; rtx mem = gen_frame_mem ( mode , addr ) ; rtx set = prologue_p ? gen_rtx_SET ( mem , reg ) : gen_rtx_SET ( reg , mem ) ; unsigned regno2 = aarch64_get_next_set_bit ( components , regno + 1 ) ; if ( regno2 == last_regno ) { insn = emit_insn ( set ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( prologue_p ) add_reg_note ( insn , REG_CFA_OFFSET , copy_rtx ( set ) ) ; else add_reg_note ( insn , REG_CFA_RESTORE , reg ) ; break ; } HOST_WIDE_INT offset2 = cfun -> machine -> frame . reg_offset [ regno2 ] ; if ( ! satisfies_constraint_Ump ( mem ) || GP_REGNUM_P ( regno ) != GP_REGNUM_P ( regno2 ) || ( offset2 - cfun -> machine -> frame . reg_offset [ regno ] ) != GET_MODE_SIZE ( mode ) ) { insn = emit_insn ( set ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( prologue_p ) add_reg_note ( insn , REG_CFA_OFFSET , copy_rtx ( set ) ) ; else add_reg_note ( insn , REG_CFA_RESTORE , reg ) ; regno = regno2 ; continue ; } rtx reg2 = gen_rtx_REG ( mode , regno2 ) ; if ( ! frame_pointer_needed ) offset2 += cfun -> machine -> frame . frame_size - cfun -> machine -> frame . hard_fp_offset ; rtx addr2 = plus_constant ( Pmode , ptr_reg , offset2 ) ; rtx mem2 = gen_frame_mem ( mode , addr2 ) ; rtx set2 = prologue_p ? gen_rtx_SET ( mem2 , reg2 ) : gen_rtx_SET ( reg2 , mem2 ) ; if ( prologue_p ) insn = emit_insn ( aarch64_gen_store_pair ( mode , mem , reg , mem2 , reg2 ) ) ; else insn = emit_insn ( aarch64_gen_load_pair ( mode , reg , mem , reg2 , mem2 ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( prologue_p ) { add_reg_note ( insn , REG_CFA_OFFSET , set ) ; add_reg_note ( insn , REG_CFA_OFFSET , set2 ) ; } else { add_reg_note ( insn , REG_CFA_RESTORE , reg ) ; add_reg_note ( insn , REG_CFA_RESTORE , reg2 ) ; } regno = aarch64_get_next_set_bit ( components , regno2 + 1 ) ; } } </s>

Do the work for aarch64_emit_prologue_components and aarch64_emit_epilogue_components . COMPONENTS is the bitmap of registers to save/restore , PROLOGUE_P indicates whether to emit the prologue sequence for these components or the epilogue sequence . That is , it determines whether we should emit stores or loads and what kind of CFA notes to attach to the insns . Otherwise the logic for the two sequences is very similar .


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

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 void aarch64_push_regs ( unsigned regno1 , unsigned regno2 , HOST_WIDE_INT adjustment ) { rtx_insn * insn ; machine_mode mode = ( regno1 <= R30_REGNUM ) ? DImode : DFmode ; if ( regno2 == INVALID_REGNUM ) return aarch64_pushwb_single_reg ( mode , regno1 , adjustment ) ; rtx reg1 = gen_rtx_REG ( mode , regno1 ) ; rtx reg2 = gen_rtx_REG ( mode , regno2 ) ; insn = emit_insn ( aarch64_gen_storewb_pair ( mode , stack_pointer_rtx , reg1 , reg2 , adjustment ) ) ; RTX_FRAME_RELATED_P ( XVECEXP ( PATTERN ( insn ) , 0 , 2 ) ) = 1 ; RTX_FRAME_RELATED_P ( XVECEXP ( PATTERN ( insn ) , 0 , 1 ) ) = 1 ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } </s>

Push registers numbered REGNO1 and REGNO2 to the stack , adjusting the stack pointer by ADJUSTMENT .


<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 ) ) { if ( cfun -> machine -> reg_is_wrapped_separately [ regno ] ) continue ; 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 -> reg_is_wrapped_separately [ regno2 ] && ( ( 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> bool aarch64_return_address_signing_enabled ( void ) { gcc_assert ( cfun -> machine -> frame . laid_out ) ; return ( aarch64_ra_sign_scope == AARCH64_FUNCTION_ALL || ( aarch64_ra_sign_scope == AARCH64_FUNCTION_NON_LEAF && cfun -> machine -> frame . reg_offset [ LR_REGNUM ] >= 0 ) ) ; } </s>

Return TRUE if return address signing should be enabled for the current function , otherwise return FALSE .


<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 ; if ( cfun -> machine -> reg_is_wrapped_separately [ regno ] ) 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 -> reg_is_wrapped_separately [ regno2 ] && ( ( 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 bool aarch64_scalar_mode_supported_p ( machine_mode mode ) { return ( mode == HFmode ? true : default_scalar_mode_supported_p ( mode ) ) ; } </s>

Implement TARGET_SCALAR_MODE_SUPPORTED_P - return TRUE if MODE is HFmode , and punt to the generic implementation otherwise .


<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 = cfun -> va_list_gpr_size ; int vr_saved = cfun -> va_list_fpr_size ; local_cum = * cum ; aarch64_function_arg_advance ( pack_cumulative_args ( & local_cum ) , mode , type , true ) ; if ( cfun -> va_list_gpr_size ) gr_saved = MIN ( NUM_ARG_REGS - local_cum . aapcs_ncrn , cfun -> va_list_gpr_size / UNITS_PER_WORD ) ; if ( cfun -> va_list_fpr_size ) vr_saved = MIN ( NUM_FP_ARG_REGS - local_cum . aapcs_nvrn , cfun -> va_list_fpr_size / UNITS_PER_VREG ) ; 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 , vr_start ; off = - ROUND_UP ( gr_saved * UNITS_PER_WORD , STACK_BOUNDARY / BITS_PER_UNIT ) ; off -= vr_saved * UNITS_PER_VREG ; vr_start = V0_REGNUM + local_cum . aapcs_nvrn ; for ( i = 0 ; i < vr_saved ; ++ 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 , vr_start + 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 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 HFmode : return V8HFmode ; 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 HFmode : return V4HFmode ; 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> rtx aarch64_simd_gen_const_vector_dup ( machine_mode mode , HOST_WIDE_INT val ) { int nunits = GET_MODE_NUNITS ( mode ) ; rtvec v = rtvec_alloc ( nunits ) ; int i ; rtx cache = GEN_INT ( val ) ; for ( i = 0 ; i < nunits ; i ++ ) RTVEC_ELT ( v , i ) = cache ; return gen_rtx_CONST_VECTOR ( mode , v ) ; } </s>


<s> static inline void aarch64_sub_sp ( int scratchreg , HOST_WIDE_INT delta , bool frame_related_p ) { aarch64_add_constant_internal ( Pmode , SP_REGNUM , scratchreg , - delta , frame_related_p , true ) ; } </s>

Subtract DELTA from the stack pointer , marking the instructions frame-related if FRAME_RELATED_P . TEMP1 is available as a temporary if nonnull .


"invalid feature modifier in %<-march=%s%>"

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 .


"invalid feature modifier in %<-mcpu=%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 .


<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=%s%>"
,
str
)
;
break
;
case
AARCH64_PARSE_INVALID_ARG
:
error
(
"unknown value %qs for -mtune"
,
str
)
;
aarch64_print_hint_for_core
(
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=%s%>"
"unknown value %qs for -mtune"


<s> static recpe_type get_recpe_type ( machine_mode mode ) { switch ( mode ) { case SFmode : return ( gen_aarch64_frecpesf ) ; case V2SFmode : return ( gen_aarch64_frecpev2sf ) ; case V4SFmode : return ( gen_aarch64_frecpev4sf ) ; case DFmode : return ( gen_aarch64_frecpedf ) ; case V2DFmode : return ( gen_aarch64_frecpev2df ) ; default : gcc_unreachable ( ) ; } } </s>

Select reciprocal initial estimate insn depending on machine mode .


<s> static recps_type get_recps_type ( machine_mode mode ) { switch ( mode ) { case SFmode : return ( gen_aarch64_frecpssf ) ; case V2SFmode : return ( gen_aarch64_frecpsv2sf ) ; case V4SFmode : return ( gen_aarch64_frecpsv4sf ) ; case DFmode : return ( gen_aarch64_frecpsdf ) ; case V2DFmode : return ( gen_aarch64_frecpsv2df ) ; default : gcc_unreachable ( ) ; } } </s>

Select reciprocal series step insn depending on machine mode .


<s> static rsqrte_type get_rsqrte_type ( machine_mode mode ) { switch ( mode ) { case DFmode : return gen_aarch64_rsqrtedf ; case SFmode : return gen_aarch64_rsqrtesf ; case V2DFmode : return gen_aarch64_rsqrtev2df ; case V2SFmode : return gen_aarch64_rsqrtev2sf ; case V4SFmode : return gen_aarch64_rsqrtev4sf ; default : gcc_unreachable ( ) ; } } </s>

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


<s> static rsqrts_type get_rsqrts_type ( machine_mode mode ) { switch ( mode ) { case DFmode : return gen_aarch64_rsqrtsdf ; case SFmode : return gen_aarch64_rsqrtssf ; case V2DFmode : return gen_aarch64_rsqrtsv2df ; case V2SFmode : return gen_aarch64_rsqrtsv2sf ; case V4SFmode : return gen_aarch64_rsqrtsv4sf ; default : gcc_unreachable ( ) ; } } </s>

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


<s> static void aarch64_add_cfa_expression ( rtx_insn * insn , unsigned int reg , rtx base , poly_int64 offset ) { rtx mem = gen_frame_mem ( DImode , plus_constant ( Pmode , base , offset ) ) ; add_reg_note ( insn , REG_CFA_EXPRESSION , gen_rtx_SET ( mem , regno_reg_rtx [ reg ] ) ) ; } </s>

Add a REG_CFA_EXPRESSION note to INSN to say that register REG is saved at BASE + OFFSET .


<s> static void aarch64_add_offset_1 ( scalar_int_mode mode , rtx dest , rtx src , HOST_WIDE_INT offset , rtx temp1 , bool frame_related_p , bool emit_move_imm ) { gcc_assert ( emit_move_imm || temp1 != NULL_RTX ) ; gcc_assert ( temp1 == NULL_RTX || ! reg_overlap_mentioned_p ( temp1 , src ) ) ; HOST_WIDE_INT moffset = abs_hwi ( offset ) ; rtx_insn * insn ; if ( ! moffset ) { if ( ! rtx_equal_p ( dest , src ) ) { insn = emit_insn ( gen_rtx_SET ( dest , src ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; } return ; } if ( aarch64_uimm12_shift ( moffset ) ) { insn = emit_insn ( gen_add3_insn ( dest , src , GEN_INT ( offset ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; return ; } if ( moffset < 0x1000000 && ( ( ! temp1 && ! can_create_pseudo_p ( ) ) || ! aarch64_move_imm ( moffset , mode ) ) ) { HOST_WIDE_INT low_off = moffset & 0xfff ; low_off = offset < 0 ? - low_off : low_off ; insn = emit_insn ( gen_add3_insn ( dest , src , GEN_INT ( low_off ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; insn = emit_insn ( gen_add2_insn ( dest , GEN_INT ( offset - low_off ) ) ) ; RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; return ; } if ( emit_move_imm ) { gcc_assert ( temp1 != NULL_RTX || can_create_pseudo_p ( ) ) ; temp1 = aarch64_force_temporary ( mode , temp1 , GEN_INT ( moffset ) ) ; } insn = emit_insn ( offset < 0 ? gen_sub3_insn ( dest , src , temp1 ) : gen_add3_insn ( dest , src , temp1 ) ) ; if ( frame_related_p ) { RTX_FRAME_RELATED_P ( insn ) = frame_related_p ; rtx adj = plus_constant ( mode , src , offset ) ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( dest , adj ) ) ; } } </s>

A subroutine of aarch64_add_offset . Set DEST to SRC + OFFSET for a non-polynomial OFFSET . MODE is the mode of the addition . FRAME_RELATED_P is true if the RTX_FRAME_RELATED flag should be set and CFA adjustments added to the generated instructions . TEMP1 , if nonnull , is a register of mode MODE that can be used as a temporary if register allocation is already complete . This temporary register may overlap DEST but must not overlap SRC . If TEMP1 is known to hold abs ( OFFSET ) , EMIT_MOVE_IMM can be set to false to avoid emitting the immediate again . Since this function may be used to adjust the stack pointer , we must ensure that it can not cause transient stack deallocation ( for example by first incrementing SP and then decrementing when adjusting by a large immediate ) .


<s> static void aarch64_autovectorize_vector_sizes ( vector_sizes * sizes ) { if ( TARGET_SVE ) sizes -> safe_push ( BYTES_PER_SVE_VECTOR ) ; sizes -> safe_push ( 16 ) ; sizes -> safe_push ( 8 ) ; } </s>

Return a list of possible vector sizes for the vectorizer to iterate over .


<s> static bool aarch64_can_change_mode_class ( machine_mode from , machine_mode to , reg_class_t ) { if ( BYTES_BIG_ENDIAN ) { bool from_sve_p = aarch64_sve_data_mode_p ( from ) ; bool to_sve_p = aarch64_sve_data_mode_p ( to ) ; if ( from_sve_p != to_sve_p ) return false ; if ( from_sve_p && GET_MODE_UNIT_SIZE ( from ) != GET_MODE_UNIT_SIZE ( to ) ) return false ; } return true ; } </s>


<s> enum aarch64_symbol_type aarch64_classify_symbol ( rtx x , HOST_WIDE_INT 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_tls_symbol_p ( x ) ) return aarch64_classify_tls_symbol ( x ) ; switch ( aarch64_cmodel ) { case AARCH64_CMODEL_TINY : if ( ( SYMBOL_REF_WEAK ( x ) && ! aarch64_symbol_binds_local_p ( x ) ) || ! IN_RANGE ( offset , - 1048575 , 1048575 ) ) return SYMBOL_FORCE_TO_MEM ; return SYMBOL_TINY_ABSOLUTE ; case AARCH64_CMODEL_SMALL : if ( ( SYMBOL_REF_WEAK ( x ) && ! aarch64_symbol_binds_local_p ( x ) ) || ! IN_RANGE ( 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 ; case AARCH64_CMODEL_LARGE : if ( ! aarch64_pcrelative_literal_loads && CONSTANT_POOL_ADDRESS_P ( x ) ) return SYMBOL_SMALL_ABSOLUTE ; else return SYMBOL_FORCE_TO_MEM ; 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> static unsigned int aarch64_classify_vector_mode ( machine_mode mode ) { if ( aarch64_advsimd_struct_mode_p ( mode ) ) return VEC_ADVSIMD | VEC_STRUCT ; if ( aarch64_sve_pred_mode_p ( mode ) ) return VEC_SVE_PRED ; scalar_mode inner = GET_MODE_INNER ( mode ) ; if ( VECTOR_MODE_P ( mode ) && ( inner == QImode || inner == HImode || inner == HFmode || inner == SImode || inner == SFmode || inner == DImode || inner == DFmode ) ) { if ( TARGET_SVE ) { if ( known_eq ( GET_MODE_BITSIZE ( mode ) , BITS_PER_SVE_VECTOR ) ) return VEC_SVE_DATA ; if ( known_eq ( GET_MODE_BITSIZE ( mode ) , BITS_PER_SVE_VECTOR * 2 ) || known_eq ( GET_MODE_BITSIZE ( mode ) , BITS_PER_SVE_VECTOR * 3 ) || known_eq ( GET_MODE_BITSIZE ( mode ) , BITS_PER_SVE_VECTOR * 4 ) ) return VEC_SVE_DATA | VEC_STRUCT ; } if ( TARGET_SIMD && ( known_eq ( GET_MODE_BITSIZE ( mode ) , 64 ) || known_eq ( GET_MODE_BITSIZE ( mode ) , 128 ) ) ) return VEC_ADVSIMD ; } return 0 ; } </s>

Return a set of flags describing the vector properties of mode MODE . Ignore modes that are not supported by the current target .


<s> static sbitmap aarch64_components_for_bb ( basic_block bb ) { bitmap in = DF_LIVE_IN ( bb ) ; bitmap gen = & DF_LIVE_BB_INFO ( bb ) -> gen ; bitmap kill = & DF_LIVE_BB_INFO ( bb ) -> kill ; sbitmap components = sbitmap_alloc ( LAST_SAVED_REGNUM + 1 ) ; bitmap_clear ( components ) ; for ( unsigned regno = 0 ; regno <= LAST_SAVED_REGNUM ; regno ++ ) if ( ( ! call_used_regs [ regno ] ) && ( bitmap_bit_p ( in , regno ) || bitmap_bit_p ( gen , regno ) || bitmap_bit_p ( kill , regno ) ) ) { unsigned regno2 , offset , offset2 ; bitmap_set_bit ( components , regno ) ; offset = cfun -> machine -> frame . reg_offset [ regno ] ; regno2 = ( ( offset & 8 ) == 0 ) ? regno + 1 : regno - 1 ; if ( regno2 <= LAST_SAVED_REGNUM ) { offset2 = cfun -> machine -> frame . reg_offset [ regno2 ] ; if ( ( offset & ~ 8 ) == ( offset2 & ~ 8 ) ) bitmap_set_bit ( components , regno2 ) ; } } return components ; } </s>


<s> static enum insn_code aarch64_constant_pool_reload_icode ( machine_mode mode ) { switch ( mode ) { case E_SFmode : return CODE_FOR_aarch64_reload_movcpsfdi ; case E_DFmode : return CODE_FOR_aarch64_reload_movcpdfdi ; case E_TFmode : return CODE_FOR_aarch64_reload_movcptfdi ; case E_V8QImode : return CODE_FOR_aarch64_reload_movcpv8qidi ; case E_V16QImode : return CODE_FOR_aarch64_reload_movcpv16qidi ; case E_V4HImode : return CODE_FOR_aarch64_reload_movcpv4hidi ; case E_V8HImode : return CODE_FOR_aarch64_reload_movcpv8hidi ; case E_V2SImode : return CODE_FOR_aarch64_reload_movcpv2sidi ; case E_V4SImode : return CODE_FOR_aarch64_reload_movcpv4sidi ; case E_V2DImode : return CODE_FOR_aarch64_reload_movcpv2didi ; case E_V2DFmode : return CODE_FOR_aarch64_reload_movcpv2dfdi ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; } </s>

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


<s> static poly_uint16 aarch64_convert_sve_vector_bits ( aarch64_sve_vector_bits_enum value ) { if ( value == SVE_SCALABLE || value == SVE_128 ) return poly_uint16 ( 2 , 2 ) ; else return ( int ) value / 64 ; } </s>

Return the VG value associated with -msve-vector-bits= value VALUE .


<s> bool aarch64_emit_approx_div ( rtx quo , rtx num , rtx den ) { machine_mode mode = GET_MODE ( quo ) ; if ( GET_MODE_INNER ( mode ) == HFmode ) return false ; bool use_approx_division_p = ( flag_mlow_precision_div || ( aarch64_tune_params . approx_modes -> division & AARCH64_APPROX_MODE ( mode ) ) ) ; if ( ! flag_finite_math_only || flag_trapping_math || ! flag_unsafe_math_optimizations || optimize_function_for_size_p ( cfun ) || ! use_approx_division_p ) return false ; if ( ! TARGET_SIMD && VECTOR_MODE_P ( mode ) ) return false ; rtx xrcp = gen_reg_rtx ( mode ) ; emit_insn ( ( * get_recpe_type ( mode ) ) ( xrcp , den ) ) ; int iterations = ( GET_MODE_INNER ( mode ) == DFmode ) ? 3 : 2 ; if ( flag_mlow_precision_div ) iterations -- ; rtx xtmp = gen_reg_rtx ( mode ) ; while ( iterations -- ) { emit_insn ( ( * get_recps_type ( mode ) ) ( xtmp , xrcp , den ) ) ; if ( iterations > 0 ) emit_set_insn ( xrcp , gen_rtx_MULT ( mode , xrcp , xtmp ) ) ; } if ( num != CONST1_RTX ( mode ) ) { rtx xnum = force_reg ( mode , num ) ; emit_set_insn ( xrcp , gen_rtx_MULT ( mode , xrcp , xnum ) ) ; } emit_set_insn ( quo , gen_rtx_MULT ( mode , xrcp , xtmp ) ) ; return true ; } </s>

Emit the instruction sequence to compute the approximation for the division of NUM by DEN in QUO and return whether the sequence was emitted or not .


<s> bool aarch64_emit_approx_sqrt ( rtx dst , rtx src , bool recp ) { machine_mode mode = GET_MODE ( dst ) ; if ( GET_MODE_INNER ( mode ) == HFmode ) { gcc_assert ( ! recp ) ; return false ; } if ( ! recp ) { if ( ! ( flag_mlow_precision_sqrt || ( aarch64_tune_params . approx_modes -> sqrt & AARCH64_APPROX_MODE ( mode ) ) ) ) return false ; if ( flag_finite_math_only || flag_trapping_math || ! flag_unsafe_math_optimizations || optimize_function_for_size_p ( cfun ) ) return false ; } else gcc_assert ( use_rsqrt_p ( mode ) ) ; machine_mode mmsk = mode_for_int_vector ( mode ) . require ( ) ; rtx xmsk = gen_reg_rtx ( mmsk ) ; if ( ! recp ) emit_insn ( gen_rtx_SET ( xmsk , gen_rtx_NEG ( mmsk , gen_rtx_EQ ( mmsk , src , CONST0_RTX ( mode ) ) ) ) ) ; rtx xdst = gen_reg_rtx ( mode ) ; emit_insn ( ( * get_rsqrte_type ( mode ) ) ( xdst , src ) ) ; int iterations = ( GET_MODE_INNER ( mode ) == DFmode ) ? 3 : 2 ; if ( ( recp && flag_mrecip_low_precision_sqrt ) || ( ! recp && flag_mlow_precision_sqrt ) ) iterations -- ; rtx x1 = gen_reg_rtx ( mode ) ; while ( iterations -- ) { rtx x2 = gen_reg_rtx ( mode ) ; emit_set_insn ( x2 , gen_rtx_MULT ( mode , xdst , xdst ) ) ; emit_insn ( ( * get_rsqrts_type ( mode ) ) ( x1 , src , x2 ) ) ; if ( iterations > 0 ) emit_set_insn ( xdst , gen_rtx_MULT ( mode , xdst , x1 ) ) ; } if ( ! recp ) { rtx xtmp = gen_reg_rtx ( mmsk ) ; emit_set_insn ( xtmp , gen_rtx_AND ( mmsk , gen_rtx_NOT ( mmsk , xmsk ) , gen_rtx_SUBREG ( mmsk , xdst , 0 ) ) ) ; emit_move_insn ( xdst , gen_rtx_SUBREG ( mode , xtmp , 0 ) ) ; emit_set_insn ( xdst , gen_rtx_MULT ( mode , xdst , src ) ) ; } emit_set_insn ( dst , gen_rtx_MULT ( mode , xdst , x1 ) ) ; return true ; } </s>

Emit instruction sequence to compute either the approximate square root or its approximate reciprocal , depending on the flag RECP , and return whether the sequence was emitted or not .


<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 E_QImode : idx = 0 ; break ; case E_HImode : idx = 1 ; break ; case E_SImode : idx = 2 ; break ; case E_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 E_QImode : gen = gen_aarch64_atomic_swpqi ; break ; case E_HImode : gen = gen_aarch64_atomic_swphi ; break ; case E_SImode : gen = gen_aarch64_atomic_swpsi ; break ; case E_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 E_SImode : gen = gen_and_one_cmpl_lshrsi3 ; break ; case E_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_inverted_unspec_cond ( rtx target , rtx_code code , machine_mode pred_mode , rtx ptrue , rtx pred , rtx op0 , rtx op1 , bool can_invert_p ) { if ( can_invert_p ) aarch64_emit_unspec_cond ( target , code , pred_mode , pred , op0 , op1 ) ; else { rtx tmp = gen_reg_rtx ( pred_mode ) ; aarch64_emit_unspec_cond ( tmp , code , pred_mode , pred , op0 , op1 ) ; emit_set_insn ( target , gen_rtx_AND ( pred_mode , gen_rtx_NOT ( pred_mode , tmp ) , ptrue ) ) ; } } </s>

If CAN_INVERT_P , emit an instruction : ( set TARGET ( unspec : PRED_MODE [ PRED OP0 OP1 ] UNSPEC_COND_ < X > ) ) where < X > is the operation associated with comparison CODE . Otherwise emit : ( set TMP ( unspec : PRED_MODE [ PRED OP0 OP1 ] UNSPEC_COND_ < X > ) ) ( set TARGET ( and : PRED_MODE ( not : PRED_MODE TMP ) PTRUE ) ) where the second instructions sets TARGET to the inverse of TMP .


<s> static void aarch64_emit_load_exclusive ( machine_mode mode , rtx rval , rtx mem , rtx model_rtx ) { rtx ( * gen ) ( rtx , rtx , rtx ) ; switch ( mode ) { case E_QImode : gen = gen_aarch64_load_exclusiveqi ; break ; case E_HImode : gen = gen_aarch64_load_exclusivehi ; break ; case E_SImode : gen = gen_aarch64_load_exclusivesi ; break ; case E_DImode : gen = gen_aarch64_load_exclusivedi ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( rval , mem , model_rtx ) ) ; } </s>


<s> static void aarch64_emit_store_exclusive ( machine_mode mode , rtx bval , rtx rval , rtx mem , rtx model_rtx ) { rtx ( * gen ) ( rtx , rtx , rtx , rtx ) ; switch ( mode ) { case E_QImode : gen = gen_aarch64_store_exclusiveqi ; break ; case E_HImode : gen = gen_aarch64_store_exclusivehi ; break ; case E_SImode : gen = gen_aarch64_store_exclusivesi ; break ; case E_DImode : gen = gen_aarch64_store_exclusivedi ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( bval , rval , mem , model_rtx ) ) ; } </s>


<s> void aarch64_emit_sve_pred_move ( rtx dest , rtx pred , rtx src ) { emit_insn ( gen_rtx_SET ( dest , gen_rtx_UNSPEC ( GET_MODE ( dest ) , gen_rtvec ( 2 , pred , src ) , UNSPEC_MERGE_PTRUE ) ) ) ; } </s>

Emit an SVE predicated move from SRC to DEST . PRED is a predicate that is known to contain PTRUE .


<s> static void aarch64_emit_unspec_cond ( rtx target , rtx_code code , machine_mode pred_mode , rtx pred , rtx op0 , rtx op1 ) { rtx unspec = aarch64_gen_unspec_cond ( code , pred_mode , pred , op0 , op1 ) ; emit_set_insn ( target , unspec ) ; } </s>

Emit an instruction : ( set TARGET ( unspec : PRED_MODE [ PRED OP0 OP1 ] UNSPEC_COND_ < X > ) ) where < X > is the operation associated with comparison CODE .


Emit : ( set TMP1 ( unspec : PRED_MODE [ PTRUE OP0 OP1 ] UNSPEC_COND_ < X1 > ) ) ( set TMP2 ( unspec : PRED_MODE [ PTRUE OP0 OP1 ] UNSPEC_COND_ < X2 > ) ) ( set TARGET ( and : PRED_MODE ( ior : PRED_MODE TMP1 TMP2 ) PTRUE ) ) where < Xi > is the operation associated with comparison CODEi .


<s> static bool aarch64_evpc_rev_global ( struct expand_vec_perm_d * d ) { poly_uint64 nelt = d -> perm . length ( ) ; if ( ! d -> one_vector_p || d -> vec_flags != VEC_SVE_DATA ) return false ; if ( ! d -> perm . series_p ( 0 , 1 , nelt - 1 , - 1 ) ) return false ; if ( d -> testing_p ) return true ; rtx src = gen_rtx_UNSPEC ( d -> vmode , gen_rtvec ( 1 , d -> op0 ) , UNSPEC_REV ) ; emit_set_insn ( d -> target , src ) ; return true ; } </s>

Recognize patterns for the REV insn , which reverses elements within a full vector .


<s> static bool aarch64_evpc_rev_local ( struct expand_vec_perm_d * d ) { HOST_WIDE_INT diff ; unsigned int i , size , unspec ; machine_mode pred_mode ; if ( d -> vec_flags == VEC_SVE_PRED || ! d -> one_vector_p || ! d -> perm [ 0 ] . is_constant ( & diff ) ) return false ; size = ( diff + 1 ) * GET_MODE_UNIT_SIZE ( d -> vmode ) ; if ( size == 8 ) { unspec = UNSPEC_REV64 ; pred_mode = VNx2BImode ; } else if ( size == 4 ) { unspec = UNSPEC_REV32 ; pred_mode = VNx4BImode ; } else if ( size == 2 ) { unspec = UNSPEC_REV16 ; pred_mode = VNx8BImode ; } else return false ; unsigned int step = diff + 1 ; for ( i = 0 ; i < step ; ++ i ) if ( ! d -> perm . series_p ( i , step , diff - i , step ) ) return false ; if ( d -> testing_p ) return true ; rtx src = gen_rtx_UNSPEC ( d -> vmode , gen_rtvec ( 1 , d -> op0 ) , unspec ) ; if ( d -> vec_flags == VEC_SVE_DATA ) { rtx pred = force_reg ( pred_mode , CONSTM1_RTX ( pred_mode ) ) ; src = gen_rtx_UNSPEC ( d -> vmode , gen_rtvec ( 2 , pred , src ) , UNSPEC_MERGE_PTRUE ) ; } emit_set_insn ( d -> target , src ) ; return true ; } </s>

Recognize patterns for the REV { 64,32,16 } insns , which reverse elements within each 64-bit , 32-bit or 16-bit granule .


<s> static bool aarch64_evpc_sve_tbl ( struct expand_vec_perm_d * d ) { unsigned HOST_WIDE_INT nelt ; if ( ! d -> one_vector_p && ! d -> perm . length ( ) . is_constant ( & nelt ) ) return false ; if ( d -> testing_p ) return true ; machine_mode sel_mode = mode_for_int_vector ( d -> vmode ) . require ( ) ; rtx sel = vec_perm_indices_to_rtx ( sel_mode , d -> perm ) ; aarch64_expand_sve_vec_perm ( d -> target , d -> op0 , d -> op1 , sel ) ; return true ; } </s>

Try to implement D using an SVE TBL instruction .


<s> void aarch64_expand_call ( rtx result , rtx mem , bool sibcall ) { rtx call , callee , tmp ; rtvec vec ; machine_mode mode ; gcc_assert ( MEM_P ( mem ) ) ; callee = XEXP ( mem , 0 ) ; mode = GET_MODE ( callee ) ; gcc_assert ( mode == Pmode ) ; if ( SYMBOL_REF_P ( callee ) ? ( aarch64_is_long_call_p ( callee ) || aarch64_is_noplt_call_p ( callee ) ) : ! REG_P ( callee ) ) XEXP ( mem , 0 ) = force_reg ( mode , callee ) ; call = gen_rtx_CALL ( VOIDmode , mem , const0_rtx ) ; if ( result != NULL_RTX ) call = gen_rtx_SET ( result , call ) ; if ( sibcall ) tmp = ret_rtx ; else tmp = gen_rtx_CLOBBER ( VOIDmode , gen_rtx_REG ( Pmode , LR_REGNUM ) ) ; vec = gen_rtvec ( 2 , call , tmp ) ; call = gen_rtx_PARALLEL ( VOIDmode , vec ) ; aarch64_emit_call_insn ( call ) ; } </s>

This function is used by the call expanders of the machine description . RESULT is the register in which the result is returned . It 's NULL for `` call '' and `` sibcall '' . MEM is the location of the function call . SIBCALL indicates whether this function call is normal call or sibling call . It will generate different pattern accordingly .


<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 E_QImode : case E_HImode : cmp_mode = SImode ; rval = gen_reg_rtx ( SImode ) ; oldval = convert_modes ( SImode , mode , oldval , true ) ; case E_SImode : case E_DImode : if ( ! aarch64_plus_operand ( oldval , mode ) ) oldval = force_reg ( cmp_mode , oldval ) ; break ; default : gcc_unreachable ( ) ; } switch ( mode ) { case E_QImode : idx = 0 ; break ; case E_HImode : idx = 1 ; break ; case E_SImode : idx = 2 ; break ; case E_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_epilogue ( bool for_sibcall ) { aarch64_layout_frame ( ) ; poly_int64 initial_adjust = cfun -> machine -> frame . initial_adjust ; HOST_WIDE_INT callee_adjust = cfun -> machine -> frame . callee_adjust ; poly_int64 final_adjust = cfun -> machine -> frame . final_adjust ; poly_int64 callee_offset = cfun -> machine -> frame . callee_offset ; unsigned reg1 = cfun -> machine -> frame . wb_candidate1 ; unsigned reg2 = cfun -> machine -> frame . wb_candidate2 ; rtx cfi_ops = NULL ; rtx_insn * insn ; bool can_inherit_p = ( initial_adjust . is_constant ( ) && final_adjust . is_constant ( ) && ! flag_stack_clash_protection ) ; bool need_barrier_p = maybe_ne ( get_frame_size ( ) + cfun -> machine -> frame . saved_varargs_size , 0 ) ; if ( maybe_gt ( final_adjust , crtl -> outgoing_args_size ) || cfun -> calls_alloca || crtl -> calls_eh_return ) { emit_insn ( gen_stack_tie ( stack_pointer_rtx , stack_pointer_rtx ) ) ; need_barrier_p = false ; } rtx ip0_rtx = gen_rtx_REG ( Pmode , IP0_REGNUM ) ; rtx ip1_rtx = gen_rtx_REG ( Pmode , IP1_REGNUM ) ; if ( frame_pointer_needed && ( maybe_ne ( final_adjust , 0 ) || cfun -> calls_alloca ) ) aarch64_add_offset ( Pmode , stack_pointer_rtx , hard_frame_pointer_rtx , - callee_offset , ip1_rtx , ip0_rtx , callee_adjust == 0 ) ; else aarch64_add_sp ( ip1_rtx , ip0_rtx , final_adjust , ! can_inherit_p || df_regs_ever_live_p ( IP1_REGNUM ) ) ; aarch64_restore_callee_saves ( DImode , callee_offset , R0_REGNUM , R30_REGNUM , callee_adjust != 0 , & cfi_ops ) ; aarch64_restore_callee_saves ( DFmode , callee_offset , V0_REGNUM , V31_REGNUM , callee_adjust != 0 , & cfi_ops ) ; if ( need_barrier_p ) emit_insn ( gen_stack_tie ( stack_pointer_rtx , stack_pointer_rtx ) ) ; if ( callee_adjust != 0 ) aarch64_pop_regs ( reg1 , reg2 , callee_adjust , & cfi_ops ) ; if ( callee_adjust != 0 || maybe_gt ( initial_adjust , 65536 ) ) { insn = get_last_insn ( ) ; rtx new_cfa = plus_constant ( Pmode , stack_pointer_rtx , initial_adjust ) ; REG_NOTES ( insn ) = alloc_reg_note ( REG_CFA_DEF_CFA , new_cfa , cfi_ops ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; cfi_ops = NULL ; } aarch64_add_sp ( ip0_rtx , ip1_rtx , initial_adjust , ! can_inherit_p || df_regs_ever_live_p ( IP0_REGNUM ) ) ; if ( cfi_ops ) { insn = get_last_insn ( ) ; cfi_ops = alloc_reg_note ( REG_CFA_DEF_CFA , stack_pointer_rtx , cfi_ops ) ; REG_NOTES ( insn ) = cfi_ops ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( aarch64_return_address_signing_enabled ( ) && ( for_sibcall || ! TARGET_ARMV8_3 || crtl -> calls_eh_return ) ) { insn = emit_insn ( gen_autisp ( ) ) ; add_reg_note ( insn , REG_CFA_TOGGLE_RA_MANGLE , const0_rtx ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( crtl -> calls_eh_return ) { emit_insn ( gen_add2_insn ( stack_pointer_rtx , EH_RETURN_STACKADJ_RTX ) ) ; } emit_use ( gen_rtx_REG ( DImode , LR_REGNUM ) ) ; if ( ! for_sibcall ) emit_jump_insn ( ret_rtx ) ; } </s>

Generate the epilogue instructions for returning from a function .


<s> void aarch64_expand_prologue ( void ) { aarch64_layout_frame ( ) ; poly_int64 frame_size = cfun -> machine -> frame . frame_size ; poly_int64 initial_adjust = cfun -> machine -> frame . initial_adjust ; HOST_WIDE_INT callee_adjust = cfun -> machine -> frame . callee_adjust ; poly_int64 final_adjust = cfun -> machine -> frame . final_adjust ; poly_int64 callee_offset = cfun -> machine -> frame . callee_offset ; unsigned reg1 = cfun -> machine -> frame . wb_candidate1 ; unsigned reg2 = cfun -> machine -> frame . wb_candidate2 ; bool emit_frame_chain = cfun -> machine -> frame . emit_frame_chain ; rtx_insn * insn ; if ( aarch64_return_address_signing_enabled ( ) ) { insn = emit_insn ( gen_pacisp ( ) ) ; add_reg_note ( insn , REG_CFA_TOGGLE_RA_MANGLE , const0_rtx ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } if ( flag_stack_usage_info ) current_function_static_stack_size = constant_lower_bound ( frame_size ) ; if ( flag_stack_check == STATIC_BUILTIN_STACK_CHECK ) { if ( crtl -> is_leaf && ! cfun -> calls_alloca ) { if ( maybe_gt ( frame_size , PROBE_INTERVAL ) && maybe_gt ( frame_size , get_stack_check_protect ( ) ) ) aarch64_emit_probe_stack_range ( get_stack_check_protect ( ) , ( frame_size - get_stack_check_protect ( ) ) ) ; } else if ( maybe_gt ( frame_size , 0 ) ) aarch64_emit_probe_stack_range ( get_stack_check_protect ( ) , frame_size ) ; } rtx ip0_rtx = gen_rtx_REG ( Pmode , IP0_REGNUM ) ; rtx ip1_rtx = gen_rtx_REG ( Pmode , IP1_REGNUM ) ; aarch64_sub_sp ( ip0_rtx , ip1_rtx , initial_adjust , true ) ; if ( callee_adjust != 0 ) aarch64_push_regs ( reg1 , reg2 , callee_adjust ) ; if ( emit_frame_chain ) { poly_int64 reg_offset = callee_adjust ; if ( callee_adjust == 0 ) { reg1 = R29_REGNUM ; reg2 = R30_REGNUM ; reg_offset = callee_offset ; aarch64_save_callee_saves ( DImode , reg_offset , reg1 , reg2 , false ) ; } aarch64_add_offset ( Pmode , hard_frame_pointer_rtx , stack_pointer_rtx , callee_offset , ip1_rtx , ip0_rtx , frame_pointer_needed ) ; if ( frame_pointer_needed && ! frame_size . is_constant ( ) ) { rtx_insn * insn = get_last_insn ( ) ; gcc_assert ( RTX_FRAME_RELATED_P ( insn ) ) ; if ( ! find_reg_note ( insn , REG_CFA_ADJUST_CFA , NULL_RTX ) ) { rtx src = plus_constant ( Pmode , stack_pointer_rtx , callee_offset ) ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , gen_rtx_SET ( hard_frame_pointer_rtx , src ) ) ; } reg_offset -= callee_offset ; aarch64_add_cfa_expression ( insn , reg2 , hard_frame_pointer_rtx , reg_offset + UNITS_PER_WORD ) ; aarch64_add_cfa_expression ( insn , reg1 , hard_frame_pointer_rtx , reg_offset ) ; } emit_insn ( gen_stack_tie ( stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; } aarch64_save_callee_saves ( DImode , callee_offset , R0_REGNUM , R30_REGNUM , callee_adjust != 0 || emit_frame_chain ) ; aarch64_save_callee_saves ( DFmode , callee_offset , V0_REGNUM , V31_REGNUM , callee_adjust != 0 || emit_frame_chain ) ; aarch64_sub_sp ( ip1_rtx , ip0_rtx , final_adjust , ! frame_pointer_needed ) ; } </s>

Generate the prologue instructions for entry into a function . Establish the stack frame by decreasing the stack pointer with a properly calculated size and , if necessary , create a frame record filled with the values of LR and previous frame pointer . The current FP is also set up if it is in use .


<s> static void aarch64_expand_sve_const_vector ( rtx dest , rtx src ) { machine_mode mode = GET_MODE ( src ) ; unsigned int npatterns = CONST_VECTOR_NPATTERNS ( src ) ; unsigned int nelts_per_pattern = CONST_VECTOR_NELTS_PER_PATTERN ( src ) ; gcc_assert ( npatterns > 1 ) ; if ( nelts_per_pattern == 1 ) { scalar_int_mode int_mode ; if ( BYTES_BIG_ENDIAN ) int_mode = TImode ; else { unsigned int int_bits = GET_MODE_UNIT_BITSIZE ( mode ) * npatterns ; gcc_assert ( int_bits <= 128 ) ; int_mode = int_mode_for_size ( int_bits , 0 ) . require ( ) ; } rtx int_value = simplify_gen_subreg ( int_mode , src , mode , 0 ) ; if ( int_value && aarch64_expand_sve_widened_duplicate ( dest , int_mode , int_value ) ) return ; } rtx_vector_builder builder ; auto_vec < rtx , 16 > vectors ( npatterns ) ; for ( unsigned int i = 0 ; i < npatterns ; ++ i ) { builder . new_vector ( mode , 1 , nelts_per_pattern ) ; for ( unsigned int j = 0 ; j < nelts_per_pattern ; ++ j ) builder . quick_push ( CONST_VECTOR_ELT ( src , i + j * npatterns ) ) ; vectors . quick_push ( force_reg ( mode , builder . build ( ) ) ) ; } while ( npatterns > 1 ) { npatterns /= 2 ; for ( unsigned int i = 0 ; i < npatterns ; ++ i ) { rtx tmp = ( npatterns == 1 ? dest : gen_reg_rtx ( mode ) ) ; rtvec v = gen_rtvec ( 2 , vectors [ i ] , vectors [ i + npatterns ] ) ; emit_set_insn ( tmp , gen_rtx_UNSPEC ( mode , v , UNSPEC_ZIP1 ) ) ; vectors [ i ] = tmp ; } } gcc_assert ( vectors [ 0 ] == dest ) ; } </s>

Expand a move of general CONST_VECTOR SRC into DEST , given that it is n't a simple duplicate or series .


<s> void aarch64_expand_sve_mem_move ( rtx dest , rtx src , machine_mode pred_mode ) { machine_mode mode = GET_MODE ( dest ) ; rtx ptrue = force_reg ( pred_mode , CONSTM1_RTX ( pred_mode ) ) ; if ( ! register_operand ( src , mode ) && ! register_operand ( dest , mode ) ) { rtx tmp = gen_reg_rtx ( mode ) ; if ( MEM_P ( src ) ) aarch64_emit_sve_pred_move ( tmp , ptrue , src ) ; else emit_move_insn ( tmp , src ) ; src = tmp ; } aarch64_emit_sve_pred_move ( dest , ptrue , src ) ; } </s>

Expand a pre-RA SVE data move from SRC to DEST in which at least one operand is in memory . In this case we need to use the predicated LD1 and ST1 instead of LDR and STR , both for correctness on big-endian targets and because LD1 and ST1 support a wider range of addressing modes . PRED_MODE is the mode of the predicate . See the comment at the head of aarch64-sve.md for details about the big-endian handling .


<s> void aarch64_expand_sve_vcond ( machine_mode data_mode , machine_mode cmp_mode , rtx * ops ) { machine_mode pred_mode = aarch64_get_mask_mode ( GET_MODE_NUNITS ( cmp_mode ) , GET_MODE_SIZE ( cmp_mode ) ) . require ( ) ; rtx pred = gen_reg_rtx ( pred_mode ) ; if ( FLOAT_MODE_P ( cmp_mode ) ) { if ( aarch64_expand_sve_vec_cmp_float ( pred , GET_CODE ( ops [ 3 ] ) , ops [ 4 ] , ops [ 5 ] , true ) ) std :: swap ( ops [ 1 ] , ops [ 2 ] ) ; } else aarch64_expand_sve_vec_cmp_int ( pred , GET_CODE ( ops [ 3 ] ) , ops [ 4 ] , ops [ 5 ] ) ; rtvec vec = gen_rtvec ( 3 , pred , ops [ 1 ] , ops [ 2 ] ) ; emit_set_insn ( ops [ 0 ] , gen_rtx_UNSPEC ( data_mode , vec , UNSPEC_SEL ) ) ; } </s>

Expand an SVE vcond pattern with operands OPS . DATA_MODE is the mode of the data being selected and CMP_MODE is the mode of the values being compared .


<s> bool aarch64_expand_sve_vec_cmp_float ( rtx target , rtx_code code , rtx op0 , rtx op1 , bool can_invert_p ) { machine_mode pred_mode = GET_MODE ( target ) ; machine_mode data_mode = GET_MODE ( op0 ) ; rtx ptrue = force_reg ( pred_mode , CONSTM1_RTX ( pred_mode ) ) ; switch ( code ) { case UNORDERED : op1 = force_reg ( data_mode , op1 ) ; aarch64_emit_unspec_cond ( target , code , pred_mode , ptrue , op0 , op1 ) ; return false ; case LT : case LE : case GT : case GE : case EQ : case NE : aarch64_emit_unspec_cond ( target , code , pred_mode , ptrue , op0 , op1 ) ; return false ; case ORDERED : op1 = force_reg ( data_mode , op1 ) ; aarch64_emit_inverted_unspec_cond ( target , UNORDERED , pred_mode , ptrue , ptrue , op0 , op1 , can_invert_p ) ; return can_invert_p ; case LTGT : aarch64_emit_unspec_cond_or ( target , LT , GT , pred_mode , ptrue , op0 , op1 ) ; return false ; case UNEQ : if ( ! flag_trapping_math ) { op1 = force_reg ( data_mode , op1 ) ; aarch64_emit_unspec_cond_or ( target , UNORDERED , EQ , pred_mode , ptrue , op0 , op1 ) ; return false ; } case UNLT : case UNLE : case UNGT : case UNGE : { rtx ordered = ptrue ; if ( flag_trapping_math ) { ordered = gen_reg_rtx ( pred_mode ) ; op1 = force_reg ( data_mode , op1 ) ; aarch64_emit_inverted_unspec_cond ( ordered , UNORDERED , pred_mode , ptrue , ptrue , op0 , op1 , false ) ; } if ( code == UNEQ ) code = NE ; else code = reverse_condition_maybe_unordered ( code ) ; aarch64_emit_inverted_unspec_cond ( target , code , pred_mode , ptrue , ordered , op0 , op1 , can_invert_p ) ; return can_invert_p ; } default : gcc_unreachable ( ) ; } } </s>

Expand an SVE floating-point comparison : TARGET = CODE ( OP0 , OP1 ) If CAN_INVERT_P is true , the caller can also handle inverted results ; return true if the result is in fact inverted .


<s> void aarch64_expand_sve_vec_cmp_int ( rtx target , rtx_code code , rtx op0 , rtx op1 ) { machine_mode pred_mode = GET_MODE ( target ) ; machine_mode data_mode = GET_MODE ( op0 ) ; if ( ! aarch64_sve_cmp_operand_p ( code , op1 ) ) op1 = force_reg ( data_mode , op1 ) ; rtx ptrue = force_reg ( pred_mode , CONSTM1_RTX ( pred_mode ) ) ; rtx unspec = aarch64_gen_unspec_cond ( code , pred_mode , ptrue , op0 , op1 ) ; emit_insn ( gen_set_clobber_cc ( target , unspec ) ) ; } </s>

Expand an SVE integer comparison : TARGET = CODE ( OP0 , OP1 ) .


<s> static bool aarch64_expand_sve_widened_duplicate ( rtx dest , scalar_int_mode src_mode , rtx src ) { if ( src_mode != TImode ) { poly_uint64 count = exact_div ( GET_MODE_SIZE ( GET_MODE ( dest ) ) , GET_MODE_SIZE ( src_mode ) ) ; machine_mode dup_mode = mode_for_vector ( src_mode , count ) . require ( ) ; emit_move_insn ( gen_lowpart ( dup_mode , dest ) , gen_const_vec_duplicate ( dup_mode , src ) ) ; return true ; } src = force_const_mem ( src_mode , src ) ; if ( ! src ) return false ; if ( ! aarch64_sve_ld1r_operand_p ( src ) ) { rtx addr = force_reg ( Pmode , XEXP ( src , 0 ) ) ; src = replace_equiv_address ( src , addr ) ; } machine_mode mode = GET_MODE ( dest ) ; unsigned int elem_bytes = GET_MODE_UNIT_SIZE ( mode ) ; machine_mode pred_mode = aarch64_sve_pred_mode ( elem_bytes ) . require ( ) ; rtx ptrue = force_reg ( pred_mode , CONSTM1_RTX ( pred_mode ) ) ; src = gen_rtx_UNSPEC ( mode , gen_rtvec ( 2 , ptrue , src ) , UNSPEC_LD1RQ ) ; emit_insn ( gen_rtx_SET ( dest , src ) ) ; return true ; } </s>

Try to duplicate SRC into SVE register DEST , given that SRC is an integer of mode INT_MODE . Return true on success .


<s> static rtx aarch64_function_value ( const_tree type , const_tree func , bool outgoing ATTRIBUTE_UNUSED ) { machine_mode mode ; int unsignedp ; int count ; machine_mode ag_mode ; mode = TYPE_MODE ( type ) ; if ( INTEGRAL_TYPE_P ( type ) ) mode = promote_function_mode ( type , mode , & unsignedp , func , 1 ) ; if ( aarch64_return_in_msb ( type ) ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( size % UNITS_PER_WORD != 0 ) { size += UNITS_PER_WORD - size % UNITS_PER_WORD ; mode = int_mode_for_size ( size * BITS_PER_UNIT , 0 ) . require ( ) ; } } if ( aarch64_vfp_is_call_or_return_candidate ( mode , type , & ag_mode , & count , NULL ) ) { if ( ! aarch64_composite_type_p ( type , mode ) ) { gcc_assert ( count == 1 && mode == ag_mode ) ; return gen_rtx_REG ( mode , V0_REGNUM ) ; } else { int i ; rtx par ; par = gen_rtx_PARALLEL ( mode , rtvec_alloc ( count ) ) ; for ( i = 0 ; i < count ; i ++ ) { rtx tmp = gen_rtx_REG ( ag_mode , V0_REGNUM + i ) ; rtx offset = gen_int_mode ( i * GET_MODE_SIZE ( ag_mode ) , Pmode ) ; tmp = gen_rtx_EXPR_LIST ( VOIDmode , tmp , offset ) ; XVECEXP ( par , 0 , i ) = tmp ; } return par ; } } else return gen_rtx_REG ( mode , R0_REGNUM ) ; } </s>

Implement TARGET_FUNCTION_VALUE . Define how to find the value returned by a function .


<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 E_QImode : gen = gen_aarch64_atomic_casqi ; break ; case E_HImode : gen = gen_aarch64_atomic_cashi ; break ; case E_SImode : gen = gen_aarch64_atomic_cassi ; break ; case E_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> static rtx aarch64_gen_loadwb_pair ( machine_mode mode , rtx base , rtx reg , rtx reg2 , HOST_WIDE_INT adjustment ) { switch ( mode ) { case E_DImode : return gen_loadwb_pairdi_di ( base , base , reg , reg2 , GEN_INT ( adjustment ) , GEN_INT ( UNITS_PER_WORD ) ) ; case E_DFmode : return gen_loadwb_pairdf_di ( base , base , reg , reg2 , GEN_INT ( adjustment ) , GEN_INT ( UNITS_PER_WORD ) ) ; default : gcc_unreachable ( ) ; } } </s>

Load the pair of register REG , REG2 of mode MODE from stack location BASE , adjusting it by ADJUSTMENT afterwards .


<s> static rtx aarch64_gen_load_pair ( machine_mode mode , rtx reg1 , rtx mem1 , rtx reg2 , rtx mem2 ) { switch ( mode ) { case E_DImode : return gen_load_pairdi ( reg1 , mem1 , reg2 , mem2 ) ; case E_DFmode : return gen_load_pairdf ( reg1 , mem1 , reg2 , mem2 ) ; default : gcc_unreachable ( ) ; } } </s>

Generate and regurn a load pair isntruction of mode MODE to load register REG1 from MEM1 and register REG2 from MEM2 .


<s> static rtx aarch64_gen_storewb_pair ( machine_mode mode , rtx base , rtx reg , rtx reg2 , HOST_WIDE_INT adjustment ) { switch ( mode ) { case E_DImode : return gen_storewb_pairdi_di ( base , base , reg , reg2 , GEN_INT ( - adjustment ) , GEN_INT ( UNITS_PER_WORD - adjustment ) ) ; case E_DFmode : return gen_storewb_pairdf_di ( base , base , reg , reg2 , GEN_INT ( - adjustment ) , GEN_INT ( UNITS_PER_WORD - adjustment ) ) ; default : gcc_unreachable ( ) ; } } </s>

Generate and return an instruction to store the pair of registers REG and REG2 of mode MODE to location BASE with write-back adjusting the stack location BASE by ADJUSTMENT .


<s> static rtx aarch64_gen_store_pair ( machine_mode mode , rtx mem1 , rtx reg1 , rtx mem2 , rtx reg2 ) { switch ( mode ) { case E_DImode : return gen_store_pairdi ( mem1 , reg1 , mem2 , reg2 ) ; case E_DFmode : return gen_store_pairdf ( mem1 , reg1 , mem2 , reg2 ) ; default : gcc_unreachable ( ) ; } } </s>

Generate and return a store pair instruction of mode MODE to store register REG1 to MEM1 and register REG2 to MEM2 .


<s> static rtx aarch64_gen_unspec_cond ( rtx_code code , machine_mode pred_mode , rtx pred , rtx op0 , rtx op1 ) { rtvec vec = gen_rtvec ( 3 , pred , op0 , op1 ) ; return gen_rtx_UNSPEC ( pred_mode , vec , aarch64_unspec_cond_code ( code ) ) ; } </s>

Return an ( unspec : PRED_MODE [ PRED OP0 OP1 ] UNSPEC_COND_ < X > ) expression , where < X > is the operation associated with comparison CODE .


<s> static opt_machine_mode aarch64_get_mask_mode ( poly_uint64 nunits , poly_uint64 nbytes ) { if ( TARGET_SVE && known_eq ( nbytes , BYTES_PER_SVE_VECTOR ) ) { unsigned int elem_nbytes = vector_element_size ( nbytes , nunits ) ; machine_mode pred_mode ; if ( aarch64_sve_pred_mode ( elem_nbytes ) . exists ( & pred_mode ) ) return pred_mode ; } return default_get_mask_mode ( nunits , nbytes ) ; } </s>