"argument of type %qT not permitted with -mgeneral-regs-only"

Return true if an argument whose type is TYPE , or mode is MODE , is suitable for passing or returning in VFP registers for the PCS variant selected . If it is , then * BASE_MODE is updated to contain a machine mode describing each element of the argument 's type and * COUNT to hold the number of such elements .


<s> void arm_emit_call_insn ( rtx pat , rtx addr , bool sibcall ) { rtx insn ; insn = emit_call_insn ( pat ) ; if ( TARGET_VXWORKS_RTP && flag_pic && ! sibcall && GET_CODE ( addr ) == SYMBOL_REF && ( SYMBOL_REF_DECL ( addr ) ? ! targetm . binds_local_p ( SYMBOL_REF_DECL ( addr ) ) : ! SYMBOL_REF_LOCAL_P ( addr ) ) ) { require_pic_register ( NULL_RTX , false ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , cfun -> machine -> pic_reg ) ; } if ( TARGET_AAPCS_BASED ) { rtx * fusage = & CALL_INSN_FUNCTION_USAGE ( insn ) ; clobber_reg ( fusage , gen_rtx_REG ( word_mode , IP_REGNUM ) ) ; } } </s>

Emit a call instruction with pattern PAT . ADDR is the address of the call target .


"parameter passing for argument of type "

Determine where to put an argument to a function . Value is zero to push the argument on the stack , or a hard register in which to store the argument . MODE is the argument 's machine mode . TYPE is the data type of the argument ( as a tree ) . This is null for libcalls where that information may not be available . CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called . NAMED is nonzero if this argument is a named parameter ( otherwise it is an extra parameter matching an ellipsis ) . On the ARM , normally the first 16 bytes are passed in registers r0-r3 ; all other arguments are passed on the stack . If ( NAMED == 0 ) ( which happens only in assign_parms , since TARGET_SETUP_INCOMING_VARARGS is defined ) , say it is passed in the stack ( function_prologue will indeed make it pass in the stack if necessary ) .


<s> void arm_load_pic_register ( unsigned long saved_regs ATTRIBUTE_UNUSED , rtx pic_reg ) { rtx l1 , labelno , pic_tmp , pic_rtx ; if ( crtl -> uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE ) return ; gcc_assert ( flag_pic ) ; if ( pic_reg == NULL_RTX ) pic_reg = cfun -> machine -> pic_reg ; if ( TARGET_VXWORKS_RTP ) { pic_rtx = gen_rtx_SYMBOL_REF ( Pmode , VXWORKS_GOTT_BASE ) ; pic_rtx = gen_rtx_CONST ( Pmode , pic_rtx ) ; emit_insn ( gen_pic_load_addr_32bit ( pic_reg , pic_rtx ) ) ; emit_insn ( gen_rtx_SET ( pic_reg , gen_rtx_MEM ( Pmode , pic_reg ) ) ) ; pic_tmp = gen_rtx_SYMBOL_REF ( Pmode , VXWORKS_GOTT_INDEX ) ; emit_insn ( gen_pic_offset_arm ( pic_reg , pic_reg , pic_tmp ) ) ; } else { labelno = GEN_INT ( pic_labelno ++ ) ; l1 = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_PIC_LABEL ) ; l1 = gen_rtx_CONST ( VOIDmode , l1 ) ; pic_rtx = plus_constant ( Pmode , l1 , TARGET_ARM ? 8 : 4 ) ; pic_rtx = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , pic_rtx ) , UNSPEC_GOTSYM_OFF ) ; pic_rtx = gen_rtx_CONST ( Pmode , pic_rtx ) ; if ( TARGET_32BIT ) { emit_insn ( gen_pic_load_addr_unified ( pic_reg , pic_rtx , labelno ) ) ; } else { if ( arm_pic_register != INVALID_REGNUM && REGNO ( pic_reg ) > LAST_LO_REGNUM ) { pic_tmp = gen_rtx_REG ( SImode , thumb_find_work_register ( saved_regs ) ) ; emit_insn ( gen_pic_load_addr_thumb1 ( pic_tmp , pic_rtx ) ) ; emit_insn ( gen_movsi ( pic_offset_table_rtx , pic_tmp ) ) ; emit_insn ( gen_pic_add_dot_plus_four ( pic_reg , pic_reg , labelno ) ) ; } else if ( arm_pic_register != INVALID_REGNUM && arm_pic_register > LAST_LO_REGNUM && REGNO ( pic_reg ) <= LAST_LO_REGNUM ) { emit_insn ( gen_pic_load_addr_unified ( pic_reg , pic_rtx , labelno ) ) ; emit_move_insn ( gen_rtx_REG ( Pmode , arm_pic_register ) , pic_reg ) ; emit_use ( gen_rtx_REG ( Pmode , arm_pic_register ) ) ; } else emit_insn ( gen_pic_load_addr_unified ( pic_reg , pic_rtx , labelno ) ) ; } } emit_use ( pic_reg ) ; } </s>

Generate code to load the PIC register . In thumb mode SCRATCH is a low register .


"iwmmxt requires an AAPCS compatible ABI for proper operation"

"iwmmxt abi requires an iwmmxt capable cpu"

"target CPU does not support interworking"

"AAPCS does not support %<-mcaller-super-interworking%>"

"AAPCS does not support %<-mcallee-super-interworking%>"

"target CPU does not support ARMv8-M Security Extensions"

"ARMv8-M Security Extensions incompatible with selected FPU"

"%<-mfloat-abi=hard%>: selected processor lacks an FPU"

Perform some validation between the desired architecture and the rest of the options .


"enabling backtrace support is only meaningful when compiling for the Thumb"

"enabling callee interworking support is only meaningful when compiling for the Thumb"

"%<-g%> with %<-mno-apcs-frame%> may not give sensible "

"cannot use %<-mtp=cp15%> with 16-bit Thumb"

"%s only supports non-pic code on M-profile targets with the "

"%s incompatible with %<-mword-relocations%>"

Check any incompatible options that the user has specified .


"target CPU does not support THUMB instructions"

"target CPU does not support unaligned accesses"

Reset options between modes that the user has specified .


"selected fp16 options are incompatible"

Reconfigure global status flags from the active_target.isa .


"parameter passing for argument of type "

Worker function for TARGET_SETUP_INCOMING_VARARGS . On the ARM , PRETEND_SIZE is set in order to have the prologue push the last named arg and all anonymous args onto the stack . XXX I know the prologue should n't be pushing registers , but it is faster that way .


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

"invalid fpu for target attribute or pragma %qs"

"auto fpu selection not currently permitted here"

"invalid architecture for target attribute or pragma %qs"

"unknown target attribute or pragma %qs"

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


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

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


Lay out a function argument using the AAPCS rules . The rule numbers referred to here are those in the AAPCS .


<s> static bool aapcs_vfp_allocate ( CUMULATIVE_ARGS * pcum , machine_mode mode , const_tree type ATTRIBUTE_UNUSED ) { int rmode_size = MAX ( GET_MODE_SIZE ( pcum -> aapcs_vfp_rmode ) , GET_MODE_SIZE ( SFmode ) ) ; int shift = rmode_size / GET_MODE_SIZE ( SFmode ) ; unsigned mask = ( 1 << ( shift * pcum -> aapcs_vfp_rcount ) ) - 1 ; int regno ; for ( regno = 0 ; regno < NUM_VFP_ARG_REGS ; regno += shift ) if ( ( ( pcum -> aapcs_vfp_regs_free >> regno ) & mask ) == mask ) { pcum -> aapcs_vfp_reg_alloc = mask << regno ; if ( mode == BLKmode || ( mode == TImode && ! ( TARGET_NEON || TARGET_HAVE_MVE ) ) || ! arm_hard_regno_mode_ok ( FIRST_VFP_REGNUM + regno , mode ) ) { int i ; int rcount = pcum -> aapcs_vfp_rcount ; int rshift = shift ; machine_mode rmode = pcum -> aapcs_vfp_rmode ; rtx par ; if ( ! ( TARGET_NEON || TARGET_HAVE_MVE ) ) { if ( rmode == V2SImode ) rmode = DImode ; else if ( rmode == V4SImode ) { rmode = DImode ; rcount *= 2 ; rshift /= 2 ; } } par = gen_rtx_PARALLEL ( mode , rtvec_alloc ( rcount ) ) ; for ( i = 0 ; i < rcount ; i ++ ) { rtx tmp = gen_rtx_REG ( rmode , FIRST_VFP_REGNUM + regno + i * rshift ) ; tmp = gen_rtx_EXPR_LIST ( VOIDmode , tmp , GEN_INT ( i * GET_MODE_SIZE ( rmode ) ) ) ; XVECEXP ( par , 0 , i ) = tmp ; } pcum -> aapcs_reg = par ; } else pcum -> aapcs_reg = gen_rtx_REG ( mode , FIRST_VFP_REGNUM + regno ) ; return true ; } return false ; } </s>

Implement the allocate field in aapcs_cp_arg_layout . See the comment there for the behaviour of this function .


<s> static rtx aapcs_vfp_allocate_return_reg ( enum arm_pcs pcs_variant ATTRIBUTE_UNUSED , machine_mode mode , const_tree type ATTRIBUTE_UNUSED ) { if ( ! use_vfp_abi ( pcs_variant , false ) ) return NULL ; if ( mode == BLKmode || ( GET_MODE_CLASS ( mode ) == MODE_INT && GET_MODE_SIZE ( mode ) >= GET_MODE_SIZE ( TImode ) && ! ( TARGET_NEON || TARGET_HAVE_MVE ) ) ) { int count ; machine_mode ag_mode ; int i ; rtx par ; int shift ; aapcs_vfp_is_call_or_return_candidate ( pcs_variant , mode , type , & ag_mode , & count ) ; if ( ! ( TARGET_NEON || TARGET_HAVE_MVE ) ) { if ( ag_mode == V2SImode ) ag_mode = DImode ; else if ( ag_mode == V4SImode ) { ag_mode = DImode ; count *= 2 ; } } shift = GET_MODE_SIZE ( ag_mode ) / GET_MODE_SIZE ( SFmode ) ; par = gen_rtx_PARALLEL ( mode , rtvec_alloc ( count ) ) ; for ( i = 0 ; i < count ; i ++ ) { rtx tmp = gen_rtx_REG ( ag_mode , FIRST_VFP_REGNUM + i * shift ) ; tmp = gen_rtx_EXPR_LIST ( VOIDmode , tmp , GEN_INT ( i * GET_MODE_SIZE ( ag_mode ) ) ) ; XVECEXP ( par , 0 , i ) = tmp ; } return par ; } return gen_rtx_REG ( mode , FIRST_VFP_REGNUM ) ; } </s>

Implement the allocate_return_reg field in aapcs_cp_arg_layout . See the comment there for the behaviour of this function .


"type %qT with %<[[no_unique_address]]%> members "

"type %qT when C++17 is enabled changed to match "

"argument of type %qT not permitted with %<-mgeneral-regs-only%>"


<s> static bool aarch_macro_fusion_pair_p ( rtx_insn * prev , rtx_insn * curr ) { rtx prev_set = single_set ( prev ) ; rtx curr_set = single_set ( curr ) ; if ( ! prev_set || ! curr_set ) return false ; if ( any_condjump_p ( curr ) ) return false ; if ( ! arm_macro_fusion_p ( ) ) return false ; if ( current_tune -> fusible_ops & tune_params :: FUSE_MOVW_MOVT && arm_sets_movw_movt_fusible_p ( prev_set , curr_set ) ) return true ; return false ; } </s>

Implement TARGET_SCHED_MACRO_FUSION_PAIR_P . Return true if PREV and CURR should be kept together during scheduling .


<s>
void
add
(
HOST_WIDE_INT
val
)
{
asm_fprintf
(
t_file
,
"\tadds\t%s, #"
HOST_WIDE_INT_PRINT_DEC
"\n"
,
dst_regname
,
val
)
;
}
</s>

Make function pointers for the various linear operators we can apply to compute a multiplicative value .


<s> static void add_attribute ( const char * mode , tree * attributes ) { size_t len = strlen ( mode ) ; tree value = build_string ( len , mode ) ; TREE_TYPE ( value ) = build_array_type ( char_type_node , build_index_type ( size_int ( len ) ) ) ; * attributes = tree_cons ( get_identifier ( "target" ) , build_tree_list ( NULL_TREE , value ) , * attributes ) ; } </s>


<s> static Mnode * add_minipool_forward_ref ( Mfix * fix ) { Mnode * max_mp = NULL ; HOST_WIDE_INT max_address = fix -> address + fix -> forwards - minipool_pad ; Mnode * mp ; if ( minipool_vector_head && ( fix -> address + get_attr_length ( fix -> insn ) >= minipool_vector_head -> max_address - fix -> fix_size ) ) return NULL ; for ( mp = minipool_vector_head ; mp != NULL ; mp = mp -> next ) { if ( GET_CODE ( fix -> value ) == GET_CODE ( mp -> value ) && fix -> mode == mp -> mode && ( ! LABEL_P ( fix -> value ) || ( CODE_LABEL_NUMBER ( fix -> value ) == CODE_LABEL_NUMBER ( mp -> value ) ) ) && rtx_equal_p ( fix -> value , mp -> value ) ) { mp -> refcount ++ ; return move_minipool_fix_forward_ref ( mp , max_mp , max_address ) ; } if ( max_mp == NULL && mp -> max_address > max_address ) max_mp = mp ; if ( ARM_DOUBLEWORD_ALIGN && max_mp == NULL && fix -> fix_size >= 8 && mp -> fix_size < 8 ) { max_mp = mp ; max_address = mp -> max_address ; } } mp = XNEW ( Mnode ) ; mp -> fix_size = fix -> fix_size ; mp -> mode = fix -> mode ; mp -> value = fix -> value ; mp -> refcount = 1 ; mp -> min_address = - 65536 ; if ( max_mp == NULL ) { mp -> max_address = max_address ; mp -> next = NULL ; mp -> prev = minipool_vector_tail ; if ( mp -> prev == NULL ) { minipool_vector_head = mp ; minipool_vector_label = gen_label_rtx ( ) ; } else mp -> prev -> next = mp ; minipool_vector_tail = mp ; } else { if ( max_address > max_mp -> max_address - mp -> fix_size ) mp -> max_address = max_mp -> max_address - mp -> fix_size ; else mp -> max_address = max_address ; mp -> next = max_mp ; mp -> prev = max_mp -> prev ; max_mp -> prev = mp ; if ( mp -> prev != NULL ) mp -> prev -> next = mp ; else minipool_vector_head = mp ; } max_mp = mp ; while ( mp -> prev != NULL && mp -> prev -> max_address > mp -> max_address - mp -> prev -> fix_size ) { mp -> prev -> max_address = mp -> max_address - mp -> prev -> fix_size ; mp = mp -> prev ; } return max_mp ; } </s>

Add a constant to the minipool for a forward reference . Returns the node added or NULL if the constant will not fit in this pool .


<s> int adjacent_mem_locations ( rtx a , rtx b ) { if ( volatile_refs_p ( a ) || volatile_refs_p ( b ) ) return 0 ; if ( ( REG_P ( XEXP ( a , 0 ) ) || ( GET_CODE ( XEXP ( a , 0 ) ) == PLUS && CONST_INT_P ( XEXP ( XEXP ( a , 0 ) , 1 ) ) ) ) && ( REG_P ( XEXP ( b , 0 ) ) || ( GET_CODE ( XEXP ( b , 0 ) ) == PLUS && CONST_INT_P ( XEXP ( XEXP ( b , 0 ) , 1 ) ) ) ) ) { HOST_WIDE_INT val0 = 0 , val1 = 0 ; rtx reg0 , reg1 ; int val_diff ; if ( GET_CODE ( XEXP ( a , 0 ) ) == PLUS ) { reg0 = XEXP ( XEXP ( a , 0 ) , 0 ) ; val0 = INTVAL ( XEXP ( XEXP ( a , 0 ) , 1 ) ) ; } else reg0 = XEXP ( a , 0 ) ; if ( GET_CODE ( XEXP ( b , 0 ) ) == PLUS ) { reg1 = XEXP ( XEXP ( b , 0 ) , 0 ) ; val1 = INTVAL ( XEXP ( XEXP ( b , 0 ) , 1 ) ) ; } else reg1 = XEXP ( b , 0 ) ; if ( ! const_ok_for_op ( val0 , PLUS ) || ! const_ok_for_op ( val1 , PLUS ) ) return 0 ; if ( arm_eliminable_register ( reg0 ) ) return 0 ; val_diff = val1 - val0 ; if ( arm_ld_sched ) { return ( optimize_size && ( REGNO ( reg0 ) == REGNO ( reg1 ) ) && ( val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4 ) && ( val_diff == 4 || val_diff == - 4 ) ) ; } return ( ( REGNO ( reg0 ) == REGNO ( reg1 ) ) && ( val_diff == 4 || val_diff == - 4 ) ) ; } return 0 ; } </s>

If the target storage locations of arguments MEM1 and MEM2 are adjacent , then return the argument that has the lower address . Otherwise , return NULL_RTX .


<s> static bool align_ok_ldrd_strd ( HOST_WIDE_INT align , HOST_WIDE_INT offset ) { return ( unaligned_access ? ( align >= BITS_PER_WORD && ( offset & 3 ) == 0 ) : ( align >= 2 * BITS_PER_WORD && ( offset & 7 ) == 0 ) ) ; } </s>

Return true if a 64-bit access with alignment ALIGN and with a constant offset OFFSET from the base pointer is permitted on this architecture .


<s> static bool any_sibcall_could_use_r3 ( void ) { edge_iterator ei ; edge e ; if ( ! crtl -> tail_call_emit ) return false ; FOR_EACH_EDGE ( e , ei , EXIT_BLOCK_PTR_FOR_FN ( cfun ) -> preds ) if ( e -> flags & EDGE_SIBCALL ) { rtx_insn * call = BB_END ( e -> src ) ; if ( ! CALL_P ( call ) ) call = prev_nonnote_nondebug_insn ( call ) ; gcc_assert ( CALL_P ( call ) && SIBLING_CALL_P ( call ) ) ; if ( find_regno_fusage ( call , USE , 3 ) || is_indirect_tailcall_p ( call ) ) return true ; } return false ; } </s>

Return true if r3 is used by any of the tail call insns in the current function .


<s> const char * arithmetic_instr ( rtx op , int shift_first_arg ) { switch ( GET_CODE ( op ) ) { case PLUS : return "add" ; case MINUS : return shift_first_arg ? "rsb" : "sub" ; case IOR : return "orr" ; case XOR : return "eor" ; case AND : return "and" ; case ASHIFT : case ASHIFTRT : case LSHIFTRT : case ROTATERT : return arm_shift_nmem ( GET_CODE ( op ) ) ; default : gcc_unreachable ( ) ; } } </s>

Return the appropriate ARM instruction for the operation code . The returned result should not be overwritten . OP is the rtx of the operation . SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted .


<s> static void arm32_output_mi_thunk ( FILE * file , tree , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { const bool long_call_p = arm_is_long_call_p ( function ) ; int this_regno = ( aggregate_value_p ( TREE_TYPE ( TREE_TYPE ( function ) ) , function ) ? R1_REGNUM : R0_REGNUM ) ; rtx temp = gen_rtx_REG ( Pmode , IP_REGNUM ) ; rtx this_rtx = gen_rtx_REG ( Pmode , this_regno ) ; reload_completed = 1 ; emit_note ( NOTE_INSN_PROLOGUE_END ) ; if ( delta != 0 ) arm_split_constant ( PLUS , Pmode , NULL_RTX , delta , this_rtx , this_rtx , false ) ; if ( vcall_offset != 0 ) { emit_move_insn ( temp , gen_rtx_MEM ( Pmode , this_rtx ) ) ; arm_split_constant ( PLUS , Pmode , NULL_RTX , vcall_offset , temp , temp , false ) ; emit_move_insn ( temp , gen_rtx_MEM ( Pmode , temp ) ) ; emit_insn ( gen_add3_insn ( this_rtx , this_rtx , temp ) ) ; } if ( ! TREE_USED ( function ) ) { assemble_external ( function ) ; TREE_USED ( function ) = 1 ; } rtx funexp = XEXP ( DECL_RTL ( function ) , 0 ) ; if ( long_call_p ) { emit_move_insn ( temp , funexp ) ; funexp = temp ; } funexp = gen_rtx_MEM ( FUNCTION_MODE , funexp ) ; rtx_insn * insn = emit_call_insn ( gen_sibcall ( funexp , const0_rtx , NULL_RTX ) ) ; SIBLING_CALL_P ( insn ) = 1 ; emit_barrier ( ) ; if ( long_call_p ) { split_all_insns_noflow ( ) ; arm_reorg ( ) ; } insn = get_insns ( ) ; shorten_branches ( insn ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; reload_completed = 0 ; } </s>


<s> int arm_address_offset_is_imm ( rtx_insn * insn ) { rtx mem , addr ; extract_insn_cached ( insn ) ; if ( REG_P ( recog_data . operand [ 0 ] ) ) return 0 ; mem = recog_data . operand [ 0 ] ; gcc_assert ( MEM_P ( mem ) ) ; addr = XEXP ( mem , 0 ) ; if ( REG_P ( addr ) || ( GET_CODE ( addr ) == PLUS && REG_P ( XEXP ( addr , 0 ) ) && CONST_INT_P ( XEXP ( addr , 1 ) ) ) ) return 1 ; else return 0 ; } </s>

Return nonzero if the offset in the address is an immediate . Otherwise , return zero .


<s> static int arm_address_register_rtx_p ( rtx x , int strict_p ) { int regno ; if ( ! REG_P ( x ) ) return 0 ; regno = REGNO ( x ) ; if ( strict_p ) return ARM_REGNO_OK_FOR_BASE_P ( regno ) ; return ( regno <= LAST_ARM_REGNUM || regno >= FIRST_PSEUDO_REGISTER || regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM ) ; } </s>

Return nonzero if X is valid as an ARM state addressing register .


<s> static void arm_add_cfa_adjust_cfa_note ( rtx insn , int size , rtx dest , rtx src ) { rtx dwarf ; RTX_FRAME_RELATED_P ( insn ) = 1 ; dwarf = gen_rtx_SET ( dest , plus_constant ( Pmode , src , size ) ) ; add_reg_note ( insn , REG_CFA_ADJUST_CFA , dwarf ) ; } </s>

Add a REG_CFA_ADJUST_CFA REG note to INSN . SIZE is the offset to be adjusted . DEST and SRC might be stack_pointer_rtx or hard_frame_pointer_rtx .


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


<s> static void arm_adjust_block_mem ( rtx mem , HOST_WIDE_INT length , rtx * loop_reg , rtx * loop_mem ) { * loop_reg = copy_addr_to_reg ( XEXP ( mem , 0 ) ) ; * loop_mem = change_address ( mem , BLKmode , * loop_reg ) ; set_mem_align ( * loop_mem , MIN ( MEM_ALIGN ( mem ) , length * BITS_PER_UNIT ) ) ; } </s>

From mips_adjust_block_mem : Helper function for doing a loop-based block operation on memory reference MEM . Each iteration of the loop will operate on LENGTH bytes of MEM . Create a new base register for use within the loop and point it to the start of MEM . Create a new memory reference that uses this register . Store them in * LOOP_REG and * LOOP_MEM respectively .


<s> static int arm_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep , int cost , unsigned int ) { rtx i_pat , d_pat ; if ( TARGET_THUMB1 && dep_type == 0 && recog_memoized ( insn ) == CODE_FOR_cbranchsi4_insn && recog_memoized ( dep ) >= 0 && get_attr_conds ( dep ) == CONDS_SET ) return 0 ; if ( current_tune -> sched_adjust_cost != NULL ) { if ( ! current_tune -> sched_adjust_cost ( insn , dep_type , dep , & cost ) ) return cost ; } if ( dep_type == REG_DEP_ANTI || dep_type == REG_DEP_OUTPUT ) return 0 ; if ( dep_type == 0 && CALL_P ( insn ) ) return 1 ; if ( ( i_pat = single_set ( insn ) ) != NULL && MEM_P ( SET_SRC ( i_pat ) ) && ( d_pat = single_set ( dep ) ) != NULL && MEM_P ( SET_DEST ( d_pat ) ) ) { rtx src_mem = XEXP ( SET_SRC ( i_pat ) , 0 ) ; if ( ( SYMBOL_REF_P ( src_mem ) && CONSTANT_POOL_ADDRESS_P ( src_mem ) ) || reg_mentioned_p ( stack_pointer_rtx , src_mem ) || reg_mentioned_p ( frame_pointer_rtx , src_mem ) || reg_mentioned_p ( hard_frame_pointer_rtx , src_mem ) ) return 1 ; } return cost ; } </s>

This function implements the target macro TARGET_SCHED_ADJUST_COST . It corrects the value of COST based on the relationship between INSN and DEP through the dependence LINK . It returns the new value . There is a per-core adjust_cost hook to adjust scheduler costs and the per-core hook can choose to completely override the generic adjust_cost function . Only put bits of code into arm_adjust_cost that are common across all cores .


<s> static bool arm_align_anon_bitfield ( void ) { return TARGET_AAPCS_BASED ; } </s>

AAPCS requires that anonymous bitfields affect structure alignment .


<s> int arm_apply_result_size ( void ) { int size = 16 ; if ( TARGET_32BIT ) { if ( TARGET_HARD_FLOAT_ABI ) size += 32 ; if ( TARGET_IWMMXT_ABI ) size += 8 ; } return size ; } </s>

Determine the amount of memory needed to store the possible return registers of an untyped call .


<s> static inline int arm_arm_address_cost ( rtx x ) { enum rtx_code c = GET_CODE ( x ) ; if ( c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC ) return 0 ; if ( c == MEM || c == LABEL_REF || c == SYMBOL_REF ) return 10 ; if ( c == PLUS ) { if ( CONST_INT_P ( XEXP ( x , 1 ) ) ) return 2 ; if ( ARITHMETIC_P ( XEXP ( x , 0 ) ) || ARITHMETIC_P ( XEXP ( x , 1 ) ) ) return 3 ; return 4 ; } return 6 ; } </s>

All address computations that can be done are free , but rtx cost returns the same for practically all of them . So we weight the different types of address here in the order ( most pref first ) : PRE/POST_INC/DEC , SHIFT or NON-INT sum , INT sum , REG , MEM or LABEL .


<s> static bool arm_array_mode_supported_p ( machine_mode mode , unsigned HOST_WIDE_INT nelems ) { if ( TARGET_NEON && ! BYTES_BIG_ENDIAN && ( VALID_NEON_DREG_MODE ( mode ) || VALID_NEON_QREG_MODE ( mode ) ) && ( nelems >= 2 && nelems <= 4 ) ) return true ; if ( TARGET_HAVE_MVE && ! BYTES_BIG_ENDIAN && VALID_MVE_MODE ( mode ) && ( nelems == 2 || nelems == 4 ) ) return true ; return false ; } </s>

Implements target hook array_mode_supported_p .


<s> static unsigned HOST_WIDE_INT arm_asan_shadow_offset ( void ) { return HOST_WIDE_INT_1U << 29 ; } </s>

Implement the TARGET_ASAN_SHADOW_OFFSET hook .


<s> void arm_asm_declare_function_name ( FILE * file , const char * name , tree decl ) { size_t cmse_name_len ; char * cmse_name = 0 ; char cmse_prefix [ ] = "__acle_se_" ; if ( use_cmse && lookup_attribute ( "cmse_nonsecure_entry" , DECL_ATTRIBUTES ( decl ) ) ) { cmse_name_len = sizeof ( cmse_prefix ) + strlen ( name ) ; cmse_name = XALLOCAVEC ( char , cmse_name_len ) ; snprintf ( cmse_name , cmse_name_len , "%s%s" , cmse_prefix , name ) ; targetm . asm_out . globalize_label ( file , cmse_name ) ; ARM_DECLARE_FUNCTION_NAME ( file , cmse_name , decl ) ; ASM_OUTPUT_TYPE_DIRECTIVE ( file , cmse_name , "function" ) ; } ARM_DECLARE_FUNCTION_NAME ( file , name , decl ) ; ASM_OUTPUT_TYPE_DIRECTIVE ( file , name , "function" ) ; ASM_DECLARE_RESULT ( file , DECL_RESULT ( decl ) ) ; ASM_OUTPUT_LABEL ( file , name ) ; if ( cmse_name ) ASM_OUTPUT_LABEL ( file , cmse_name ) ; ARM_OUTPUT_FN_UNWIND ( file , TRUE ) ; } </s>

Output in FILE asm statements needed to declare the NAME of the function defined by its DECL node .


<s> static bool arm_asm_elf_flags_numeric ( unsigned int flags , unsigned int * num ) { if ( flags & SECTION_ARM_PURECODE ) { * num = 0x20000000 ; if ( ! ( flags & SECTION_DEBUG ) ) * num |= 0x2 ; if ( flags & SECTION_EXCLUDE ) * num |= 0x80000000 ; if ( flags & SECTION_WRITE ) * num |= 0x1 ; if ( flags & SECTION_CODE ) * num |= 0x4 ; if ( flags & SECTION_MERGE ) * num |= 0x10 ; if ( flags & SECTION_STRINGS ) * num |= 0x20 ; if ( flags & SECTION_TLS ) * num |= 0x400 ; if ( HAVE_COMDAT_GROUP && ( flags & SECTION_LINKONCE ) ) * num |= 0x200 ; return true ; } return false ; } </s>

Implement the TARGET_ASM_ELF_FLAGS_NUMERIC hook . For pure-code sections there is no letter code for this attribute , so output all the section flags numerically when this is needed .


<s> static void arm_asm_emit_except_personality ( rtx personality ) { fputs ( "\t.personality\t" , asm_out_file ) ; output_addr_const ( asm_out_file , personality ) ; fputc ( '\n' , asm_out_file ) ; } </s>


<s> void arm_asm_output_labelref ( FILE * stream , const char * name ) { int skip ; int verbatim = 0 ; while ( ( skip = arm_get_strip_length ( * name ) ) ) { verbatim |= ( * name == '*' ) ; name += skip ; } if ( verbatim ) fputs ( name , stream ) ; else asm_fprintf ( stream , "%U%s" , name ) ; } </s>

If there is a ' * ' anywhere in the name 's prefix , then emit the stripped name verbatim , otherwise prepend an underscore if leading underscores are being used .


<s>
static
void
arm_asm_trampoline_template
(
FILE
*
f
)
{
fprintf
(
f
,
"\t.syntax unified\n"
)
;
if
(
TARGET_FDPIC
)
{
if
(
TARGET_ARM
)
fprintf
(
f
,
"\t.arm\n"
)
;
else
if
(
TARGET_THUMB2
)
fprintf
(
f
,
"\t.thumb\n"
)
;
else
gcc_unreachable
(
)
;
assemble_aligned_integer
(
UNITS_PER_WORD
,
const0_rtx
)
;
assemble_aligned_integer
(
UNITS_PER_WORD
,
const0_rtx
)
;
asm_fprintf
(
f
,
"\tldr\t%r, [%r, #%d]\n"
,
STATIC_CHAIN_REGNUM
,
PC_REGNUM
,
TARGET_THUMB2
8
:
4
)
;
asm_fprintf
(
f
,
"\tldr\t%r, [%r, #%d]\n"
,
PIC_OFFSET_TABLE_REGNUM
,
PC_REGNUM
,
TARGET_THUMB2
8
:
4
)
;
asm_fprintf
(
f
,
"\tldr\t%r, [%r, #%d]\n"
,
PC_REGNUM
,
PC_REGNUM
,
TARGET_THUMB2
8
:
4
)
;
assemble_aligned_integer
(
UNITS_PER_WORD
,
const0_rtx
)
;
}
else
if
(
TARGET_ARM
)
{
fprintf
(
f
,
"\t.arm\n"
)
;
asm_fprintf
(
f
,
"\tldr\t%r, [%r, #0]\n"
,
STATIC_CHAIN_REGNUM
,
PC_REGNUM
)
;
asm_fprintf
(
f
,
"\tldr\t%r, [%r, #0]\n"
,
PC_REGNUM
,
PC_REGNUM
)
;
}
else
if
(
TARGET_THUMB2
)
{
fprintf
(
f
,
"\t.thumb\n"
)
;
asm_fprintf
(
f
,
"\tldr.w\t%r, [%r, #4]\n"
,
STATIC_CHAIN_REGNUM
,
PC_REGNUM
)
;
asm_fprintf
(
f
,
"\tldr.w\t%r, [%r, #4]\n"
,
PC_REGNUM
,
PC_REGNUM
)
;
}
else
{
ASM_OUTPUT_ALIGN
(
f
,
2
)
;
fprintf
(
f
,
"\t.code\t16\n"
)
;
fprintf
(
f
,
".Ltrampoline_start:\n"
)
;
asm_fprintf
(
f
,
"\tpush\t{r0, r1}\n"
)
;
asm_fprintf
(
f
,
"\tldr\tr0, [%r, #8]\n"
,
PC_REGNUM
)
;
asm_fprintf
(
f
,
"\tmov\t%r, r0\n"
,
STATIC_CHAIN_REGNUM
)
;
asm_fprintf
(
f
,
"\tldr\tr0, [%r, #8]\n"
,
PC_REGNUM
)
;
asm_fprintf
(
f
,
"\tstr\tr0, [%r, #4]\n"
,
SP_REGNUM
)
;
asm_fprintf
(
f
,
"\tpop\t{r0, %r}\n"
,
PC_REGNUM
)
;
}
assemble_aligned_integer
(
UNITS_PER_WORD
,
const0_rtx
)
;
assemble_aligned_integer
(
UNITS_PER_WORD
,
const0_rtx
)
;
}
</s>

Output assembler code for a block containing the constant parts of a trampoline , leaving space for the variable parts . On the ARM , ( if r8 is the static chain regnum , and remembering that referencing pc adds an offset of 8 ) the trampoline looks like : ldr r8 , [ pc , # 0 ] ldr pc , [ pc ] .word static chain value .word function 's address XXX FIXME : When the trampoline returns , r8 will be clobbered .


<s> static bool arm_assemble_integer ( rtx x , unsigned int size , int aligned_p ) { machine_mode mode ; if ( size == UNITS_PER_WORD && aligned_p ) { fputs ( "\t.word\t" , asm_out_file ) ; output_addr_const ( asm_out_file , x ) ; if ( NEED_GOT_RELOC && flag_pic && making_const_table && ( SYMBOL_REF_P ( x ) || LABEL_REF_P ( x ) ) ) { if ( ! arm_pic_data_is_text_relative || ( SYMBOL_REF_P ( x ) && ( ! SYMBOL_REF_LOCAL_P ( x ) || ( SYMBOL_REF_DECL ( x ) ? DECL_WEAK ( SYMBOL_REF_DECL ( x ) ) : 0 ) || ( SYMBOL_REF_FUNCTION_P ( x ) && ! arm_fdpic_local_funcdesc_p ( x ) ) ) ) ) { if ( TARGET_FDPIC && SYMBOL_REF_FUNCTION_P ( x ) ) fputs ( "(GOTFUNCDESC)" , asm_out_file ) ; else fputs ( "(GOT)" , asm_out_file ) ; } else { if ( TARGET_FDPIC && SYMBOL_REF_FUNCTION_P ( x ) ) fputs ( "(GOTOFFFUNCDESC)" , asm_out_file ) ; else { bool is_readonly ; if ( ! TARGET_FDPIC || arm_is_segment_info_known ( x , & is_readonly ) ) fputs ( "(GOTOFF)" , asm_out_file ) ; else fputs ( "(GOT)" , asm_out_file ) ; } } } if ( TARGET_FDPIC && ! making_const_table && SYMBOL_REF_P ( x ) && SYMBOL_REF_FUNCTION_P ( x ) ) fputs ( "(FUNCDESC)" , asm_out_file ) ; fputc ( '\n' , asm_out_file ) ; return true ; } mode = GET_MODE ( x ) ; if ( arm_vector_mode_supported_p ( mode ) ) { int i , units ; gcc_assert ( GET_CODE ( x ) == CONST_VECTOR ) ; units = CONST_VECTOR_NUNITS ( x ) ; size = GET_MODE_UNIT_SIZE ( mode ) ; if ( GET_MODE_CLASS ( mode ) == MODE_VECTOR_INT ) for ( i = 0 ; i < units ; i ++ ) { rtx elt = CONST_VECTOR_ELT ( x , i ) ; assemble_integer ( elt , size , i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT , 1 ) ; } else for ( i = 0 ; i < units ; i ++ ) { rtx elt = CONST_VECTOR_ELT ( x , i ) ; assemble_real ( * CONST_DOUBLE_REAL_VALUE ( elt ) , as_a < scalar_float_mode > ( GET_MODE_INNER ( mode ) ) , i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT ) ; } return true ; } return default_assemble_integer ( x , size , aligned_p ) ; } </s>

Target hook for assembling integer objects . The ARM version needs to handle word-sized values specially .


<s> int arm_attr_length_move_neon ( rtx_insn * insn ) { rtx reg , mem , addr ; int load ; machine_mode mode ; extract_insn_cached ( insn ) ; if ( REG_P ( recog_data . operand [ 0 ] ) && REG_P ( recog_data . operand [ 1 ] ) ) { mode = GET_MODE ( recog_data . operand [ 0 ] ) ; switch ( mode ) { case E_EImode : case E_OImode : return 8 ; case E_CImode : return 12 ; case E_XImode : return 16 ; default : gcc_unreachable ( ) ; } } load = REG_P ( recog_data . operand [ 0 ] ) ; reg = recog_data . operand [ ! load ] ; mem = recog_data . operand [ load ] ; gcc_assert ( MEM_P ( mem ) ) ; addr = XEXP ( mem , 0 ) ; if ( GET_CODE ( addr ) == CONST && GET_CODE ( XEXP ( addr , 0 ) ) == PLUS ) addr = XEXP ( addr , 0 ) ; if ( LABEL_REF_P ( addr ) || GET_CODE ( addr ) == PLUS ) { int insns = REG_NREGS ( reg ) / 2 ; return insns * 4 ; } else return 4 ; } </s>

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


<s> int arm_attr_length_pop_multi ( rtx * operands , bool return_pc , bool write_back_p ) { if ( TARGET_ARM ) return 4 ; if ( TARGET_THUMB1 ) return 2 ; rtx parallel_op = operands [ 0 ] ; unsigned indx = XVECLEN ( parallel_op , 0 ) - 1 ; unsigned regno = REGNO ( operands [ 1 ] ) ; unsigned first_indx = 0 ; first_indx += return_pc ? 1 : 0 ; first_indx += write_back_p ? 1 : 0 ; bool pop_p = ( regno == SP_REGNUM && write_back_p ) ; bool ldm_p = ! pop_p ; if ( ldm_p && REGNO_REG_CLASS ( regno ) == HI_REGS ) return 4 ; for ( ; indx >= first_indx ; indx -- ) { regno = REGNO ( XEXP ( XVECEXP ( parallel_op , 0 , indx ) , 0 ) ) ; if ( REGNO_REG_CLASS ( regno ) == HI_REGS && ( regno != PC_REGNUM || ldm_p ) ) return 4 ; } return 2 ; } </s>

Compute the attribute `` length '' of insn . Currently , this function is used for `` * load_multiple_with_writeback '' , `` * pop_multiple_with_return '' and `` * pop_multiple_with_writeback_and_return '' . OPERANDS is the toplevel PARALLEL rtx , RETURN_PC is true if OPERANDS contains return insn . WRITE_BACK_P is true if OPERANDS contains insn which explicit updates base register .


<s> int arm_attr_length_push_multi ( rtx parallel_op , rtx first_op ) { int i , regno , hi_reg ; int num_saves = XVECLEN ( parallel_op , 0 ) ; if ( TARGET_ARM ) return 4 ; if ( TARGET_THUMB1 ) return 2 ; regno = REGNO ( first_op ) ; hi_reg = ( REGNO_REG_CLASS ( regno ) == HI_REGS ) && ( regno != LR_REGNUM ) ; for ( i = 1 ; i < num_saves && ! hi_reg ; i ++ ) { regno = REGNO ( XEXP ( XVECEXP ( parallel_op , 0 , i ) , 0 ) ) ; hi_reg |= ( REGNO_REG_CLASS ( regno ) == HI_REGS ) && ( regno != LR_REGNUM ) ; } if ( ! hi_reg ) return 2 ; return 4 ; } </s>

Compute the atrribute `` length '' of insn `` * push_multi '' . So this function MUST be kept in sync with that insn pattern .


<s> static int arm_barrier_cost ( rtx_insn * insn ) { int base_cost = 50 ; rtx_insn * next = next_nonnote_insn ( insn ) ; if ( next != NULL && LABEL_P ( next ) ) base_cost -= 20 ; switch ( GET_CODE ( insn ) ) { case CODE_LABEL : return 50 ; case INSN : case CALL_INSN : return base_cost ; case JUMP_INSN : return base_cost - 10 ; default : return base_cost + 10 ; } } </s>

Return the cost of forcibly inserting a barrier after INSN .


<s> static void arm_block_arith_comp_libfuncs_for_mode ( machine_mode mode ) { set_optab_libfunc ( add_optab , mode , NULL ) ; set_optab_libfunc ( sdiv_optab , mode , NULL ) ; set_optab_libfunc ( smul_optab , mode , NULL ) ; set_optab_libfunc ( neg_optab , mode , NULL ) ; set_optab_libfunc ( sub_optab , mode , NULL ) ; set_optab_libfunc ( eq_optab , mode , NULL ) ; set_optab_libfunc ( ne_optab , mode , NULL ) ; set_optab_libfunc ( lt_optab , mode , NULL ) ; set_optab_libfunc ( le_optab , mode , NULL ) ; set_optab_libfunc ( ge_optab , mode , NULL ) ; set_optab_libfunc ( gt_optab , mode , NULL ) ; set_optab_libfunc ( unord_optab , mode , NULL ) ; } </s>

Record that we have no arithmetic or comparison libfuncs for machine mode MODE .


<s> static void arm_block_move_unaligned_loop ( rtx dest , rtx src , HOST_WIDE_INT length , unsigned int interleave_factor , HOST_WIDE_INT bytes_per_iter ) { rtx src_reg , dest_reg , final_src , test ; HOST_WIDE_INT leftover ; leftover = length % bytes_per_iter ; length -= leftover ; arm_adjust_block_mem ( src , bytes_per_iter , & src_reg , & src ) ; arm_adjust_block_mem ( dest , bytes_per_iter , & dest_reg , & dest ) ; final_src = expand_simple_binop ( Pmode , PLUS , src_reg , GEN_INT ( length ) , 0 , 0 , OPTAB_WIDEN ) ; rtx_code_label * label = gen_label_rtx ( ) ; emit_label ( label ) ; arm_block_move_unaligned_straight ( dest , src , bytes_per_iter , interleave_factor ) ; emit_move_insn ( src_reg , plus_constant ( Pmode , src_reg , bytes_per_iter ) ) ; emit_move_insn ( dest_reg , plus_constant ( Pmode , dest_reg , bytes_per_iter ) ) ; test = gen_rtx_NE ( VOIDmode , src_reg , final_src ) ; emit_jump_insn ( gen_cbranchsi4 ( test , src_reg , final_src , label ) ) ; if ( leftover ) arm_block_move_unaligned_straight ( dest , src , leftover , interleave_factor ) ; } </s>

From mips_block_move_loop : Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER bytes at a time . LENGTH must be at least BYTES_PER_ITER . Assume that the memory regions do not overlap .


<s> static int arm_block_set_max_insns ( void ) { if ( optimize_function_for_size_p ( cfun ) ) return 4 ; else return current_tune -> max_insns_inline_memset ; } </s>

Maximum number of instructions to set block of memory .


<s> static bool arm_block_set_non_vect_profit_p ( rtx val , unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT align , bool unaligned_p , bool use_strd_p ) { int num = 0 ; const int leftover [ 8 ] = { 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 } ; if ( unaligned_p ) { num = arm_const_inline_cost ( SET , val ) ; num += length / align + length % align ; } else if ( use_strd_p ) { num = arm_const_double_inline_cost ( val ) ; num += ( length >> 3 ) + leftover [ length & 7 ] ; } else { num = arm_const_inline_cost ( SET , val ) ; num += ( length >> 2 ) + leftover [ length & 3 ] ; } if ( unaligned_access && length > 3 && ( length & 3 ) == 3 ) num -- ; return ( num <= arm_block_set_max_insns ( ) ) ; } </s>

Return TRUE if it 's profitable to set block of memory for non-vectorized case . VAL is the value to set the memory with . LENGTH is the number of bytes to set . ALIGN is the alignment of the destination memory in bytes . UNALIGNED_P is TRUE if we can only set the memory with instructions meeting alignment requirements . USE_STRD_P is TRUE if we can use strd to set the memory .


<s> static bool arm_block_set_unaligned_non_vect ( rtx dstbase , unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT value , unsigned HOST_WIDE_INT align ) { unsigned int i ; rtx dst , addr , mem ; rtx val_exp , val_reg , reg ; machine_mode mode ; HOST_WIDE_INT v = value ; gcc_assert ( align == 1 || align == 2 ) ; if ( align == 2 ) v |= ( value << BITS_PER_UNIT ) ; v = sext_hwi ( v , BITS_PER_WORD ) ; val_exp = GEN_INT ( v ) ; if ( ! arm_block_set_non_vect_profit_p ( val_exp , length , align , true , false ) ) return false ; dst = copy_addr_to_reg ( XEXP ( dstbase , 0 ) ) ; mode = ( align == 2 ? HImode : QImode ) ; val_reg = force_reg ( SImode , val_exp ) ; reg = gen_lowpart ( mode , val_reg ) ; for ( i = 0 ; ( i + GET_MODE_SIZE ( mode ) <= length ) ; i += GET_MODE_SIZE ( mode ) ) { addr = plus_constant ( Pmode , dst , i ) ; mem = adjust_automodify_address ( dstbase , mode , addr , i ) ; emit_move_insn ( mem , reg ) ; } if ( i + 1 == length ) { reg = gen_lowpart ( QImode , val_reg ) ; addr = plus_constant ( Pmode , dst , i ) ; mem = adjust_automodify_address ( dstbase , QImode , addr , i ) ; emit_move_insn ( mem , reg ) ; i ++ ; } gcc_assert ( i == length ) ; return true ; } </s>

Set a block of memory using plain strh/strb instructions , only using instructions allowed by ALIGN on processor . We fill the first LENGTH bytes of the memory area starting from DSTBASE with byte constant VALUE . ALIGN is the alignment requirement of memory .


<s> static bool arm_block_set_unaligned_vect ( rtx dstbase , unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT value , unsigned HOST_WIDE_INT align ) { unsigned int i , nelt_v16 , nelt_v8 , nelt_mode ; rtx dst , mem ; rtx val_vec , reg ; rtx ( * gen_func ) ( rtx , rtx ) ; machine_mode mode ; unsigned HOST_WIDE_INT v = value ; unsigned int offset = 0 ; gcc_assert ( ( align & 0x3 ) != 0 ) ; nelt_v8 = GET_MODE_NUNITS ( V8QImode ) ; nelt_v16 = GET_MODE_NUNITS ( V16QImode ) ; if ( length >= nelt_v16 ) { mode = V16QImode ; gen_func = gen_movmisalignv16qi ; } else { mode = V8QImode ; gen_func = gen_movmisalignv8qi ; } nelt_mode = GET_MODE_NUNITS ( mode ) ; gcc_assert ( length >= nelt_mode ) ; if ( ! arm_block_set_vect_profit_p ( length , align , mode ) ) return false ; dst = copy_addr_to_reg ( XEXP ( dstbase , 0 ) ) ; mem = adjust_automodify_address ( dstbase , mode , dst , offset ) ; v = sext_hwi ( v , BITS_PER_WORD ) ; reg = gen_reg_rtx ( mode ) ; val_vec = gen_const_vec_duplicate ( mode , GEN_INT ( v ) ) ; emit_move_insn ( reg , val_vec ) ; for ( i = 0 ; ( i + nelt_mode <= length ) ; i += nelt_mode ) { emit_insn ( ( * gen_func ) ( mem , reg ) ) ; if ( i + 2 * nelt_mode <= length ) { emit_insn ( gen_add2_insn ( dst , GEN_INT ( nelt_mode ) ) ) ; offset += nelt_mode ; mem = adjust_automodify_address ( dstbase , mode , dst , offset ) ; } } gcc_assert ( ( i + nelt_v8 ) > length || mode == V16QImode ) ; if ( i + nelt_v8 < length ) { emit_insn ( gen_add2_insn ( dst , GEN_INT ( length - i ) ) ) ; offset += length - i ; mem = adjust_automodify_address ( dstbase , mode , dst , offset ) ; if ( ( length & 1 ) != 0 && align >= 2 ) set_mem_align ( mem , BITS_PER_UNIT ) ; emit_insn ( gen_movmisalignv16qi ( mem , reg ) ) ; } else if ( i < length && i + nelt_v8 >= length ) { if ( mode == V16QImode ) reg = gen_lowpart ( V8QImode , reg ) ; emit_insn ( gen_add2_insn ( dst , GEN_INT ( ( length - i ) + ( nelt_mode - nelt_v8 ) ) ) ) ; offset += ( length - i ) + ( nelt_mode - nelt_v8 ) ; mem = adjust_automodify_address ( dstbase , V8QImode , dst , offset ) ; if ( ( length & 1 ) != 0 && align >= 2 ) set_mem_align ( mem , BITS_PER_UNIT ) ; emit_insn ( gen_movmisalignv8qi ( mem , reg ) ) ; } return true ; } </s>

Set a block of memory using vectorization instructions for the unaligned case . We fill the first LENGTH bytes of the memory area starting from DSTBASE with byte constant VALUE . ALIGN is the alignment requirement of memory . Return TRUE if succeeded .


<s> static bool arm_block_set_vect ( rtx dstbase , unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT value , unsigned HOST_WIDE_INT align ) { if ( ( ( align & 3 ) != 0 || ( length & 3 ) != 0 ) && ( ! unaligned_access || BYTES_BIG_ENDIAN ) ) return false ; if ( ( align & 3 ) == 0 ) return arm_block_set_aligned_vect ( dstbase , length , value , align ) ; else return arm_block_set_unaligned_vect ( dstbase , length , value , align ) ; } </s>

Set a block of memory using vectorization instructions for both aligned and unaligned cases . We fill the first LENGTH bytes of the memory area starting from DSTBASE with byte constant VALUE . ALIGN is the alignment requirement of memory .


<s> static bool arm_block_set_vect_profit_p ( unsigned HOST_WIDE_INT length , unsigned HOST_WIDE_INT align , machine_mode mode ) { int num ; bool unaligned_p = ( ( align & 3 ) != 0 ) ; unsigned int nelt = GET_MODE_NUNITS ( mode ) ; num = 1 ; num += ( length + nelt - 1 ) / nelt ; if ( ! unaligned_p && ( length & 3 ) != 0 ) num ++ ; if ( ! unaligned_p && mode == V16QImode ) num -- ; return ( num <= arm_block_set_max_insns ( ) ) ; } </s>

Return TRUE if it 's profitable to set block of memory for vectorized case . LENGTH is the number of bytes to set . ALIGN is the alignment of destination memory in bytes . MODE is the vector mode used to set the memory .


Return the type to use as __builtin_va_list .


<s> static bool arm_cannot_copy_insn_p ( rtx_insn * insn ) { if ( recog_memoized ( insn ) == CODE_FOR_tlscall ) return true ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , PATTERN ( insn ) , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == UNSPEC && ( XINT ( x , 1 ) == UNSPEC_PIC_BASE || XINT ( x , 1 ) == UNSPEC_PIC_UNIFIED ) ) return true ; } rtx set = single_set ( insn ) ; if ( set ) { rtx src = SET_SRC ( set ) ; if ( GET_CODE ( src ) == ZERO_EXTEND ) src = XEXP ( src , 0 ) ; if ( GET_CODE ( src ) == UNSPEC_VOLATILE && ( XINT ( src , 1 ) == VUNSPEC_LL || XINT ( src , 1 ) == VUNSPEC_LAX ) ) return true ; } return false ; } </s>

Must not copy any rtx that uses a pc-relative address .


<s> static bool arm_cannot_force_const_mem ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { rtx base , offset ; split_const ( x , & base , & offset ) ; if ( SYMBOL_REF_P ( base ) ) { if ( ( SYMBOL_REF_FLAGS ( base ) & SYMBOL_FLAG_FUNCTION ) && INTVAL ( offset ) != 0 ) return true ; if ( ARM_OFFSETS_MUST_BE_WITHIN_SECTIONS_P && ! offset_within_block_p ( base , INTVAL ( offset ) ) ) return true ; } return arm_tls_referenced_p ( x ) ; } </s>


<s> static bool arm_can_change_mode_class ( machine_mode from , machine_mode to , reg_class_t rclass ) { if ( TARGET_BIG_END && ! ( GET_MODE_SIZE ( from ) == 16 && GET_MODE_SIZE ( to ) == 8 ) && ( GET_MODE_SIZE ( from ) > UNITS_PER_WORD || GET_MODE_SIZE ( to ) > UNITS_PER_WORD ) && reg_classes_intersect_p ( VFP_REGS , rclass ) ) return false ; return true ; } </s>

Implement TARGET_CAN_CHANGE_MODE_CLASS . In VFPv1 , VFP registers could only be accessed in the mode they were set , so subregs would be invalid there . However , we do n't support VFPv1 at the moment , and the restriction was lifted in VFPv2 . In big-endian mode , modes greater than word size ( i.e . DFmode ) are stored in VFP registers in little-endian order . We ca n't describe that accurately to GCC , so avoid taking subregs of such values . The only exception is going from a 128-bit to a 64-bit type . In that case the data layout happens to be consistent for big-endian , so we explicitly allow that case .


<s> bool arm_can_eliminate ( const int from , const int to ) { return ( ( to == FRAME_POINTER_REGNUM && from == ARG_POINTER_REGNUM ) ? false : ( to == STACK_POINTER_REGNUM && frame_pointer_needed ) ? false : ( to == ARM_HARD_FRAME_POINTER_REGNUM && TARGET_THUMB ) ? false : ( to == THUMB_HARD_FRAME_POINTER_REGNUM && TARGET_ARM ) ? false : true ) ; } </s>

Given FROM and TO register numbers , say whether this elimination is allowed . Frame pointer elimination is automatically handled . All eliminations are permissible . Note that ARG_POINTER_REGNUM and HARD_FRAME_POINTER_REGNUM are in fact the same thing . If we need a frame pointer , we must eliminate FRAME_POINTER_REGNUM into HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM or ARG_POINTER_REGNUM .


<s> static bool arm_can_inline_p ( tree caller , tree callee ) { tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET ( caller ) ; tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET ( callee ) ; bool can_inline = true ; struct cl_target_option * caller_opts = TREE_TARGET_OPTION ( caller_tree ? caller_tree : target_option_default_node ) ; struct cl_target_option * callee_opts = TREE_TARGET_OPTION ( callee_tree ? callee_tree : target_option_default_node ) ; if ( callee_opts == caller_opts ) return true ; struct arm_build_target caller_target ; struct arm_build_target callee_target ; caller_target . isa = sbitmap_alloc ( isa_num_bits ) ; callee_target . isa = sbitmap_alloc ( isa_num_bits ) ; arm_configure_build_target ( & caller_target , caller_opts , false ) ; arm_configure_build_target ( & callee_target , callee_opts , false ) ; if ( ! bitmap_subset_p ( callee_target . isa , caller_target . isa ) ) can_inline = false ; sbitmap_free ( caller_target . isa ) ; sbitmap_free ( callee_target . isa ) ; return can_inline ; } </s>

Hook to determine if one function can safely inline another .


<s> static bool arm_can_output_mi_thunk ( const_tree , HOST_WIDE_INT , HOST_WIDE_INT vcall_offset , const_tree ) { if ( vcall_offset && TARGET_THUMB1 ) return false ; return true ; } </s>

Can output mi_thunk for all cases except for non-zero vcall_offset in Thumb1 .


<s> bool arm_change_mode_p ( tree func ) { if ( TREE_CODE ( func ) != FUNCTION_DECL ) return false ; tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET ( func ) ; if ( ! callee_tree ) callee_tree = target_option_default_node ; struct cl_target_option * callee_opts = TREE_TARGET_OPTION ( callee_tree ) ; int flags = callee_opts -> x_target_flags ; return ( TARGET_THUMB_P ( flags ) != TARGET_THUMB ) ; } </s>

Check that FUNC is called with a different mode .


<s> static bool arm_class_likely_spilled_p ( reg_class_t rclass ) { if ( ( TARGET_THUMB1 && rclass == LO_REGS ) || rclass == CC_REG ) return true ; return default_class_likely_spilled_p ( rclass ) ; } </s>

Implement TARGET_CLASS_LIKELY_SPILLED_P . We need to define this for LO_REGS on Thumb-1 . Otherwise we can end up using r0-r4 for function arguments , r7 for the stack frame and do n't have enough left over to do doubleword arithmetic . For Thumb-2 all the potentially problematic instructions accept high registers so this is not necessary . Care needs to be taken to avoid adding new Thumb-2 patterns that require many low registers .


<s> static unsigned long arm_compute_func_type ( void ) { unsigned long type = ARM_FT_UNKNOWN ; tree a ; tree attr ; gcc_assert ( TREE_CODE ( current_function_decl ) == FUNCTION_DECL ) ; if ( optimize > 0 && ( TREE_NOTHROW ( current_function_decl ) || ! ( flag_unwind_tables || ( flag_exceptions && arm_except_unwind_info ( & global_options ) != UI_SJLJ ) ) ) && TREE_THIS_VOLATILE ( current_function_decl ) ) type |= ARM_FT_VOLATILE ; if ( cfun -> static_chain_decl != NULL ) type |= ARM_FT_NESTED ; attr = DECL_ATTRIBUTES ( current_function_decl ) ; a = lookup_attribute ( "naked" , attr ) ; if ( a != NULL_TREE ) type |= ARM_FT_NAKED ; a = lookup_attribute ( "isr" , attr ) ; if ( a == NULL_TREE ) a = lookup_attribute ( "interrupt" , attr ) ; if ( a == NULL_TREE ) type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL ; else type |= arm_isr_value ( TREE_VALUE ( a ) ) ; if ( lookup_attribute ( "cmse_nonsecure_entry" , attr ) ) type |= ARM_FT_CMSE_ENTRY ; return type ; } </s>

Computes the type of the current function .

arm 0 "naked" "isr" "interrupt" "cmse_nonsecure_entry"


<s> HOST_WIDE_INT arm_compute_initial_elimination_offset ( unsigned int from , unsigned int to ) { arm_stack_offsets * offsets ; offsets = arm_get_frame_offsets ( ) ; switch ( from ) { case ARG_POINTER_REGNUM : switch ( to ) { case THUMB_HARD_FRAME_POINTER_REGNUM : return 0 ; case FRAME_POINTER_REGNUM : return offsets -> soft_frame - offsets -> saved_args ; case ARM_HARD_FRAME_POINTER_REGNUM : return offsets -> frame - offsets -> saved_args - 4 ; case STACK_POINTER_REGNUM : return offsets -> outgoing_args - ( offsets -> saved_args + 4 ) ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; case FRAME_POINTER_REGNUM : switch ( to ) { case THUMB_HARD_FRAME_POINTER_REGNUM : return 0 ; case ARM_HARD_FRAME_POINTER_REGNUM : return offsets -> frame - offsets -> soft_frame ; case STACK_POINTER_REGNUM : return offsets -> outgoing_args - offsets -> soft_frame ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; default : gcc_unreachable ( ) ; } } </s>

Compute the distance from register FROM to register TO . These can be the arg pointer ( 26 ) , the soft frame pointer ( 25 ) , the stack pointer ( 13 ) or the hard frame pointer ( 11 ) . Typical stack layout looks like this : old stack pointer - > | | -- -- | | \ | | saved arguments for | | vararg functions | | / -- hard FP & arg pointer - > | | \ | | stack | | frame | | / -- | | \ | | call saved | | registers soft frame pointer - > | | / -- | | \ | | local | | variables | | / -- | | \ | | outgoing | | arguments current stack pointer - > | | / -- For a given funciton some or all of these stack compomnents may not be needed , giving rise to the possibility of eliminating some of the registers . The values returned by this function must reflect the behaviour of arm_expand_prologue ( ) and arm_compute_save_reg_mask ( ) . The sign of the number returned reflects the direction of stack growth , so the values are positive for all eliminations except from the soft frame pointer to the hard frame pointer .


<s> static unsigned long arm_compute_save_core_reg_mask ( void ) { unsigned int save_reg_mask = 0 ; unsigned long func_type = arm_current_func_type ( ) ; unsigned int reg ; if ( IS_NAKED ( func_type ) ) return 0 ; if ( TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM ) save_reg_mask |= ( 1 << ARM_HARD_FRAME_POINTER_REGNUM ) | ( 1 << IP_REGNUM ) | ( 1 << LR_REGNUM ) | ( 1 << PC_REGNUM ) ; save_reg_mask |= arm_compute_save_reg0_reg12_mask ( ) ; if ( df_regs_ever_live_p ( LR_REGNUM ) || ( save_reg_mask && optimize_size && ARM_FUNC_TYPE ( func_type ) == ARM_FT_NORMAL && ! crtl -> tail_call_emit && ! crtl -> calls_eh_return ) ) save_reg_mask |= 1 << LR_REGNUM ; if ( cfun -> machine -> lr_save_eliminated ) save_reg_mask &= ~ ( 1 << LR_REGNUM ) ; if ( TARGET_REALLY_IWMMXT && ( ( bit_count ( save_reg_mask ) + ARM_NUM_INTS ( crtl -> args . pretend_args_size + arm_compute_static_chain_stack_bytes ( ) ) ) % 2 ) != 0 ) { for ( reg = 4 ; reg <= 12 ; reg ++ ) if ( ( save_reg_mask & ( 1 << reg ) ) == 0 ) break ; if ( reg <= 12 ) save_reg_mask |= ( 1 << reg ) ; else { cfun -> machine -> sibcall_blocked = 1 ; save_reg_mask |= ( 1 << 3 ) ; } } if ( TARGET_THUMB2 && IS_NESTED ( func_type ) && flag_pic && ( save_reg_mask & THUMB2_WORK_REGS ) == 0 ) { reg = thumb_find_work_register ( 1 << 4 ) ; if ( ! call_used_or_fixed_reg_p ( reg ) ) save_reg_mask |= ( 1 << reg ) ; } return save_reg_mask ; } </s>

Compute a bit mask of which core registers need to be saved on the stack for the current function . This is used by arm_compute_frame_layout , which may add extra registers .


<s> static unsigned long arm_compute_save_reg0_reg12_mask ( void ) { unsigned long func_type = arm_current_func_type ( ) ; unsigned long save_reg_mask = 0 ; unsigned int reg ; if ( IS_INTERRUPT ( func_type ) ) { unsigned int max_reg ; if ( ARM_FUNC_TYPE ( func_type ) == ARM_FT_FIQ ) max_reg = 7 ; else max_reg = 12 ; for ( reg = 0 ; reg <= max_reg ; reg ++ ) if ( reg_needs_saving_p ( reg ) ) save_reg_mask |= ( 1 << reg ) ; if ( PIC_REGISTER_MAY_NEED_SAVING && crtl -> uses_pic_offset_table ) save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; } else if ( IS_VOLATILE ( func_type ) ) { if ( frame_pointer_needed ) save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM ; if ( df_regs_ever_live_p ( ARM_HARD_FRAME_POINTER_REGNUM ) ) save_reg_mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM ; if ( df_regs_ever_live_p ( THUMB_HARD_FRAME_POINTER_REGNUM ) ) save_reg_mask |= 1 << THUMB_HARD_FRAME_POINTER_REGNUM ; } else { for ( reg = 0 ; reg <= 11 ; reg ++ ) if ( df_regs_ever_live_p ( reg ) && callee_saved_reg_p ( reg ) ) save_reg_mask |= ( 1 << reg ) ; if ( frame_pointer_needed ) save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM ; if ( PIC_REGISTER_MAY_NEED_SAVING && ( df_regs_ever_live_p ( PIC_OFFSET_TABLE_REGNUM ) || crtl -> uses_pic_offset_table ) ) save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; if ( IS_STACKALIGN ( func_type ) ) save_reg_mask |= 1 ; } if ( crtl -> calls_eh_return ) { unsigned int i ; for ( i = 0 ; ; i ++ ) { reg = EH_RETURN_DATA_REGNO ( i ) ; if ( reg == INVALID_REGNUM ) break ; save_reg_mask |= 1 << reg ; } } return save_reg_mask ; } </s>

Compute the register save mask for registers 0 through 12 inclusive . This code is used by arm_compute_save_reg_mask .


<s> static int arm_compute_static_chain_stack_bytes ( void ) { if ( cfun -> machine -> static_chain_stack_bytes != - 1 ) return cfun -> machine -> static_chain_stack_bytes ; if ( IS_NESTED ( arm_current_func_type ( ) ) && ( ( TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM ) || ( ( flag_stack_check == STATIC_BUILTIN_STACK_CHECK || flag_stack_clash_protection ) && ! df_regs_ever_live_p ( LR_REGNUM ) ) ) && arm_r3_live_at_start_p ( ) && crtl -> args . pretend_args_size == 0 ) return 4 ; return 0 ; } </s>

Compute the number of bytes used to store the static chain register on the stack , above the stack frame . We need to know this accurately to get the alignment of the rest of the stack frame correct .


<s>
static
int
arm_comp_type_attributes
(
const_tree
type1
,
const_tree
type2
)
{
int
l1
,
l2
,
s1
,
s2
;
tree
attrs1
=
lookup_attribute
(
"Advanced SIMD type"
,
TYPE_ATTRIBUTES
(
type1
)
)
;
tree
attrs2
=
lookup_attribute
(
"Advanced SIMD type"
,
TYPE_ATTRIBUTES
(
type2
)
)
;
if
(
bool
(
attrs1
)
!=
bool
(
attrs2
)
)
return
0
;
if
(
attrs1
&&
!
attribute_value_equal
(
attrs1
,
attrs2
)
)
return
0
;
if
(
TREE_CODE
(
type1
)
!=
FUNCTION_TYPE
)
return
1
;
l1
=
lookup_attribute
(
"long_call"
,
TYPE_ATTRIBUTES
(
type1
)
)
!=
;
l2
=
lookup_attribute
(
"long_call"
,
TYPE_ATTRIBUTES
(
type2
)
)
!=
;
s1
=
lookup_attribute
(
"short_call"
,
TYPE_ATTRIBUTES
(
type1
)
)
!=
;
s2
=
lookup_attribute
(
"short_call"
,
TYPE_ATTRIBUTES
(
type2
)
)
!=
;
if
(
l1
|
l2
|
s1
|
s2
)
{
if
(
(
l1
!=
l2
)
||
(
s1
!=
s2
)
)
return
0
;
if
(
(
l1
&
s2
)
||
(
l2
&
s1
)
)
return
0
;
}
l1
=
lookup_attribute
(
"isr"
,
TYPE_ATTRIBUTES
(
type1
)
)
!=
;
if
(
!
l1
)
l1
=
lookup_attribute
(
"interrupt"
,
TYPE_ATTRIBUTES
(
type1
)
)
!=
;
l2
=
lookup_attribute
(
"isr"
,
TYPE_ATTRIBUTES
(
type2
)
)
!=
;
if
(
!
l2
)
l1
=
lookup_attribute
(
"interrupt"
,
TYPE_ATTRIBUTES
(
type2
)
)
!=
;
if
(
l1
!=
l2
)
return
0
;
l1
=
lookup_attribute
(
"cmse_nonsecure_call"
,
TYPE_ATTRIBUTES
(
type1
)
)
!=
;
l2
=
lookup_attribute
(
"cmse_nonsecure_call"
,
TYPE_ATTRIBUTES
(
type2
)
)
!=
;
if
(
l1
!=
l2
)
return
0
;
return
1
;
}
</s>

Return 0 if the attributes for two types are incompatible , 1 if they are compatible , and 2 if they are nearly compatible ( which causes a warning to be generated ) .


<s> static HOST_WIDE_INT arm_constant_alignment ( const_tree exp , HOST_WIDE_INT align ) { unsigned int factor = ( TARGET_THUMB || ! arm_tune_xscale ? 1 : 2 ) ; if ( TREE_CODE ( exp ) == STRING_CST && ! optimize_size ) return MAX ( align , BITS_PER_WORD * factor ) ; return align ; } </s>

Implement TARGET_CONSTANT_ALIGNMENT . Make strings word-aligned so strcpy from constants will be faster .


<s> inline static int arm_constant_limit ( bool size_p ) { return size_p ? 1 : current_tune -> constant_limit ; } </s>

The maximum number of insns to be used when loading a constant .


<s> void arm_const_bounds ( rtx operand , HOST_WIDE_INT low , HOST_WIDE_INT high ) { bounds_check ( operand , low , high , NULL_TREE , "constant" ) ; } </s>


<s> bool arm_const_double_by_immediates ( rtx val ) { machine_mode mode = GET_MODE ( val ) ; rtx part ; if ( mode == VOIDmode ) mode = DImode ; part = gen_highpart_mode ( SImode , mode , val ) ; gcc_assert ( CONST_INT_P ( part ) ) ; if ( ! const_ok_for_arm ( INTVAL ( part ) ) ) return false ; part = gen_lowpart ( SImode , val ) ; gcc_assert ( CONST_INT_P ( part ) ) ; if ( ! const_ok_for_arm ( INTVAL ( part ) ) ) return false ; return true ; } </s>

Return true if it is possible to inline both the high and low parts of a 64-bit constant into 32-bit data processing instructions .


<s> bool arm_const_double_by_parts ( rtx val ) { machine_mode mode = GET_MODE ( val ) ; rtx part ; if ( optimize_size || arm_ld_sched ) return true ; if ( mode == VOIDmode ) mode = DImode ; part = gen_highpart_mode ( SImode , mode , val ) ; gcc_assert ( CONST_INT_P ( part ) ) ; if ( const_ok_for_arm ( INTVAL ( part ) ) || const_ok_for_arm ( ~ INTVAL ( part ) ) ) return true ; part = gen_lowpart ( SImode , val ) ; gcc_assert ( CONST_INT_P ( part ) ) ; if ( const_ok_for_arm ( INTVAL ( part ) ) || const_ok_for_arm ( ~ INTVAL ( part ) ) ) return true ; return false ; } </s>

Return true if it is worthwhile to split a 64-bit constant into two 32-bit operations . This is the case if optimizing for size , or if we have load delay slots , or if one 32-bit part can be done with a single data operation .


<s> int arm_const_double_inline_cost ( rtx val ) { rtx lowpart , highpart ; machine_mode mode ; mode = GET_MODE ( val ) ; if ( mode == VOIDmode ) mode = DImode ; gcc_assert ( GET_MODE_SIZE ( mode ) == 8 ) ; lowpart = gen_lowpart ( SImode , val ) ; highpart = gen_highpart_mode ( SImode , mode , val ) ; gcc_assert ( CONST_INT_P ( lowpart ) ) ; gcc_assert ( CONST_INT_P ( highpart ) ) ; return ( arm_gen_constant ( SET , SImode , NULL_RTX , INTVAL ( lowpart ) , NULL_RTX , NULL_RTX , 0 , 0 ) + arm_gen_constant ( SET , SImode , NULL_RTX , INTVAL ( highpart ) , NULL_RTX , NULL_RTX , 0 , 0 ) ) ; } </s>

Return the cost of synthesizing a 64-bit constant VAL inline . Returns the number of insns needed , or 99 if we do n't know how to do it .


<s> static bool arm_const_double_prefer_rsbs_rsc ( rtx op ) { if ( TARGET_THUMB || ! CONST_INT_P ( op ) ) return false ; HOST_WIDE_INT hi , lo ; lo = UINTVAL ( op ) & 0xffffffffULL ; hi = UINTVAL ( op ) >> 32 ; return const_ok_for_arm ( lo ) && const_ok_for_arm ( hi ) ; } </s>

Return TRUE if op is a constant where both the low and top words are suitable for RSB/RSC instructions . This is never true for Thumb , since we do not have RSC in that case .


<s> int arm_const_double_rtx ( rtx x ) { const REAL_VALUE_TYPE * r ; if ( ! fp_consts_inited ) init_fp_table ( ) ; r = CONST_DOUBLE_REAL_VALUE ( x ) ; if ( REAL_VALUE_MINUS_ZERO ( * r ) ) return 0 ; if ( real_equal ( r , & value_fp0 ) ) return 1 ; return 0 ; } </s>

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


<s> static inline int arm_const_inline_cost ( enum rtx_code code , rtx val ) { return arm_gen_constant ( code , SImode , NULL_RTX , INTVAL ( val ) , NULL_RTX , NULL_RTX , 1 , 0 ) ; } </s>


<s> static bool arm_const_not_ok_for_debug_p ( rtx p ) { tree decl_op0 = NULL ; tree decl_op1 = NULL ; if ( GET_CODE ( p ) == UNSPEC ) return true ; if ( GET_CODE ( p ) == MINUS ) { if ( GET_CODE ( XEXP ( p , 1 ) ) == SYMBOL_REF ) { decl_op1 = SYMBOL_REF_DECL ( XEXP ( p , 1 ) ) ; if ( decl_op1 && GET_CODE ( XEXP ( p , 0 ) ) == SYMBOL_REF && ( decl_op0 = SYMBOL_REF_DECL ( XEXP ( p , 0 ) ) ) ) { if ( ( VAR_P ( decl_op1 ) || TREE_CODE ( decl_op1 ) == CONST_DECL ) && ( VAR_P ( decl_op0 ) || TREE_CODE ( decl_op0 ) == CONST_DECL ) ) return ( get_variable_section ( decl_op1 , false ) != get_variable_section ( decl_op0 , false ) ) ; if ( TREE_CODE ( decl_op1 ) == LABEL_DECL && TREE_CODE ( decl_op0 ) == LABEL_DECL ) return ( DECL_CONTEXT ( decl_op1 ) != DECL_CONTEXT ( decl_op0 ) ) ; } return true ; } } return false ; } </s>

This is a temporary fix for PR60655 . Ideally we need to handle most of these cases in the generic part but currently we reject minus ( .. ) ( sym_ref ) . We try to ameliorate the case with minus ( sym_ref1 ) ( sym_ref2 ) where they are in the same section .


<s> static bool arm_cookie_has_size ( void ) { return TARGET_AAPCS_BASED ; } </s>

The EABI says that array cookies should also contain the element size .


<s> bool arm_coproc_builtin_available ( enum unspecv builtin ) { if ( TARGET_THUMB1 ) return false ; switch ( builtin ) { case VUNSPEC_CDP : case VUNSPEC_LDC : case VUNSPEC_LDCL : case VUNSPEC_STC : case VUNSPEC_STCL : case VUNSPEC_MCR : case VUNSPEC_MRC : if ( arm_arch4 ) return true ; break ; case VUNSPEC_CDP2 : case VUNSPEC_LDC2 : case VUNSPEC_LDC2L : case VUNSPEC_STC2 : case VUNSPEC_STC2L : case VUNSPEC_MCR2 : case VUNSPEC_MRC2 : if ( arm_arch5t ) return true ; break ; case VUNSPEC_MCRR : case VUNSPEC_MRRC : if ( arm_arch6 || arm_arch5te ) return true ; break ; case VUNSPEC_MCRR2 : case VUNSPEC_MRRC2 : if ( arm_arch6 ) return true ; break ; default : gcc_unreachable ( ) ; } return false ; } </s>

This function checks for the availability of the coprocessor builtin passed in BUILTIN for the current target . Returns true if it is available and false otherwise . If a BUILTIN is passed for which this function has not been implemented it will cause an exception .


<s> bool arm_coproc_ldc_stc_legitimate_address ( rtx op ) { HOST_WIDE_INT range ; if ( ! MEM_P ( op ) ) return false ; op = XEXP ( op , 0 ) ; if ( REG_P ( op ) ) return true ; switch GET_CODE ( op ) { case PLUS : { if ( ! REG_P ( XEXP ( op , 0 ) ) ) return false ; op = XEXP ( op , 1 ) ; if ( ! CONST_INT_P ( op ) ) return false ; range = INTVAL ( op ) ; if ( ! IN_RANGE ( range , - 1020 , 1020 ) ) return false ; return ( range % 4 ) == 0 ; } case PRE_INC : case POST_INC : case PRE_DEC : case POST_DEC : return REG_P ( XEXP ( op , 0 ) ) ; default : gcc_unreachable ( ) ; } return false ; } </s>

This function returns true if OP is a valid memory operand for the ldc and stc coprocessor instructions and false otherwise .


<s> int arm_coproc_mem_operand ( rtx op , bool wb ) { return arm_coproc_mem_operand_wb ( op , wb ? 2 : 1 ) ; } </s>

Return TRUE if OP is a valid coprocessor memory address pattern . WB if true if writeback address modes are allowed .


<s> int arm_coproc_mem_operand_no_writeback ( rtx op ) { return arm_coproc_mem_operand_wb ( op , 0 ) ; } </s>

Return TRUE if OP is a valid coprocessor memory address pattern in a context in which no writeback address modes are allowed .


<s> int arm_coproc_mem_operand_wb ( rtx op , int wb_level ) { gcc_assert ( wb_level == 0 || wb_level == 1 || wb_level == 2 ) ; rtx ind ; if ( ! ( reload_in_progress || reload_completed || lra_in_progress ) && ( reg_mentioned_p ( frame_pointer_rtx , op ) || reg_mentioned_p ( arg_pointer_rtx , op ) || reg_mentioned_p ( virtual_incoming_args_rtx , op ) || reg_mentioned_p ( virtual_outgoing_args_rtx , op ) || reg_mentioned_p ( virtual_stack_dynamic_rtx , op ) || reg_mentioned_p ( virtual_stack_vars_rtx , op ) ) ) return FALSE ; if ( ! MEM_P ( op ) ) return FALSE ; ind = XEXP ( op , 0 ) ; if ( reload_completed && ( LABEL_REF_P ( ind ) || ( GET_CODE ( ind ) == CONST && GET_CODE ( XEXP ( ind , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( ind , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( ind , 0 ) , 1 ) ) ) ) ) return TRUE ; if ( REG_P ( ind ) ) return arm_address_register_rtx_p ( ind , 0 ) ; if ( wb_level > 0 && ( GET_CODE ( ind ) == POST_INC || GET_CODE ( ind ) == PRE_DEC || ( wb_level > 1 && ( GET_CODE ( ind ) == PRE_INC || GET_CODE ( ind ) == POST_DEC ) ) ) ) return arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) ; if ( wb_level > 1 && ( GET_CODE ( ind ) == POST_MODIFY || GET_CODE ( ind ) == PRE_MODIFY ) && arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) && GET_CODE ( XEXP ( ind , 1 ) ) == PLUS && rtx_equal_p ( XEXP ( XEXP ( ind , 1 ) , 0 ) , XEXP ( ind , 0 ) ) ) ind = XEXP ( ind , 1 ) ; int factor = MIN ( GET_MODE_SIZE ( GET_MODE ( op ) ) , 4 ) ; if ( GET_CODE ( ind ) == PLUS && REG_P ( XEXP ( ind , 0 ) ) && REG_MODE_OK_FOR_BASE_P ( XEXP ( ind , 0 ) , VOIDmode ) && CONST_INT_P ( XEXP ( ind , 1 ) ) && IN_RANGE ( INTVAL ( XEXP ( ind , 1 ) ) , - 255 * factor , 255 * factor ) && ( INTVAL ( XEXP ( ind , 1 ) ) & ( factor - 1 ) ) == 0 ) return TRUE ; return FALSE ; } </s>

Return TRUE if OP is a valid coprocessor memory address pattern . WB level is 2 if full writeback address modes are allowed , 1 if limited writeback address modes ( POST_INC and PRE_DEC ) are allowed and 0 if no writeback at all is supported .


<s> static int arm_cortex_m_branch_cost ( bool speed_p , bool predictable_p ) { return ( TARGET_32BIT && speed_p ) ? 1 : arm_default_branch_cost ( speed_p , predictable_p ) ; } </s>

Thumb-2 branches are relatively cheap on Cortex-M processors ( `` 1 + P cycles '' on Cortex-M4 , where P varies from 1 to 3 according to some criteria ) , since sequences of non-executed instructions in IT blocks probably take the same amount of time as executed instructions ( and the IT instruction itself takes space in icache ) . This function was experimentally determined to give good results on a popular embedded benchmark .


<s> int arm_count_ldrdstrd_insns ( rtx * operands , bool load ) { int count ; rtx ops [ 2 ] ; int regnum , memnum ; if ( load ) regnum = 0 , memnum = 1 ; else regnum = 1 , memnum = 0 ; ops [ regnum ] = gen_rtx_REG ( DImode , REGNO ( operands [ 0 ] ) ) ; ops [ memnum ] = adjust_address ( operands [ 2 ] , DImode , 0 ) ; output_move_double ( ops , false , & count ) ; return count ; } </s>

Same as above , but operands are a register/memory pair in SImode . Assumes operands has the base register in position 0 and memory in position 2 ( which is the order provided by the arm_ { ldrd , strd } patterns ) .


<s> int arm_count_output_move_double_insns ( rtx * operands ) { int count ; rtx ops [ 2 ] ; ops [ 0 ] = operands [ 0 ] ; ops [ 1 ] = operands [ 1 ] ; output_move_double ( ops , false , & count ) ; return count ; } </s>

Compute the number of instructions emitted by output_move_double .


<s> static int arm_cpymemqi_unaligned ( rtx * operands ) { HOST_WIDE_INT length = INTVAL ( operands [ 2 ] ) ; if ( optimize_size ) { bool src_aligned = MEM_ALIGN ( operands [ 1 ] ) >= BITS_PER_WORD ; bool dst_aligned = MEM_ALIGN ( operands [ 0 ] ) >= BITS_PER_WORD ; unsigned int interleave_factor = ( src_aligned || dst_aligned ) ? 2 : 1 ; HOST_WIDE_INT bytes_per_iter = ( src_aligned || dst_aligned ) ? 8 : 4 ; if ( length > 12 ) arm_block_move_unaligned_loop ( operands [ 0 ] , operands [ 1 ] , length , interleave_factor , bytes_per_iter ) ; else arm_block_move_unaligned_straight ( operands [ 0 ] , operands [ 1 ] , length , interleave_factor ) ; } else { if ( length > 32 ) arm_block_move_unaligned_loop ( operands [ 0 ] , operands [ 1 ] , length , 4 , 16 ) ; else arm_block_move_unaligned_straight ( operands [ 0 ] , operands [ 1 ] , length , 4 ) ; } return 1 ; } </s>

Emit a block move when either the source or destination is unaligned ( not aligned to a four-byte boundary ) . This may need further tuning depending on core type , optimize_size setting , etc .


<s> unsigned long arm_current_func_type ( void ) { if ( ARM_FUNC_TYPE ( cfun -> machine -> func_type ) == ARM_FT_UNKNOWN ) cfun -> machine -> func_type = arm_compute_func_type ( ) ; return cfun -> machine -> func_type ; } </s>

Returns the type of the current function .


<s> static bool arm_cxx_cdtor_returns_this ( void ) { return TARGET_AAPCS_BASED ; } </s>

The EABI says constructors and destructors should return a pointer to the object constructed/destroyed .


<s> static bool arm_cxx_guard_mask_bit ( void ) { return TARGET_AAPCS_BASED ; } </s>

The EABI says test the least significant bit of a guard variable .


<s> static tree arm_cxx_guard_type ( void ) { return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node ; } </s>

The generic C++ ABI says 64-bit ( long long ) . The EABI says 32-bit .


<s> static bool arm_cxx_key_method_may_be_inline ( void ) { return ! TARGET_AAPCS_BASED ; } </s>

The EABI says that an inline function may never be the key method .


<s> static bool arm_cxx_use_aeabi_atexit ( void ) { return TARGET_AAPCS_BASED ; } </s>

The EABI says __aeabi_atexit should be used to register static destructors .


<s> unsigned int arm_dbx_register_number ( unsigned int regno ) { if ( regno < 16 ) return regno ; if ( IS_VFP_REGNUM ( regno ) ) { if ( VFP_REGNO_OK_FOR_SINGLE ( regno ) ) return 64 + regno - FIRST_VFP_REGNUM ; else return 256 + ( regno - FIRST_VFP_REGNUM ) / 2 ; } if ( IS_IWMMXT_GR_REGNUM ( regno ) ) return 104 + regno - FIRST_IWMMXT_GR_REGNUM ; if ( IS_IWMMXT_REGNUM ( regno ) ) return 112 + regno - FIRST_IWMMXT_REGNUM ; return DWARF_FRAME_REGISTERS ; } </s>

Map internal gcc register numbers to DWARF2 register numbers .


"unable to compute real location of stacked parameter"

Handle a special case when computing the offset of an argument from the frame pointer .


<s>
void
arm_declare_function_name
(
FILE
*
stream
,
const
char
*
name
,
tree
decl
)
{
tree
target_parts
=
DECL_FUNCTION_SPECIFIC_TARGET
(
decl
)
;
struct
cl_target_option
*
targ_options
;
if
(
target_parts
)
targ_options
=
TREE_TARGET_OPTION
(
target_parts
)
;
else
targ_options
=
TREE_TARGET_OPTION
(
target_option_current_node
)
;
gcc_assert
(
targ_options
)
;
arm_print_asm_arch_directives
(
stream
,
targ_options
)
;
fprintf
(
stream
,
"\t.syntax unified\n"
)
;
if
(
TARGET_THUMB
)
{
if
(
is_called_in_ARM_mode
(
decl
)
||
(
TARGET_THUMB1
&&
!
TARGET_THUMB1_ONLY
&&
cfun
->
is_thunk
)
)
fprintf
(
stream
,
"\t.code 32\n"
)
;
else
if
(
TARGET_THUMB1
)
fprintf
(
stream
,
"\t.code\t16\n\t.thumb_func\n"
)
;
else
fprintf
(
stream
,
"\t.thumb\n\t.thumb_func\n"
)
;
}
else
fprintf
(
stream
,
"\t.arm\n"
)
;
if
(
TARGET_POKE_FUNCTION_NAME
)
arm_poke_function_name
(
stream
,
(
const
char
*
)
name
)
;
}
</s>

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


<s> void arm_decompose_di_binop ( rtx op1 , rtx op2 , rtx * lo_op1 , rtx * hi_op1 , rtx * lo_op2 , rtx * hi_op2 ) { * lo_op1 = gen_lowpart ( SImode , op1 ) ; * hi_op1 = gen_highpart ( SImode , op1 ) ; * lo_op2 = simplify_gen_subreg ( SImode , op2 , DImode , subreg_lowpart_offset ( SImode , DImode ) ) ; * hi_op2 = simplify_gen_subreg ( SImode , op2 , DImode , subreg_highpart_offset ( SImode , DImode ) ) ; } </s>

Decompose operands for a 64-bit binary operation in OP1 and OP2 into its component 32-bit subregs . OP2 may be an immediate constant and we want to simplify it in that case .


<s> static bool arm_default_short_enums ( void ) { return ARM_DEFAULT_SHORT_ENUMS ; } </s>

AAPCS based ABIs use short enums by default .


<s> static rtx arm_dwarf_register_span ( rtx rtl ) { machine_mode mode ; unsigned regno ; rtx parts [ 16 ] ; int nregs ; int i ; regno = REGNO ( rtl ) ; if ( ! IS_VFP_REGNUM ( regno ) ) return NULL_RTX ; mode = GET_MODE ( rtl ) ; if ( GET_MODE_SIZE ( mode ) < 8 ) return NULL_RTX ; if ( VFP_REGNO_OK_FOR_SINGLE ( regno ) ) { nregs = GET_MODE_SIZE ( mode ) / 4 ; for ( i = 0 ; i < nregs ; i += 2 ) if ( TARGET_BIG_END ) { parts [ i ] = gen_rtx_REG ( SImode , regno + i + 1 ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i ) ; } else { parts [ i ] = gen_rtx_REG ( SImode , regno + i ) ; parts [ i + 1 ] = gen_rtx_REG ( SImode , regno + i + 1 ) ; } } else { nregs = GET_MODE_SIZE ( mode ) / 8 ; for ( i = 0 ; i < nregs ; i ++ ) parts [ i ] = gen_rtx_REG ( DImode , regno + i ) ; } return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( nregs , parts ) ) ; } </s>

Dwarf models VFPv3 registers as 32 64-bit registers . GCC models tham as 64 32-bit registers , so we need to describe this to the DWARF generation code . Other registers can use the default .


<s> static void arm_elf_asm_constructor ( rtx symbol , int priority ) { arm_elf_asm_cdtor ( symbol , priority , true ) ; } </s>

Add a function to the list of static constructors .


<s> static void arm_elf_asm_destructor ( rtx symbol , int priority ) { arm_elf_asm_cdtor ( symbol , priority , false ) ; } </s>

Add a function to the list of static destructors .


<s> static unsigned int arm_elf_section_type_flags ( tree decl , const char * name , int reloc ) { unsigned int flags = default_section_type_flags ( decl , name , reloc ) ; if ( decl && TREE_CODE ( decl ) == FUNCTION_DECL && target_pure_code ) flags |= SECTION_ARM_PURECODE ; return flags ; } </s>

Implements the TARGET_SECTION_FLAGS hook . If DECL is a function declaration and pure-code is passed as an option then add the SFH_ARM_PURECODE attribute to the section flags . NAME is the section 's name and RELOC indicates whether the declarations initializer may contain runtime relocations .


<s> int arm_eliminable_register ( rtx x ) { return REG_P ( x ) && ( REGNO ( x ) == FRAME_POINTER_REGNUM || REGNO ( x ) == ARG_POINTER_REGNUM || ( REGNO ( x ) >= FIRST_VIRTUAL_REGISTER && REGNO ( x ) <= LAST_VIRTUAL_REGISTER ) ) ; } </s>

Return true if X is a register that will be eliminated later on .


<s> void arm_emit_call_insn ( rtx pat , rtx addr , bool sibcall ) { rtx insn ; insn = emit_call_insn ( pat ) ; if ( TARGET_VXWORKS_RTP && flag_pic && ! sibcall && SYMBOL_REF_P ( addr ) && ( SYMBOL_REF_DECL ( addr ) ? ! targetm . binds_local_p ( SYMBOL_REF_DECL ( addr ) ) : ! SYMBOL_REF_LOCAL_P ( addr ) ) ) { require_pic_register ( NULL_RTX , false ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , cfun -> machine -> pic_reg ) ; } if ( TARGET_FDPIC ) { rtx fdpic_reg = gen_rtx_REG ( Pmode , FDPIC_REGNUM ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , fdpic_reg ) ; } if ( TARGET_AAPCS_BASED ) { rtx * fusage = & CALL_INSN_FUNCTION_USAGE ( insn ) ; clobber_reg ( fusage , gen_rtx_REG ( word_mode , IP_REGNUM ) ) ; } } </s>

Emit a call instruction with pattern PAT . ADDR is the address of the call target .


<s>
void
arm_emit_eabi_attribute
(
const
char
*
name
,
int
num
,
int
val
)
{
asm_fprintf
(
asm_out_file
,
"\t.eabi_attribute %d, %d"
,
num
,
val
)
;
if
(
flag_verbose_asm
||
flag_debug_asm
)
asm_fprintf
(
asm_out_file
,
"\t%s %s"
,
ASM_COMMENT_START
,
name
)
;
asm_fprintf
(
asm_out_file
,
"\n"
)
;
}
</s>

This function is used to emit an EABI tag and its associated value . We emit the numerical value of the tag in case the assembler does not support textual tags . ( Eg gas prior to 2.20 ) . If requested we include the tag name in a comment so that anyone reading the assembler output will know which tag is being set . This function is not static because arm-c.cc needs it too .

arm
"\t.eabi_attribute %d, %d"
"\t%s %s"
"\n"


<s> void arm_emit_fp16_const ( rtx c ) { long bits ; bits = real_to_target ( NULL , CONST_DOUBLE_REAL_VALUE ( c ) , HFmode ) ; if ( WORDS_BIG_ENDIAN ) assemble_zeros ( 2 ) ; assemble_integer ( GEN_INT ( bits ) , 2 , BITS_PER_WORD , 1 ) ; if ( ! WORDS_BIG_ENDIAN ) assemble_zeros ( 2 ) ; } </s>

Emit a fp16 constant appropriately padded to occupy a 4-byte word . HFmode constant pool entries are actually loaded with ldr .


<s> static void arm_emit_ldrd_pop ( unsigned long saved_regs_mask ) { int j = 0 ; int offset = 0 ; rtx par = NULL_RTX ; rtx dwarf = NULL_RTX ; rtx tmp , mem ; gcc_assert ( ! ( ( saved_regs_mask & ( 1 << SP_REGNUM ) ) ) ) ; j = 0 ; while ( j <= LAST_ARM_REGNUM ) if ( saved_regs_mask & ( 1 << j ) ) { if ( ( j % 2 ) == 0 && ( saved_regs_mask & ( 1 << ( j + 1 ) ) ) && ( j + 1 ) != PC_REGNUM ) { if ( offset > 0 ) mem = gen_frame_mem ( DImode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; else mem = gen_frame_mem ( DImode , stack_pointer_rtx ) ; tmp = gen_rtx_SET ( gen_rtx_REG ( DImode , j ) , mem ) ; tmp = emit_insn ( tmp ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; dwarf = alloc_reg_note ( REG_CFA_RESTORE , gen_rtx_REG ( SImode , j ) , NULL_RTX ) ; dwarf = alloc_reg_note ( REG_CFA_RESTORE , gen_rtx_REG ( SImode , j + 1 ) , dwarf ) ; REG_NOTES ( tmp ) = dwarf ; offset += 8 ; j += 2 ; } else if ( j != PC_REGNUM ) { if ( offset > 0 ) mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; else mem = gen_frame_mem ( SImode , stack_pointer_rtx ) ; tmp = gen_rtx_SET ( gen_rtx_REG ( SImode , j ) , mem ) ; tmp = emit_insn ( tmp ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; REG_NOTES ( tmp ) = alloc_reg_note ( REG_CFA_RESTORE , gen_rtx_REG ( SImode , j ) , NULL_RTX ) ; offset += 4 ; j += 1 ; } else j ++ ; } else j ++ ; if ( offset > 0 ) { tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; tmp = emit_insn ( tmp ) ; arm_add_cfa_adjust_cfa_note ( tmp , offset , stack_pointer_rtx , stack_pointer_rtx ) ; offset = 0 ; } if ( saved_regs_mask & ( 1 << PC_REGNUM ) ) { par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( 2 ) ) ; XVECEXP ( par , 0 , 0 ) = ret_rtx ; tmp = gen_rtx_SET ( gen_rtx_REG ( SImode , PC_REGNUM ) , gen_frame_mem ( SImode , gen_rtx_POST_INC ( SImode , stack_pointer_rtx ) ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , 1 ) = tmp ; par = emit_jump_insn ( par ) ; dwarf = alloc_reg_note ( REG_CFA_RESTORE , gen_rtx_REG ( SImode , PC_REGNUM ) , NULL_RTX ) ; REG_NOTES ( par ) = dwarf ; arm_add_cfa_adjust_cfa_note ( par , UNITS_PER_WORD , stack_pointer_rtx , stack_pointer_rtx ) ; } } </s>

LDRD in ARM mode needs consecutive registers as operands . This function emits LDRD whenever possible , otherwise it emits single-word loads . It uses offset addressing and then generates one separate stack udpate . This provides more scheduling freedom , compared to writeback on every load . However , if the function returns using load into PC directly ( i.e. , if PC is in SAVED_REGS_MASK ) , the stack needs to be updated before the last load . TODO : Add a peephole optimization to recognize the new epilogue sequence as an LDM instruction whenever possible . TODO : Add peephole optimization to merge the load at stack-offset zero with the stack update instruction using load with writeback in post-index addressing mode .


<s> static void arm_emit_load_exclusive ( machine_mode mode , rtx rval , rtx mem , bool acq ) { rtx ( * gen ) ( rtx , rtx ) ; if ( acq ) { switch ( mode ) { case E_QImode : gen = gen_arm_load_acquire_exclusiveqi ; break ; case E_HImode : gen = gen_arm_load_acquire_exclusivehi ; break ; case E_SImode : gen = gen_arm_load_acquire_exclusivesi ; break ; case E_DImode : gen = gen_arm_load_acquire_exclusivedi ; break ; default : gcc_unreachable ( ) ; } } else { switch ( mode ) { case E_QImode : gen = gen_arm_load_exclusiveqi ; break ; case E_HImode : gen = gen_arm_load_exclusivehi ; break ; case E_SImode : gen = gen_arm_load_exclusivesi ; break ; case E_DImode : gen = gen_arm_load_exclusivedi ; break ; default : gcc_unreachable ( ) ; } } emit_insn ( gen ( rval , mem ) ) ; } </s>

Emit the load-exclusive and store-exclusive instructions . Use acquire and release versions if necessary .


<s> static void arm_emit_multi_reg_pop ( unsigned long saved_regs_mask ) { int num_regs = 0 ; int i , j ; rtx par ; rtx dwarf = NULL_RTX ; rtx tmp , reg ; bool return_in_pc = saved_regs_mask & ( 1 << PC_REGNUM ) ; int offset_adj ; int emit_update ; offset_adj = return_in_pc ? 1 : 0 ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) if ( saved_regs_mask & ( 1 << i ) ) num_regs ++ ; gcc_assert ( num_regs && num_regs <= 16 ) ; emit_update = ( saved_regs_mask & ( 1 << SP_REGNUM ) ) ? 0 : 1 ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs + emit_update + offset_adj ) ) ; if ( return_in_pc ) XVECEXP ( par , 0 , 0 ) = ret_rtx ; if ( emit_update ) { tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , 4 * num_regs ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , offset_adj ) = tmp ; } for ( j = 0 , i = 0 ; j < num_regs ; i ++ ) if ( saved_regs_mask & ( 1 << i ) ) { reg = gen_rtx_REG ( SImode , i ) ; if ( ( num_regs == 1 ) && emit_update && ! return_in_pc ) { tmp = gen_frame_mem ( SImode , gen_rtx_POST_INC ( Pmode , stack_pointer_rtx ) ) ; tmp = emit_insn ( gen_rtx_SET ( reg , tmp ) ) ; REG_NOTES ( tmp ) = alloc_reg_note ( REG_CFA_RESTORE , reg , dwarf ) ; return ; } tmp = gen_rtx_SET ( reg , gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , 4 * j ) ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j + emit_update + offset_adj ) = tmp ; if ( i != PC_REGNUM ) dwarf = alloc_reg_note ( REG_CFA_RESTORE , reg , dwarf ) ; j ++ ; } if ( return_in_pc ) par = emit_jump_insn ( par ) ; else par = emit_insn ( par ) ; REG_NOTES ( par ) = dwarf ; if ( ! return_in_pc ) arm_add_cfa_adjust_cfa_note ( par , UNITS_PER_WORD * num_regs , stack_pointer_rtx , stack_pointer_rtx ) ; } </s>

Generate and emit an insn pattern that we will recognize as a pop_multi . SAVED_REGS_MASK shows which registers need to be restored . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information .


<s> static void arm_emit_probe_stack_range ( HOST_WIDE_INT first , HOST_WIDE_INT size , unsigned int regno1 , unsigned long live_regs ) { rtx reg1 = gen_rtx_REG ( Pmode , regno1 ) ; if ( size <= PROBE_INTERVAL ) { emit_move_insn ( reg1 , GEN_INT ( first + PROBE_INTERVAL ) ) ; emit_set_insn ( reg1 , gen_rtx_MINUS ( Pmode , stack_pointer_rtx , reg1 ) ) ; emit_stack_probe ( plus_constant ( Pmode , reg1 , PROBE_INTERVAL - size ) ) ; } else if ( size <= 5 * PROBE_INTERVAL ) { HOST_WIDE_INT i , rem ; emit_move_insn ( reg1 , GEN_INT ( first + PROBE_INTERVAL ) ) ; emit_set_insn ( reg1 , gen_rtx_MINUS ( Pmode , stack_pointer_rtx , reg1 ) ) ; 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 > 4095 || ( TARGET_THUMB2 && rem > 255 ) ) { emit_set_insn ( reg1 , plus_constant ( Pmode , reg1 , - PROBE_INTERVAL ) ) ; emit_stack_probe ( plus_constant ( Pmode , reg1 , PROBE_INTERVAL - rem ) ) ; } else emit_stack_probe ( plus_constant ( Pmode , reg1 , - rem ) ) ; } else { HOST_WIDE_INT rounded_size ; struct scratch_reg sr ; get_scratch_register_on_entry ( & sr , regno1 , live_regs ) ; emit_move_insn ( reg1 , GEN_INT ( first ) ) ; rounded_size = size & - PROBE_INTERVAL ; emit_move_insn ( sr . reg , GEN_INT ( rounded_size ) ) ; emit_set_insn ( reg1 , gen_rtx_MINUS ( Pmode , stack_pointer_rtx , reg1 ) ) ; emit_set_insn ( sr . reg , gen_rtx_MINUS ( Pmode , reg1 , sr . reg ) ) ; emit_insn ( gen_probe_stack_range ( reg1 , reg1 , sr . reg ) ) ; if ( size != rounded_size ) { HOST_WIDE_INT rem = size - rounded_size ; if ( rem > 4095 || ( TARGET_THUMB2 && rem > 255 ) ) { emit_set_insn ( sr . reg , plus_constant ( Pmode , sr . reg , - PROBE_INTERVAL ) ) ; emit_stack_probe ( plus_constant ( Pmode , sr . reg , PROBE_INTERVAL - rem ) ) ; } else emit_stack_probe ( plus_constant ( Pmode , sr . reg , - rem ) ) ; } release_scratch_register_on_entry ( & sr ) ; } 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 . REGNO1 is the index number of the 1st scratch register and LIVE_REGS is the mask of live registers .


<s> void arm_emit_speculation_barrier_function ( ) { emit_library_call ( speculation_barrier_libfunc , LCT_NORMAL , VOIDmode ) ; } </s>

Emit a speculation barrier on target architectures that do not have DSB/ISB directly . Such systems probably do n't need a barrier themselves , but if the code is ever run on a later architecture , it might become a problem .


<s> static void arm_emit_vfp_multi_reg_pop ( int first_reg , int num_regs , rtx base_reg ) { int i , j ; rtx par ; rtx dwarf = NULL_RTX ; rtx tmp , reg ; gcc_assert ( num_regs && num_regs <= 32 ) ; if ( num_regs == 2 && ! arm_arch6 ) { if ( first_reg == 15 ) first_reg -- ; num_regs ++ ; } if ( num_regs > 16 ) { arm_emit_vfp_multi_reg_pop ( first_reg , 16 , base_reg ) ; arm_emit_vfp_multi_reg_pop ( first_reg + 16 , num_regs - 16 , base_reg ) ; return ; } par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs + 1 ) ) ; tmp = gen_rtx_SET ( base_reg , plus_constant ( Pmode , base_reg , 8 * num_regs ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , 0 ) = tmp ; for ( j = 0 , i = first_reg ; j < num_regs ; i += 2 ) { reg = gen_rtx_REG ( DFmode , i ) ; tmp = gen_rtx_SET ( reg , gen_frame_mem ( DFmode , plus_constant ( Pmode , base_reg , 8 * j ) ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( par , 0 , j + 1 ) = tmp ; dwarf = alloc_reg_note ( REG_CFA_RESTORE , reg , dwarf ) ; j ++ ; } par = emit_insn ( par ) ; REG_NOTES ( par ) = dwarf ; if ( REGNO ( base_reg ) == IP_REGNUM ) { RTX_FRAME_RELATED_P ( par ) = 1 ; add_reg_note ( par , REG_CFA_DEF_CFA , hard_frame_pointer_rtx ) ; } else arm_add_cfa_adjust_cfa_note ( par , 2 * UNITS_PER_WORD * num_regs , base_reg , base_reg ) ; } </s>

Generate and emit an insn pattern that we will recognize as a pop_multi of NUM_REGS consecutive VFP regs , starting at FIRST_REG . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information .


<s> static void arm_encode_section_info ( tree decl , rtx rtl , int first ) { if ( optimize > 0 && TREE_CONSTANT ( decl ) ) SYMBOL_REF_FLAG ( XEXP ( rtl , 0 ) ) = 1 ; default_encode_section_info ( decl , rtl , first ) ; } </s>

Symbols in the text segment can be accessed without indirecting via the constant pool ; it may take an extra binary operation , but this is still faster than indirecting via memory . Do n't do this when not optimizing , since we wo n't be calculating al of the offsets necessary to do this simplification .


<s> static bool arm_evpc_neon_vext ( struct expand_vec_perm_d * d ) { unsigned int i , nelt = d -> perm . length ( ) ; rtx offset ; unsigned int location ; unsigned int next = d -> perm [ 0 ] + 1 ; if ( BYTES_BIG_ENDIAN ) return false ; for ( i = 1 ; i < nelt ; next ++ , i ++ ) { if ( next == 2 * nelt ) return false ; if ( d -> one_vector_p && ( next == nelt ) ) { if ( ( nelt == 2 ) && ( d -> vmode != V2DImode ) ) return false ; else next = 0 ; } if ( d -> perm [ i ] != next ) return false ; } location = d -> perm [ 0 ] ; if ( d -> testing_p ) return true ; offset = GEN_INT ( location ) ; if ( d -> vmode == E_DImode ) return false ; emit_insn ( gen_neon_vext ( d -> vmode , d -> target , d -> op0 , d -> op1 , offset ) ) ; return true ; } </s>


<s> static bool arm_evpc_neon_vrev ( struct expand_vec_perm_d * d ) { unsigned int i , j , diff , nelt = d -> perm . length ( ) ; rtx ( * gen ) ( machine_mode , rtx , rtx ) ; if ( ! d -> one_vector_p ) return false ; diff = d -> perm [ 0 ] ; switch ( diff ) { case 7 : switch ( d -> vmode ) { case E_V16QImode : case E_V8QImode : gen = gen_neon_vrev64 ; break ; default : return false ; } break ; case 3 : switch ( d -> vmode ) { case E_V16QImode : case E_V8QImode : gen = gen_neon_vrev32 ; break ; case E_V8HImode : case E_V4HImode : case E_V8HFmode : case E_V4HFmode : gen = gen_neon_vrev64 ; break ; default : return false ; } break ; case 1 : switch ( d -> vmode ) { case E_V16QImode : case E_V8QImode : gen = gen_neon_vrev16 ; break ; case E_V8HImode : case E_V4HImode : gen = gen_neon_vrev32 ; break ; case E_V4SImode : case E_V2SImode : case E_V4SFmode : case E_V2SFmode : gen = gen_neon_vrev64 ; 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 -> vmode , d -> target , d -> op0 ) ) ; return true ; } </s>


<s> static bool arm_evpc_neon_vtbl ( struct expand_vec_perm_d * d ) { rtx rperm [ MAX_VECT_LEN ] , sel ; machine_mode vmode = d -> vmode ; unsigned int i , nelt = d -> perm . length ( ) ; if ( BYTES_BIG_ENDIAN ) return false ; if ( d -> testing_p ) return true ; if ( vmode != V8QImode && vmode != V16QImode ) return false ; for ( i = 0 ; i < nelt ; ++ i ) rperm [ i ] = GEN_INT ( d -> perm [ i ] ) ; sel = gen_rtx_CONST_VECTOR ( vmode , gen_rtvec_v ( nelt , rperm ) ) ; sel = force_reg ( vmode , sel ) ; arm_expand_vec_perm_1 ( d -> target , d -> op0 , d -> op1 , sel ) ; return true ; } </s>

The NEON VTBL instruction is a fully variable permuation that 's even stronger than what we expose via VEC_PERM_EXPR . What it does n't do is mask the index operand as VEC_PERM_EXPR requires . Therefore we can do slightly better by expanding this as a constant where we do n't have to apply a mask .


<s> static bool arm_evpc_neon_vtrn ( struct expand_vec_perm_d * d ) { unsigned int i , odd , mask , nelt = d -> perm . length ( ) ; rtx out0 , out1 , in0 , in1 ; if ( GET_MODE_UNIT_SIZE ( d -> 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 ) { std :: swap ( in0 , in1 ) ; odd = ! odd ; } out0 = d -> target ; out1 = gen_reg_rtx ( d -> vmode ) ; if ( odd ) std :: swap ( out0 , out1 ) ; emit_insn ( gen_neon_vtrn_internal ( d -> vmode , out0 , in0 , in1 , out1 ) ) ; return true ; } </s>


<s> static bool arm_evpc_neon_vuzp ( struct expand_vec_perm_d * d ) { unsigned int i , odd , mask , nelt = d -> perm . length ( ) ; rtx out0 , out1 , in0 , in1 ; int first_elem ; int swap_nelt ; if ( GET_MODE_UNIT_SIZE ( d -> vmode ) >= 8 ) return false ; swap_nelt = BYTES_BIG_ENDIAN && ! d -> one_vector_p && GET_MODE_SIZE ( d -> vmode ) == 8 ? nelt : 0 ; first_elem = d -> perm [ neon_endian_lane_map ( d -> vmode , 0 ) ] ^ swap_nelt ; if ( first_elem == neon_endian_lane_map ( d -> vmode , 0 ) ) odd = 0 ; else if ( first_elem == neon_endian_lane_map ( d -> vmode , 1 ) ) odd = 1 ; else return false ; mask = ( d -> one_vector_p ? nelt - 1 : 2 * nelt - 1 ) ; for ( i = 0 ; i < nelt ; i ++ ) { unsigned elt = ( neon_pair_endian_lane_map ( d -> vmode , i ) * 2 + odd ) & mask ; if ( ( d -> perm [ i ] ^ swap_nelt ) != neon_pair_endian_lane_map ( d -> vmode , elt ) ) return false ; } if ( d -> testing_p ) return true ; in0 = d -> op0 ; in1 = d -> op1 ; if ( swap_nelt != 0 ) std :: swap ( in0 , in1 ) ; out0 = d -> target ; out1 = gen_reg_rtx ( d -> vmode ) ; if ( odd ) std :: swap ( out0 , out1 ) ; emit_insn ( gen_neon_vuzp_internal ( d -> vmode , out0 , in0 , in1 , out1 ) ) ; return true ; } </s>


<s> static bool arm_evpc_neon_vzip ( struct expand_vec_perm_d * d ) { unsigned int i , high , mask , nelt = d -> perm . length ( ) ; rtx out0 , out1 , in0 , in1 ; int first_elem ; bool is_swapped ; if ( GET_MODE_UNIT_SIZE ( d -> vmode ) >= 8 ) return false ; is_swapped = BYTES_BIG_ENDIAN ; first_elem = d -> perm [ neon_endian_lane_map ( d -> vmode , 0 ) ^ is_swapped ] ; high = nelt / 2 ; if ( first_elem == neon_endian_lane_map ( d -> vmode , high ) ) ; else if ( first_elem == neon_endian_lane_map ( d -> vmode , 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 = neon_pair_endian_lane_map ( d -> vmode , i + high ) & mask ; if ( d -> perm [ neon_pair_endian_lane_map ( d -> vmode , 2 * i + is_swapped ) ] != elt ) return false ; elt = neon_pair_endian_lane_map ( d -> vmode , i + nelt + high ) & mask ; if ( d -> perm [ neon_pair_endian_lane_map ( d -> vmode , 2 * i + ! is_swapped ) ] != elt ) return false ; } if ( d -> testing_p ) return true ; in0 = d -> op0 ; in1 = d -> op1 ; if ( is_swapped ) std :: swap ( in0 , in1 ) ; out0 = d -> target ; out1 = gen_reg_rtx ( d -> vmode ) ; if ( high ) std :: swap ( out0 , out1 ) ; emit_insn ( gen_neon_vzip_internal ( d -> vmode , out0 , in0 , in1 , out1 ) ) ; return true ; } </s>


<s> static enum flt_eval_method arm_excess_precision ( enum excess_precision_type type ) { switch ( type ) { case EXCESS_PRECISION_TYPE_FAST : case EXCESS_PRECISION_TYPE_STANDARD : return ( TARGET_VFP_FP16INST ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT ) ; case EXCESS_PRECISION_TYPE_IMPLICIT : case EXCESS_PRECISION_TYPE_FLOAT16 : return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 ; default : gcc_unreachable ( ) ; } return FLT_EVAL_METHOD_UNPREDICTABLE ; } </s>

Set the value of FLT_EVAL_METHOD . ISO/IEC TS 18661-3 defines two values that we 'd like to make use of : 0 : evaluate all operations and constants , whose semantic type has at most the range and precision of type float , to the range and precision of float ; evaluate all other operations and constants to the range and precision of the semantic type ; N , where _FloatN is a supported interchange floating type evaluate all operations and constants , whose semantic type has at most the range and precision of _FloatN type , to the range and precision of the _FloatN type ; evaluate all other operations and constants to the range and precision of the semantic type ; If we have the ARMv8.2-A extensions then we support _Float16 in native precision , so we should set this to 16 . Otherwise , we support the type , but want to evaluate expressions in float precision , so set this to 0 .


<s> static void arm_expand_builtin_va_start ( tree valist , rtx nextarg ) { valist = arm_extract_valist_ptr ( valist ) ; std_expand_builtin_va_start ( valist , nextarg ) ; } </s>


<s> void arm_expand_compare_and_swap ( rtx operands [ ] ) { rtx bval , bdst , rval , mem , oldval , newval , is_weak , mod_s , mod_f , x ; machine_mode mode , cmp_mode ; 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 ) ; if ( TARGET_HAVE_LDACQ && 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 : rval = gen_reg_rtx ( SImode ) ; oldval = convert_modes ( SImode , mode , oldval , true ) ; case E_SImode : if ( ! arm_add_operand ( oldval , SImode ) ) oldval = force_reg ( SImode , oldval ) ; break ; case E_DImode : if ( ! cmpdi_operand ( oldval , mode ) ) oldval = force_reg ( mode , oldval ) ; break ; default : gcc_unreachable ( ) ; } if ( TARGET_THUMB1 ) cmp_mode = E_SImode ; else cmp_mode = CC_Zmode ; bdst = TARGET_THUMB1 ? bval : gen_rtx_REG ( CC_Zmode , CC_REGNUM ) ; emit_insn ( gen_atomic_compare_and_swap_1 ( cmp_mode , mode , bdst , rval , mem , oldval , newval , is_weak , mod_s , mod_f ) ) ; if ( mode == QImode || mode == HImode ) emit_move_insn ( operands [ 1 ] , gen_lowpart ( mode , rval ) ) ; if ( TARGET_THUMB1 ) emit_insn ( gen_cstoresi_eq0_thumb1 ( bval , bdst ) ) ; else { x = gen_rtx_EQ ( SImode , bdst , const0_rtx ) ; emit_insn ( gen_rtx_SET ( bval , x ) ) ; } } </s>


<s> static void arm_expand_divmod_libfunc ( rtx libfunc , machine_mode mode , rtx op0 , rtx op1 , rtx * quot_p , rtx * rem_p ) { if ( mode == SImode ) gcc_assert ( ! TARGET_IDIV ) ; scalar_int_mode libval_mode = smallest_int_mode_for_size ( 2 * GET_MODE_BITSIZE ( mode ) ) ; rtx libval = emit_library_call_value ( libfunc , NULL_RTX , LCT_CONST , libval_mode , op0 , mode , op1 , mode ) ; rtx quotient = simplify_gen_subreg ( mode , libval , libval_mode , 0 ) ; rtx remainder = simplify_gen_subreg ( mode , libval , libval_mode , GET_MODE_SIZE ( mode ) ) ; gcc_assert ( quotient ) ; gcc_assert ( remainder ) ; * quot_p = quotient ; * rem_p = remainder ; } </s>

Generate call to __aeabi_ [ mode ] divmod ( op0 , op1 ) .


<s> void arm_expand_vcond ( rtx * operands , machine_mode cmp_result_mode ) { rtx mask ; if ( TARGET_HAVE_MVE ) mask = gen_reg_rtx ( arm_mode_to_pred_mode ( cmp_result_mode ) . require ( ) ) ; else mask = gen_reg_rtx ( cmp_result_mode ) ; bool inverted = arm_expand_vector_compare ( mask , GET_CODE ( operands [ 3 ] ) , operands [ 4 ] , operands [ 5 ] , true ) ; if ( inverted ) std :: swap ( operands [ 1 ] , operands [ 2 ] ) ; if ( TARGET_NEON ) emit_insn ( gen_neon_vbsl ( GET_MODE ( operands [ 0 ] ) , operands [ 0 ] , mask , operands [ 1 ] , operands [ 2 ] ) ) ; else { machine_mode cmp_mode = GET_MODE ( operands [ 0 ] ) ; switch ( GET_MODE_CLASS ( cmp_mode ) ) { case MODE_VECTOR_INT : emit_insn ( gen_mve_vpselq ( VPSELQ_S , cmp_mode , operands [ 0 ] , operands [ 1 ] , operands [ 2 ] , mask ) ) ; break ; case MODE_VECTOR_FLOAT : if ( TARGET_HAVE_MVE_FLOAT ) emit_insn ( gen_mve_vpselq_f ( cmp_mode , operands [ 0 ] , operands [ 1 ] , operands [ 2 ] , mask ) ) ; else gcc_unreachable ( ) ; break ; default : gcc_unreachable ( ) ; } } } </s>

Expand a vcond or vcondu pattern with operands OPERANDS . CMP_RESULT_MODE is the mode of the comparison result .