<s> static void arm_expand_vec_perm_1 ( rtx target , rtx op0 , rtx op1 , rtx sel ) { machine_mode vmode = GET_MODE ( target ) ; bool one_vector_p = rtx_equal_p ( op0 , op1 ) ; gcc_checking_assert ( vmode == V8QImode || vmode == V16QImode ) ; gcc_checking_assert ( GET_MODE ( op0 ) == vmode ) ; gcc_checking_assert ( GET_MODE ( op1 ) == vmode ) ; gcc_checking_assert ( GET_MODE ( sel ) == vmode ) ; gcc_checking_assert ( TARGET_NEON ) ; if ( one_vector_p ) { if ( vmode == V8QImode ) emit_insn ( gen_neon_vtbl1v8qi ( target , op0 , sel ) ) ; else emit_insn ( gen_neon_vtbl1v16qi ( target , op0 , sel ) ) ; } else { rtx pair ; if ( vmode == V8QImode ) { pair = gen_reg_rtx ( V16QImode ) ; emit_insn ( gen_neon_vcombinev8qi ( pair , op0 , op1 ) ) ; pair = gen_lowpart ( TImode , pair ) ; emit_insn ( gen_neon_vtbl2v8qi ( target , pair , sel ) ) ; } else { pair = gen_reg_rtx ( OImode ) ; emit_insn ( gen_neon_vcombinev16qi ( pair , op0 , op1 ) ) ; emit_insn ( gen_neon_vtbl2v16qi ( target , pair , sel ) ) ; } } } </s>


<s> static tree arm_extract_valist_ptr ( tree valist ) { if ( TREE_TYPE ( valist ) == error_mark_node ) return error_mark_node ; if ( TARGET_AAPCS_BASED ) { tree ap_field = TYPE_FIELDS ( TREE_TYPE ( valist ) ) ; valist = build3 ( COMPONENT_REF , TREE_TYPE ( ap_field ) , valist , ap_field , NULL_TREE ) ; } return valist ; } </s>

Return an expression of type `` void * '' pointing to the next available argument in a variable-argument list . VALIST is the user-level va_list object , of type __builtin_va_list .


<s> static bool arm_fdpic_local_funcdesc_p ( rtx fnx ) { tree fn ; enum symbol_visibility vis ; bool ret ; if ( ! TARGET_FDPIC ) return true ; if ( ! SYMBOL_REF_LOCAL_P ( fnx ) ) return false ; fn = SYMBOL_REF_DECL ( fnx ) ; if ( ! fn ) return false ; vis = DECL_VISIBILITY ( fn ) ; if ( vis == VISIBILITY_PROTECTED ) DECL_VISIBILITY ( fn ) = VISIBILITY_DEFAULT ; ret = default_binds_local_p_1 ( fn , flag_pic ) ; DECL_VISIBILITY ( fn ) = vis ; return ret ; } </s>

Test whether a local function descriptor is canonical , i.e. , whether we can use GOTOFFFUNCDESC to compute the address of the function .


<s> static int arm_first_cycle_multipass_dfa_lookahead ( void ) { int issue_rate = arm_issue_rate ( ) ; return issue_rate > 1 && ! sched_fusion ? issue_rate : 0 ; } </s>

Return how many instructions should scheduler lookahead to choose the best one .


<s> static bool arm_fixed_condition_code_regs ( unsigned int * p1 , unsigned int * p2 ) { if ( ! TARGET_32BIT ) return false ; * p1 = CC_REGNUM ; * p2 = TARGET_VFP_BASE ? VFPCC_REGNUM : INVALID_REGNUM ; return true ; } </s>

Implement TARGET_FIXED_CONDITION_CODE_REGS . We only have condition code registers when not targetting Thumb1 . The VFP condition register only exists when generating hard-float code .


<s> static opt_scalar_float_mode arm_floatn_mode ( int n , bool extended ) { if ( ! extended && n == 16 ) { if ( arm_fp16_format == ARM_FP16_FORMAT_IEEE ) return HFmode ; return opt_scalar_float_mode ( ) ; } return default_floatn_mode ( n , extended ) ; } </s>

Implement TARGET_FLOATN_MODE . Make very sure that we do n't provide _Float16 if we are using anything other than ieee format for 16-bit floating point . Otherwise , punt to the default implementation .


<s> bool arm_frame_pointer_required ( void ) { if ( SUBTARGET_FRAME_POINTER_REQUIRED ) return true ; if ( cfun -> has_nonlocal_label ) return true ; if ( TARGET_ARM && TARGET_APCS_FRAME && ! crtl -> is_leaf ) return true ; if ( ! IS_INTERRUPT ( arm_current_func_type ( ) ) && ( flag_stack_check == STATIC_BUILTIN_STACK_CHECK || flag_stack_clash_protection ) && arm_except_unwind_info ( & global_options ) == UI_TARGET && cfun -> can_throw_non_call_exceptions ) { HOST_WIDE_INT size = get_frame_size ( ) ; if ( size <= 0 ) return false ; if ( crtl -> is_leaf && ! cfun -> calls_alloca ) { size += 32 * UNITS_PER_WORD ; if ( size > PROBE_INTERVAL && size > get_stack_check_protect ( ) ) return true ; } else return true ; } return false ; } </s>


"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> static void arm_function_arg_advance ( cumulative_args_t pcum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * pcum = get_cumulative_args ( pcum_v ) ; if ( pcum -> pcs_variant <= ARM_PCS_AAPCS_LOCAL ) { aapcs_layout_arg ( pcum , arg . mode , arg . type , arg . named ) ; if ( pcum -> aapcs_cprc_slot >= 0 ) { aapcs_cp_arg_layout [ pcum -> aapcs_cprc_slot ] . advance ( pcum , arg . mode , arg . type ) ; pcum -> aapcs_cprc_slot = - 1 ; } pcum -> aapcs_arg_processed = false ; pcum -> aapcs_ncrn = pcum -> aapcs_next_ncrn ; pcum -> aapcs_reg = NULL_RTX ; pcum -> aapcs_partial = 0 ; } else { pcum -> nargs += 1 ; if ( arm_vector_mode_supported_p ( arg . mode ) && pcum -> named_count > pcum -> nargs && TARGET_IWMMXT_ABI ) pcum -> iwmmxt_nregs += 1 ; else pcum -> nregs += ARM_NUM_REGS2 ( arg . mode , arg . type ) ; } } </s>

Update the data in PCUM to advance over an argument of mode MODE and data type TYPE . ( TYPE is null for libcalls where that information may not be available . )


<s> static pad_direction arm_function_arg_padding ( machine_mode mode , const_tree type ) { if ( ! TARGET_AAPCS_BASED ) return default_function_arg_padding ( mode , type ) ; if ( type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P ( type ) ) return PAD_DOWNWARD ; return PAD_UPWARD ; } </s>

Implement TARGET_FUNCTION_ARG_PADDING ; return PAD_UPWARD if the lowest byte of a stack argument has useful data . For legacy APCS ABIs we use the default . For AAPCS based ABIs small aggregate types are placed in the lowest memory address .


<s> static bool arm_function_in_section_p ( tree decl , section * section ) { if ( ! decl_binds_to_current_def_p ( decl ) ) return false ; if ( ! DECL_SECTION_NAME ( decl ) ) { if ( flag_function_sections || DECL_COMDAT_GROUP ( decl ) ) return false ; } return function_section ( decl ) == section ; } </s>

Return true if DECL is known to be linked into section SECTION .


<s> static bool arm_function_ok_for_sibcall ( tree decl , tree exp ) { unsigned long func_type ; if ( cfun -> machine -> sibcall_blocked ) return false ; if ( TARGET_FDPIC ) { if ( decl == NULL ) return false ; } if ( TARGET_THUMB1 ) return false ; if ( TARGET_VXWORKS_RTP && flag_pic && decl && ! targetm . binds_local_p ( decl ) ) return false ; if ( TARGET_APCS_FRAME && TARGET_ARM && TARGET_HARD_FLOAT && decl && arm_is_long_call_p ( decl ) ) return false ; if ( TARGET_INTERWORK && decl && TREE_PUBLIC ( decl ) && ! TREE_ASM_WRITTEN ( decl ) ) return false ; func_type = arm_current_func_type ( ) ; if ( IS_INTERRUPT ( func_type ) ) return false ; if ( IS_CMSE_ENTRY ( arm_current_func_type ( ) ) ) return false ; if ( TREE_CODE ( exp ) == CALL_EXPR ) { tree fntype = TREE_TYPE ( TREE_TYPE ( CALL_EXPR_FN ( exp ) ) ) ; if ( lookup_attribute ( "cmse_nonsecure_call" , TYPE_ATTRIBUTES ( fntype ) ) ) return false ; } if ( ! VOID_TYPE_P ( TREE_TYPE ( DECL_RESULT ( cfun -> decl ) ) ) ) { rtx a , b ; tree decl_or_type = decl ; if ( ! decl ) decl_or_type = TREE_TYPE ( TREE_TYPE ( CALL_EXPR_FN ( exp ) ) ) ; a = arm_function_value ( TREE_TYPE ( exp ) , decl_or_type , false ) ; b = arm_function_value ( TREE_TYPE ( DECL_RESULT ( cfun -> decl ) ) , cfun -> decl , false ) ; if ( ! rtx_equal_p ( a , b ) ) return false ; } if ( IS_STACKALIGN ( func_type ) ) return false ; if ( TARGET_AAPCS_BASED && arm_abi == ARM_ABI_AAPCS && decl && DECL_WEAK ( decl ) ) return false ; if ( ! decl && CALL_EXPR_BY_DESCRIPTOR ( exp ) && ! flag_trampolines ) { tree fntype = TREE_TYPE ( TREE_TYPE ( CALL_EXPR_FN ( exp ) ) ) ; CUMULATIVE_ARGS cum ; cumulative_args_t cum_v ; arm_init_cumulative_args ( & cum , fntype , NULL_RTX , NULL_TREE ) ; cum_v = pack_cumulative_args ( & cum ) ; for ( tree t = TYPE_ARG_TYPES ( fntype ) ; t ; t = TREE_CHAIN ( t ) ) { tree type = TREE_VALUE ( t ) ; if ( ! VOID_TYPE_P ( type ) ) { function_arg_info arg ( type , true ) ; arm_function_arg_advance ( cum_v , arg ) ; } } function_arg_info arg ( integer_type_node , true ) ; if ( ! arm_function_arg ( cum_v , arg ) ) return false ; } return true ; } </s>

Return non-zero if it is ok to make a tail-call to DECL .


<s> static section * arm_function_section ( tree decl , enum node_frequency freq , bool startup , bool exit ) { const char * section_name ; section * sec ; if ( ! decl || TREE_CODE ( decl ) != FUNCTION_DECL ) return default_function_section ( decl , freq , startup , exit ) ; if ( ! target_pure_code ) return default_function_section ( decl , freq , startup , exit ) ; section_name = DECL_SECTION_NAME ( decl ) ; if ( ! section_name ) { section * default_sec = default_function_section ( decl , freq , startup , exit ) ; if ( default_sec ) default_sec -> common . flags |= SECTION_ARM_PURECODE ; return default_sec ; } sec = get_named_section ( decl , section_name , 0 ) ; if ( ! sec ) sec = get_named_section ( decl , NULL , 0 ) ; sec -> common . flags |= SECTION_ARM_PURECODE ; return sec ; } </s>

Implement the TARGET_ASM_FUNCTION_SECTION hook . If pure-code is passed as an option , make sure all functions are in sections that have the SHF_ARM_PURECODE attribute .


<s> static rtx arm_function_value ( const_tree type , const_tree func , bool outgoing ATTRIBUTE_UNUSED ) { machine_mode mode ; int unsignedp ATTRIBUTE_UNUSED ; rtx r ATTRIBUTE_UNUSED ; mode = TYPE_MODE ( type ) ; if ( TARGET_AAPCS_BASED ) return aapcs_allocate_return_reg ( mode , type , func ) ; if ( INTEGRAL_TYPE_P ( type ) ) mode = arm_promote_function_mode ( type , mode , & unsignedp , func , 1 ) ; if ( arm_return_in_msb ( type ) ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( size % UNITS_PER_WORD != 0 ) { size += UNITS_PER_WORD - size % UNITS_PER_WORD ; mode = int_mode_for_size ( size * BITS_PER_UNIT , 0 ) . require ( ) ; } } return arm_libcall_value_1 ( mode ) ; } </s>

Define how to find the value returned by a function .


<s> static bool arm_function_value_regno_p ( const unsigned int regno ) { if ( regno == ARG_REGISTER ( 1 ) || ( TARGET_32BIT && TARGET_AAPCS_BASED && TARGET_HARD_FLOAT && regno == FIRST_VFP_REGNUM ) || ( TARGET_IWMMXT_ABI && regno == FIRST_IWMMXT_REGNUM ) ) return true ; return false ; } </s>


<s> bool arm_fusion_enabled_p ( tune_params :: fuse_ops op ) { return current_tune -> fusible_ops & op ; } </s>

Return true iff the instruction fusion described by OP is enabled .


<s> rtx arm_gen_compare_reg ( rtx_code code , rtx x , rtx y , rtx scratch ) { if ( GET_MODE ( x ) == DImode || GET_MODE ( y ) == DImode ) return arm_gen_dicompare_reg ( code , x , y , scratch ) ; machine_mode mode = SELECT_CC_MODE ( code , x , y ) ; rtx cc_reg = gen_rtx_REG ( mode , CC_REGNUM ) ; if ( mode == CC_RSBmode ) { if ( ! scratch ) scratch = gen_rtx_SCRATCH ( SImode ) ; emit_insn ( gen_rsb_imm_compare_scratch ( scratch , GEN_INT ( ~ UINTVAL ( x ) ) , y ) ) ; } else emit_set_insn ( cc_reg , gen_rtx_COMPARE ( mode , x , y ) ) ; return cc_reg ; } </s>

X and Y are two things to compare using CODE . Emit the compare insn and return the rtx for register 0 in the proper mode . FP means this is a floating point compare : I do n't think that it is needed on the arm .


<s> const char * arm_gen_far_branch ( rtx * operands , int pos_label , const char * dest , const char * branch_format ) { rtx_code_label * tmp_label = gen_label_rtx ( ) ; char label_buf [ 256 ] ; char buffer [ 128 ] ; ASM_GENERATE_INTERNAL_LABEL ( label_buf , dest , \ CODE_LABEL_NUMBER ( tmp_label ) ) ; const char * label_ptr = arm_strip_name_encoding ( label_buf ) ; rtx dest_label = operands [ pos_label ] ; operands [ pos_label ] = tmp_label ; snprintf ( buffer , sizeof ( buffer ) , "%s%s" , branch_format , label_ptr ) ; output_asm_insn ( buffer , operands ) ; snprintf ( buffer , sizeof ( buffer ) , "b\t%%l0%d\n%s:" , pos_label , label_ptr ) ; operands [ pos_label ] = dest_label ; output_asm_insn ( buffer , operands ) ; return "" ; } </s>

Generate code to enable conditional branches in functions over 1 MiB . Parameters are : operands : is the operands list of the asm insn ( see arm_cond_branch or arm_cond_branch_reversed ) . pos_label : is an index into the operands array where operands [ pos_label ] is the asm label of the final jump destination . dest : is a string which is used to generate the asm label of the intermediate destination branch_format : is a string denoting the intermediate branch format , e.g . `` beq '' , `` bne '' , etc .


<s> rtx arm_gen_load_multiple ( int * regs , int count , rtx basereg , int write_back , rtx basemem , HOST_WIDE_INT * offsetp ) { return arm_gen_multiple_op ( TRUE , regs , count , basereg , write_back , basemem , offsetp ) ; } </s>


<s> static rtx arm_gen_load_multiple_1 ( int count , int * regs , rtx * mems , rtx basereg , HOST_WIDE_INT wback_offset ) { int i = 0 , j ; rtx result ; if ( ! multiple_operation_profitable_p ( false , count , 0 ) ) { rtx seq ; start_sequence ( ) ; for ( i = 0 ; i < count ; i ++ ) emit_move_insn ( gen_rtx_REG ( SImode , regs [ i ] ) , mems [ i ] ) ; if ( wback_offset != 0 ) emit_move_insn ( basereg , plus_constant ( Pmode , basereg , wback_offset ) ) ; seq = get_insns ( ) ; end_sequence ( ) ; return seq ; } result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count + ( wback_offset != 0 ? 1 : 0 ) ) ) ; if ( wback_offset != 0 ) { XVECEXP ( result , 0 , 0 ) = gen_rtx_SET ( basereg , plus_constant ( Pmode , basereg , wback_offset ) ) ; i = 1 ; count ++ ; } for ( j = 0 ; i < count ; i ++ , j ++ ) XVECEXP ( result , 0 , i ) = gen_rtx_SET ( gen_rtx_REG ( SImode , regs [ j ] ) , mems [ j ] ) ; return result ; } </s>

Generate a load-multiple instruction . COUNT is the number of loads in the instruction ; REGS and MEMS are arrays containing the operands . BASEREG is the base register to be used in addressing the memory operands . WBACK_OFFSET is nonzero if the instruction should update the base register .


<s> static rtx arm_gen_multiple_op ( bool is_load , int * regs , int count , rtx basereg , bool write_back , rtx basemem , HOST_WIDE_INT * offsetp ) { rtx mems [ MAX_LDM_STM_OPS ] ; HOST_WIDE_INT offset = * offsetp ; int i ; gcc_assert ( count <= MAX_LDM_STM_OPS ) ; if ( GET_CODE ( basereg ) == PLUS ) basereg = XEXP ( basereg , 0 ) ; for ( i = 0 ; i < count ; i ++ ) { rtx addr = plus_constant ( Pmode , basereg , i * 4 ) ; mems [ i ] = adjust_automodify_address_nv ( basemem , SImode , addr , offset ) ; offset += 4 ; } if ( write_back ) * offsetp = offset ; if ( is_load ) return arm_gen_load_multiple_1 ( count , regs , mems , basereg , write_back ? 4 * count : 0 ) ; else return arm_gen_store_multiple_1 ( count , regs , mems , basereg , write_back ? 4 * count : 0 ) ; } </s>

Generate either a load-multiple or a store-multiple instruction . This function can be used in situations where we can start with a single MEM rtx and adjust its address upwards . COUNT is the number of operations in the instruction , not counting a possible update of the base register . REGS is an array containing the register operands . BASEREG is the base register to be used in addressing the memory operands , which are constructed from BASEMEM . WRITE_BACK specifies whether the generated instruction should include an update of the base register . OFFSETP is used to pass an offset to and from this function ; this offset is not used when constructing the address ( instead BASEMEM should have an appropriate offset in its address ) , it is used only for setting MEM_OFFSET . It is updated only if WRITE_BACK is true .


<s> rtx arm_gen_return_addr_mask ( void ) { rtx reg = gen_reg_rtx ( Pmode ) ; emit_insn ( gen_return_addr_mask ( reg ) ) ; return reg ; } </s>

Generate a sequence of insns that will generate the correct return address mask depending on the physical architecture that the program is running on .


<s> bool arm_gen_setmem ( rtx * operands ) { rtx dstbase = operands [ 0 ] ; unsigned HOST_WIDE_INT length ; unsigned HOST_WIDE_INT value ; unsigned HOST_WIDE_INT align ; if ( ! CONST_INT_P ( operands [ 2 ] ) || ! CONST_INT_P ( operands [ 1 ] ) ) return false ; length = UINTVAL ( operands [ 1 ] ) ; if ( length > 64 ) return false ; value = ( UINTVAL ( operands [ 2 ] ) & 0xFF ) ; align = UINTVAL ( operands [ 3 ] ) ; if ( TARGET_NEON && length >= 8 && current_tune -> string_ops_prefer_neon && arm_block_set_vect ( dstbase , length , value , align ) ) return true ; if ( ! unaligned_access && ( align & 3 ) != 0 ) return arm_block_set_unaligned_non_vect ( dstbase , length , value , align ) ; return arm_block_set_aligned_non_vect ( dstbase , length , value , align ) ; } </s>

Expand string store operation . Firstly we try to do that by using vectorization instructions , then try with ARM unaligned access and double-word store if profitable . OPERANDS [ 0 ] is the destination , OPERANDS [ 1 ] is the number of bytes , operands [ 2 ] is the value to initialize the memory , OPERANDS [ 3 ] is the known alignment of the destination .


<s> static rtx arm_gen_store_multiple_1 ( int count , int * regs , rtx * mems , rtx basereg , HOST_WIDE_INT wback_offset ) { int i = 0 , j ; rtx result ; if ( GET_CODE ( basereg ) == PLUS ) basereg = XEXP ( basereg , 0 ) ; if ( ! multiple_operation_profitable_p ( false , count , 0 ) ) { rtx seq ; start_sequence ( ) ; for ( i = 0 ; i < count ; i ++ ) emit_move_insn ( mems [ i ] , gen_rtx_REG ( SImode , regs [ i ] ) ) ; if ( wback_offset != 0 ) emit_move_insn ( basereg , plus_constant ( Pmode , basereg , wback_offset ) ) ; seq = get_insns ( ) ; end_sequence ( ) ; return seq ; } result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count + ( wback_offset != 0 ? 1 : 0 ) ) ) ; if ( wback_offset != 0 ) { XVECEXP ( result , 0 , 0 ) = gen_rtx_SET ( basereg , plus_constant ( Pmode , basereg , wback_offset ) ) ; i = 1 ; count ++ ; } for ( j = 0 ; i < count ; i ++ , j ++ ) XVECEXP ( result , 0 , i ) = gen_rtx_SET ( mems [ j ] , gen_rtx_REG ( SImode , regs [ j ] ) ) ; return result ; } </s>

Generate a store-multiple instruction . COUNT is the number of stores in the instruction ; REGS and MEMS are arrays containing the operands . BASEREG is the base register to be used in addressing the memory operands . WBACK_OFFSET is nonzero if the instruction should update the base register .


<s> void arm_gen_unlikely_cbranch ( enum rtx_code code , machine_mode cc_mode , rtx label_ref ) { rtx x ; x = gen_rtx_fmt_ee ( code , VOIDmode , gen_rtx_REG ( cc_mode , CC_REGNUM ) , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( VOIDmode , label_ref ) , pc_rtx ) ; emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; } </s>

Generate RTL for a conditional branch with rtx comparison CODE in mode CC_MODE . The destination of the unlikely conditional branch is LABEL_REF .


<s> static tree arm_get_cookie_size ( tree type ) { tree size ; if ( ! TARGET_AAPCS_BASED ) return default_cxx_get_cookie_size ( type ) ; size = build_int_cst ( sizetype , 8 ) ; return size ; } </s>

The EABI specifies that all array cookies are 8 bytes long .


<s> static arm_stack_offsets * arm_get_frame_offsets ( void ) { struct arm_stack_offsets * offsets ; offsets = & cfun -> machine -> stack_offsets ; return offsets ; } </s>

Calculate stack offsets . These are used to calculate register elimination offsets and in prologue/epilogue code . Also calculates which registers should be saved .


<s> opt_machine_mode arm_get_mask_mode ( machine_mode mode ) { if ( TARGET_HAVE_MVE ) return arm_mode_to_pred_mode ( mode ) ; return default_get_mask_mode ( mode ) ; } </s>


"variadic functions must use the base AAPCS variant"

Get the PCS variant to use for this call . TYPE is the function 's type specification , DECL is the specific declartion . DECL may be null if the call could be indirect or if this is a library call .


<s> static int arm_get_strip_length ( int c ) { switch ( c ) { ARM_NAME_ENCODING_LENGTHS default : return 0 ; } } </s>

Return the length of a function name prefix that starts with the character ' c ' .


<s> static int arm_get_vfp_saved_size ( void ) { unsigned int regno ; int count ; int saved ; saved = 0 ; if ( TARGET_VFP_BASE ) { count = 0 ; for ( regno = FIRST_VFP_REGNUM ; regno < LAST_VFP_REGNUM ; regno += 2 ) { if ( ! reg_needs_saving_p ( regno ) && ! reg_needs_saving_p ( regno + 1 ) ) { if ( count > 0 ) { if ( count == 2 && ! arm_arch6 ) count ++ ; saved += count * 8 ; } count = 0 ; } else count ++ ; } if ( count > 0 ) { if ( count == 2 && ! arm_arch6 ) count ++ ; saved += count * 8 ; } } return saved ; } </s>

Return the number of bytes required to save VFP registers .


<s> static tree arm_gimplify_va_arg_expr ( tree valist , tree type , gimple_seq * pre_p , gimple_seq * post_p ) { valist = arm_extract_valist_ptr ( valist ) ; return std_gimplify_va_arg_expr ( valist , type , pre_p , post_p ) ; } </s>


"%qE attribute ignored without %<-mcmse%> "

"%qE attribute only applies to base type of a "

Called upon detection of the use of the cmse_nonsecure_call attribute , this function will check whether the attribute is allowed here and will add the attribute to the function type tree or otherwise issue a diagnostic . The reason we check this at declaration time is to only allow the use of the attribute with declarations of function pointers and not function declarations . This function checks NODE is of the expected type and issues diagnostics otherwise using NAME . If it is not of the expected type * NO_ADD_ATTRS will be set to true .


"%qE attribute only applies to functions"

"%qE attribute has no effect on functions "

Called upon detection of the use of the cmse_nonsecure_entry attribute , this function will check whether the attribute is allowed here and will add the attribute to the function declaration tree or otherwise issue a warning .


Handle an attribute requiring a FUNCTION_DECL ; arguments as in struct attribute_spec.handler .


"FP registers might be clobbered despite %qE attribute: compile with %<-mgeneral-regs-only%>"

Handle an `` interrupt '' or `` isr '' attribute ; arguments as in struct attribute_spec.handler .


<s> static tree arm_handle_notshared_attribute ( tree * node , tree name ATTRIBUTE_UNUSED , tree args ATTRIBUTE_UNUSED , int flags ATTRIBUTE_UNUSED , bool * no_add_attrs ) { tree decl = TYPE_NAME ( * node ) ; if ( decl ) { DECL_VISIBILITY ( decl ) = VISIBILITY_HIDDEN ; DECL_VISIBILITY_SPECIFIED ( decl ) = 1 ; * no_add_attrs = false ; } return NULL_TREE ; } </s>

Handle the `` notshared '' attribute . This attribute is another way of requesting hidden visibility . ARM 's compiler supports `` __declspec ( notshared ) '' ; we support the same thing via an attribute .


<s> static bool arm_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( GET_MODE_CLASS ( mode ) == MODE_CC ) return ( regno == CC_REGNUM || ( TARGET_VFP_BASE && regno == VFPCC_REGNUM ) ) ; if ( regno == CC_REGNUM && GET_MODE_CLASS ( mode ) != MODE_CC ) return false ; if ( IS_VPR_REGNUM ( regno ) ) return mode == HImode || mode == V16BImode || mode == V8BImode || mode == V4BImode ; if ( TARGET_THUMB1 ) return ( ARM_NUM_REGS ( mode ) < 2 ) || ( regno < LAST_LO_REGNUM ) ; if ( TARGET_VFP_BASE && IS_VFP_REGNUM ( regno ) ) { if ( mode == DFmode || mode == DImode ) return VFP_REGNO_OK_FOR_DOUBLE ( regno ) ; if ( mode == HFmode || mode == BFmode || mode == HImode || mode == SFmode || mode == SImode ) return VFP_REGNO_OK_FOR_SINGLE ( regno ) ; if ( TARGET_NEON ) return ( VALID_NEON_DREG_MODE ( mode ) && VFP_REGNO_OK_FOR_DOUBLE ( regno ) ) || ( VALID_NEON_QREG_MODE ( mode ) && NEON_REGNO_OK_FOR_QUAD ( regno ) ) || ( mode == TImode && NEON_REGNO_OK_FOR_NREGS ( regno , 2 ) ) || ( mode == EImode && NEON_REGNO_OK_FOR_NREGS ( regno , 3 ) ) || ( mode == OImode && NEON_REGNO_OK_FOR_NREGS ( regno , 4 ) ) || ( mode == CImode && NEON_REGNO_OK_FOR_NREGS ( regno , 6 ) ) || ( mode == XImode && NEON_REGNO_OK_FOR_NREGS ( regno , 8 ) ) ; if ( TARGET_HAVE_MVE ) return ( ( VALID_MVE_MODE ( mode ) && NEON_REGNO_OK_FOR_QUAD ( regno ) ) || ( mode == OImode && NEON_REGNO_OK_FOR_NREGS ( regno , 4 ) ) || ( mode == XImode && NEON_REGNO_OK_FOR_NREGS ( regno , 8 ) ) ) ; return false ; } if ( TARGET_REALLY_IWMMXT ) { if ( IS_IWMMXT_GR_REGNUM ( regno ) ) return mode == SImode ; if ( IS_IWMMXT_REGNUM ( regno ) ) return VALID_IWMMXT_REG_MODE ( mode ) ; } if ( regno <= LAST_ARM_REGNUM ) { if ( ARM_NUM_REGS ( mode ) > 4 ) return false ; if ( TARGET_THUMB2 && ! ( TARGET_HAVE_MVE || TARGET_CDE ) ) return true ; return ! ( ( TARGET_LDRD || TARGET_CDE ) && GET_MODE_SIZE ( mode ) > 4 && ( regno & 1 ) != 0 ) ; } if ( regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM ) return GET_MODE_CLASS ( mode ) == MODE_INT ; return false ; } </s>

Returns true if REGNO is a valid register for holding a quantity of type MODE .


<s> static unsigned int arm_hard_regno_nregs ( unsigned int regno , machine_mode mode ) { if ( IS_VPR_REGNUM ( regno ) ) return CEIL ( GET_MODE_SIZE ( mode ) , 2 ) ; if ( TARGET_32BIT && regno > PC_REGNUM && regno != FRAME_POINTER_REGNUM && regno != ARG_POINTER_REGNUM && ! IS_VFP_REGNUM ( regno ) ) return 1 ; return ARM_NUM_REGS ( mode ) ; } </s>

Implement TARGET_HARD_REGNO_NREGS . On the ARM core regs are UNITS_PER_WORD bytes wide .


<s> static bool arm_have_conditional_execution ( void ) { bool has_cond_exec , enable_ifcvt_trans ; has_cond_exec = ! TARGET_THUMB1 ; enable_ifcvt_trans = TARGET_COND_ARITH && ! reload_completed ; return has_cond_exec && ! enable_ifcvt_trans ; } </s>

Implement the TARGET_HAVE_CONDITIONAL_EXECUTION hook . All modes except THUMB1 have conditional execution . If we have conditional arithmetic , return false before reload to enable some ifcvt transformations .


<s> static const char * arm_identify_fpu_from_isa ( sbitmap isa ) { auto_sbitmap fpubits ( isa_num_bits ) ; auto_sbitmap cand_fpubits ( isa_num_bits ) ; bitmap_and ( fpubits , isa , isa_all_fpubits_internal ) ; if ( bitmap_empty_p ( fpubits ) ) return "softvfp" ; for ( unsigned int i = 0 ; i < TARGET_FPU_auto ; i ++ ) { arm_initialize_isa ( cand_fpubits , all_fpus [ i ] . isa_bits ) ; if ( bitmap_equal_p ( fpubits , cand_fpubits ) ) return all_fpus [ i ] . name ; } gcc_unreachable ( ) ; } </s>

Match an ISA feature bitmap to a named FPU . We always use the first entry that exactly matches the feature set , so that we effectively canonicalize the FPU name for the assembler .


<s> void arm_init_cumulative_args ( CUMULATIVE_ARGS * pcum , tree fntype , rtx libname , tree fndecl ATTRIBUTE_UNUSED ) { if ( fntype ) pcum -> pcs_variant = arm_get_pcs_model ( fntype , fndecl ) ; else pcum -> pcs_variant = arm_pcs_default ; if ( pcum -> pcs_variant <= ARM_PCS_AAPCS_LOCAL ) { if ( arm_libcall_uses_aapcs_base ( libname ) ) pcum -> pcs_variant = ARM_PCS_AAPCS ; pcum -> aapcs_ncrn = pcum -> aapcs_next_ncrn = 0 ; pcum -> aapcs_reg = NULL_RTX ; pcum -> aapcs_partial = 0 ; pcum -> aapcs_arg_processed = false ; pcum -> aapcs_cprc_slot = - 1 ; pcum -> can_split = true ; if ( pcum -> pcs_variant != ARM_PCS_AAPCS ) { int i ; for ( i = 0 ; i < ARM_NUM_COPROC_SLOTS ; i ++ ) { pcum -> aapcs_cprc_failed [ i ] = false ; aapcs_cp_arg_layout [ i ] . cum_init ( pcum , fntype , libname , fndecl ) ; } } return ; } pcum -> nregs = 0 ; pcum -> iwmmxt_nregs = 0 ; pcum -> can_split = true ; pcum -> named_count = 0 ; pcum -> nargs = 0 ; if ( TARGET_REALLY_IWMMXT && fntype ) { tree fn_arg ; for ( fn_arg = TYPE_ARG_TYPES ( fntype ) ; fn_arg ; fn_arg = TREE_CHAIN ( fn_arg ) ) pcum -> named_count += 1 ; if ( ! pcum -> named_count ) pcum -> named_count = INT_MAX ; } } </s>

Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE . For a library call , FNTYPE is NULL .


<s> void arm_init_expanders ( void ) { init_machine_status = arm_init_machine_status ; if ( cfun ) mark_reg_pointer ( arg_pointer_rtx , PARM_BOUNDARY ) ; } </s>

Do anything needed before RTL is emitted for each function .


<s> static struct machine_function * arm_init_machine_status ( void ) { struct machine_function * machine ; machine = ggc_cleared_alloc < machine_function > ( ) ; machine -> func_type = ARM_FT_UNKNOWN ; machine -> static_chain_stack_bytes = - 1 ; return machine ; } </s>

Functions to save and restore machine-specific function data .


<s> static void arm_insert_attributes ( tree fndecl , tree * attributes ) { const char * mode ; if ( ! TARGET_FLIP_THUMB ) return ; if ( TREE_CODE ( fndecl ) != FUNCTION_DECL || DECL_EXTERNAL ( fndecl ) || fndecl_built_in_p ( fndecl ) || DECL_ARTIFICIAL ( fndecl ) ) return ; if ( current_function_decl ) { mode = TARGET_THUMB ? "thumb" : "arm" ; add_attribute ( mode , attributes ) ; return ; } if ( lookup_attribute ( "target" , * attributes ) != NULL ) return ; mode = thumb_flipper ? "thumb" : "arm" ; add_attribute ( mode , attributes ) ; thumb_flipper = ! thumb_flipper ; } </s>

For testing . Insert thumb or arm modes alternatively on functions .

arm "thumb" "arm" "target" "thumb" "arm"


"operation not permitted on type %<bfloat16_t%>"

Return the diagnostic message string if the binary operation OP is not permitted on TYPE1 and TYPE2 , NULL otherwise .


"invalid conversion from type %<bfloat16_t%>"

"invalid conversion to type %<bfloat16_t%>"

Return the diagnostic message string if conversion from FROMTYPE to TOTYPE is not allowed , NULL otherwise .


Return the diagnostic message string if the unary operation OP is not permitted on TYPE , NULL otherwise .


<s>
static
const
char
*
arm_invalid_within_doloop
(
const
rtx_insn
*
insn
)
{
if
(
!
TARGET_HAVE_LOB
)
return
default_invalid_within_doloop
(
insn
)
;
if
(
CALL_P
(
insn
)
)
return
"Function call in the loop."
;
if
(
reg_mentioned_p
(
gen_rtx_REG
(
SImode
,
LR_REGNUM
)
,
insn
)
)
return
"LR is used inside loop."
;
return
;
}
</s>

NULL if insn INSN is valid within a low-overhead loop . Otherwise return why doloop can not be applied .

arm
"Function call in the loop."
"LR is used inside loop."


<s> static unsigned long arm_isr_value ( tree argument ) { const isr_attribute_arg * ptr ; const char * arg ; if ( ! arm_arch_notm ) return ARM_FT_NORMAL | ARM_FT_STACKALIGN ; if ( argument == NULL_TREE ) return ARM_FT_ISR ; if ( TREE_VALUE ( argument ) == NULL_TREE || TREE_CODE ( TREE_VALUE ( argument ) ) != STRING_CST ) return ARM_FT_UNKNOWN ; arg = TREE_STRING_POINTER ( TREE_VALUE ( argument ) ) ; for ( ptr = isr_attribute_args ; ptr -> arg != NULL ; ptr ++ ) if ( streq ( arg , ptr -> arg ) ) return ptr -> return_value ; return ARM_FT_UNKNOWN ; } </s>

Returns the ( interrupt ) function type of the current function , or ARM_FT_UNKNOWN if the type can not be determined .


<s> static int arm_issue_rate ( void ) { return current_tune -> issue_rate ; } </s>

Most ARM cores are single issue , but some newer ones can dual issue . The scheduler descriptions rely on this being correct .


<s> extern bool arm_is_constant_pool_ref ( rtx x ) { return ( MEM_P ( x ) && GET_CODE ( XEXP ( x , 0 ) ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( XEXP ( x , 0 ) ) ) ; } </s>

return TRUE if x is a reference to a value in a constant pool


<s> bool arm_is_long_call_p ( tree decl ) { tree attrs ; if ( ! decl ) return TARGET_LONG_CALLS ; attrs = TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ; if ( lookup_attribute ( "short_call" , attrs ) ) return false ; if ( ! flag_reorder_blocks_and_partition && TREE_CODE ( decl ) == FUNCTION_DECL && arm_function_in_section_p ( decl , current_function_section ( ) ) ) return false ; if ( lookup_attribute ( "long_call" , attrs ) ) return true ; return TARGET_LONG_CALLS ; } </s>

Return nonzero if a 32-bit `` long_call '' should be generated for a call from the current function to DECL . We generate a long_call if the function : a. has an __attribute__ ( ( long call ) ) or b. is within the scope of a # pragma long_calls or c. the -mlong-calls command line switch has been specified However we do not generate a long call if the function : d. has an __attribute__ ( ( short_call ) ) or e. is inside the scope of a # pragma no_long_calls or f. is defined in the same section as the current function .


<s> static bool arm_is_segment_info_known ( rtx orig , bool * is_readonly ) { * is_readonly = false ; if ( LABEL_REF_P ( orig ) ) { * is_readonly = true ; return true ; } if ( SYMBOL_REF_P ( orig ) ) { if ( CONSTANT_POOL_ADDRESS_P ( orig ) ) { * is_readonly = true ; return true ; } if ( SYMBOL_REF_LOCAL_P ( orig ) && ! SYMBOL_REF_EXTERNAL_P ( orig ) && SYMBOL_REF_DECL ( orig ) && ( ! DECL_P ( SYMBOL_REF_DECL ( orig ) ) || ! DECL_COMMON ( SYMBOL_REF_DECL ( orig ) ) ) ) { tree decl = SYMBOL_REF_DECL ( orig ) ; tree init = ( TREE_CODE ( decl ) == VAR_DECL ) ? DECL_INITIAL ( decl ) : ( TREE_CODE ( decl ) == CONSTRUCTOR ) ? decl : 0 ; int reloc = 0 ; bool named_section , readonly ; if ( init && init != error_mark_node ) reloc = compute_reloc_for_constant ( init ) ; named_section = TREE_CODE ( decl ) == VAR_DECL && lookup_attribute ( "section" , DECL_ATTRIBUTES ( decl ) ) ; readonly = decl_readonly_section ( decl , reloc ) ; if ( named_section ) return false ; * is_readonly = readonly ; return true ; } return false ; } gcc_unreachable ( ) ; } </s>

Try to determine whether an object , referenced via ORIG , will be placed in the text or data segment . This is used in FDPIC mode , to decide which relocations to use when accessing ORIG . * IS_READONLY is set to true if ORIG is a read-only location , false otherwise . Return true if we could determine the location of ORIG , false otherwise . * IS_READONLY is valid only when we return true .


<s> int arm_legitimate_address_outer_p ( machine_mode mode , rtx x , RTX_CODE outer , int strict_p ) { bool use_ldrd ; enum rtx_code code = GET_CODE ( x ) ; if ( arm_address_register_rtx_p ( x , strict_p ) ) return 1 ; use_ldrd = ( TARGET_LDRD && ( mode == DImode || mode == DFmode ) ) ; if ( code == POST_INC || code == PRE_DEC || ( ( code == PRE_INC || code == POST_DEC ) && ( use_ldrd || GET_MODE_SIZE ( mode ) <= 4 ) ) ) return arm_address_register_rtx_p ( XEXP ( x , 0 ) , strict_p ) ; else if ( ( code == POST_MODIFY || code == PRE_MODIFY ) && arm_address_register_rtx_p ( XEXP ( x , 0 ) , strict_p ) && GET_CODE ( XEXP ( x , 1 ) ) == PLUS && rtx_equal_p ( XEXP ( XEXP ( x , 1 ) , 0 ) , XEXP ( x , 0 ) ) ) { rtx addend = XEXP ( XEXP ( x , 1 ) , 1 ) ; if ( use_ldrd && GET_CODE ( x ) == POST_MODIFY && REG_P ( addend ) ) return 0 ; return ( ( use_ldrd || GET_MODE_SIZE ( mode ) <= 4 ) && arm_legitimate_index_p ( mode , addend , outer , strict_p ) ) ; } else if ( reload_completed && ( code == LABEL_REF || ( code == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == LABEL_REF && CONST_INT_P ( XEXP ( XEXP ( x , 0 ) , 1 ) ) ) ) ) return 1 ; else if ( mode == TImode || ( TARGET_NEON && VALID_NEON_STRUCT_MODE ( mode ) ) ) return 0 ; else if ( code == PLUS ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; return ( ( arm_address_register_rtx_p ( xop0 , strict_p ) && ( ( CONST_INT_P ( xop1 ) && arm_legitimate_index_p ( mode , xop1 , outer , strict_p ) ) || ( ! strict_p && will_be_in_index_register ( xop1 ) ) ) ) || ( arm_address_register_rtx_p ( xop1 , strict_p ) && arm_legitimate_index_p ( mode , xop0 , outer , strict_p ) ) ) ; } else if ( GET_CODE ( x ) == MINUS ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; return ( arm_address_register_rtx_p ( xop0 , strict_p ) && arm_legitimate_index_p ( mode , xop1 , outer , strict_p ) ) ; } else if ( GET_MODE_CLASS ( mode ) != MODE_FLOAT && code == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( x ) && ! ( flag_pic && symbol_mentioned_p ( get_pool_constant ( x ) ) && ! pcrel_constant_p ( get_pool_constant ( x ) ) ) ) return 1 ; return 0 ; } </s>

Return nonzero if X is a valid ARM state address operand .


<s> bool arm_legitimate_address_p ( machine_mode mode , rtx x , bool strict_p ) { if ( TARGET_ARM ) return arm_legitimate_address_outer_p ( mode , x , SET , strict_p ) ; else if ( TARGET_THUMB2 ) return thumb2_legitimate_address_p ( mode , x , strict_p ) ; else return thumb1_legitimate_address_p ( mode , x , strict_p ) ; } </s>


<s> static bool arm_legitimate_constant_p_1 ( machine_mode , rtx x ) { if ( GET_CODE ( x ) == CONST_VECTOR && ! neon_make_constant ( x , false ) ) return false ; return flag_pic || ! label_mentioned_p ( x ) ; } </s>

Implement TARGET_LEGITIMATE_CONSTANT_P . On the ARM , allow any integer ( invalid ones are removed later by insn patterns ) , nice doubles and symbol_refs which refer to the function 's constant pool XXX . When generating pic allow anything .


<s> static rtx arm_libcall_value ( machine_mode mode , const_rtx libcall ) { if ( TARGET_AAPCS_BASED && arm_pcs_default != ARM_PCS_AAPCS && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) { if ( arm_libcall_uses_aapcs_base ( libcall ) ) return gen_rtx_REG ( mode , ARG_REGISTER ( 1 ) ) ; } return arm_libcall_value_1 ( mode ) ; } </s>

Define how to find the value returned by a library function assuming the value has mode MODE .


<s> rtx arm_load_function_descriptor ( rtx funcdesc ) { rtx fnaddr_reg = gen_reg_rtx ( Pmode ) ; rtx pic_reg = gen_rtx_REG ( Pmode , FDPIC_REGNUM ) ; rtx fnaddr = gen_rtx_MEM ( Pmode , funcdesc ) ; rtx gotaddr = gen_rtx_MEM ( Pmode , plus_constant ( Pmode , funcdesc , 4 ) ) ; emit_move_insn ( fnaddr_reg , fnaddr ) ; emit_insn ( gen_restore_pic_register_after_call ( pic_reg , gotaddr ) ) ; return fnaddr_reg ; } </s>

Emit insns to load the function address from FUNCDESC ( an FDPIC function descriptor ) into a register and the GOT address into the FDPIC register , returning an rtx for the register holding the function address .


<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 || TARGET_FDPIC ) 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 .


<s> int arm_max_const_double_inline_cost ( ) { return ( ( optimize_size || arm_ld_sched ) ? 3 : 4 ) ; } </s>

Return maximum allowed cost of synthesizing a 64-bit constant VAL inline . Returns the number of insns needed , or 99 if we always want to synthesize the value .


<s> int arm_memory_move_cost ( machine_mode mode , reg_class_t rclass , bool in ATTRIBUTE_UNUSED ) { if ( TARGET_32BIT ) return 10 ; else { if ( GET_MODE_SIZE ( mode ) < 4 ) return 8 ; else return ( ( 2 * GET_MODE_SIZE ( mode ) ) * ( rclass == LO_REGS ? 1 : 2 ) ) ; } } </s>


<s> static bool arm_mem_costs ( rtx x , const struct cpu_cost_table * extra_cost , int * cost , bool speed_p ) { machine_mode mode = GET_MODE ( x ) ; * cost = COSTS_N_INSNS ( 1 ) ; if ( flag_pic && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && will_be_in_index_register ( XEXP ( XEXP ( x , 0 ) , 1 ) ) ) * cost += COSTS_N_INSNS ( 1 ) ; if ( speed_p ) { arm_addr_mode_op op_type ; switch ( GET_CODE ( XEXP ( x , 0 ) ) ) { default : case REG : op_type = AMO_DEFAULT ; break ; case MINUS : case PLUS : op_type = AMO_NO_WB ; break ; case PRE_INC : case PRE_DEC : case POST_INC : case POST_DEC : case PRE_MODIFY : case POST_MODIFY : op_type = AMO_WB ; break ; } if ( VECTOR_MODE_P ( mode ) ) * cost += current_tune -> addr_mode_costs -> vector [ op_type ] ; else if ( FLOAT_MODE_P ( mode ) ) * cost += current_tune -> addr_mode_costs -> fp [ op_type ] ; else * cost += current_tune -> addr_mode_costs -> integer [ op_type ] ; } if ( speed_p ) { if ( FLOAT_MODE_P ( mode ) ) { if ( GET_MODE_SIZE ( mode ) == 8 ) * cost += extra_cost -> ldst . loadd ; else * cost += extra_cost -> ldst . loadf ; } else if ( VECTOR_MODE_P ( mode ) ) * cost += extra_cost -> ldst . loadv ; else { if ( GET_MODE_SIZE ( mode ) == 8 ) * cost += extra_cost -> ldst . ldrd ; else * cost += extra_cost -> ldst . load ; } } return true ; } </s>

Helper function for arm_rtx_costs_internal . Calculates the cost of a MEM , considering the costs of the addressing mode and memory access separately .


<s> static bool arm_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { if ( GET_MODE_CLASS ( mode1 ) == GET_MODE_CLASS ( mode2 ) ) return true ; if ( ( TARGET_NEON && ( VALID_NEON_DREG_MODE ( mode1 ) || VALID_NEON_QREG_MODE ( mode1 ) || VALID_NEON_STRUCT_MODE ( mode1 ) ) && ( VALID_NEON_DREG_MODE ( mode2 ) || VALID_NEON_QREG_MODE ( mode2 ) || VALID_NEON_STRUCT_MODE ( mode2 ) ) ) || ( TARGET_HAVE_MVE && ( VALID_MVE_MODE ( mode1 ) || VALID_MVE_STRUCT_MODE ( mode1 ) ) && ( VALID_MVE_MODE ( mode2 ) || VALID_MVE_STRUCT_MODE ( mode2 ) ) ) ) return true ; return false ; } </s>


<s> enum reg_class arm_mode_base_reg_class ( machine_mode mode ) { if ( TARGET_HAVE_MVE && ( mode == E_V8QImode || mode == E_V4QImode || mode == E_V4HImode ) ) return LO_REGS ; return MODE_BASE_REG_REG_CLASS ( mode ) ; } </s>

If given mode matches , load from memory to LO_REGS . ( i.e [ Rn ] , Rn < = LO_REGS ) .


<s> opt_machine_mode arm_mode_to_pred_mode ( machine_mode mode ) { switch ( GET_MODE_NUNITS ( mode ) ) { case 16 : return V16BImode ; case 8 : return V8BImode ; case 4 : return V4BImode ; } return opt_machine_mode ( ) ; } </s>

Return the mode for the MVE vector of predicates corresponding to MODE .


<s> static bool arm_must_pass_in_stack ( const function_arg_info & arg ) { if ( TARGET_AAPCS_BASED ) return must_pass_in_stack_var_size ( arg ) ; else return must_pass_in_stack_var_size_or_pad ( arg ) ; } </s>

Return true if a type must be passed in memory . For AAPCS , small aggregates ( padded to the size of a word ) should be passed in a register .


<s> static int arm_needs_doubleword_align ( machine_mode mode , const_tree type ) { if ( ! type ) return GET_MODE_ALIGNMENT ( mode ) > PARM_BOUNDARY ; if ( ! AGGREGATE_TYPE_P ( type ) ) return TYPE_ALIGN ( TYPE_MAIN_VARIANT ( type ) ) > PARM_BOUNDARY ; if ( TREE_CODE ( type ) == ARRAY_TYPE ) return TYPE_ALIGN ( TREE_TYPE ( type ) ) > PARM_BOUNDARY ; int ret = 0 ; int ret2 = 0 ; for ( tree field = TYPE_FIELDS ( type ) ; field ; field = DECL_CHAIN ( field ) ) if ( DECL_ALIGN ( field ) > PARM_BOUNDARY ) { if ( TREE_CODE ( field ) == FIELD_DECL ) return 1 ; else ret = - 1 ; } else if ( TREE_CODE ( field ) == FIELD_DECL && DECL_BIT_FIELD_TYPE ( field ) && TYPE_ALIGN ( DECL_BIT_FIELD_TYPE ( field ) ) > PARM_BOUNDARY ) ret2 = 1 ; if ( ret2 ) return 2 ; return ret ; } </s>

Return 1 if double word alignment is required for argument passing . Return -1 if double word alignment used to be required for argument passing before PR77728 ABI fix , but is not required anymore . Return 0 if double word alignment is not required and was n't requried before either .


"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 architecture 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 only supports non-pic code on M-profile targets"

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

"incompatible options %<-mstack-protector-guard=global%> and "

Reset options between modes that the user has specified .


<s> static void arm_option_params_internal ( void ) { if ( TARGET_THUMB1 ) { targetm . min_anchor_offset = 0 ; targetm . max_anchor_offset = 127 ; } else if ( TARGET_THUMB2 ) { targetm . min_anchor_offset = - 248 ; targetm . max_anchor_offset = 4095 ; } else { targetm . min_anchor_offset = TARGET_MIN_ANCHOR_OFFSET ; targetm . max_anchor_offset = TARGET_MAX_ANCHOR_OFFSET ; } max_insns_skipped = optimize_size ? 4 : current_tune -> max_insns_skipped ; if ( TARGET_THUMB2 ) max_insns_skipped = MIN ( max_insns_skipped , MAX_INSN_PER_IT_BLOCK ) ; if ( TARGET_THUMB1 ) targetm . md_asm_adjust = thumb1_md_asm_adjust ; else targetm . md_asm_adjust = arm_md_asm_adjust ; } </s>

Recompute the global settings depending on target attribute options .


<s>
static
void
arm_option_print
(
FILE
*
file
,
int
indent
,
struct
cl_target_option
*
ptr
)
{
int
flags
=
ptr
->
x_target_flags
;
const
char
*
fpu_name
;
fpu_name
=
(
ptr
->
x_arm_fpu_index
==
TARGET_FPU_auto
"auto"
:
all_fpus
[
ptr
->
x_arm_fpu_index
]
.
name
)
;
fprintf
(
file
,
"%*sselected isa %s\n"
,
indent
,
""
,
TARGET_THUMB2_P
(
flags
)
"thumb2"
:
TARGET_THUMB_P
(
flags
)
"thumb1"
:
"arm"
)
;
if
(
ptr
->
x_arm_arch_string
)
fprintf
(
file
,
"%*sselected architecture %s\n"
,
indent
,
""
,
ptr
->
x_arm_arch_string
)
;
if
(
ptr
->
x_arm_cpu_string
)
fprintf
(
file
,
"%*sselected CPU %s\n"
,
indent
,
""
,
ptr
->
x_arm_cpu_string
)
;
if
(
ptr
->
x_arm_tune_string
)
fprintf
(
file
,
"%*sselected tune %s\n"
,
indent
,
""
,
ptr
->
x_arm_tune_string
)
;
fprintf
(
file
,
"%*sselected fpu %s\n"
,
indent
,
""
,
fpu_name
)
;
}
</s>

arm
"auto"
"%*sselected isa %s\n"
""
"thumb2"
"thumb1"
"arm"
"%*sselected architecture %s\n"
""
"%*sselected CPU %s\n"
""
"%*sselected tune %s\n"
""
"%*sselected fpu %s\n"
""


"selected fp16 options are incompatible"

"%<-mstack-protector-guard=tls%> needs a hardware TLS register"

Reconfigure global status flags from the active_target.isa .


<s> static void arm_option_restore ( struct gcc_options * , struct gcc_options * , struct cl_target_option * ptr ) { arm_configure_build_target ( & arm_active_target , ptr , false ) ; arm_option_reconfigure_globals ( ) ; } </s>


<s> static void arm_option_save ( struct cl_target_option * ptr , struct gcc_options * opts ) { ptr -> x_arm_arch_string = opts -> x_arm_arch_string ; ptr -> x_arm_cpu_string = opts -> x_arm_cpu_string ; ptr -> x_arm_tune_string = opts -> x_arm_tune_string ; } </s>


<s> void arm_order_regs_for_local_alloc ( void ) { const int arm_reg_alloc_order [ ] = REG_ALLOC_ORDER ; memcpy ( reg_alloc_order , arm_reg_alloc_order , sizeof ( reg_alloc_order ) ) ; if ( TARGET_THUMB ) memcpy ( reg_alloc_order , thumb_core_reg_alloc_order , sizeof ( thumb_core_reg_alloc_order ) ) ; } </s>

Adjust register allocation order when compiling for Thumb .


<s> static bool arm_output_addr_const_extra ( FILE * fp , rtx x ) { if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) return arm_emit_tls_decoration ( fp , x ) ; else if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_PIC_LABEL ) { char label [ 256 ] ; int labelno = INTVAL ( XVECEXP ( x , 0 , 0 ) ) ; ASM_GENERATE_INTERNAL_LABEL ( label , "LPIC" , labelno ) ; assemble_name_raw ( fp , label ) ; return TRUE ; } else if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_GOTSYM_OFF ) { assemble_name ( fp , "_GLOBAL_OFFSET_TABLE_" ) ; if ( GOT_PCREL ) fputs ( "+." , fp ) ; fputs ( "-(" , fp ) ; output_addr_const ( fp , XVECEXP ( x , 0 , 0 ) ) ; fputc ( ')' , fp ) ; return TRUE ; } else if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_SYMBOL_OFFSET ) { output_addr_const ( fp , XVECEXP ( x , 0 , 0 ) ) ; if ( GOT_PCREL ) fputs ( "+." , fp ) ; fputs ( "-(" , fp ) ; output_addr_const ( fp , XVECEXP ( x , 0 , 1 ) ) ; fputc ( ')' , fp ) ; return TRUE ; } else if ( GET_CODE ( x ) == CONST_VECTOR ) return arm_emit_vector_const ( fp , x ) ; return FALSE ; } </s>


<s> static void arm_output_dwarf_dtprel ( FILE * file , int size , rtx x ) { gcc_assert ( size == 4 ) ; fputs ( "\t.word\t" , file ) ; output_addr_const ( file , x ) ; fputs ( "(tlsldo)" , file ) ; } </s>

ARM implementation of TARGET_ASM_OUTPUT_DWARF_DTPREL .


<s> void arm_output_fn_unwind ( FILE * f , bool prologue ) { if ( arm_except_unwind_info ( & global_options ) != UI_TARGET ) return ; if ( prologue ) fputs ( "\t.fnstart\n" , f ) ; else { if ( ! ( flag_unwind_tables || crtl -> uses_eh_lsda ) && ( TREE_NOTHROW ( current_function_decl ) || crtl -> all_throwers_are_sibcalls ) ) fputs ( "\t.cantunwind\n" , f ) ; fputs ( "\t.fnend\n" , f ) ; } } </s>

Output unwind directives for the start/end of a function .


"\t%@ Function supports interworking.\n"

"\t%@ Fast Interrupt Service Routine.\n"

"\t%@ Naked Function: prologue and epilogue provided by programmer.\n"

"\t%@ Volatile: function does not return.\n"

"\t%@ Nested: function declared inside another function.\n"

"\t%@ Stack Align: May be called with mis-aligned SP.\n"

"\t%@ Non-secure entry function: called from non-secure code.\n"

"\t%@ args = %wd, pretend = %d, frame = %wd\n"

"\t%@ frame_needed = %d, uses_anonymous_args = %d\n"

Place some comments into the assembler stream describing the current function .


<s>
const
char
*
arm_output_iwmmxt_shift_immediate
(
const
char
*
insn_name
,
rtx
*
operands
,
bool
wror_or_wsra
)
{
int
shift
=
INTVAL
(
operands
[
2
]
)
;
char
templ
[
50
]
;
machine_mode
opmode
=
GET_MODE
(
operands
[
0
]
)
;
gcc_assert
(
shift
>=
0
)
;
if
(
(
(
opmode
==
V4HImode
)
&&
(
shift
>
15
)
)
||
(
(
opmode
==
V2SImode
)
&&
(
shift
>
31
)
)
||
(
(
opmode
==
DImode
)
&&
(
shift
>
63
)
)
)
{
if
(
wror_or_wsra
)
{
sprintf
(
templ
,
"%s\t%%0, %%1, #%d"
,
insn_name
,
32
)
;
output_asm_insn
(
templ
,
operands
)
;
if
(
opmode
==
DImode
)
{
sprintf
(
templ
,
"%s\t%%0, %%0, #%d"
,
insn_name
,
32
)
;
output_asm_insn
(
templ
,
operands
)
;
}
}
else
{
sprintf
(
templ
,
"wzero\t%%0"
)
;
output_asm_insn
(
templ
,
operands
)
;
}
return
""
;
}
if
(
(
opmode
==
DImode
)
&&
(
shift
>
32
)
)
{
sprintf
(
templ
,
"%s\t%%0, %%1, #%d"
,
insn_name
,
32
)
;
output_asm_insn
(
templ
,
operands
)
;
sprintf
(
templ
,
"%s\t%%0, %%0, #%d"
,
insn_name
,
shift
32
)
;
output_asm_insn
(
templ
,
operands
)
;
}
else
{
sprintf
(
templ
,
"%s\t%%0, %%1, #%d"
,
insn_name
,
shift
)
;
output_asm_insn
(
templ
,
operands
)
;
}
return
""
;
}
</s>

Output assembly for a WMMX immediate shift instruction .


<s>
const
char
*
arm_output_iwmmxt_tinsr
(
rtx
*
operands
)
{
int
mask
=
INTVAL
(
operands
[
3
]
)
;
int
i
;
char
templ
[
50
]
;
int
units
=
mode_nunits
[
GET_MODE
(
operands
[
0
]
)
]
;
gcc_assert
(
(
mask
&
(
mask
1
)
)
==
0
)
;
for
(
i
=
0
;
i
<
units
;
++
i
)
{
if
(
(
mask
&
0x01
)
==
1
)
{
break
;
}
mask
>>=
1
;
}
gcc_assert
(
i
<
units
)
;
{
switch
(
GET_MODE
(
operands
[
0
]
)
)
{
case
E_V8QImode
:
sprintf
(
templ
,
"tinsrb%%?\t%%0, %%2, #%d"
,
i
)
;
break
;
case
E_V4HImode
:
sprintf
(
templ
,
"tinsrh%%?\t%%0, %%2, #%d"
,
i
)
;
break
;
case
E_V2SImode
:
sprintf
(
templ
,
"tinsrw%%?\t%%0, %%2, #%d"
,
i
)
;
break
;
default
:
gcc_unreachable
(
)
;
break
;
}
output_asm_insn
(
templ
,
operands
)
;
}
return
""
;
}
</s>

Output assembly for a WMMX tinsr instruction .


<s> static void arm_output_mi_thunk ( FILE * file , tree thunk , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { const char * fnname = IDENTIFIER_POINTER ( DECL_ASSEMBLER_NAME ( thunk ) ) ; assemble_start_function ( thunk , fnname ) ; if ( TARGET_32BIT ) arm32_output_mi_thunk ( file , thunk , delta , vcall_offset , function ) ; else arm_thumb1_mi_thunk ( file , thunk , delta , vcall_offset , function ) ; assemble_end_function ( thunk , fnname ) ; } </s>

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


<s>
void
arm_output_multireg_pop
(
rtx
*
operands
,
bool
return_pc
,
rtx
cond
,
bool
reverse
,
bool
update
)
{
int
i
;
char
pattern
[
100
]
;
int
offset
;
const
char
*
conditional
;
int
num_saves
=
XVECLEN
(
operands
[
0
]
,
0
)
;
unsigned
int
regno
;
unsigned
int
regno_base
=
REGNO
(
operands
[
1
]
)
;
bool
interrupt_p
=
IS_INTERRUPT
(
arm_current_func_type
(
)
)
;
offset
=
0
;
offset
+=
update
1
:
0
;
offset
+=
return_pc
1
:
0
;
for
(
i
=
offset
;
i
<
num_saves
;
i
++
)
{
regno
=
REGNO
(
XEXP
(
XVECEXP
(
operands
[
0
]
,
0
,
i
)
,
0
)
)
;
gcc_assert
(
(
regno
!=
SP_REGNUM
)
||
(
regno_base
==
SP_REGNUM
)
)
;
if
(
regno
==
regno_base
)
gcc_assert
(
!
update
)
;
}
conditional
=
reverse
"%?%D0"
:
"%?%d0"
;
if
(
(
regno_base
==
SP_REGNUM
)
&&
update
&&
!
(
interrupt_p
&&
return_pc
)
)
sprintf
(
pattern
,
"pop%s\t{"
,
conditional
)
;
else
{
if
(
regno_base
==
SP_REGNUM
)
sprintf
(
pattern
,
"ldmfd%s\t"
,
conditional
)
;
else
if
(
update
)
sprintf
(
pattern
,
"ldmia%s\t"
,
conditional
)
;
else
sprintf
(
pattern
,
"ldm%s\t"
,
conditional
)
;
strcat
(
pattern
,
reg_names
[
regno_base
]
)
;
if
(
update
)
strcat
(
pattern
,
"!, {"
)
;
else
strcat
(
pattern
,
", {"
)
;
}
strcat
(
pattern
,
reg_names
[
REGNO
(
XEXP
(
XVECEXP
(
operands
[
0
]
,
0
,
offset
)
,
0
)
)
]
)
;
for
(
i
=
offset
+
1
;
i
<
num_saves
;
i
++
)
{
strcat
(
pattern
,
", "
)
;
strcat
(
pattern
,
reg_names
[
REGNO
(
XEXP
(
XVECEXP
(
operands
[
0
]
,
0
,
i
)
,
0
)
)
]
)
;
}
strcat
(
pattern
,
"}"
)
;
if
(
interrupt_p
&&
return_pc
)
strcat
(
pattern
,
"^"
)
;
output_asm_insn
(
pattern
,
&
cond
)
;
}
</s>

OPERANDS [ 0 ] is the entire list of insns that constitute pop , OPERANDS [ 1 ] is the base register , RETURN_PC is true iff return insn is in the list , UPDATE is true iff the list contains explicit update of base register .


<s>
const
char
*
arm_output_shift
(
rtx
*
operands
,
int
set_flags
)
{
char
pattern
[
100
]
;
static
const
char
flag_chars
[
3
]
=
{
'?'
,
'.'
,
'!'
}
;
const
char
*
shift
;
HOST_WIDE_INT
val
;
char
c
;
c
=
flag_chars
[
set_flags
]
;
shift
=
shift_op
(
operands
[
3
]
,
&
val
)
;
if
(
shift
)
{
if
(
val
!=
1
)
operands
[
2
]
=
GEN_INT
(
val
)
;
sprintf
(
pattern
,
"%s%%%c\t%%0, %%1, %%2"
,
shift
,
c
)
;
}
else
sprintf
(
pattern
,
"mov%%%c\t%%0, %%1"
,
c
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>

Output assembly for a shift instruction . SET_FLAGS determines how the instruction modifies the condition codes . 0 - Do not set condition codes . 1 - Set condition codes . 2 - Use smallest instruction .


<s> static bool arm_output_ttype ( rtx x ) { fputs ( "\t.word\t" , asm_out_file ) ; output_addr_const ( asm_out_file , x ) ; if ( ! CONST_INT_P ( x ) ) fputs ( "(TARGET2)" , asm_out_file ) ; fputc ( '\n' , asm_out_file ) ; return TRUE ; } </s>

Output a reference from a function exception table to the type_info object X . The EABI specifies that the symbol should be relocated by an R_ARM_TARGET2 relocation .


<s> static void arm_override_options_after_change ( void ) { arm_override_options_after_change_1 ( & global_options , & global_options_set ) ; } </s>


<s> bool arm_pad_reg_upward ( machine_mode mode , tree type , int first ATTRIBUTE_UNUSED ) { if ( TARGET_AAPCS_BASED && BYTES_BIG_ENDIAN ) { if ( type ) { if ( ( AGGREGATE_TYPE_P ( type ) || TREE_CODE ( type ) == COMPLEX_TYPE || FIXED_POINT_TYPE_P ( type ) ) && int_size_in_bytes ( type ) <= 4 ) return true ; } else { if ( ( COMPLEX_MODE_P ( mode ) || ALL_FIXED_POINT_MODE_P ( mode ) ) && GET_MODE_SIZE ( mode ) <= 4 ) return true ; } } return ! BYTES_BIG_ENDIAN ; } </s>

Similarly , for use by BLOCK_REG_PADDING ( MODE , TYPE , FIRST ) . For non-AAPCS , return ! BYTES_BIG_ENDIAN if the least significant byte of the register has useful data , and return the opposite if the most significant byte does . For AAPCS , small aggregates and small complex types are always padded upwards .


<s> static bool arm_pass_by_reference ( cumulative_args_t , const function_arg_info & arg ) { return arg . type && TREE_CODE ( TYPE_SIZE ( arg . type ) ) != INTEGER_CST ; } </s>

Variable sized types are passed by reference . This is a GCC extension to the ARM ABI .


<s> static rtx_insn * arm_pic_static_addr ( rtx orig , rtx reg ) { rtx l1 , labelno , offset_rtx ; rtx_insn * insn ; gcc_assert ( flag_pic ) ; bool is_readonly = false ; bool info_known = false ; if ( TARGET_FDPIC && SYMBOL_REF_P ( orig ) && ! SYMBOL_REF_FUNCTION_P ( orig ) ) info_known = arm_is_segment_info_known ( orig , & is_readonly ) ; if ( TARGET_FDPIC && SYMBOL_REF_P ( orig ) && ! SYMBOL_REF_FUNCTION_P ( orig ) && ! info_known ) { rtx pic_reg = gen_rtx_REG ( Pmode , FDPIC_REGNUM ) ; insn = calculate_pic_address_constant ( reg , pic_reg , orig ) ; } else if ( TARGET_FDPIC && SYMBOL_REF_P ( orig ) && ( SYMBOL_REF_FUNCTION_P ( orig ) || ! is_readonly ) ) { rtx pic_reg = gen_rtx_REG ( Pmode , FDPIC_REGNUM ) ; rtx l1 = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , orig ) , UNSPEC_PIC_SYM ) ; emit_insn ( gen_movsi ( reg , l1 ) ) ; insn = emit_insn ( gen_addsi3 ( reg , reg , pic_reg ) ) ; } else { labelno = GEN_INT ( pic_labelno ++ ) ; l1 = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_PIC_LABEL ) ; l1 = gen_rtx_CONST ( VOIDmode , l1 ) ; offset_rtx = plus_constant ( Pmode , l1 , TARGET_ARM ? 8 : 4 ) ; offset_rtx = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , orig , offset_rtx ) , UNSPEC_SYMBOL_OFFSET ) ; offset_rtx = gen_rtx_CONST ( Pmode , offset_rtx ) ; insn = emit_insn ( gen_pic_load_addr_unified ( reg , offset_rtx , labelno ) ) ; } return insn ; } </s>

Generate code to load the address of a static var when flag_pic is set .


<s> void arm_poke_function_name ( FILE * stream , const char * name ) { unsigned long alignlength ; unsigned long length ; rtx x ; length = strlen ( name ) + 1 ; alignlength = ROUND_UP_WORD ( length ) ; ASM_OUTPUT_ASCII ( stream , name , length ) ; ASM_OUTPUT_ALIGN ( stream , 2 ) ; x = GEN_INT ( ( unsigned HOST_WIDE_INT ) 0xff000000 + alignlength ) ; assemble_aligned_integer ( UNITS_PER_WORD , x ) ; } </s>

Write the function name into the code section , directly preceding the function prologue . Code will be output similar to this : t0 .ascii `` arm_poke_function_name '' , 0 .align t1 .word 0xff000000 + ( t1 - t0 ) arm_poke_function_name mov ip , sp stmfd sp ! , { fp , ip , lr , pc } sub fp , ip , # 4 When performing a stack backtrace , code can inspect the value of 'pc ' stored at 'fp ' + 0 . If the trace function then looks at location pc - 12 and the top 8 bits are set , then we know that there is a function name embedded immediately preceding this location and has length ( ( pc [ -3 ] ) & 0xff000000 ) . We assume that pc is declared as a pointer to an unsigned long . It is of no benefit to output the function name if we are assembling a leaf function . These function types will not contain a stack backtrace structure , therefore it is not possible to determine the function name .


<s> static reg_class_t arm_preferred_reload_class ( rtx x ATTRIBUTE_UNUSED , reg_class_t rclass ) { if ( TARGET_32BIT ) return rclass ; else { if ( rclass == GENERAL_REGS ) return LO_REGS ; else return rclass ; } } </s>

Worker function for TARGET_PREFERRED_RELOAD_CLASS . Given an rtx X being reloaded into a reg required to be in class CLASS , return the class of reg to actually use . In general this is just CLASS , but for the Thumb core registers and immediate constants we prefer a LO_REGS class or a subset .


<s> static machine_mode arm_preferred_simd_mode ( scalar_mode mode ) { if ( TARGET_NEON ) switch ( mode ) { case E_HFmode : return TARGET_NEON_VECTORIZE_DOUBLE ? V4HFmode : V8HFmode ; case E_SFmode : return TARGET_NEON_VECTORIZE_DOUBLE ? V2SFmode : V4SFmode ; case E_SImode : return TARGET_NEON_VECTORIZE_DOUBLE ? V2SImode : V4SImode ; case E_HImode : return TARGET_NEON_VECTORIZE_DOUBLE ? V4HImode : V8HImode ; case E_QImode : return TARGET_NEON_VECTORIZE_DOUBLE ? V8QImode : V16QImode ; case E_DImode : if ( ! TARGET_NEON_VECTORIZE_DOUBLE ) return V2DImode ; break ; default : ; } if ( TARGET_REALLY_IWMMXT ) switch ( mode ) { case E_SImode : return V2SImode ; case E_HImode : return V4HImode ; case E_QImode : return V8QImode ; default : ; } if ( TARGET_HAVE_MVE ) switch ( mode ) { case E_QImode : return V16QImode ; case E_HImode : return V8HImode ; case E_SImode : return V4SImode ; default : ; } if ( TARGET_HAVE_MVE_FLOAT ) switch ( mode ) { case E_HFmode : return V8HFmode ; case E_SFmode : return V4SFmode ; default : ; } return word_mode ; } </s>

Use the option -mvectorize-with-neon-double to override the use of quardword registers when autovectorizing for Neon , at least until multiple vector widths are supported properly by the middle-end .


<s> static void arm_pre_atomic_barrier ( enum memmodel model ) { if ( need_atomic_barrier_p ( model , true ) ) emit_insn ( gen_memory_barrier ( ) ) ; } </s>

Emit a memory barrier around an atomic sequence according to MODEL .


<s>
static
void
arm_print_asm_arch_directives
(
FILE
*
stream
,
cl_target_option
*
targ_options
)
{
arm_build_target
build_target
;
if
(
last_asm_targ_options
==
targ_options
)
return
;
last_asm_targ_options
=
targ_options
;
build_target
.
isa
=
sbitmap_alloc
(
isa_num_bits
)
;
arm_configure_build_target
(
&
build_target
,
targ_options
,
false
)
;
if
(
build_target
.
core_name
&&
!
bitmap_bit_p
(
build_target
.
isa
,
isa_bit_quirk_no_asmcpu
)
)
{
const
char
*
truncated_name
=
arm_rewrite_selected_cpu
(
build_target
.
core_name
)
;
asm_fprintf
(
stream
,
"\t.cpu %s\n"
,
truncated_name
)
;
}
const
arch_option
*
arch
=
arm_parse_arch_option_name
(
all_architectures
,
"-march"
,
build_target
.
arch_name
)
;
auto_sbitmap
opt_bits
(
isa_num_bits
)
;
gcc_assert
(
arch
)
;
if
(
strcmp
(
build_target
.
arch_name
,
"armv7ve"
)
==
0
)
{
asm_fprintf
(
stream
,
"\t.arch armv7-a\n"
)
;
asm_fprintf
(
stream
,
"\t.arch_extension virt\n"
)
;
asm_fprintf
(
stream
,
"\t.arch_extension idiv\n"
)
;
asm_fprintf
(
stream
,
"\t.arch_extension sec\n"
)
;
asm_fprintf
(
stream
,
"\t.arch_extension mp\n"
)
;
}
else
asm_fprintf
(
stream
,
"\t.arch %s\n"
,
build_target
.
arch_name
)
;
const
char
*
fpu_name
=
(
TARGET_SOFT_FLOAT
"softvfp"
:
arm_identify_fpu_from_isa
(
build_target
.
isa
)
)
;
asm_fprintf
(
stream
,
"\t.fpu %s\n"
,
fpu_name
)
;
if
(
!
arch
->
common
.
extensions
)
return
;
for
(
const
struct
cpu_arch_extension
*
opt
=
arch
->
common
.
extensions
;
opt
->
name
!=
;
opt
++
)
{
if
(
!
opt
->
remove
)
{
arm_initialize_isa
(
opt_bits
,
opt
->
isa_bits
)
;
if
(
(
bitmap_bit_p
(
opt_bits
,
isa_bit_mve
)
&&
!
TARGET_HAVE_MVE
)
||
(
bitmap_bit_p
(
opt_bits
,
isa_bit_mve_float
)
&&
!
TARGET_HAVE_MVE_FLOAT
)
)
continue
;
if
(
bitmap_subset_p
(
opt_bits
,
build_target
.
isa
)
&&
!
bitmap_subset_p
(
opt_bits
,
isa_all_fpubits_internal
)
)
asm_fprintf
(
stream
,
"\t.arch_extension %s\n"
,
opt
->
name
)
;
}
}
}
</s>

Print .arch and .arch_extension directives corresponding to the current architecture configuration .

arm
"\t.cpu %s\n"
"-march"
"armv7ve"
0
"\t.arch armv7-a\n"
"\t.arch_extension virt\n"
"\t.arch_extension idiv\n"
"\t.arch_extension sec\n"
"\t.arch_extension mp\n"
"\t.arch %s\n"
"softvfp"
"\t.fpu %s\n"
"\t.arch_extension %s\n"


"predicated instruction in conditional sequence"

Print condition code to STREAM . Helper function for arm_print_operand .


<s> static bool arm_print_operand_punct_valid_p ( unsigned char code ) { return ( code == '@' || code == '|' || code == '.' || code == '(' || code == ')' || code == '#' || ( TARGET_32BIT && ( code == '?' ) ) || ( TARGET_THUMB2 && ( code == '!' ) ) || ( TARGET_THUMB && ( code == '_' ) ) ) ; } </s>

Target hook for indicating whether a punctuation character for TARGET_PRINT_OPERAND is valid .


This function is used to print CPU tuning information as comment in assembler file . Pointers are not printed for now .


<s> static void arm_print_value ( FILE * f , rtx x ) { switch ( GET_CODE ( x ) ) { case CONST_INT : fprintf ( f , HOST_WIDE_INT_PRINT_HEX , INTVAL ( x ) ) ; return ; case CONST_DOUBLE : { char fpstr [ 20 ] ; real_to_decimal ( fpstr , CONST_DOUBLE_REAL_VALUE ( x ) , sizeof ( fpstr ) , 0 , 1 ) ; fputs ( fpstr , f ) ; } return ; case CONST_VECTOR : { int i ; fprintf ( f , "<" ) ; for ( i = 0 ; i < CONST_VECTOR_NUNITS ( x ) ; i ++ ) { fprintf ( f , HOST_WIDE_INT_PRINT_HEX , INTVAL ( CONST_VECTOR_ELT ( x , i ) ) ) ; if ( i < ( CONST_VECTOR_NUNITS ( x ) - 1 ) ) fputc ( ',' , f ) ; } fprintf ( f , ">" ) ; } return ; case CONST_STRING : fprintf ( f , "\"%s\"" , XSTR ( x , 0 ) ) ; return ; case SYMBOL_REF : fprintf ( f , "`%s'" , XSTR ( x , 0 ) ) ; return ; case LABEL_REF : fprintf ( f , "L%d" , INSN_UID ( XEXP ( x , 0 ) ) ) ; return ; case CONST : arm_print_value ( f , XEXP ( x , 0 ) ) ; return ; case PLUS : arm_print_value ( f , XEXP ( x , 0 ) ) ; fprintf ( f , "+" ) ; arm_print_value ( f , XEXP ( x , 1 ) ) ; return ; case PC : fprintf ( f , "pc" ) ; return ; default : fprintf ( f , "????" ) ; return ; } } </s>

Print a symbolic form of X to the debug file , F .


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


<s> static bool arm_promote_prototypes ( const_tree t ATTRIBUTE_UNUSED ) { return ! TARGET_AAPCS_BASED ; } </s>

We ca n't rely on the caller doing the proper promotion when using APCS or ATPCS .


<s> static bool arm_r3_live_at_start_p ( void ) { return REGNO_REG_SET_P ( df_get_live_out ( ENTRY_BLOCK_PTR_FOR_FN ( cfun ) ) , 3 ) ; } </s>

Return true if r3 is live at the start of the function .


<s> int arm_register_move_cost ( machine_mode mode ATTRIBUTE_UNUSED , reg_class_t from , reg_class_t to ) { if ( TARGET_32BIT ) { if ( ( IS_VFP_CLASS ( from ) && ! IS_VFP_CLASS ( to ) ) || ( ! IS_VFP_CLASS ( from ) && IS_VFP_CLASS ( to ) ) ) return 15 ; else if ( ( from == IWMMXT_REGS && to != IWMMXT_REGS ) || ( from != IWMMXT_REGS && to == IWMMXT_REGS ) ) return 4 ; else if ( from == IWMMXT_GR_REGS || to == IWMMXT_GR_REGS ) return 20 ; else return 2 ; } else { if ( from == HI_REGS || to == HI_REGS ) return 4 ; else return 2 ; } } </s>

Implement TARGET_REGISTER_MOVE_COST . Moves between VFP_REGS and GENERAL_REGS are a single insn , but it is typically more expensive than a single memory access . We set the cost to less than two memory accesses so that floating point to integer conversion does not go through memory .


<s> enum reg_class arm_regno_class ( int regno ) { if ( regno == PC_REGNUM ) return NO_REGS ; if ( IS_VPR_REGNUM ( regno ) ) return VPR_REG ; if ( TARGET_THUMB1 ) { if ( regno == STACK_POINTER_REGNUM ) return STACK_REG ; if ( regno == CC_REGNUM ) return CC_REG ; if ( regno < 8 ) return LO_REGS ; return HI_REGS ; } if ( TARGET_THUMB2 && regno < 8 ) return LO_REGS ; if ( regno <= LAST_ARM_REGNUM || regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM ) return TARGET_THUMB2 ? HI_REGS : GENERAL_REGS ; if ( regno == CC_REGNUM || regno == VFPCC_REGNUM ) return TARGET_THUMB2 ? CC_REG : NO_REGS ; if ( IS_VFP_REGNUM ( regno ) ) { if ( regno <= D7_VFP_REGNUM ) return VFP_D0_D7_REGS ; else if ( regno <= LAST_LO_VFP_REGNUM ) return VFP_LO_REGS ; else return VFP_HI_REGS ; } if ( IS_IWMMXT_REGNUM ( regno ) ) return IWMMXT_REGS ; if ( IS_IWMMXT_GR_REGNUM ( regno ) ) return IWMMXT_GR_REGS ; return NO_REGS ; } </s>

For efficiency and historical reasons LO_REGS , HI_REGS and CC_REGS are not used in arm mode .


<s> static void arm_relayout_function ( tree fndecl ) { if ( DECL_USER_ALIGN ( fndecl ) ) return ; tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) ; if ( ! callee_tree ) callee_tree = target_option_default_node ; struct cl_target_option * opts = TREE_TARGET_OPTION ( callee_tree ) ; SET_DECL_ALIGN ( fndecl , FUNCTION_ALIGNMENT ( FUNCTION_BOUNDARY_P ( opts -> x_target_flags ) ) ) ; } </s>

Hook to fix function 's alignment affected by target attribute .


<s> void arm_reset_previous_fndecl ( void ) { arm_previous_fndecl = NULL_TREE ; } </s>


<s> rtx arm_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return NULL_RTX ; return get_hard_reg_initial_val ( Pmode , LR_REGNUM ) ; } </s>

Return an RTX indicating where the return address to the calling function can be found .


<s> static bool arm_return_in_memory ( const_tree type , const_tree fntype ) { HOST_WIDE_INT size ; size = int_size_in_bytes ( type ) ; if ( TARGET_AAPCS_BASED ) { if ( ! AGGREGATE_TYPE_P ( type ) && TREE_CODE ( type ) != VECTOR_TYPE && TREE_CODE ( type ) != COMPLEX_TYPE ) return false ; if ( ( ( unsigned HOST_WIDE_INT ) size ) <= UNITS_PER_WORD ) return false ; if ( aapcs_select_return_coproc ( type , fntype ) >= 0 ) return false ; if ( TREE_CODE ( type ) == VECTOR_TYPE ) return ( size < 0 || size > ( 4 * UNITS_PER_WORD ) ) ; return true ; } if ( TREE_CODE ( type ) == VECTOR_TYPE ) return ( size < 0 || size > ( 4 * UNITS_PER_WORD ) ) ; if ( ! AGGREGATE_TYPE_P ( type ) && ( TREE_CODE ( type ) != VECTOR_TYPE ) ) return false ; if ( arm_abi != ARM_ABI_APCS ) { return ( size < 0 || size > UNITS_PER_WORD ) ; } if ( size < 0 || size > UNITS_PER_WORD ) return true ; if ( TREE_CODE ( type ) == RECORD_TYPE ) { tree field ; for ( field = TYPE_FIELDS ( type ) ; field && TREE_CODE ( field ) != FIELD_DECL ; field = DECL_CHAIN ( field ) ) continue ; if ( field == NULL ) return false ; if ( FLOAT_TYPE_P ( TREE_TYPE ( field ) ) ) return true ; if ( arm_return_in_memory ( TREE_TYPE ( field ) , NULL_TREE ) ) return true ; for ( field = DECL_CHAIN ( field ) ; field ; field = DECL_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( ! DECL_BIT_FIELD_TYPE ( field ) ) return true ; } return false ; } if ( TREE_CODE ( type ) == UNION_TYPE ) { tree field ; for ( field = TYPE_FIELDS ( type ) ; field ; field = DECL_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( FLOAT_TYPE_P ( TREE_TYPE ( field ) ) ) return true ; if ( arm_return_in_memory ( TREE_TYPE ( field ) , NULL_TREE ) ) return true ; } return false ; } return true ; } </s>

Decide whether a type should be returned in memory ( true ) or in a register ( false ) . This is called by the macro RETURN_IN_MEMORY .


<s> static bool arm_return_in_msb ( const_tree valtype ) { return ( TARGET_AAPCS_BASED && BYTES_BIG_ENDIAN && ( AGGREGATE_TYPE_P ( valtype ) || TREE_CODE ( valtype ) == COMPLEX_TYPE || FIXED_POINT_TYPE_P ( valtype ) ) ) ; } </s>

Values which must be returned in the most-significant end of the return register .


<s>
static
bool
arm_rtx_costs
(
rtx
x
,
machine_mode
mode
ATTRIBUTE_UNUSED
,
int
outer_code
,
int
opno
ATTRIBUTE_UNUSED
,
int
*
total
,
bool
speed
)
{
bool
result
;
int
code
=
GET_CODE
(
x
)
;
gcc_assert
(
current_tune
->
insn_extra_cost
)
;
result
=
arm_rtx_costs_internal
(
x
,
(
enum
rtx_code
)
code
,
(
enum
rtx_code
)
outer_code
,
current_tune
->
insn_extra_cost
,
total
,
speed
)
;
if
(
dump_file
&&
arm_verbose_cost
)
{
print_rtl_single
(
dump_file
,
x
)
;
fprintf
(
dump_file
,
"\n%s cost: %d (%s)\n"
,
speed
"Hot"
:
"Cold"
,
*
total
,
result
"final"
:
"partial"
)
;
}
return
result
;
}
</s>

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


<s> bool arm_sat_operator_match ( rtx lo_bound , rtx hi_bound , int * mask , bool * signed_sat ) { int log = exact_log2 ( INTVAL ( hi_bound ) + 1 ) ; if ( log == - 1 ) return false ; if ( INTVAL ( lo_bound ) == 0 ) { if ( mask ) * mask = log ; if ( signed_sat ) * signed_sat = false ; return true ; } if ( INTVAL ( lo_bound ) == - INTVAL ( hi_bound ) - 1 ) { if ( mask ) * mask = log + 1 ; if ( signed_sat ) * signed_sat = true ; return true ; } return false ; } </s>

Match pair of min/max operators that can be implemented via usat/ssat .


<s> static int arm_save_coproc_regs ( void ) { int saved_size = 0 ; unsigned reg ; unsigned start_reg ; rtx insn ; if ( TARGET_REALLY_IWMMXT ) for ( reg = LAST_IWMMXT_REGNUM ; reg >= FIRST_IWMMXT_REGNUM ; reg -- ) if ( reg_needs_saving_p ( reg ) ) { insn = gen_rtx_PRE_DEC ( Pmode , stack_pointer_rtx ) ; insn = gen_rtx_MEM ( V2SImode , insn ) ; insn = emit_set_insn ( insn , gen_rtx_REG ( V2SImode , reg ) ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; saved_size += 8 ; } if ( TARGET_VFP_BASE ) { start_reg = FIRST_VFP_REGNUM ; for ( reg = FIRST_VFP_REGNUM ; reg < LAST_VFP_REGNUM ; reg += 2 ) { if ( ! reg_needs_saving_p ( reg ) && ! reg_needs_saving_p ( reg + 1 ) ) { if ( start_reg != reg ) saved_size += vfp_emit_fstmd ( start_reg , ( reg - start_reg ) / 2 ) ; start_reg = reg + 2 ; } } if ( start_reg != reg ) saved_size += vfp_emit_fstmd ( start_reg , ( reg - start_reg ) / 2 ) ; } return saved_size ; } </s>

Emit RTL to save coprocessor registers on function entry . Returns the number of bytes pushed .


<s> static bool arm_scalar_mode_supported_p ( scalar_mode mode ) { if ( mode == HFmode ) return ( arm_fp16_format != ARM_FP16_FORMAT_NONE ) ; else if ( ALL_FIXED_POINT_MODE_P ( mode ) ) return true ; else return default_scalar_mode_supported_p ( mode ) ; } </s>

Implement TARGET_SCALAR_MODE_SUPPORTED_P . This simply adds HFmode as a supported mode ; even though we do n't implement arithmetic on this type directly , it 's supported by optabs conversions , much the way the double-word arithmetic is special-cased in the default hook .


<s> static bool arm_sched_can_speculate_insn ( rtx_insn * insn ) { switch ( get_attr_type ( insn ) ) { case TYPE_SDIV : case TYPE_UDIV : case TYPE_FDIVS : case TYPE_FDIVD : case TYPE_FSQRTS : case TYPE_FSQRTD : case TYPE_NEON_FP_SQRT_S : case TYPE_NEON_FP_SQRT_D : case TYPE_NEON_FP_SQRT_S_Q : case TYPE_NEON_FP_SQRT_D_Q : case TYPE_NEON_FP_DIV_S : case TYPE_NEON_FP_DIV_D : case TYPE_NEON_FP_DIV_S_Q : case TYPE_NEON_FP_DIV_D_Q : return false ; default : return true ; } } </s>

Implement TARGET_SCHED_CAN_SPECULATE_INSN . Return true if INSN can be scheduled for speculative execution . Reject the long-running division and square-root instructions .


<s> static void arm_sched_fusion_priority ( rtx_insn * insn , int max_pri , int * fusion_pri , int * pri ) { int tmp , off_val ; bool is_load ; rtx base , offset ; gcc_assert ( INSN_P ( insn ) ) ; tmp = max_pri - 1 ; if ( ! fusion_load_store ( insn , & base , & offset , & is_load ) ) { * pri = tmp ; * fusion_pri = tmp ; return ; } if ( is_load ) * fusion_pri = tmp - 1 ; else * fusion_pri = tmp - 2 ; tmp /= 2 ; tmp -= ( ( REGNO ( base ) & 0xff ) << 20 ) ; off_val = ( int ) ( INTVAL ( offset ) ) ; if ( off_val >= 0 ) tmp -= ( off_val & 0xfffff ) ; else tmp += ( ( - off_val ) & 0xfffff ) ; * pri = tmp ; return ; } </s>

Implement the TARGET_SCHED_FUSION_PRIORITY hook . Currently we only support to fuse ldr or str instructions , so FUSION_PRI and PRI are only calculated for these instructions . For other instruction , FUSION_PRI and PRI are simply set to MAX_PRI . In the future , other kind instruction fusion can be supported by returning different priorities . It 's important that irrelevant instructions get the largest FUSION_PRI .


<s> static int arm_sched_reorder ( FILE * file , int verbose , rtx_insn * * ready , int * n_readyp , int clock ) { switch ( arm_tune ) { case TARGET_CPU_cortexa7 : cortexa7_sched_reorder ( file , verbose , ready , n_readyp , clock ) ; break ; default : break ; } return arm_issue_rate ( ) ; } </s>


<s> static int arm_sched_variable_issue ( FILE * , int , rtx_insn * insn , int more ) { if ( DEBUG_INSN_P ( insn ) ) return more ; rtx_code code = GET_CODE ( PATTERN ( insn ) ) ; if ( code == USE || code == CLOBBER ) return more ; if ( get_attr_type ( insn ) == TYPE_NO_INSN ) return more ; return more - 1 ; } </s>


<s> machine_mode arm_select_dominance_cc_mode ( rtx x , rtx y , HOST_WIDE_INT cond_or ) { enum rtx_code cond1 , cond2 ; int swapped = 0 ; if ( ( arm_select_cc_mode ( cond1 = GET_CODE ( x ) , XEXP ( x , 0 ) , XEXP ( x , 1 ) ) != CCmode ) || ( arm_select_cc_mode ( cond2 = GET_CODE ( y ) , XEXP ( y , 0 ) , XEXP ( y , 1 ) ) != CCmode ) ) return CCmode ; if ( cond_or == DOM_CC_NX_OR_Y ) cond1 = reverse_condition ( cond1 ) ; if ( cond1 != cond2 && ! comparison_dominates_p ( cond1 , cond2 ) && ( swapped = 1 , ! comparison_dominates_p ( cond2 , cond1 ) ) ) return CCmode ; if ( swapped ) std :: swap ( cond1 , cond2 ) ; switch ( cond1 ) { case EQ : if ( cond_or == DOM_CC_X_AND_Y ) return CC_DEQmode ; switch ( cond2 ) { case EQ : return CC_DEQmode ; case LE : return CC_DLEmode ; case LEU : return CC_DLEUmode ; case GE : return CC_DGEmode ; case GEU : return CC_DGEUmode ; default : gcc_unreachable ( ) ; } case LT : if ( cond_or == DOM_CC_X_AND_Y ) return CC_DLTmode ; switch ( cond2 ) { case LT : return CC_DLTmode ; case LE : return CC_DLEmode ; case NE : return CC_DNEmode ; default : gcc_unreachable ( ) ; } case GT : if ( cond_or == DOM_CC_X_AND_Y ) return CC_DGTmode ; switch ( cond2 ) { case GT : return CC_DGTmode ; case GE : return CC_DGEmode ; case NE : return CC_DNEmode ; default : gcc_unreachable ( ) ; } case LTU : if ( cond_or == DOM_CC_X_AND_Y ) return CC_DLTUmode ; switch ( cond2 ) { case LTU : return CC_DLTUmode ; case LEU : return CC_DLEUmode ; case NE : return CC_DNEmode ; default : gcc_unreachable ( ) ; } case GTU : if ( cond_or == DOM_CC_X_AND_Y ) return CC_DGTUmode ; switch ( cond2 ) { case GTU : return CC_DGTUmode ; case GEU : return CC_DGEUmode ; case NE : return CC_DNEmode ; default : gcc_unreachable ( ) ; } case NE : gcc_assert ( cond1 == cond2 ) ; return CC_DNEmode ; case LE : gcc_assert ( cond1 == cond2 ) ; return CC_DLEmode ; case GE : gcc_assert ( cond1 == cond2 ) ; return CC_DGEmode ; case LEU : gcc_assert ( cond1 == cond2 ) ; return CC_DLEUmode ; case GEU : gcc_assert ( cond1 == cond2 ) ; return CC_DGEUmode ; default : gcc_unreachable ( ) ; } } </s>

Select a dominance comparison mode if possible for a test of the general form ( OP ( COND_OR ( X ) ( Y ) ) ( const_int 0 ) ) . We support three forms . COND_OR == DOM_CC_X_AND_Y = > ( X & & Y ) COND_OR == DOM_CC_NX_OR_Y = > ( ( ! X ) || Y ) COND_OR == DOM_CC_X_OR_Y = > ( X || Y ) In all cases OP will be either EQ or NE , but we do n't need to know which here . If we are unable to support a dominance comparison we return CC mode . This will then fail to match for the RTL expressions that generate this call .


<s> static bool arm_sets_movw_movt_fusible_p ( rtx prev_set , rtx curr_set ) { rtx set_dest = SET_DEST ( curr_set ) ; if ( GET_MODE ( set_dest ) != SImode ) return false ; if ( GET_CODE ( set_dest ) == ZERO_EXTRACT ) { if ( CONST_INT_P ( SET_SRC ( curr_set ) ) && CONST_INT_P ( SET_SRC ( prev_set ) ) && REG_P ( XEXP ( set_dest , 0 ) ) && REG_P ( SET_DEST ( prev_set ) ) && REGNO ( XEXP ( set_dest , 0 ) ) == REGNO ( SET_DEST ( prev_set ) ) ) return true ; } else if ( GET_CODE ( SET_SRC ( curr_set ) ) == LO_SUM && REG_P ( SET_DEST ( curr_set ) ) && REG_P ( SET_DEST ( prev_set ) ) && GET_CODE ( SET_SRC ( prev_set ) ) == HIGH && REGNO ( SET_DEST ( curr_set ) ) == REGNO ( SET_DEST ( prev_set ) ) ) return true ; return false ; } </s>

Return true if the two back-to-back sets PREV_SET , CURR_SET are suitable for MOVW / MOVT macro fusion .


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


<s> static void arm_set_current_function ( tree fndecl ) { if ( ! fndecl || fndecl == arm_previous_fndecl ) return ; tree old_tree = ( arm_previous_fndecl ? DECL_FUNCTION_SPECIFIC_TARGET ( arm_previous_fndecl ) : NULL_TREE ) ; tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET ( fndecl ) ; if ( ! new_tree && old_tree ) new_tree = target_option_default_node ; if ( old_tree == new_tree ) return ; arm_previous_fndecl = fndecl ; cl_target_option_restore ( & global_options , & global_options_set , TREE_TARGET_OPTION ( new_tree ) ) ; save_restore_target_globals ( new_tree ) ; arm_override_options_after_change_1 ( & global_options , & global_options_set ) ; } </s>

Establish appropriate back-end context for processing the function FNDECL . The argument might be NULL to indicate processing at top level , outside of any function scope .


<s> static void arm_set_default_type_attributes ( tree type ) { if ( TREE_CODE ( type ) == FUNCTION_TYPE || TREE_CODE ( type ) == METHOD_TYPE ) { tree type_attr_list , attr_name ; type_attr_list = TYPE_ATTRIBUTES ( type ) ; if ( arm_pragma_long_calls == LONG ) attr_name = get_identifier ( "long_call" ) ; else if ( arm_pragma_long_calls == SHORT ) attr_name = get_identifier ( "short_call" ) ; else return ; type_attr_list = tree_cons ( attr_name , NULL_TREE , type_attr_list ) ; TYPE_ATTRIBUTES ( type ) = type_attr_list ; } } </s>

Assigns default attributes to newly defined type . This is used to set short_call/long_call attributes for function types of functions defined inside corresponding # pragma scopes .


<s> static void arm_set_fixed_optab_libfunc ( optab optable , machine_mode mode , const char * funcname , const char * modename , int num_suffix ) { char buffer [ 50 ] ; if ( num_suffix == 0 ) sprintf ( buffer , "__gnu_%s%s" , funcname , modename ) ; else sprintf ( buffer , "__gnu_%s%s%d" , funcname , modename , num_suffix ) ; set_optab_libfunc ( optable , mode , buffer ) ; } </s>

A small helper for setting fixed-point library libfuncs .


<s> static const char * arm_shift_nmem ( enum rtx_code code ) { switch ( code ) { case ASHIFT : return ARM_LSL_NAME ; case ASHIFTRT : return "asr" ; case LSHIFTRT : return "lsr" ; case ROTATERT : return "ror" ; default : abort ( ) ; } } </s>

Return the name of a shifter operation .


<s> static unsigned HOST_WIDE_INT arm_shift_truncation_mask ( machine_mode mode ) { return mode == SImode ? 255 : 0 ; } </s>

Implement TARGET_SHIFT_TRUNCATION_MASK . SImode shifts use normal ARM insns and therefore guarantee that the shift count is modulo 256 . DImode shifts ( those implemented by lib1funcs.asm or by optabs.c ) guarantee no particular behavior for out-of-range counts .


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

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


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

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


<s> static unsigned arm_size_return_regs ( void ) { machine_mode mode ; if ( crtl -> return_rtx != 0 ) mode = GET_MODE ( crtl -> return_rtx ) ; else mode = DECL_MODE ( DECL_RESULT ( current_function_decl ) ) ; return GET_MODE_SIZE ( mode ) ; } </s>

Calculate the size of the return value that is passed in registers .


<s> bool arm_small_register_classes_for_mode_p ( machine_mode mode ATTRIBUTE_UNUSED ) { return TARGET_THUMB1 ; } </s>

Implements target hook small_register_classes_for_mode_p .


<s> void arm_split_compare_and_swap ( rtx operands [ ] ) { rtx rval , mem , oldval , newval , neg_bval , mod_s_rtx ; machine_mode mode ; enum memmodel mod_s , mod_f ; bool is_weak ; rtx_code_label * label1 , * label2 ; rtx x , cond ; rval = operands [ 1 ] ; mem = operands [ 2 ] ; oldval = operands [ 3 ] ; newval = operands [ 4 ] ; is_weak = ( operands [ 5 ] != const0_rtx ) ; mod_s_rtx = operands [ 6 ] ; mod_s = memmodel_from_int ( INTVAL ( mod_s_rtx ) ) ; mod_f = memmodel_from_int ( INTVAL ( operands [ 7 ] ) ) ; neg_bval = TARGET_THUMB1 ? operands [ 0 ] : operands [ 8 ] ; mode = GET_MODE ( mem ) ; bool is_armv8_sync = arm_arch8 && is_mm_sync ( mod_s ) ; bool use_acquire = TARGET_HAVE_LDACQ && aarch_mm_needs_acquire ( mod_s_rtx ) ; bool use_release = TARGET_HAVE_LDACQ && aarch_mm_needs_release ( mod_s_rtx ) ; if ( is_armv8_sync ) use_acquire = false ; if ( ! ( use_acquire || use_release ) ) arm_pre_atomic_barrier ( mod_s ) ; label1 = NULL ; if ( ! is_weak ) { label1 = gen_label_rtx ( ) ; emit_label ( label1 ) ; } label2 = gen_label_rtx ( ) ; arm_emit_load_exclusive ( mode , rval , mem , use_acquire ) ; if ( TARGET_32BIT ) { cond = arm_gen_compare_reg ( NE , rval , oldval , neg_bval ) ; x = gen_rtx_NE ( VOIDmode , cond , const0_rtx ) ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , x , gen_rtx_LABEL_REF ( Pmode , label2 ) , pc_rtx ) ; emit_unlikely_jump ( gen_rtx_SET ( pc_rtx , x ) ) ; } else { cond = gen_rtx_NE ( VOIDmode , rval , oldval ) ; if ( thumb1_cmpneg_operand ( oldval , SImode ) ) { rtx src = rval ; if ( ! satisfies_constraint_L ( oldval ) ) { gcc_assert ( satisfies_constraint_J ( oldval ) ) ; emit_move_insn ( neg_bval , rval ) ; src = neg_bval ; } emit_unlikely_jump ( gen_cbranchsi4_neg_late ( neg_bval , src , oldval , label2 , cond ) ) ; } else { emit_move_insn ( neg_bval , const1_rtx ) ; emit_unlikely_jump ( gen_cbranchsi4_insn ( cond , rval , oldval , label2 ) ) ; } } arm_emit_store_exclusive ( mode , neg_bval , mem , newval , use_release ) ; if ( TARGET_32BIT ) { cond = gen_rtx_REG ( CCmode , CC_REGNUM ) ; x = gen_rtx_COMPARE ( CCmode , neg_bval , const0_rtx ) ; emit_insn ( gen_rtx_SET ( cond , x ) ) ; } if ( ! is_weak ) { x = gen_rtx_NE ( VOIDmode , neg_bval , const0_rtx ) ; emit_unlikely_jump ( gen_cbranchsi4 ( x , neg_bval , const0_rtx , label1 ) ) ; } if ( ! is_mm_relaxed ( mod_f ) ) emit_label ( label2 ) ; if ( is_armv8_sync || ! ( use_acquire || use_release ) ) arm_post_atomic_barrier ( mod_s ) ; if ( is_mm_relaxed ( mod_f ) ) emit_label ( label2 ) ; } </s>

Split a compare and swap pattern . It is IMPLEMENTATION DEFINED whether another memory store between the load-exclusive and store-exclusive can reset the monitor from Exclusive to Open state . This means we must wait until after reload to split the pattern , lest we get a register spill in the middle of the atomic sequence .


<s> int arm_split_constant ( enum rtx_code code , machine_mode mode , rtx insn , HOST_WIDE_INT val , rtx target , rtx source , int subtargets ) { rtx cond ; if ( insn && GET_CODE ( PATTERN ( insn ) ) == COND_EXEC ) cond = COND_EXEC_TEST ( PATTERN ( insn ) ) ; else cond = NULL_RTX ; if ( subtargets || code == SET || ( REG_P ( target ) && REG_P ( source ) && REGNO ( target ) != REGNO ( source ) ) ) { if ( ! cfun -> machine -> after_arm_reorg && ! cond && ( arm_gen_constant ( code , mode , NULL_RTX , val , target , source , 1 , 0 ) > ( arm_constant_limit ( optimize_function_for_size_p ( cfun ) ) + ( code != SET ) ) ) ) { if ( code == SET ) { if ( TARGET_USE_MOVT ) arm_emit_movpair ( target , GEN_INT ( val ) ) ; else emit_set_insn ( target , GEN_INT ( val ) ) ; return 1 ; } else { rtx temp = subtargets ? gen_reg_rtx ( mode ) : target ; if ( TARGET_USE_MOVT ) arm_emit_movpair ( temp , GEN_INT ( val ) ) ; else emit_set_insn ( temp , GEN_INT ( val ) ) ; if ( code == MINUS ) emit_set_insn ( target , gen_rtx_MINUS ( mode , temp , source ) ) ; else emit_set_insn ( target , gen_rtx_fmt_ee ( code , mode , source , temp ) ) ; return 2 ; } } } return arm_gen_constant ( code , mode , cond , val , target , source , subtargets , 1 ) ; } </s>

Emit a sequence of insns to handle a large constant . CODE is the code of the operation required , it can be any of SET , PLUS , IOR , AND , XOR , MINUS ; MODE is the mode in which the operation is being performed ; VAL is the integer to operate on ; SOURCE is the other operand ( a register , or a null-pointer for SET ) ; SUBTARGETS means it is safe to create scratch registers if that will either produce a simpler sequence , or we will want to cse the values . Return value is the number of insns emitted .


<s> static tree arm_stack_protect_guard ( void ) { if ( arm_stack_protector_guard == SSP_GLOBAL ) return default_stack_protect_guard ( ) ; return NULL_TREE ; } </s>

Implement TARGET_STACK_PROTECT_GUARD . In case of a global variable based guard use the default else return a null tree .


<s> rtx arm_stack_protect_tls_canary_mem ( bool reload ) { rtx tp = gen_reg_rtx ( SImode ) ; if ( reload ) emit_insn ( gen_reload_tp_hard ( tp ) ) ; else emit_insn ( gen_load_tp_hard ( tp ) ) ; rtx reg = gen_reg_rtx ( SImode ) ; rtx offset = GEN_INT ( arm_stack_protector_guard_offset ) ; emit_set_insn ( reg , gen_rtx_PLUS ( SImode , tp , offset ) ) ; return gen_rtx_MEM ( SImode , reg ) ; } </s>

Generate insns that produce the address of the stack canary


<s> const char * arm_strip_name_encoding ( const char * name ) { int skip ; while ( ( skip = arm_get_strip_length ( * name ) ) ) name += skip ; return name ; } </s>

Return a pointer to a function 's name with any and all prefix encodings stripped from it .


<s> static void arm_test_cpu_arch_data ( void ) { const arch_option * arch ; const cpu_option * cpu ; auto_sbitmap target_isa ( isa_num_bits ) ; auto_sbitmap isa1 ( isa_num_bits ) ; auto_sbitmap isa2 ( isa_num_bits ) ; for ( arch = all_architectures ; arch -> common . name != NULL ; ++ arch ) { const cpu_arch_extension * ext1 , * ext2 ; if ( arch -> common . extensions == NULL ) continue ; arm_initialize_isa ( target_isa , arch -> common . isa_bits ) ; for ( ext1 = arch -> common . extensions ; ext1 -> name != NULL ; ++ ext1 ) { if ( ext1 -> alias ) continue ; arm_initialize_isa ( isa1 , ext1 -> isa_bits ) ; for ( ext2 = ext1 + 1 ; ext2 -> name != NULL ; ++ ext2 ) { if ( ext2 -> alias || ext1 -> remove != ext2 -> remove ) continue ; arm_initialize_isa ( isa2 , ext2 -> isa_bits ) ; ASSERT_TRUE ( ! bitmap_subset_p ( isa2 , isa1 ) ) ; ASSERT_TRUE ( ! bitmap_intersect_p ( isa2 , target_isa ) ) ; } } } for ( cpu = all_cores ; cpu -> common . name != NULL ; ++ cpu ) { const cpu_arch_extension * ext1 , * ext2 ; if ( cpu -> common . extensions == NULL ) continue ; arm_initialize_isa ( target_isa , arch -> common . isa_bits ) ; for ( ext1 = cpu -> common . extensions ; ext1 -> name != NULL ; ++ ext1 ) { if ( ext1 -> alias ) continue ; arm_initialize_isa ( isa1 , ext1 -> isa_bits ) ; for ( ext2 = ext1 + 1 ; ext2 -> name != NULL ; ++ ext2 ) { if ( ext2 -> alias || ext1 -> remove != ext2 -> remove ) continue ; arm_initialize_isa ( isa2 , ext2 -> isa_bits ) ; ASSERT_TRUE ( ! bitmap_subset_p ( isa2 , isa1 ) ) ; ASSERT_TRUE ( ! bitmap_intersect_p ( isa2 , target_isa ) ) ; } } } } </s>

Scan the static data tables generated by parsecpu.awk looking for potential issues with the data . We primarily check for inconsistencies in the option extensions at present ( extensions that duplicate others but are n't marked as aliases ) . Furthermore , for correct canonicalization later options must never be a subset of an earlier option . Any extension should also only specify other feature bits and never an architecture bit . The architecture is inferred from the declaration of the extension .


"Error: found feature bits in the ALL_FPU_INTERAL"

" group that are not defined by any FPU.\n"

Scan the static data tables generated by parsecpu.awk looking for potential issues with the data . Here we check for consistency between the fpu bits , in particular we check that ISA_ALL_FPU_INTERNAL does not contain a feature bit that is not defined by any FPU flag .


"accessing thread-local storage is not currently supported "

"with %<-mpure-code%> or %<-mslow-flash-data%>"

Return TRUE if X contains any TLS symbol references .


<s> static rtx arm_trampoline_adjust_address ( rtx addr ) { if ( TARGET_THUMB && ! TARGET_FDPIC ) addr = expand_simple_binop ( Pmode , IOR , addr , const1_rtx , NULL , 0 , OPTAB_LIB_WIDEN ) ; return addr ; } </s>

Thumb trampolines should be entered in thumb mode , so set the bottom bit of the address .


<s> static void arm_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr , mem , a_tramp ; emit_block_move ( m_tramp , assemble_trampoline_template ( ) , GEN_INT ( TRAMPOLINE_SIZE ) , BLOCK_OP_NORMAL ) ; if ( TARGET_FDPIC ) { rtx funcdesc = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx fnaddr = gen_rtx_MEM ( Pmode , funcdesc ) ; rtx gotaddr = gen_rtx_MEM ( Pmode , plus_constant ( Pmode , funcdesc , 4 ) ) ; rtx trampoline_code_start = plus_constant ( Pmode , XEXP ( m_tramp , 0 ) , TARGET_THUMB2 ? 9 : 8 ) ; mem = adjust_address ( m_tramp , SImode , 0 ) ; emit_move_insn ( mem , trampoline_code_start ) ; mem = adjust_address ( m_tramp , SImode , 4 ) ; emit_move_insn ( mem , gen_rtx_REG ( Pmode , PIC_OFFSET_TABLE_REGNUM ) ) ; mem = adjust_address ( m_tramp , SImode , 20 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , 24 ) ; emit_move_insn ( mem , gotaddr ) ; mem = adjust_address ( m_tramp , SImode , 28 ) ; emit_move_insn ( mem , fnaddr ) ; } else { mem = adjust_address ( m_tramp , SImode , TARGET_32BIT ? 8 : 12 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , TARGET_32BIT ? 12 : 16 ) ; fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; emit_move_insn ( mem , fnaddr ) ; } a_tramp = XEXP ( m_tramp , 0 ) ; maybe_emit_call_builtin___clear_cache ( a_tramp , plus_constant ( ptr_mode , a_tramp , TRAMPOLINE_SIZE ) ) ; } </s>

Emit RTL insns to initialize the variable parts of a trampoline .


<s>
static
void
arm_unwind_emit
(
FILE
*
out_file
,
rtx_insn
*
insn
)
{
rtx
note
,
pat
;
bool
handled_one
=
false
;
if
(
arm_except_unwind_info
(
&
global_options
)
!=
UI_TARGET
)
return
;
if
(
!
(
flag_unwind_tables
||
crtl
->
uses_eh_lsda
)
&&
(
TREE_NOTHROW
(
current_function_decl
)
||
crtl
->
all_throwers_are_sibcalls
)
)
return
;
if
(
NOTE_P
(
insn
)
||
!
RTX_FRAME_RELATED_P
(
insn
)
)
return
;
for
(
note
=
REG_NOTES
(
insn
)
;
note
;
note
=
XEXP
(
note
,
1
)
)
{
switch
(
REG_NOTE_KIND
(
note
)
)
{
case
REG_FRAME_RELATED_EXPR
:
pat
=
XEXP
(
note
,
0
)
;
goto
found
;
case
REG_CFA_REGISTER
:
pat
=
XEXP
(
note
,
0
)
;
if
(
pat
==
)
{
pat
=
PATTERN
(
insn
)
;
if
(
GET_CODE
(
pat
)
==
PARALLEL
)
pat
=
XVECEXP
(
pat
,
0
,
0
)
;
}
{
rtx
dest
,
src
;
unsigned
reg
;
src
=
SET_SRC
(
pat
)
;
dest
=
SET_DEST
(
pat
)
;
gcc_assert
(
src
==
stack_pointer_rtx
)
;
reg
=
REGNO
(
dest
)
;
asm_fprintf
(
out_file
,
"\t.unwind_raw 0, 0x%x @ vsp = r%d\n"
,
reg
+
0x90
,
reg
)
;
}
handled_one
=
true
;
break
;
case
REG_CFA_DEF_CFA
:
case
REG_CFA_ADJUST_CFA
:
case
REG_CFA_RESTORE
:
return
;
case
REG_CFA_EXPRESSION
:
case
REG_CFA_OFFSET
:
gcc_unreachable
(
)
;
default
:
break
;
}
}
if
(
handled_one
)
return
;
pat
=
PATTERN
(
insn
)
;
found
:
switch
(
GET_CODE
(
pat
)
)
{
case
SET
:
arm_unwind_emit_set
(
out_file
,
pat
)
;
break
;
case
SEQUENCE
:
arm_unwind_emit_sequence
(
out_file
,
pat
)
;
break
;
default
:
abort
(
)
;
}
}
</s>

Emit unwind directives for the given insn .