<s> virtual unsigned int execute ( function * ) { return rest_of_insert_bti ( ) ; } </s>


<s> static unsigned int rest_of_insert_bti ( void ) { timevar_push ( TV_MACH_DEP ) ; rtx bti_insn ; rtx_insn * insn ; basic_block bb ; bb = 0 ; FOR_EACH_BB_FN ( bb , cfun ) { for ( insn = BB_HEAD ( bb ) ; insn != NEXT_INSN ( BB_END ( bb ) ) ; insn = NEXT_INSN ( insn ) ) { if ( LABEL_P ( insn ) && ( LABEL_PRESERVE_P ( insn ) || bb -> flags & BB_NON_LOCAL_GOTO_TARGET ) ) { bti_insn = aarch_gen_bti_j ( ) ; emit_insn_after ( bti_insn , insn ) ; continue ; } if ( JUMP_P ( insn ) ) { rtx_jump_table_data * table ; if ( tablejump_p ( insn , NULL , & table ) ) { rtvec vec = table -> get_labels ( ) ; int j ; rtx_insn * label ; for ( j = GET_NUM_ELEM ( vec ) - 1 ; j >= 0 ; -- j ) { label = as_a < rtx_insn * > ( XEXP ( RTVEC_ELT ( vec , j ) , 0 ) ) ; rtx_insn * next = next_nonnote_nondebug_insn ( label ) ; if ( aarch_bti_j_insn_p ( next ) ) continue ; bti_insn = aarch_gen_bti_j ( ) ; emit_insn_after ( bti_insn , label ) ; } } } if ( CALL_P ( insn ) && ( find_reg_note ( insn , REG_SETJMP , NULL ) ) ) { bti_insn = aarch_gen_bti_j ( ) ; emit_insn_after ( bti_insn , insn ) ; continue ; } } } if ( ! cgraph_node :: get ( cfun -> decl ) -> only_called_directly_p ( ) ) { bb = ENTRY_BLOCK_PTR_FOR_FN ( cfun ) -> next_bb ; insn = BB_HEAD ( bb ) ; if ( ! aarch_pac_insn_p ( get_first_nonnote_insn ( ) ) ) { bti_insn = aarch_gen_bti_c ( ) ; emit_insn_before ( bti_insn , insn ) ; } } timevar_pop ( TV_MACH_DEP ) ; return 0 ; } </s>

This is implemented as a late RTL pass that runs before branch shortening and does the following .


<s> enum aarch_parse_opt_result aarch_parse_branch_protection ( const char * const_str , char * * last_str ) { char * str_root = xstrdup ( const_str ) ; char * token_save = NULL ; char * str = strtok_r ( str_root , "+" , & token_save ) ; enum aarch_parse_opt_result res = AARCH_PARSE_OK ; if ( ! str ) res = AARCH_PARSE_MISSING_ARG ; else { char * next_str = strtok_r ( NULL , "+" , & token_save ) ; aarch_handle_no_branch_protection ( NULL , NULL ) ; while ( str && res == AARCH_PARSE_OK ) { const aarch_branch_protect_type * type = aarch_branch_protect_types ; bool found = false ; while ( type && type -> name && ! found && res == AARCH_PARSE_OK ) { if ( strcmp ( str , type -> name ) == 0 ) { found = true ; res = type -> handler ( str , next_str ) ; str = next_str ; next_str = strtok_r ( NULL , "+" , & token_save ) ; } else type ++ ; } if ( found && res == AARCH_PARSE_OK ) { bool found_subtype = true ; while ( found_subtype ) { found_subtype = false ; const aarch_branch_protect_type * subtype = type -> subtypes ; while ( str && subtype && subtype -> name && ! found_subtype && res == AARCH_PARSE_OK ) { if ( strcmp ( str , subtype -> name ) == 0 ) { found_subtype = true ; res = subtype -> handler ( str , next_str ) ; str = next_str ; next_str = strtok_r ( NULL , "+" , & token_save ) ; } else subtype ++ ; } } } else if ( ! found ) res = AARCH_PARSE_INVALID_ARG ; } } if ( last_str ) { if ( str ) strcpy ( * last_str , str ) ; else * last_str = NULL ; } if ( res == AARCH_PARSE_OK ) { if ( ! accepted_branch_protection_string ) accepted_branch_protection_string = ( char * ) xmalloc ( BRANCH_PROTECT_STR_MAX + 1 ) ; strncpy ( accepted_branch_protection_string , const_str , BRANCH_PROTECT_STR_MAX + 1 ) ; accepted_branch_protection_string [ BRANCH_PROTECT_STR_MAX ] = '\0' ; } return res ; } </s>

Parses CONST_STR for branch protection features specified in aarch64_branch_protect_types , and set any global variables required . Returns the parsing result and assigns LAST_STR to the last processed token from CONST_STR so that it can be used for error reporting .


<s> int aarch_crypto_can_dual_issue ( rtx_insn * producer_insn , rtx_insn * consumer_insn ) { rtx producer_set , consumer_set ; rtx producer_src , consumer_src ; producer_set = single_set ( producer_insn ) ; consumer_set = single_set ( consumer_insn ) ; producer_src = producer_set ? SET_SRC ( producer_set ) : NULL ; consumer_src = consumer_set ? SET_SRC ( consumer_set ) : NULL ; if ( producer_src && consumer_src && GET_CODE ( producer_src ) == UNSPEC && GET_CODE ( consumer_src ) == UNSPEC && ( ( XINT ( producer_src , 1 ) == UNSPEC_AESE && XINT ( consumer_src , 1 ) == UNSPEC_AESMC ) || ( XINT ( producer_src , 1 ) == UNSPEC_AESD && XINT ( consumer_src , 1 ) == UNSPEC_AESIMC ) ) ) { unsigned int regno = REGNO ( SET_DEST ( producer_set ) ) ; return REGNO ( SET_DEST ( consumer_set ) ) == regno && REGNO ( XVECEXP ( consumer_src , 0 , 0 ) ) == regno ; } return 0 ; } </s>

In ARMv8-A there 's a general expectation that AESE/AESMC and AESD/AESIMC sequences of the form : AESE Vn , _ AESMC Vn , Vn will issue both instructions in a single cycle on super-scalar implementations . This function identifies such pairs .


<s> int arm_no_early_alu_shift_dep ( rtx producer , rtx consumer ) { rtx value , op ; rtx early_op ; if ( ! arm_get_set_operands ( producer , consumer , & value , & op ) ) return 0 ; if ( ( early_op = arm_find_shift_sub_rtx ( op ) ) ) { if ( REG_P ( early_op ) ) early_op = op ; return ! reg_overlap_mentioned_p ( value , early_op ) ; } return 0 ; } </s>

Return nonzero if the CONSUMER instruction ( an ALU op ) does not have an early register shift value or amount dependency on the result of PRODUCER .


<s> int aarch_crypto_can_dual_issue ( rtx_insn * producer_insn , rtx_insn * consumer_insn ) { rtx producer_set , consumer_set ; rtx producer_src , consumer_src ; producer_set = single_set ( producer_insn ) ; consumer_set = single_set ( consumer_insn ) ; producer_src = producer_set ? SET_SRC ( producer_set ) : NULL ; consumer_src = consumer_set ? SET_SRC ( consumer_set ) : NULL ; if ( producer_src && consumer_src && GET_CODE ( producer_src ) == UNSPEC && GET_CODE ( consumer_src ) == UNSPEC && ( ( XINT ( producer_src , 1 ) == UNSPEC_AESE && XINT ( consumer_src , 1 ) == UNSPEC_AESMC ) || ( XINT ( producer_src , 1 ) == UNSPEC_AESD && XINT ( consumer_src , 1 ) == UNSPEC_AESIMC ) ) ) { unsigned int regno = REGNO ( SET_DEST ( producer_set ) ) ; return ( REGNO ( SET_DEST ( consumer_set ) ) == regno || ! reload_completed ) && REGNO ( XVECEXP ( consumer_src , 0 , 0 ) ) == regno ; } return 0 ; } </s>


Return nonzero if the CONSUMER instruction is some sort of arithmetic or logic + shift operation , and the register we are writing in PRODUCER is not used in a register shift by register operation .


<s> int aarch_accumulator_forwarding ( rtx_insn * producer , rtx_insn * consumer ) { rtx producer_set = single_set ( producer ) ; rtx consumer_set = single_set ( consumer ) ; if ( ! producer_set || ! consumer_set ) return 0 ; rtx dest = SET_DEST ( producer_set ) ; rtx mla = SET_SRC ( consumer_set ) ; if ( ! REG_P ( dest ) ) return 0 ; rtx accumulator ; if ( GET_CODE ( mla ) == ZERO_EXTEND ) mla = XEXP ( mla , 0 ) ; switch ( GET_CODE ( mla ) ) { case PLUS : if ( GET_CODE ( XEXP ( mla , 0 ) ) == MULT ) accumulator = XEXP ( mla , 1 ) ; else return 0 ; break ; case MINUS : if ( GET_CODE ( XEXP ( mla , 1 ) ) == MULT ) accumulator = XEXP ( mla , 0 ) ; else return 0 ; break ; case FMA : { if ( REG_P ( XEXP ( mla , 1 ) ) && REG_P ( XEXP ( mla , 2 ) ) && ( REG_P ( XEXP ( mla , 0 ) ) || GET_CODE ( XEXP ( mla , 0 ) ) == NEG ) ) { accumulator = XEXP ( mla , 2 ) ; } else if ( REG_P ( XEXP ( mla , 1 ) ) && GET_CODE ( XEXP ( mla , 2 ) ) == NEG && ( REG_P ( XEXP ( mla , 0 ) ) || GET_CODE ( XEXP ( mla , 0 ) ) == NEG ) ) { accumulator = XEXP ( XEXP ( mla , 2 ) , 0 ) ; } else return 0 ; break ; } default : return 0 ; } if ( SUBREG_P ( accumulator ) ) accumulator = SUBREG_REG ( accumulator ) ; if ( ! REG_P ( accumulator ) ) return 0 ; return ( REGNO ( dest ) == REGNO ( accumulator ) ) ; } </s>

Return non-zero if the destination of PRODUCER feeds the accumulator operand of an MLA-like operation .


<s> bool aarch_mm_needs_acquire ( rtx const_int ) { enum memmodel model = memmodel_from_int ( INTVAL ( const_int ) ) ; return ! ( is_mm_relaxed ( model ) || is_mm_consume ( model ) || is_mm_release ( model ) ) ; } </s>

Return non-zero if the RTX representing a memory model is a memory model that needs acquire semantics .


<s> bool aarch_mm_needs_release ( rtx const_int ) { enum memmodel model = memmodel_from_int ( INTVAL ( const_int ) ) ; return ! ( is_mm_relaxed ( model ) || is_mm_consume ( model ) || is_mm_acquire ( model ) ) ; } </s>

Return non-zero if the RTX representing a memory model is a memory model that needs release semantics .


<s> bool aarch_rev16_p ( rtx x ) { rtx left_sub_rtx , right_sub_rtx ; bool is_rev = false ; if ( GET_CODE ( x ) != IOR ) return false ; left_sub_rtx = XEXP ( x , 0 ) ; right_sub_rtx = XEXP ( x , 1 ) ; is_rev = aarch_rev16_p_1 ( left_sub_rtx , right_sub_rtx , GET_MODE ( x ) ) ; if ( ! is_rev ) is_rev = aarch_rev16_p_1 ( right_sub_rtx , left_sub_rtx , GET_MODE ( x ) ) ; return is_rev ; } </s>

Recognise a sequence of bitwise operations corresponding to a rev16 operation . These will be of the form : ( ( x > > 8 ) & 0x00ff00ff ) | ( ( x < < 8 ) & 0xff00ff00 ) for SImode and with similar but wider bitmasks for DImode . The two sub-expressions of the IOR can appear on either side so check both permutations with the help of aarch_rev16_p_1 above .


<s> int arm_early_load_addr_dep ( rtx producer , rtx consumer ) { rtx value , addr ; if ( ! arm_get_set_operands ( producer , consumer , & value , & addr ) ) return 0 ; return reg_overlap_mentioned_p ( value , addr ) ; } </s>

Return nonzero if the CONSUMER instruction ( a load ) does need PRODUCER 's value to calculate the address .


<s> int arm_early_load_addr_dep_ptr ( rtx producer , rtx consumer ) { rtx value = arm_find_sub_rtx_with_code ( PATTERN ( producer ) , SET , false ) ; rtx addr = arm_find_sub_rtx_with_code ( PATTERN ( consumer ) , SET , false ) ; if ( ! value || ! addr || ! MEM_P ( SET_SRC ( value ) ) ) return 0 ; value = SET_DEST ( value ) ; addr = SET_SRC ( addr ) ; return GET_MODE ( value ) == Pmode && reg_overlap_mentioned_p ( value , addr ) ; } </s>

Return nonzero if the CONSUMER instruction ( a load ) does need a Pmode PRODUCER 's value to calculate the address .


<s> int arm_early_store_addr_dep ( rtx producer , rtx consumer ) { return ! arm_no_early_store_addr_dep ( producer , consumer ) ; } </s>

Return nonzero if the CONSUMER instruction ( a store ) does need PRODUCER 's value to calculate the address .


<s> int arm_early_store_addr_dep_ptr ( rtx producer , rtx consumer ) { rtx value = arm_find_sub_rtx_with_code ( PATTERN ( producer ) , SET , false ) ; rtx addr = arm_find_sub_rtx_with_code ( PATTERN ( consumer ) , SET , false ) ; if ( ! value || ! addr || ! MEM_P ( SET_SRC ( value ) ) ) return 0 ; value = SET_DEST ( value ) ; addr = SET_DEST ( addr ) ; return GET_MODE ( value ) == Pmode && reg_overlap_mentioned_p ( value , addr ) ; } </s>

Return nonzero if the CONSUMER instruction ( a store ) does need a Pmode PRODUCER 's value to calculate the address .


<s> static rtx arm_find_shift_sub_rtx ( rtx pattern ) { return arm_find_sub_rtx_with_code ( pattern , ASHIFT , true ) ; } </s>

Traverse PATTERN looking for any sub-rtx which looks like a shift .


<s> static rtx arm_find_sub_rtx_with_code ( rtx pattern , rtx_code code , bool find_any_shift ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , pattern , NONCONST ) { rtx x = * iter ; if ( find_any_shift ) { if ( arm_rtx_shift_left_p ( x ) ) return x ; else for ( unsigned int i = 0 ; i < ARRAY_SIZE ( shift_rtx_codes ) ; i ++ ) if ( GET_CODE ( x ) == shift_rtx_codes [ i ] ) return x ; } if ( GET_CODE ( x ) == code ) return x ; } return NULL_RTX ; } </s>

Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE . If FIND_ANY_SHIFT then we are interested in anything which can reasonably be described as a SHIFT RTX .


<s> static int arm_get_set_operands ( rtx producer , rtx consumer , rtx * set_source , rtx * set_destination ) { rtx set_producer = arm_find_sub_rtx_with_code ( PATTERN ( producer ) , SET , false ) ; rtx set_consumer = arm_find_sub_rtx_with_code ( PATTERN ( consumer ) , SET , false ) ; if ( set_producer && set_consumer ) { * set_source = SET_DEST ( set_producer ) ; * set_destination = SET_SRC ( set_consumer ) ; return 1 ; } return 0 ; } </s>

PRODUCER and CONSUMER are two potentially dependant RTX . PRODUCER ( possibly ) contains a SET which will provide a result we can access using the SET_DEST macro . We will place the RTX which would be written by PRODUCER in SET_SOURCE . Similarly , CONSUMER ( possibly ) contains a SET which has an operand we can access using SET_SRC . We place this operand in SET_DESTINATION . Return nonzero if we found the SET RTX we expected .


<s> int arm_mac_accumulator_is_mul_result ( rtx producer , rtx consumer ) { rtx mul = PATTERN ( producer ) ; rtx mac = PATTERN ( consumer ) ; rtx mul_result ; rtx mac_op0 , mac_op1 , mac_acc ; if ( GET_CODE ( mul ) == COND_EXEC ) mul = COND_EXEC_CODE ( mul ) ; if ( GET_CODE ( mac ) == COND_EXEC ) mac = COND_EXEC_CODE ( mac ) ; if ( ( GET_CODE ( mul ) != SET || GET_CODE ( XEXP ( mul , 1 ) ) != MULT ) || ( GET_CODE ( mac ) != SET || GET_CODE ( XEXP ( mac , 1 ) ) != PLUS || GET_CODE ( XEXP ( XEXP ( mac , 1 ) , 0 ) ) != MULT ) ) return 0 ; mul_result = XEXP ( mul , 0 ) ; mac_op0 = XEXP ( XEXP ( XEXP ( mac , 1 ) , 0 ) , 0 ) ; mac_op1 = XEXP ( XEXP ( XEXP ( mac , 1 ) , 0 ) , 1 ) ; mac_acc = XEXP ( XEXP ( mac , 1 ) , 1 ) ; return ( reg_overlap_mentioned_p ( mul_result , mac_acc ) && ! reg_overlap_mentioned_p ( mul_result , mac_op0 ) && ! reg_overlap_mentioned_p ( mul_result , mac_op1 ) ) ; } </s>

Return non-zero if the consumer ( a multiply-accumulate instruction ) has an accumulator dependency on the result of the producer ( a multiplication instruction ) and no other dependency on that result .


<s> int arm_mac_accumulator_is_result ( rtx producer , rtx consumer ) { rtx result ; rtx op0 , op1 , acc ; producer = PATTERN ( producer ) ; consumer = PATTERN ( consumer ) ; if ( GET_CODE ( producer ) == COND_EXEC ) producer = COND_EXEC_CODE ( producer ) ; if ( GET_CODE ( consumer ) == COND_EXEC ) consumer = COND_EXEC_CODE ( consumer ) ; if ( GET_CODE ( producer ) != SET ) return 0 ; result = XEXP ( producer , 0 ) ; if ( GET_CODE ( consumer ) != SET ) return 0 ; if ( GET_CODE ( XEXP ( consumer , 1 ) ) == PLUS ) { if ( GET_CODE ( XEXP ( XEXP ( consumer , 1 ) , 0 ) ) != MULT ) return 0 ; op0 = XEXP ( XEXP ( XEXP ( consumer , 1 ) , 0 ) , 0 ) ; op1 = XEXP ( XEXP ( XEXP ( consumer , 1 ) , 0 ) , 1 ) ; acc = XEXP ( XEXP ( consumer , 1 ) , 1 ) ; } else if ( GET_CODE ( XEXP ( consumer , 1 ) ) == MINUS ) { if ( GET_CODE ( XEXP ( XEXP ( consumer , 1 ) , 1 ) ) != MULT ) return 0 ; op0 = XEXP ( XEXP ( XEXP ( consumer , 1 ) , 1 ) , 0 ) ; op1 = XEXP ( XEXP ( XEXP ( consumer , 1 ) , 1 ) , 1 ) ; acc = XEXP ( XEXP ( consumer , 1 ) , 0 ) ; } else return 0 ; return ( reg_overlap_mentioned_p ( result , acc ) && ! reg_overlap_mentioned_p ( result , op0 ) && ! reg_overlap_mentioned_p ( result , op1 ) ) ; } </s>

Return non-zero iff the consumer ( a multiply-accumulate or a multiple-subtract instruction ) has an accumulator dependency on the result of the producer and no other dependency on that result . It does not check if the producer is multiply-accumulate instruction .


<s> int arm_no_early_alu_shift_dep ( rtx producer , rtx consumer ) { rtx value , op ; rtx early_op ; if ( ! arm_get_set_operands ( producer , consumer , & value , & op ) ) return 0 ; if ( ( early_op = arm_find_shift_sub_rtx ( op ) ) ) return ! reg_overlap_mentioned_p ( value , early_op ) ; return 0 ; } </s>


<s> int arm_no_early_alu_shift_value_dep ( rtx producer , rtx consumer ) { rtx value , op ; rtx early_op ; if ( ! arm_get_set_operands ( producer , consumer , & value , & op ) ) return 0 ; if ( ( early_op = arm_find_shift_sub_rtx ( op ) ) ) if ( ! reg_overlap_mentioned_p ( value , XEXP ( early_op , 0 ) ) ) return 1 ; return 0 ; } </s>

Return nonzero if the CONSUMER instruction ( an ALU op ) does not have an early register shift value dependency on the result of PRODUCER .


<s> int arm_no_early_mul_dep ( rtx producer , rtx consumer ) { rtx value , op ; if ( ! arm_get_set_operands ( producer , consumer , & value , & op ) ) return 0 ; if ( GET_CODE ( op ) == PLUS || GET_CODE ( op ) == MINUS ) { if ( GET_CODE ( XEXP ( op , 0 ) ) == MULT ) return ! reg_overlap_mentioned_p ( value , XEXP ( op , 0 ) ) ; else return ! reg_overlap_mentioned_p ( value , XEXP ( op , 1 ) ) ; } return 0 ; } </s>

Return nonzero if the CONSUMER ( a mul or mac op ) does not have an early register mult dependency on the result of PRODUCER .


<s> int arm_no_early_store_addr_dep ( rtx producer , rtx consumer ) { rtx value = arm_find_sub_rtx_with_code ( PATTERN ( producer ) , SET , false ) ; rtx addr = arm_find_sub_rtx_with_code ( PATTERN ( consumer ) , SET , false ) ; if ( value ) value = SET_DEST ( value ) ; if ( addr ) addr = SET_DEST ( addr ) ; if ( ! value || ! addr ) return 0 ; return ! reg_overlap_mentioned_p ( value , addr ) ; } </s>

Return nonzero if the CONSUMER instruction ( a store ) does not need PRODUCER 's value to calculate the address .


<s> bool arm_rtx_shift_left_p ( rtx x ) { enum rtx_code code = GET_CODE ( x ) ; if ( code == MULT && CONST_INT_P ( XEXP ( x , 1 ) ) && exact_log2 ( INTVAL ( XEXP ( x , 1 ) ) ) > 0 ) return true ; if ( code == ASHIFT ) return true ; return false ; } </s>

Return TRUE if X is either an arithmetic shift left , or is a multiplication by a power of two .


<s> static void arm_init_builtin ( unsigned int fcode , arm_builtin_datum * d , const char * prefix ) { bool print_type_signature_p = false ; char type_signature [ SIMD_MAX_BUILTIN_ARGS ] = { 0 } ; char namebuf [ 60 ] ; tree ftype = NULL ; tree fndecl = NULL ; d -> fcode = fcode ; int op_num = insn_data [ d -> code ] . n_operands - 1 ; int arg_num = d -> qualifiers [ 0 ] & qualifier_void ? op_num + 1 : op_num ; tree return_type = void_type_node , args = void_list_node ; tree eltype ; for ( ; op_num >= 0 ; arg_num -- , op_num -- ) { machine_mode op_mode = insn_data [ d -> code ] . operand [ op_num ] . mode ; enum arm_type_qualifiers qualifiers = d -> qualifiers [ arg_num ] ; if ( qualifiers & qualifier_unsigned ) { type_signature [ arg_num ] = 'u' ; print_type_signature_p = true ; } else if ( qualifiers & qualifier_poly ) { type_signature [ arg_num ] = 'p' ; print_type_signature_p = true ; } else type_signature [ arg_num ] = 's' ; if ( qualifiers & qualifier_internal ) continue ; if ( qualifiers & qualifier_map_mode ) op_mode = d -> mode ; if ( qualifiers & qualifier_predicate ) op_mode = HImode ; if ( qualifiers & qualifier_pointer && VECTOR_MODE_P ( op_mode ) ) op_mode = GET_MODE_INNER ( op_mode ) ; if ( qualifiers & qualifier_void_pointer ) eltype = qualifiers & qualifier_const ? const_ptr_type_node : ptr_type_node ; else { eltype = arm_simd_builtin_type ( op_mode , qualifiers ) ; gcc_assert ( eltype != NULL ) ; if ( qualifiers & qualifier_const ) eltype = build_qualified_type ( eltype , TYPE_QUAL_CONST ) ; if ( qualifiers & qualifier_pointer ) eltype = build_pointer_type ( eltype ) ; } if ( arg_num == 0 ) return_type = eltype ; else args = tree_cons ( NULL_TREE , eltype , args ) ; } ftype = build_function_type ( return_type , args ) ; gcc_assert ( ftype != NULL ) ; if ( print_type_signature_p && IN_RANGE ( fcode , ARM_BUILTIN_VFP_BASE , ARM_BUILTIN_ACLE_BASE - 1 ) ) snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s_%s" , prefix , d -> name , type_signature ) ; else snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s" , prefix , d -> name ) ; fndecl = add_builtin_function ( namebuf , ftype , fcode , BUILT_IN_MD , NULL , NULL_TREE ) ; arm_builtin_decls [ fcode ] = fndecl ; } </s>

Set up a builtin . It will use information stored in the argument struct D to derive the builtin 's type signature and name . It will append the name in D to the PREFIX passed and use these to create a builtin declaration that is then stored in 'arm_builtin_decls ' under index FCODE . This FCODE is also written back to D for future use .


<s> static rtx arm_expand_neon_builtin ( int fcode , tree exp , rtx target ) { neon_builtin_datum * d = & neon_builtin_data [ fcode - ARM_BUILTIN_NEON_BASE ] ; enum insn_code icode = d -> code ; builtin_arg args [ SIMD_MAX_BUILTIN_ARGS ] ; int num_args = insn_data [ d -> code ] . n_operands ; int is_void = 0 ; int k ; is_void = ! ! ( d -> qualifiers [ 0 ] & qualifier_void ) ; num_args += is_void ; for ( k = 1 ; k < num_args ; k ++ ) { int qualifiers_k = k ; int operands_k = k - is_void ; int expr_args_k = k - 1 ; if ( d -> qualifiers [ qualifiers_k ] & qualifier_immediate ) args [ k ] = NEON_ARG_CONSTANT ; else if ( d -> qualifiers [ qualifiers_k ] & qualifier_maybe_immediate ) { rtx arg = expand_normal ( CALL_EXPR_ARG ( exp , ( expr_args_k ) ) ) ; bool op_const_int_p = ( CONST_INT_P ( arg ) && ( * insn_data [ icode ] . operand [ operands_k ] . predicate ) ( arg , insn_data [ icode ] . operand [ operands_k ] . mode ) ) ; args [ k ] = op_const_int_p ? NEON_ARG_CONSTANT : NEON_ARG_COPY_TO_REG ; } else if ( d -> qualifiers [ qualifiers_k ] & qualifier_pointer ) args [ k ] = NEON_ARG_MEMORY ; else args [ k ] = NEON_ARG_COPY_TO_REG ; } args [ k ] = NEON_ARG_STOP ; return arm_expand_neon_args ( target , d -> mode , fcode , icode , ! is_void , exp , args [ 1 ] , args [ 2 ] , args [ 3 ] , args [ 4 ] , NEON_ARG_STOP ) ; } </s>

Expand a Neon builtin , i.e . those registered only if TARGET_NEON holds . Most of these are `` special '' because they do n't have symbolic constants defined per-instruction or per instruction-variant . Instead , the required info is looked up in the table neon_builtin_data .


<s> static rtx arm_expand_ternop_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; tree arg1 = CALL_EXPR_ARG ( exp , 1 ) ; tree arg2 = CALL_EXPR_ARG ( exp , 2 ) ; rtx op0 = expand_normal ( arg0 ) ; rtx op1 = expand_normal ( arg1 ) ; rtx op2 = expand_normal ( arg2 ) ; rtx op3 = NULL_RTX ; bool builtin_sha1cpm_p = false ; if ( insn_data [ icode ] . n_operands == 5 ) { gcc_assert ( icode == CODE_FOR_crypto_sha1c || icode == CODE_FOR_crypto_sha1p || icode == CODE_FOR_crypto_sha1m ) ; builtin_sha1cpm_p = true ; } machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; machine_mode mode1 = insn_data [ icode ] . operand [ 2 ] . mode ; machine_mode mode2 = insn_data [ icode ] . operand [ 3 ] . mode ; if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( VECTOR_MODE_P ( mode1 ) ) op1 = safe_vector_operand ( op1 , mode1 ) ; if ( VECTOR_MODE_P ( mode2 ) ) op2 = safe_vector_operand ( op2 , mode2 ) ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; gcc_assert ( ( GET_MODE ( op0 ) == mode0 || GET_MODE ( op0 ) == VOIDmode ) && ( GET_MODE ( op1 ) == mode1 || GET_MODE ( op1 ) == VOIDmode ) && ( GET_MODE ( op2 ) == mode2 || GET_MODE ( op2 ) == VOIDmode ) ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 2 ] . predicate ) ( op1 , mode1 ) ) op1 = copy_to_mode_reg ( mode1 , op1 ) ; if ( ! ( * insn_data [ icode ] . operand [ 3 ] . predicate ) ( op2 , mode2 ) ) op2 = copy_to_mode_reg ( mode2 , op2 ) ; if ( builtin_sha1cpm_p ) op3 = GEN_INT ( TARGET_BIG_END ? 1 : 0 ) ; if ( builtin_sha1cpm_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 , op2 , op3 ) ; else pat = GEN_FCN ( icode ) ( target , op0 , op1 , op2 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx arm_expand_unop_builtin ( enum insn_code icode , tree exp , rtx target , int do_load ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; rtx op0 = expand_normal ( arg0 ) ; rtx op1 = NULL_RTX ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; bool builtin_sha1h_p = false ; if ( insn_data [ icode ] . n_operands == 3 ) { gcc_assert ( icode == CODE_FOR_crypto_sha1h ) ; builtin_sha1h_p = true ; } if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; if ( do_load ) op0 = gen_rtx_MEM ( mode0 , copy_to_mode_reg ( Pmode , op0 ) ) ; else { if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; } if ( builtin_sha1h_p ) op1 = GEN_INT ( TARGET_BIG_END ? 1 : 0 ) ; if ( builtin_sha1h_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( target , op0 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>

Subroutine of arm_expand_builtin to take care of unop insns .


"You must enable NEON instructions (e.g. -mfloat-abi=softfp -mfpu=neon) to use these intrinsics."

"%Klane index must be a constant immediate"


<s> static void arm_init_neon_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_NEON_PATTERN_START ; arm_init_simd_builtin_types ( ) ; arm_init_simd_builtin_scalar_types ( ) ; tree lane_check_fpr = build_function_type_list ( void_type_node , intSI_type_node , intSI_type_node , NULL ) ; arm_builtin_decls [ ARM_BUILTIN_NEON_LANE_CHECK ] = add_builtin_function ( "__builtin_arm_lane_check" , lane_check_fpr , ARM_BUILTIN_NEON_LANE_CHECK , BUILT_IN_MD , NULL , NULL_TREE ) ; for ( i = 0 ; i < ARRAY_SIZE ( neon_builtin_data ) ; i ++ , fcode ++ ) { bool print_type_signature_p = false ; char type_signature [ SIMD_MAX_BUILTIN_ARGS ] = { 0 } ; neon_builtin_datum * d = & neon_builtin_data [ i ] ; char namebuf [ 60 ] ; tree ftype = NULL ; tree fndecl = NULL ; d -> fcode = fcode ; int op_num = insn_data [ d -> code ] . n_operands - 1 ; int arg_num = d -> qualifiers [ 0 ] & qualifier_void ? op_num + 1 : op_num ; tree return_type = void_type_node , args = void_list_node ; tree eltype ; for ( ; op_num >= 0 ; arg_num -- , op_num -- ) { machine_mode op_mode = insn_data [ d -> code ] . operand [ op_num ] . mode ; enum arm_type_qualifiers qualifiers = d -> qualifiers [ arg_num ] ; if ( qualifiers & qualifier_unsigned ) { type_signature [ arg_num ] = 'u' ; print_type_signature_p = true ; } else if ( qualifiers & qualifier_poly ) { type_signature [ arg_num ] = 'p' ; print_type_signature_p = true ; } else type_signature [ arg_num ] = 's' ; if ( qualifiers & qualifier_internal ) continue ; if ( qualifiers & qualifier_map_mode ) op_mode = d -> mode ; if ( qualifiers & qualifier_pointer && VECTOR_MODE_P ( op_mode ) ) op_mode = GET_MODE_INNER ( op_mode ) ; eltype = arm_simd_builtin_type ( op_mode , ( qualifiers & qualifier_unsigned ) != 0 , ( qualifiers & qualifier_poly ) != 0 ) ; gcc_assert ( eltype != NULL ) ; if ( qualifiers & qualifier_const ) eltype = build_qualified_type ( eltype , TYPE_QUAL_CONST ) ; if ( qualifiers & qualifier_pointer ) eltype = build_pointer_type ( eltype ) ; if ( arg_num == 0 ) return_type = eltype ; else args = tree_cons ( NULL_TREE , eltype , args ) ; } ftype = build_function_type ( return_type , args ) ; gcc_assert ( ftype != NULL ) ; if ( print_type_signature_p ) snprintf ( namebuf , sizeof ( namebuf ) , "__builtin_neon_%s_%s" , d -> name , type_signature ) ; else snprintf ( namebuf , sizeof ( namebuf ) , "__builtin_neon_%s" , d -> name ) ; fndecl = add_builtin_function ( namebuf , ftype , fcode , BUILT_IN_MD , NULL , NULL_TREE ) ; arm_builtin_decls [ fcode ] = fndecl ; } } </s>

Set up all the NEON builtins , even builtins for instructions that are not in the current target ISA to allow the user to compile particular modules with different target specific options that differ from the command line options . Such builtins will be rejected in arm_expand_builtin .


<s> static rtx arm_expand_acle_builtin ( int fcode , tree exp , rtx target ) { arm_builtin_datum * d = & acle_builtin_data [ fcode - ARM_BUILTIN_ACLE_PATTERN_START ] ; return arm_expand_builtin_1 ( fcode , exp , target , d ) ; } </s>

Expand an ACLE builtin , i.e . those registered only if their respective target constraints are met . This check happens within arm_expand_builtin_args .


Expand a builtin . These builtins are `` special '' because they do n't have symbolic constants defined per-instruction or per instruction-variant . Instead , the required info is looked up in the ARM_BUILTIN_DATA record that is passed into the function .


<s> static void arm_init_acle_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_ACLE_PATTERN_START ; for ( i = 0 ; i < ARRAY_SIZE ( acle_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & acle_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_arm" ) ; } } </s>

Set up ACLE builtins , even builtins for instructions that are not in the current target ISA to allow the user to compile particular modules with different target specific options that differ from the command line options . Such builtins will be rejected in arm_expand_builtin .


<s> static void arm_init_builtin ( unsigned int fcode , arm_builtin_datum * d , const char * prefix ) { bool print_type_signature_p = false ; char type_signature [ SIMD_MAX_BUILTIN_ARGS ] = { 0 } ; char namebuf [ 60 ] ; tree ftype = NULL ; tree fndecl = NULL ; d -> fcode = fcode ; int op_num = insn_data [ d -> code ] . n_operands - 1 ; int arg_num = d -> qualifiers [ 0 ] & qualifier_void ? op_num + 1 : op_num ; tree return_type = void_type_node , args = void_list_node ; tree eltype ; for ( ; op_num >= 0 ; arg_num -- , op_num -- ) { machine_mode op_mode = insn_data [ d -> code ] . operand [ op_num ] . mode ; enum arm_type_qualifiers qualifiers = d -> qualifiers [ arg_num ] ; if ( qualifiers & qualifier_unsigned ) { type_signature [ arg_num ] = 'u' ; print_type_signature_p = true ; } else if ( qualifiers & qualifier_poly ) { type_signature [ arg_num ] = 'p' ; print_type_signature_p = true ; } else type_signature [ arg_num ] = 's' ; if ( qualifiers & qualifier_internal ) continue ; if ( qualifiers & qualifier_map_mode ) op_mode = d -> mode ; if ( qualifiers & qualifier_pointer && VECTOR_MODE_P ( op_mode ) ) op_mode = GET_MODE_INNER ( op_mode ) ; eltype = arm_simd_builtin_type ( op_mode , ( qualifiers & qualifier_unsigned ) != 0 , ( qualifiers & qualifier_poly ) != 0 ) ; gcc_assert ( eltype != NULL ) ; if ( qualifiers & qualifier_const ) eltype = build_qualified_type ( eltype , TYPE_QUAL_CONST ) ; if ( qualifiers & qualifier_pointer ) eltype = build_pointer_type ( eltype ) ; if ( arg_num == 0 ) return_type = eltype ; else args = tree_cons ( NULL_TREE , eltype , args ) ; } ftype = build_function_type ( return_type , args ) ; gcc_assert ( ftype != NULL ) ; if ( print_type_signature_p && IN_RANGE ( fcode , ARM_BUILTIN_VFP_BASE , ARM_BUILTIN_ACLE_BASE - 1 ) ) snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s_%s" , prefix , d -> name , type_signature ) ; else snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s" , prefix , d -> name ) ; fndecl = add_builtin_function ( namebuf , ftype , fcode , BUILT_IN_MD , NULL , NULL_TREE ) ; arm_builtin_decls [ fcode ] = fndecl ; } </s>


<s> static void arm_init_neon_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_NEON_PATTERN_START ; arm_init_simd_builtin_types ( ) ; arm_init_simd_builtin_scalar_types ( ) ; tree lane_check_fpr = build_function_type_list ( void_type_node , intSI_type_node , intSI_type_node , NULL ) ; arm_builtin_decls [ ARM_BUILTIN_NEON_LANE_CHECK ] = add_builtin_function ( "__builtin_arm_lane_check" , lane_check_fpr , ARM_BUILTIN_NEON_LANE_CHECK , BUILT_IN_MD , NULL , NULL_TREE ) ; for ( i = 0 ; i < ARRAY_SIZE ( neon_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & neon_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_neon" ) ; } } </s>


" (e.g. %<-mfloat-abi=softfp%> %<-mfpu=neon%>)"


<s> tree arm_builtin_decl ( unsigned code , bool initialize_p ATTRIBUTE_UNUSED ) { if ( code >= ARM_BUILTIN_MAX ) return error_mark_node ; return arm_builtin_decls [ code ] ; } </s>


<s>
bool
arm_check_builtin_call
(
location_t
,
vec
<
location_t
>
,
tree
fndecl
,
tree
,
unsigned
int
,
tree
*
)
{
int
fcode
=
DECL_MD_FUNCTION_CODE
(
fndecl
)
;
if
(
fcode
==
ARM_BUILTIN_saturation_occurred
||
fcode
==
ARM_BUILTIN_set_saturation
)
{
if
(
cfun
&&
cfun
->
decl
)
DECL_ATTRIBUTES
(
cfun
->
decl
)
=
tree_cons
(
get_identifier
(
"acle qbit"
)
,
NULL_TREE
,
DECL_ATTRIBUTES
(
cfun
->
decl
)
)
;
}
if
(
fcode
==
ARM_BUILTIN_sel
)
{
if
(
cfun
&&
cfun
->
decl
)
DECL_ATTRIBUTES
(
cfun
->
decl
)
=
tree_cons
(
get_identifier
(
"acle gebits"
)
,
NULL_TREE
,
DECL_ATTRIBUTES
(
cfun
->
decl
)
)
;
}
return
true
;
}
</s>

Implement TARGET_CHECK_BUILTIN_CALL . Record a read of the Q bit through intrinsics in the machine function .


"saturation bit range must be in the range [%wd, %wd]"

"saturation bit range must be a constant immediate"


<s> static rtx arm_expand_binop_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; tree arg1 = CALL_EXPR_ARG ( exp , 1 ) ; rtx op0 = expand_normal ( arg0 ) ; rtx op1 = expand_normal ( arg1 ) ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; machine_mode mode1 = insn_data [ icode ] . operand [ 2 ] . mode ; if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( VECTOR_MODE_P ( mode1 ) ) op1 = safe_vector_operand ( op1 , mode1 ) ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; gcc_assert ( ( GET_MODE ( op0 ) == mode0 || GET_MODE ( op0 ) == VOIDmode ) && ( GET_MODE ( op1 ) == mode1 || GET_MODE ( op1 ) == VOIDmode ) ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 2 ] . predicate ) ( op1 , mode1 ) ) op1 = copy_to_mode_reg ( mode1 , op1 ) ; pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>

Subroutine of arm_expand_builtin to take care of binop insns .


<s>
static
rtx
arm_expand_mve_builtin
(
int
fcode
,
tree
exp
,
rtx
target
)
{
if
(
fcode
>=
ARM_BUILTIN_MVE_BASE
&&
!
TARGET_HAVE_MVE
)
{
fatal_error
(
input_location
,
"You must enable MVE instructions"
" to use these intrinsics"
)
;
return
const0_rtx
;
}
arm_builtin_datum
*
d
=
&
mve_builtin_data
[
fcode
ARM_BUILTIN_MVE_PATTERN_START
]
;
return
arm_expand_builtin_1
(
fcode
,
exp
,
target
,
d
)
;
}
</s>

Expand an MVE builtin , i.e . those registered only if their respective target constraints are met . This check happens within arm_expand_builtin .

arm
"You must enable MVE instructions"
" to use these intrinsics"


<s> static rtx arm_expand_ternop_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; tree arg1 = CALL_EXPR_ARG ( exp , 1 ) ; tree arg2 = CALL_EXPR_ARG ( exp , 2 ) ; rtx op0 = expand_normal ( arg0 ) ; rtx op1 = expand_normal ( arg1 ) ; rtx op2 = expand_normal ( arg2 ) ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; machine_mode mode1 = insn_data [ icode ] . operand [ 2 ] . mode ; machine_mode mode2 = insn_data [ icode ] . operand [ 3 ] . mode ; if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( VECTOR_MODE_P ( mode1 ) ) op1 = safe_vector_operand ( op1 , mode1 ) ; if ( VECTOR_MODE_P ( mode2 ) ) op2 = safe_vector_operand ( op2 , mode2 ) ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; gcc_assert ( ( GET_MODE ( op0 ) == mode0 || GET_MODE ( op0 ) == VOIDmode ) && ( GET_MODE ( op1 ) == mode1 || GET_MODE ( op1 ) == VOIDmode ) && ( GET_MODE ( op2 ) == mode2 || GET_MODE ( op2 ) == VOIDmode ) ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 2 ] . predicate ) ( op1 , mode1 ) ) op1 = copy_to_mode_reg ( mode1 , op1 ) ; if ( ! ( * insn_data [ icode ] . operand [ 3 ] . predicate ) ( op2 , mode2 ) ) op2 = copy_to_mode_reg ( mode2 , op2 ) ; pat = GEN_FCN ( icode ) ( target , op0 , op1 , op2 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx arm_expand_unop_builtin ( enum insn_code icode , tree exp , rtx target , int do_load ) { rtx pat ; tree arg0 = CALL_EXPR_ARG ( exp , 0 ) ; rtx op0 = expand_normal ( arg0 ) ; machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; if ( ! target || GET_MODE ( target ) != tmode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , tmode ) ) target = gen_reg_rtx ( tmode ) ; if ( do_load ) op0 = gen_rtx_MEM ( mode0 , copy_to_mode_reg ( Pmode , op0 ) ) ; else { if ( VECTOR_MODE_P ( mode0 ) ) op0 = safe_vector_operand ( op0 , mode0 ) ; if ( ! ( * insn_data [ icode ] . operand [ 1 ] . predicate ) ( op0 , mode0 ) ) op0 = copy_to_mode_reg ( mode0 , op0 ) ; } pat = GEN_FCN ( icode ) ( target , op0 ) ; if ( ! pat ) return 0 ; emit_insn ( pat ) ; return target ; } </s>


<s>
static
rtx
arm_expand_vfp_builtin
(
int
fcode
,
tree
exp
,
rtx
target
)
{
if
(
fcode
>=
ARM_BUILTIN_VFP_BASE
&&
!
TARGET_HARD_FLOAT
)
{
fatal_error
(
input_location
,
"You must enable VFP instructions"
" to use these intrinsics."
)
;
return
const0_rtx
;
}
arm_builtin_datum
*
d
=
&
vfp_builtin_data
[
fcode
ARM_BUILTIN_VFP_PATTERN_START
]
;
return
arm_expand_builtin_1
(
fcode
,
exp
,
target
,
d
)
;
}
</s>

Expand a VFP builtin . These builtins are treated like neon builtins except that the data is looked up in table VFP_BUILTIN_DATA .

arm
"You must enable VFP instructions"
" to use these intrinsics."


<s> static void arm_init_acle_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_ACLE_PATTERN_START ; tree sat_check_fpr = build_function_type_list ( void_type_node , intSI_type_node , intSI_type_node , intSI_type_node , NULL ) ; arm_builtin_decls [ ARM_BUILTIN_SAT_IMM_CHECK ] = add_builtin_function ( "__builtin_sat_imm_check" , sat_check_fpr , ARM_BUILTIN_SAT_IMM_CHECK , BUILT_IN_MD , NULL , NULL_TREE ) ; for ( i = 0 ; i < ARRAY_SIZE ( acle_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & acle_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_arm" ) ; } } </s>


<s> static void arm_init_bf16_types ( void ) { arm_bf16_type_node = make_node ( REAL_TYPE ) ; TYPE_PRECISION ( arm_bf16_type_node ) = 16 ; SET_TYPE_MODE ( arm_bf16_type_node , BFmode ) ; layout_type ( arm_bf16_type_node ) ; lang_hooks . types . register_builtin_type ( arm_bf16_type_node , "__bf16" ) ; arm_bf16_ptr_type_node = build_pointer_type ( arm_bf16_type_node ) ; } </s>

Initialize the backend REAL_TYPE type supporting bfloat types .


<s> static void arm_init_builtin ( unsigned int fcode , arm_builtin_datum * d , const char * prefix ) { bool print_type_signature_p = false ; char type_signature [ SIMD_MAX_BUILTIN_ARGS ] = { 0 } ; char namebuf [ 60 ] ; tree ftype = NULL ; tree fndecl = NULL ; d -> fcode = fcode ; int op_num = insn_data [ d -> code ] . n_operands - 1 ; int arg_num = d -> qualifiers [ 0 ] & qualifier_void ? op_num + 1 : op_num ; tree return_type = void_type_node , args = void_list_node ; tree eltype ; for ( ; op_num >= 0 ; arg_num -- , op_num -- ) { machine_mode op_mode = insn_data [ d -> code ] . operand [ op_num ] . mode ; enum arm_type_qualifiers qualifiers = d -> qualifiers [ arg_num ] ; if ( qualifiers & qualifier_unsigned ) { type_signature [ arg_num ] = 'u' ; print_type_signature_p = true ; } else if ( qualifiers & qualifier_poly ) { type_signature [ arg_num ] = 'p' ; print_type_signature_p = true ; } else type_signature [ arg_num ] = 's' ; if ( qualifiers & qualifier_internal ) continue ; if ( qualifiers & qualifier_map_mode ) op_mode = d -> mode ; if ( qualifiers & qualifier_predicate ) op_mode = HImode ; if ( qualifiers & qualifier_pointer && VECTOR_MODE_P ( op_mode ) ) op_mode = GET_MODE_INNER ( op_mode ) ; if ( qualifiers & qualifier_void_pointer ) eltype = qualifiers & qualifier_const ? const_ptr_type_node : ptr_type_node ; else { eltype = arm_simd_builtin_type ( op_mode , ( qualifiers & qualifier_unsigned ) != 0 , ( qualifiers & qualifier_poly ) != 0 ) ; gcc_assert ( eltype != NULL ) ; if ( qualifiers & qualifier_const ) eltype = build_qualified_type ( eltype , TYPE_QUAL_CONST ) ; if ( qualifiers & qualifier_pointer ) eltype = build_pointer_type ( eltype ) ; } if ( arg_num == 0 ) return_type = eltype ; else args = tree_cons ( NULL_TREE , eltype , args ) ; } ftype = build_function_type ( return_type , args ) ; gcc_assert ( ftype != NULL ) ; if ( print_type_signature_p && IN_RANGE ( fcode , ARM_BUILTIN_VFP_BASE , ARM_BUILTIN_ACLE_BASE - 1 ) ) snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s_%s" , prefix , d -> name , type_signature ) ; else snprintf ( namebuf , sizeof ( namebuf ) , "%s_%s" , prefix , d -> name ) ; fndecl = add_builtin_function ( namebuf , ftype , fcode , BUILT_IN_MD , NULL , NULL_TREE ) ; arm_builtin_decls [ fcode ] = fndecl ; } </s>


<s> static void arm_init_mve_builtins ( void ) { volatile unsigned int i , fcode = ARM_BUILTIN_MVE_PATTERN_START ; arm_init_simd_builtin_scalar_types ( ) ; arm_init_simd_builtin_types ( ) ; tree get_fpscr_nzcvqc = build_function_type_list ( intSI_type_node , NULL ) ; tree set_fpscr_nzcvqc = build_function_type_list ( void_type_node , intSI_type_node , NULL ) ; arm_builtin_decls [ ARM_BUILTIN_GET_FPSCR_NZCVQC ] = add_builtin_function ( "__builtin_arm_get_fpscr_nzcvqc" , get_fpscr_nzcvqc , ARM_BUILTIN_GET_FPSCR_NZCVQC , BUILT_IN_MD , NULL , NULL_TREE ) ; arm_builtin_decls [ ARM_BUILTIN_SET_FPSCR_NZCVQC ] = add_builtin_function ( "__builtin_arm_set_fpscr_nzcvqc" , set_fpscr_nzcvqc , ARM_BUILTIN_SET_FPSCR_NZCVQC , BUILT_IN_MD , NULL , NULL_TREE ) ; for ( i = 0 ; i < ARRAY_SIZE ( mve_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & mve_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_mve" ) ; } } </s>

Set up all the MVE builtins mentioned in arm_mve_builtins.def file .


<s> static void arm_init_neon_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_NEON_PATTERN_START ; arm_init_simd_builtin_types ( ) ; arm_init_simd_builtin_scalar_types ( ) ; for ( i = 0 ; i < ARRAY_SIZE ( neon_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & neon_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_neon" ) ; } } </s>


<s> static void arm_init_vfp_builtins ( void ) { unsigned int i , fcode = ARM_BUILTIN_VFP_PATTERN_START ; for ( i = 0 ; i < ARRAY_SIZE ( vfp_builtin_data ) ; i ++ , fcode ++ ) { arm_builtin_datum * d = & vfp_builtin_data [ i ] ; arm_init_builtin ( fcode , d , "__builtin_neon" ) ; } } </s>

Set up all the scalar floating point builtins .


EXP is a pointer argument to a vector scatter store intrinsics . Consider the following example : VSTRW < v > . < dt > Qd , [ Qm { , # +/- < imm > } ] ! When < Qm > used as the base register for the target address , this function is used to derive and return an expression for the accessed memory . The intrinsic function operates on a block of registers that has mode REG_MODE . This block contains vectors of type TYPE_MODE . The function references the memory at EXP of type TYPE and in mode MEM_MODE . This mode may be BLKmode if no more suitable mode is available .


EXP is a pointer argument to a Neon load or store intrinsic . Derive and return an expression for the accessed memory . The intrinsic function operates on a block of registers that has mode REG_MODE . This block contains vectors of type TYPE_MODE . The function references the memory at EXP of type TYPE and in mode MEM_MODE ; this mode may be BLKmode if no more suitable mode is available .


<s> static rtx safe_vector_operand ( rtx x , machine_mode mode ) { if ( x != const0_rtx ) return x ; x = gen_reg_rtx ( mode ) ; emit_insn ( gen_iwmmxt_clrdi ( mode == DImode ? x : gen_rtx_SUBREG ( DImode , x , 0 ) ) ) ; return x ; } </s>

Errors in the source file can cause expand_expr to return const0_rtx where we expect a vector . To avoid crashing , use one of the vector clear instructions .


Hook to validate the current # pragma GCC target and set the arch custom mode state . If ARGS is NULL , then POP_TARGET is used to reset the options .


<s> void arm_register_target_pragmas ( void ) { targetm . target_option . pragma_parse = arm_pragma_target_parse ; REGISTER_SUBTARGET_PRAGMAS ( ) ; } </s>

Register target pragmas . We need to add the hook for parsing # pragma GCC option here rather than in arm.cc since it will pull in various preprocessor functions , and those are not present in languages like fortran without a preprocessor .


<s> void arm_lang_object_attributes_init ( void ) { arm_lang_output_object_attributes_hook = arm_output_c_attributes ; } </s>

Setup so that common code calls arm_output_c_attributes .


<s> static void arm_output_c_attributes ( void ) { int wchar_size = ( int ) ( TYPE_PRECISION ( wchar_type_node ) / BITS_PER_UNIT ) ; arm_emit_eabi_attribute ( "Tag_ABI_PCS_wchar_t" , 18 , wchar_size ) ; } </s>

Output C specific EABI object attributes . These can not be done in arm.c because they require information from the C frontend .


"%<#pragma GCC arm%> requires a string parameter"

"unknown %<#pragma GCC arm%> option %qs"


<s> void arm_register_target_pragmas ( void ) { targetm . target_option . pragma_parse = arm_pragma_target_parse ; targetm . resolve_overloaded_builtin = arm_resolve_overloaded_builtin ; c_register_pragma ( "GCC" , "arm" , arm_pragma_arm ) ; REGISTER_SUBTARGET_PRAGMAS ( ) ; } </s>


<s> tree arm_resolve_overloaded_builtin ( location_t loc , tree fndecl , void * arglist ) { if ( arm_describe_resolver ( fndecl ) == arm_cde_resolver ) return arm_resolve_cde_builtin ( loc , fndecl , arglist ) ; return NULL_TREE ; } </s>

Implement TARGET_RESOLVE_OVERLOADED_BUILTIN . This is currently only used for the MVE related builtins for the CDE extension . Here we ensure the type of arguments is such that the size is correct , and then return a tree that describes the same function call but with the relevant types cast as necessary .


<s> static void def_or_undef_macro ( struct cpp_reader * pfile , const char * name , bool def_p ) { if ( def_p ) cpp_define ( pfile , name ) ; else cpp_undef ( pfile , name ) ; } </s>

Define or undefine macros based on the current target . If the user does # pragma GCC target , we need to adjust the macros dynamically .


<s> static tree arm_d_handle_target_float_abi ( void ) { const char * abi ; switch ( arm_float_abi ) { case ARM_FLOAT_ABI_HARD : abi = "hard" ; break ; case ARM_FLOAT_ABI_SOFT : abi = "soft" ; break ; case ARM_FLOAT_ABI_SOFTFP : abi = "softfp" ; break ; default : abi = "" ; break ; } return build_string_literal ( strlen ( abi ) + 1 , abi ) ; } </s>

Handle a call to ` __traits ( getTargetInfo , `` floatAbi '' ) ' .


<s> void arm_d_register_target_info ( void ) { const struct d_target_info_spec handlers [ ] = { { "floatAbi" , arm_d_handle_target_float_abi } , { NULL , NULL } , } ; d_add_target_info_handlers ( handlers ) ; } </s>


<s> void arm_d_target_versions ( void ) { d_add_builtin_version ( "ARM" ) ; if ( TARGET_THUMB || TARGET_THUMB2 ) { d_add_builtin_version ( "Thumb" ) ; d_add_builtin_version ( "ARM_Thumb" ) ; } if ( TARGET_HARD_FLOAT_ABI ) d_add_builtin_version ( "ARM_HardFloat" ) ; else { if ( TARGET_SOFT_FLOAT ) d_add_builtin_version ( "ARM_SoftFloat" ) ; else if ( TARGET_HARD_FLOAT ) d_add_builtin_version ( "ARM_SoftFP" ) ; } if ( TARGET_SOFT_FLOAT ) d_add_builtin_version ( "D_SoftFloat" ) ; else if ( TARGET_HARD_FLOAT ) d_add_builtin_version ( "D_HardFloat" ) ; } </s>

Implement TARGET_D_CPU_VERSIONS for ARM targets .


<s> static tree arm_mve_type_for_scalar_type ( tree eltype ) { for ( unsigned int i = 0 ; i < __TYPE_FINAL ; ++ i ) if ( arm_simd_types [ i ] . eltype == eltype && GET_MODE_SIZE ( arm_simd_types [ i ] . mode ) == 16 ) return arm_simd_types [ i ] . itype ; gcc_unreachable ( ) ; } </s>

Return the MVE abi type with element of type TYPE .


"this definition requires the MVE ISA extension"

Implement # pragma GCC arm `` arm_mve_types.h '' .


<s> static void register_builtin_tuple_types ( vector_type_index type ) { const vector_type_info * info = & vector_types [ type ] ; if ( scalar_types [ type ] == boolean_type_node || ( info -> requires_float && ! TARGET_HAVE_MVE_FLOAT ) ) return ; const char * vector_type_name = info -> acle_name ; char buffer [ sizeof ( "float32x4x2_t" ) ] ; for ( unsigned int num_vectors = 2 ; num_vectors <= 4 ; num_vectors += 2 ) { snprintf ( buffer , sizeof ( buffer ) , "%.*sx%d_t" , ( int ) strlen ( vector_type_name ) - 2 , vector_type_name , num_vectors ) ; tree vectype = acle_vector_types [ 0 ] [ type ] ; tree arrtype = build_array_type_nelts ( vectype , num_vectors ) ; gcc_assert ( TYPE_MODE_RAW ( arrtype ) == TYPE_MODE ( arrtype ) ) ; tree field = build_decl ( input_location , FIELD_DECL , get_identifier ( "val" ) , arrtype ) ; tree t = lang_hooks . types . simulate_record_decl ( input_location , buffer , make_array_slice ( & field , 1 ) ) ; gcc_assert ( TYPE_MODE_RAW ( t ) == TYPE_MODE ( t ) ) ; acle_vector_types [ num_vectors >> 1 ] [ type ] = TREE_TYPE ( t ) ; } } </s>

Register tuple type TYPE with NUM_VECTORS arity under its arm_mve_types.h name .


<s> static void register_builtin_types ( ) { scalar_types [ VECTOR_TYPE_ ## ACLE_NAME ] = SCALAR_TYPE ; for ( unsigned int i = 0 ; i < NUM_VECTOR_TYPES ; ++ i ) { if ( vector_types [ i ] . requires_float && ! TARGET_HAVE_MVE_FLOAT ) continue ; tree eltype = scalar_types [ i ] ; tree vectype ; if ( eltype == boolean_type_node ) { vectype = get_typenode_from_name ( UINT16_TYPE ) ; gcc_assert ( GET_MODE_SIZE ( TYPE_MODE ( vectype ) ) == 2 ) ; } else { vectype = arm_mve_type_for_scalar_type ( eltype ) ; gcc_assert ( VECTOR_MODE_P ( TYPE_MODE ( vectype ) ) && GET_MODE_SIZE ( TYPE_MODE ( vectype ) ) == 16 ) ; } abi_vector_types [ i ] = vectype ; } } </s>

Register the built-in RVV ABI types , such as __rvv_int32m1_t .


<s> static void register_vector_type ( vector_type_index type ) { if ( vector_types [ type ] . requires_float && ! TARGET_HAVE_MVE_FLOAT ) return ; tree vectype = abi_vector_types [ type ] ; tree id = get_identifier ( vector_types [ type ] . acle_name ) ; tree decl = build_decl ( input_location , TYPE_DECL , id , vectype ) ; decl = lang_hooks . decls . pushdecl ( decl ) ; if ( decl && TREE_CODE ( decl ) == TYPE_DECL && TREE_TYPE ( decl ) != error_mark_node && TYPE_MAIN_VARIANT ( TREE_TYPE ( decl ) ) == vectype ) vectype = TREE_TYPE ( decl ) ; acle_vector_types [ 0 ] [ type ] = vectype ; } </s>

Register vector type TYPE under its risv_vector.h name .


<s> bool aarch_bti_enabled ( void ) { return aarch_enable_bti != 0 ; } </s>

Return TRUE if Branch Target Identification Mechanism is enabled .


<s> bool aarch_bti_j_insn_p ( rtx_insn * insn ) { if ( ! insn || ! INSN_P ( insn ) ) return false ; rtx pat = PATTERN ( insn ) ; return GET_CODE ( pat ) == UNSPEC_VOLATILE && XINT ( pat , 1 ) == VUNSPEC_BTI_NOP ; } </s>


<s> bool aarch_pac_insn_p ( rtx x ) { if ( ! x || ! INSN_P ( x ) ) return false ; rtx pat = PATTERN ( x ) ; if ( GET_CODE ( pat ) == SET ) { rtx tmp = XEXP ( pat , 1 ) ; if ( tmp && ( ( GET_CODE ( tmp ) == UNSPEC && XINT ( tmp , 1 ) == UNSPEC_PAC_NOP ) || ( GET_CODE ( tmp ) == UNSPEC_VOLATILE && XINT ( tmp , 1 ) == VUNSPEC_PACBTI_NOP ) ) ) return true ; } return false ; } </s>

Check if X ( or any sub-rtx of X ) is a PACIASP/PACIBSP instruction .


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


<s> static bool arm_bfi_1_p ( rtx op0 , rtx op1 , rtx * sub0 , rtx * sub1 ) { unsigned HOST_WIDE_INT const1 ; unsigned HOST_WIDE_INT const2 = 0 ; if ( ! CONST_INT_P ( XEXP ( op0 , 1 ) ) ) return false ; const1 = UINTVAL ( XEXP ( op0 , 1 ) ) ; if ( ! CONST_INT_P ( XEXP ( op1 , 1 ) ) || ~ UINTVAL ( XEXP ( op1 , 1 ) ) != const1 ) return false ; if ( GET_CODE ( XEXP ( op0 , 0 ) ) == ASHIFT && CONST_INT_P ( XEXP ( XEXP ( op0 , 0 ) , 1 ) ) ) { const2 = UINTVAL ( XEXP ( XEXP ( op0 , 0 ) , 1 ) ) ; * sub0 = XEXP ( XEXP ( op0 , 0 ) , 0 ) ; } else * sub0 = XEXP ( op0 , 0 ) ; if ( const2 >= GET_MODE_BITSIZE ( GET_MODE ( op0 ) ) ) return false ; * sub1 = XEXP ( op1 , 0 ) ; return exact_log2 ( const1 + ( HOST_WIDE_INT_1U << const2 ) ) >= 0 ; } </s>


<s> static bool arm_bfi_p ( rtx x , rtx * sub0 , rtx * sub1 ) { if ( GET_CODE ( x ) != IOR ) return false ; if ( GET_CODE ( XEXP ( x , 0 ) ) != AND || GET_CODE ( XEXP ( x , 1 ) ) != AND ) return false ; return ( arm_bfi_1_p ( XEXP ( x , 0 ) , XEXP ( x , 1 ) , sub0 , sub1 ) || arm_bfi_1_p ( XEXP ( x , 1 ) , XEXP ( x , 0 ) , sub1 , sub0 ) ) ; } </s>

Recognize a BFI idiom . Helper for arm_rtx_costs_internal . The format looks something like : ( IOR ( AND ( reg1 ) ( ~const1 ) ) ( AND ( ASHIFT ( reg2 ) ( const2 ) ) ( const1 ) ) ) where const1 is a consecutive sequence of 1-bits with the least-significant non-zero bit starting at bit position const2 . If const2 is zero , then the shift will not appear at all , due to canonicalization . The two arms of the IOR expression may be flipped .


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

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


<s> bool arm_current_function_pac_enabled_p ( void ) { return ( aarch_ra_sign_scope == AARCH_FUNCTION_ALL || ( aarch_ra_sign_scope == AARCH_FUNCTION_NON_LEAF && ! crtl -> is_leaf ) ) ; } </s>

Return TRUE if return address signing mechanism is enabled .


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

Map internal gcc register numbers to DWARF2 register numbers .


<s> static int arm_effective_regno ( rtx op , bool strict ) { gcc_assert ( REG_P ( op ) ) ; if ( ! strict || REGNO ( op ) < FIRST_PSEUDO_REGISTER || ! reg_renumber || reg_renumber [ REGNO ( op ) ] < 0 ) return REGNO ( op ) ; return reg_renumber [ REGNO ( op ) ] ; } </s>

In non-STRICT mode , return the register number ; in STRICT mode return the hard regno or the replacement if it wo n't be a mem . Otherwise , return the original pseudo number .


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

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


<s> void arm_expand_vcond ( rtx * operands , machine_mode cmp_result_mode ) { rtx mask = gen_reg_rtx ( cmp_result_mode ) ; bool inverted = arm_expand_vector_compare ( mask , GET_CODE ( operands [ 3 ] ) , operands [ 4 ] , operands [ 5 ] , true ) ; if ( inverted ) std :: swap ( operands [ 1 ] , operands [ 2 ] ) ; emit_insn ( gen_neon_vbsl ( GET_MODE ( operands [ 0 ] ) , operands [ 0 ] , mask , operands [ 1 ] , operands [ 2 ] ) ) ; } </s>

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


<s> bool arm_expand_vector_compare ( rtx target , rtx_code code , rtx op0 , rtx op1 , bool can_invert ) { machine_mode cmp_result_mode = GET_MODE ( target ) ; machine_mode cmp_mode = GET_MODE ( op0 ) ; bool inverted ; switch ( code ) { case UNORDERED : case UNLT : case UNLE : case UNGT : case UNGE : case UNEQ : case NE : code = reverse_condition_maybe_unordered ( code ) ; if ( ! can_invert ) { rtx tmp = gen_reg_rtx ( cmp_result_mode ) ; if ( arm_expand_vector_compare ( tmp , code , op0 , op1 , true ) ) gcc_unreachable ( ) ; emit_insn ( gen_rtx_SET ( target , gen_rtx_NOT ( cmp_result_mode , tmp ) ) ) ; return false ; } inverted = true ; break ; default : inverted = false ; break ; } switch ( code ) { case LE : case LT : if ( op1 != CONST0_RTX ( cmp_mode ) ) { code = swap_condition ( code ) ; std :: swap ( op0 , op1 ) ; } case EQ : case GE : case GT : emit_insn ( gen_neon_vc ( code , cmp_mode , target , op0 , op1 ) ) ; return inverted ; case GEU : case GTU : emit_insn ( gen_neon_vc ( code , cmp_mode , target , op0 , force_reg ( cmp_mode , op1 ) ) ) ; return inverted ; case LEU : case LTU : emit_insn ( gen_neon_vc ( swap_condition ( code ) , cmp_mode , target , force_reg ( cmp_mode , op1 ) , op0 ) ) ; return inverted ; case LTGT : case ORDERED : { rtx gt_res = gen_reg_rtx ( cmp_result_mode ) ; rtx alt_res = gen_reg_rtx ( cmp_result_mode ) ; rtx_code alt_code = ( code == LTGT ? LT : LE ) ; if ( arm_expand_vector_compare ( gt_res , GT , op0 , op1 , true ) || arm_expand_vector_compare ( alt_res , alt_code , op0 , op1 , true ) ) gcc_unreachable ( ) ; emit_insn ( gen_rtx_SET ( target , gen_rtx_IOR ( cmp_result_mode , gt_res , alt_res ) ) ) ; return inverted ; } default : gcc_unreachable ( ) ; } } </s>

Expand code to compare vectors OP0 and OP1 using condition CODE . If CAN_INVERT , store either the result or its inverse in TARGET and return true if TARGET contains the inverse . If ! CAN_INVERT , always store the result in TARGET , never its inverse . Note that the handling of floating-point comparisons is not IEEE compliant .


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


<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 VALID_MVE_PRED_MODE ( mode ) ; 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 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 ; machine -> pacspval_needed = 0 ; return machine ; } </s>

Functions to save and restore machine-specific function data .


<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_HAVE_MVE && ( VALID_MVE_PRED_MODE ( mode1 ) && VALID_MVE_PRED_MODE ( 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> 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 ; case 2 : return V2QImode ; } return opt_machine_mode ( ) ; } </s>

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


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


"target CPU does not support THUMB instructions"

"target CPU does not support unaligned accesses"

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

"This architecture does not support branch protection "

"Return address signing is not supported with %<-mtpcs-frame%>."

Reset options between modes that the user has specified .


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


<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 ( IS_PAC_REGNUM ( regno ) ) return PAC_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 .


"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_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
||
IS_PAC_REGNUM
(
REGNO
(
src
)
)
)
;
reg
=
REGNO
(
dest
)
;
if
(
IS_PAC_REGNUM
(
REGNO
(
src
)
)
)
arm_unwind_emit_set
(
out_file
,
PATTERN
(
insn
)
)
;
else
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 .


<s>
static
void
arm_unwind_emit_set
(
FILE
*
out_file
,
rtx
p
)
{
rtx
e0
;
rtx
e1
;
unsigned
reg
;
e0
=
XEXP
(
p
,
0
)
;
e1
=
XEXP
(
p
,
1
)
;
switch
(
GET_CODE
(
e0
)
)
{
case
MEM
:
if
(
GET_CODE
(
XEXP
(
e0
,
0
)
)
!=
PRE_DEC
||
!
REG_P
(
XEXP
(
XEXP
(
e0
,
0
)
,
0
)
)
||
REGNO
(
XEXP
(
XEXP
(
e0
,
0
)
,
0
)
)
!=
SP_REGNUM
)
abort
(
)
;
asm_fprintf
(
out_file
,
"\t.save "
)
;
if
(
IS_VFP_REGNUM
(
REGNO
(
e1
)
)
)
asm_fprintf
(
out_file
,
"{d%d}\n"
,
(
REGNO
(
e1
)
FIRST_VFP_REGNUM
)
/
2
)
;
else
asm_fprintf
(
out_file
,
"{%r}\n"
,
REGNO
(
e1
)
)
;
break
;
case
REG
:
if
(
REGNO
(
e0
)
==
SP_REGNUM
)
{
if
(
GET_CODE
(
e1
)
!=
PLUS
||
!
REG_P
(
XEXP
(
e1
,
0
)
)
||
REGNO
(
XEXP
(
e1
,
0
)
)
!=
SP_REGNUM
||
!
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
abort
(
)
;
asm_fprintf
(
out_file
,
"\t.pad #%wd\n"
,
INTVAL
(
XEXP
(
e1
,
1
)
)
)
;
}
else
if
(
REGNO
(
e0
)
==
HARD_FRAME_POINTER_REGNUM
)
{
HOST_WIDE_INT
offset
;
if
(
GET_CODE
(
e1
)
==
PLUS
)
{
if
(
!
REG_P
(
XEXP
(
e1
,
0
)
)
||
!
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
abort
(
)
;
reg
=
REGNO
(
XEXP
(
e1
,
0
)
)
;
offset
=
INTVAL
(
XEXP
(
e1
,
1
)
)
;
asm_fprintf
(
out_file
,
"\t.setfp %r, %r, #%wd\n"
,
HARD_FRAME_POINTER_REGNUM
,
reg
,
offset
)
;
}
else
if
(
REG_P
(
e1
)
)
{
reg
=
REGNO
(
e1
)
;
asm_fprintf
(
out_file
,
"\t.setfp %r, %r\n"
,
HARD_FRAME_POINTER_REGNUM
,
reg
)
;
}
else
abort
(
)
;
}
else
if
(
REG_P
(
e1
)
&&
REGNO
(
e1
)
==
SP_REGNUM
)
{
asm_fprintf
(
out_file
,
"\t.movsp %r\n"
,
REGNO
(
e0
)
)
;
}
else
if
(
GET_CODE
(
e1
)
==
PLUS
&&
REG_P
(
XEXP
(
e1
,
0
)
)
&&
REGNO
(
XEXP
(
e1
,
0
)
)
==
SP_REGNUM
&&
CONST_INT_P
(
XEXP
(
e1
,
1
)
)
)
{
asm_fprintf
(
out_file
,
"\t.movsp %r, #%d\n"
,
REGNO
(
e0
)
,
(
int
)
INTVAL
(
XEXP
(
e1
,
1
)
)
)
;
}
else
if
(
REGNO
(
e0
)
==
IP_REGNUM
&&
arm_current_function_pac_enabled_p
(
)
)
{
if
(
cfun
->
machine
->
pacspval_needed
)
asm_fprintf
(
out_file
,
"\t.pacspval\n"
)
;
}
else
abort
(
)
;
break
;
default
:
abort
(
)
;
}
}
</s>


<s> tree arm_valid_target_attribute_tree ( tree args , struct gcc_options * opts , struct gcc_options * opts_set ) { struct cl_target_option cl_opts ; if ( ! arm_valid_target_attribute_rec ( args , opts ) ) return NULL_TREE ; cl_target_option_save ( & cl_opts , opts , opts_set ) ; arm_configure_build_target ( & arm_active_target , & cl_opts , opts_set , false ) ; arm_option_check_internal ( opts ) ; arm_option_reconfigure_globals ( ) ; arm_options_perform_arch_sanity_checks ( ) ; arm_option_override_internal ( opts , opts_set ) ; return build_target_option_node ( opts , opts_set ) ; } </s>

Return a TARGET_OPTION_NODE tree of the target options listed or NULL .


<s> static bool arm_vectorize_vec_perm_const ( machine_mode vmode , machine_mode op_mode , rtx target , rtx op0 , rtx op1 , const vec_perm_indices & sel ) { if ( vmode != op_mode ) return false ; struct expand_vec_perm_d d ; int i , nelt , which ; if ( ! VALID_NEON_DREG_MODE ( vmode ) && ! VALID_NEON_QREG_MODE ( vmode ) ) return false ; d . target = target ; if ( op0 ) { rtx nop0 = force_reg ( vmode , op0 ) ; if ( op0 == op1 ) op1 = nop0 ; op0 = nop0 ; } if ( op1 ) op1 = force_reg ( vmode , op1 ) ; d . op0 = op0 ; d . op1 = op1 ; d . vmode = vmode ; gcc_assert ( VECTOR_MODE_P ( d . vmode ) ) ; d . testing_p = ! target ; nelt = GET_MODE_NUNITS ( d . vmode ) ; for ( i = which = 0 ; i < nelt ; ++ i ) { int ei = sel [ i ] & ( 2 * nelt - 1 ) ; which |= ( ei < nelt ? 1 : 2 ) ; } switch ( which ) { default : gcc_unreachable ( ) ; case 3 : d . one_vector_p = false ; if ( d . testing_p || ! rtx_equal_p ( op0 , op1 ) ) break ; case 2 : d . op0 = op1 ; d . one_vector_p = true ; break ; case 1 : d . op1 = op0 ; d . one_vector_p = true ; break ; } d . perm . new_vector ( sel . encoding ( ) , d . one_vector_p ? 1 : 2 , nelt ) ; if ( ! d . testing_p ) return arm_expand_vec_perm_const_1 ( & d ) ; d . target = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 1 ) ; d . op1 = d . op0 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 2 ) ; if ( ! d . one_vector_p ) d . op1 = gen_raw_REG ( d . vmode , LAST_VIRTUAL_REGISTER + 3 ) ; start_sequence ( ) ; bool ret = arm_expand_vec_perm_const_1 ( & d ) ; end_sequence ( ) ; return ret ; } </s>


<s> bool arm_vector_mode_supported_p ( machine_mode mode ) { if ( TARGET_NEON && ( mode == V2SFmode || mode == V4SImode || mode == V8HImode || mode == V4HFmode || mode == V16QImode || mode == V4SFmode || mode == V2DImode || mode == V8HFmode || mode == V4BFmode || mode == V8BFmode ) ) return true ; if ( ( TARGET_NEON || TARGET_IWMMXT ) && ( ( mode == V2SImode ) || ( mode == V4HImode ) || ( mode == V8QImode ) ) ) return true ; if ( TARGET_INT_SIMD && ( mode == V4UQQmode || mode == V4QQmode || mode == V2UHQmode || mode == V2HQmode || mode == V2UHAmode || mode == V2HAmode ) ) return true ; if ( TARGET_HAVE_MVE && ( VALID_MVE_SI_MODE ( mode ) || VALID_MVE_PRED_MODE ( mode ) ) ) return true ; if ( TARGET_HAVE_MVE_FLOAT && ( mode == V2DFmode || mode == V4SFmode || mode == V8HFmode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


<s> static rtx emit_multi_reg_push ( unsigned long mask , unsigned long dwarf_regs_mask ) { int num_regs = 0 ; int num_dwarf_regs = 0 ; int i , j ; rtx par ; rtx dwarf ; int dwarf_par_index ; rtx tmp , reg ; dwarf_regs_mask &= ~ ( 1 << PC_REGNUM ) ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) { if ( mask & ( 1 << i ) ) num_regs ++ ; if ( dwarf_regs_mask & ( 1 << i ) ) num_dwarf_regs ++ ; } gcc_assert ( num_regs && num_regs <= 16 ) ; gcc_assert ( ( dwarf_regs_mask & ~ mask ) == 0 ) ; par = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( num_regs ) ) ; dwarf = gen_rtx_SEQUENCE ( VOIDmode , rtvec_alloc ( num_dwarf_regs + 1 ) ) ; dwarf_par_index = 1 ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) { if ( mask & ( 1 << i ) ) { rtx dwarf_reg = reg = gen_rtx_REG ( SImode , i ) ; if ( arm_current_function_pac_enabled_p ( ) && i == IP_REGNUM ) dwarf_reg = gen_rtx_REG ( SImode , RA_AUTH_CODE ) ; XVECEXP ( par , 0 , 0 ) = gen_rtx_SET ( gen_frame_mem ( BLKmode , gen_rtx_PRE_MODIFY ( Pmode , stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ) ) , gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSH_MULT ) ) ; if ( dwarf_regs_mask & ( 1 << i ) ) { tmp = gen_rtx_SET ( gen_frame_mem ( SImode , stack_pointer_rtx ) , dwarf_reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; } break ; } } for ( j = 1 , i ++ ; j < num_regs ; i ++ ) { if ( mask & ( 1 << i ) ) { rtx dwarf_reg = reg = gen_rtx_REG ( SImode , i ) ; if ( arm_current_function_pac_enabled_p ( ) && i == IP_REGNUM ) dwarf_reg = gen_rtx_REG ( SImode , RA_AUTH_CODE ) ; XVECEXP ( par , 0 , j ) = gen_rtx_USE ( VOIDmode , reg ) ; if ( dwarf_regs_mask & ( 1 << i ) ) { tmp = gen_rtx_SET ( gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , 4 * j ) ) , dwarf_reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; } j ++ ; } } par = emit_insn ( par ) ; tmp = gen_rtx_SET ( stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , - 4 * num_regs ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 0 ) = tmp ; add_reg_note ( par , REG_FRAME_RELATED_EXPR , dwarf ) ; return par ; } </s>

Generate and emit an insn that we will recognize as a push_multi . Unfortunately , since this insn does not reflect very well the actual semantics of the operation , we need to annotate the insn for the benefit of DWARF2 frame unwind information .


<s> rtx mve_bool_vec_to_const ( rtx const_vec ) { machine_mode mode = GET_MODE ( const_vec ) ; if ( ! VECTOR_MODE_P ( mode ) ) return const_vec ; unsigned n_elts = GET_MODE_NUNITS ( mode ) ; unsigned el_prec = GET_MODE_PRECISION ( GET_MODE_INNER ( mode ) ) ; unsigned shift_c = 16 / n_elts ; unsigned i ; int hi_val = 0 ; for ( i = 0 ; i < n_elts ; i ++ ) { rtx el = CONST_VECTOR_ELT ( const_vec , i ) ; unsigned HOST_WIDE_INT elpart ; gcc_assert ( CONST_INT_P ( el ) ) ; elpart = INTVAL ( el ) & ( ( 1U << el_prec ) - 1 ) ; unsigned index = BYTES_BIG_ENDIAN ? n_elts - i - 1 : i ; hi_val |= elpart << ( index * shift_c ) ; } return gen_int_mode ( hi_val , SImode ) ; } </s>

Return a HI representation of CONST_VEC suitable for MVE predicates .


<s> int mve_struct_mem_operand ( rtx op ) { rtx ind = XEXP ( op , 0 ) ; if ( REG_P ( ind ) ) return arm_address_register_rtx_p ( ind , 0 ) ; if ( GET_CODE ( ind ) == POST_INC ) return arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) ; return FALSE ; } </s>

Return TRUE if OP is a mem suitable for loading/storing an MVE struct type .


<s> int mve_vector_mem_operand ( machine_mode mode , rtx op , bool strict ) { enum rtx_code code ; int val , reg_no ; if ( REG_P ( op ) ) { reg_no = arm_effective_regno ( op , strict ) ; return ( ( ( mode == E_V8QImode || mode == E_V4QImode || mode == E_V4HImode ) ? reg_no <= LAST_LO_REGNUM : reg_no < LAST_ARM_REGNUM ) || ( ! strict && reg_no >= FIRST_PSEUDO_REGISTER ) ) ; } code = GET_CODE ( op ) ; if ( code == POST_INC || code == PRE_DEC || code == PRE_INC || code == POST_DEC ) { reg_no = arm_effective_regno ( XEXP ( op , 0 ) , strict ) ; return ( ( ( mode == E_V8QImode || mode == E_V4QImode || mode == E_V4HImode ) ? reg_no <= LAST_LO_REGNUM : ( reg_no < LAST_ARM_REGNUM && reg_no != SP_REGNUM ) ) || ( ! strict && reg_no >= FIRST_PSEUDO_REGISTER ) ) ; } else if ( ( ( code == POST_MODIFY || code == PRE_MODIFY ) && GET_CODE ( XEXP ( op , 1 ) ) == PLUS && XEXP ( op , 0 ) == XEXP ( XEXP ( op , 1 ) , 0 ) && REG_P ( XEXP ( op , 0 ) ) && GET_CODE ( XEXP ( XEXP ( op , 1 ) , 1 ) ) == CONST_INT ) || ( reload_completed && code == PLUS && REG_P ( XEXP ( op , 0 ) ) && GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT ) ) { reg_no = arm_effective_regno ( XEXP ( op , 0 ) , strict ) ; if ( code == PLUS ) val = INTVAL ( XEXP ( op , 1 ) ) ; else val = INTVAL ( XEXP ( XEXP ( op , 1 ) , 1 ) ) ; switch ( mode ) { case E_V16QImode : case E_V8QImode : case E_V4QImode : if ( abs ( val ) > 127 ) return FALSE ; break ; case E_V8HImode : case E_V8HFmode : case E_V4HImode : case E_V4HFmode : if ( val % 2 != 0 || abs ( val ) > 254 ) return FALSE ; break ; case E_V4SImode : case E_V4SFmode : if ( val % 4 != 0 || abs ( val ) > 508 ) return FALSE ; break ; default : return FALSE ; } return ( ( ! strict && reg_no >= FIRST_PSEUDO_REGISTER ) || ( MVE_STN_LDW_MODE ( mode ) ? reg_no <= LAST_LO_REGNUM : ( reg_no < LAST_ARM_REGNUM && ( code == PLUS || reg_no != SP_REGNUM ) ) ) ) ; } return FALSE ; } </s>

This function returns TRUE on matching mode and op.1 . For given modes , check for [ Rn ] , return TRUE for Rn < = LO_REGS.2 . For other modes , check for [ Rn ] , return TRUE for Rn < R15 ( expect R13 ) .


<s> rtx neon_make_constant ( rtx vals , bool generate ) { machine_mode mode = GET_MODE ( vals ) ; rtx target ; rtx const_vec = NULL_RTX ; int n_elts = GET_MODE_NUNITS ( mode ) ; int n_const = 0 ; int i ; if ( GET_CODE ( vals ) == CONST_VECTOR ) const_vec = vals ; else if ( GET_CODE ( vals ) == PARALLEL ) { for ( i = 0 ; i < n_elts ; ++ i ) { rtx x = XVECEXP ( vals , 0 , i ) ; if ( CONST_INT_P ( x ) || CONST_DOUBLE_P ( x ) ) n_const ++ ; } if ( n_const == n_elts ) const_vec = gen_rtx_CONST_VECTOR ( mode , XVEC ( vals , 0 ) ) ; } else gcc_unreachable ( ) ; if ( const_vec != NULL && simd_immediate_valid_for_move ( const_vec , mode , NULL , NULL ) ) return const_vec ; else if ( TARGET_HAVE_MVE && VALID_MVE_PRED_MODE ( mode ) ) return mve_bool_vec_to_const ( const_vec ) ; else if ( ( target = neon_vdup_constant ( vals , generate ) ) != NULL_RTX ) return target ; else if ( const_vec != NULL_RTX ) return arm_disable_literal_pool ? NULL_RTX : const_vec ; else return NULL_RTX ; } </s>

Generate code to load VALS , which is a PARALLEL containing only constants ( for vec_init ) or CONST_VECTOR , efficiently into a register . Returns an RTX to copy into the register , or NULL_RTX for a PARALLEL that can not be converted into a CONST_VECTOR .


"asm flags not supported in thumb1 mode"

Worker function for TARGET_MD_ASM_ADJUST , while in thumb1 mode . Unlike the arm version , we do NOT implement asm flag outputs .


<s> static int thumb2_legitimate_address_p ( machine_mode mode , rtx x , int strict_p ) { bool use_ldrd ; enum rtx_code code = GET_CODE ( x ) ; if ( TARGET_HAVE_MVE && VALID_MVE_PRED_MODE ( mode ) ) mode = HImode ; if ( TARGET_HAVE_MVE && VALID_MVE_MODE ( mode ) ) return mve_vector_mem_operand ( mode , x , strict_p ) ; 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 ) ; HOST_WIDE_INT offset ; if ( ! CONST_INT_P ( addend ) ) return 0 ; offset = INTVAL ( addend ) ; if ( GET_MODE_SIZE ( mode ) <= 4 ) return ( offset > - 256 && offset < 256 ) ; return ( use_ldrd && offset > - 1024 && offset < 1024 && ( offset & 3 ) == 0 ) ; } 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 ) ) || ( TARGET_HAVE_MVE && VALID_MVE_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 ) && ( thumb2_legitimate_index_p ( mode , xop1 , strict_p ) || ( ! strict_p && will_be_in_index_register ( xop1 ) ) ) ) || ( arm_address_register_rtx_p ( xop1 , strict_p ) && thumb2_legitimate_index_p ( mode , xop0 , strict_p ) ) ) ; } else if ( can_avoid_literal_pool_for_label_p ( x ) ) return 0 ; 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 Thumb-2 address operand .


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

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


<s> static unsigned long arm_compute_func_type ( ) { unsigned long type = ARM_FT_UNKNOWN ; tree a ; tree attr ; if ( TREE_CODE ( current_function_decl ) != FUNCTION_DECL ) abort ( ) ; if ( optimize > 0 && current_function_nothrow && TREE_THIS_VOLATILE ( current_function_decl ) ) type |= ARM_FT_VOLATILE ; if ( current_function_needs_context ) type |= ARM_FT_NESTED ; attr = DECL_ATTRIBUTES ( current_function_decl ) ; a = lookup_attribute ( "naked" , attr ) ; if ( a != NULL_TREE ) type |= ARM_FT_NAKED ; if ( cfun -> machine -> eh_epilogue_sp_ofs != NULL_RTX ) type |= ARM_FT_EXCEPTION_HANDLER ; else { a = lookup_attribute ( "isr" , attr ) ; if ( a == NULL_TREE ) a = lookup_attribute ( "interrupt" , attr ) ; if ( a == NULL_TREE ) type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL ; else type |= arm_isr_value ( TREE_VALUE ( a ) ) ; } return type ; } </s>

Computes the type of the current function .


<s> static unsigned long arm_compute_save_reg0_reg12_mask ( ) { unsigned long func_type = arm_current_func_type ( ) ; unsigned int save_reg_mask = 0 ; unsigned int reg ; if ( IS_INTERRUPT ( func_type ) ) { unsigned int max_reg ; if ( ARM_FUNC_TYPE ( func_type ) == ARM_FT_FIQ ) max_reg = 7 ; else max_reg = 12 ; for ( reg = 0 ; reg <= max_reg ; reg ++ ) if ( regs_ever_live [ reg ] || ( ! current_function_is_leaf && call_used_regs [ reg ] ) ) save_reg_mask |= ( 1 << reg ) ; } else { for ( reg = 0 ; reg <= 10 ; reg ++ ) if ( regs_ever_live [ reg ] && ! call_used_regs [ reg ] ) save_reg_mask |= ( 1 << reg ) ; if ( ! TARGET_APCS_FRAME && ! frame_pointer_needed && regs_ever_live [ HARD_FRAME_POINTER_REGNUM ] && ! call_used_regs [ HARD_FRAME_POINTER_REGNUM ] ) save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM ; if ( flag_pic && ! TARGET_SINGLE_PIC_BASE && regs_ever_live [ PIC_OFFSET_TABLE_REGNUM ] ) save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; } return save_reg_mask ; } </s>

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


<s> static unsigned long arm_compute_save_reg_mask ( ) { unsigned int save_reg_mask = 0 ; unsigned long func_type = arm_current_func_type ( ) ; if ( IS_NAKED ( func_type ) ) return 0 ; if ( frame_pointer_needed ) save_reg_mask |= ( 1 << ARM_HARD_FRAME_POINTER_REGNUM ) | ( 1 << IP_REGNUM ) | ( 1 << LR_REGNUM ) | ( 1 << PC_REGNUM ) ; if ( IS_VOLATILE ( func_type ) ) return save_reg_mask ; save_reg_mask |= arm_compute_save_reg0_reg12_mask ( ) ; if ( regs_ever_live [ LR_REGNUM ] || ( save_reg_mask && optimize_size && ARM_FUNC_TYPE ( func_type ) == ARM_FT_NORMAL ) ) save_reg_mask |= 1 << LR_REGNUM ; if ( cfun -> machine -> lr_save_eliminated ) save_reg_mask &= ~ ( 1 << LR_REGNUM ) ; return save_reg_mask ; } </s>

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


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

Returns the type of the current function .


<s> static int arm_get_strip_length ( char 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 ' .


Do anything needed before RTL is emitted for each function .


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


"interrupt Service Routines cannot be coded in Thumb mode"

Generate the rest of a function 's prologue .


<s> int thumb_far_jump_used_p ( int in_prologue ) { rtx insn ; if ( cfun -> machine -> far_jump_used ) return 1 ; if ( ! in_prologue ) { if ( regs_ever_live [ ARG_POINTER_REGNUM ] ) cfun -> machine -> arg_pointer_live = 1 ; else if ( ! cfun -> machine -> arg_pointer_live ) return 0 ; } for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( GET_CODE ( insn ) == JUMP_INSN && GET_CODE ( PATTERN ( insn ) ) != ADDR_VEC && GET_CODE ( PATTERN ( insn ) ) != ADDR_DIFF_VEC && get_attr_far_jump ( insn ) == FAR_JUMP_YES ) { cfun -> machine -> far_jump_used = 1 ; return 1 ; } } return 0 ; } </s>

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


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

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


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

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


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

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


<s> static bool arm_9e_rtx_costs ( rtx x , int code , int outer_code , int * total ) { enum machine_mode mode = GET_MODE ( x ) ; int nonreg_cost ; int cost ; if ( TARGET_THUMB ) { switch ( code ) { case MULT : * total = COSTS_N_INSNS ( 3 ) ; return true ; default : * total = thumb_rtx_costs ( x , code , outer_code ) ; return true ; } } switch ( code ) { case MULT : if ( mode == DImode && ( GET_CODE ( XEXP ( x , 0 ) ) == GET_CODE ( XEXP ( x , 1 ) ) ) && ( GET_CODE ( XEXP ( x , 0 ) ) == ZERO_EXTEND || GET_CODE ( XEXP ( x , 0 ) ) == SIGN_EXTEND ) ) { * total = 3 ; return true ; } if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT ) { * total = 30 ; return true ; } if ( mode == DImode ) { cost = 7 ; nonreg_cost = 8 ; } else { cost = 2 ; nonreg_cost = 4 ; } * total = cost + ( REG_OR_SUBREG_REG ( XEXP ( x , 0 ) ) ? 0 : nonreg_cost ) + ( REG_OR_SUBREG_REG ( XEXP ( x , 1 ) ) ? 0 : nonreg_cost ) ; return true ; default : * total = arm_rtx_costs_1 ( x , code , outer_code ) ; return true ; } } </s>


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

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


<s> static int arm_adjust_cost ( rtx insn , rtx link , rtx dep , int cost ) { rtx i_pat , d_pat ; if ( arm_tune_xscale && REG_NOTE_KIND ( link ) == 0 && recog_memoized ( insn ) >= 0 && recog_memoized ( dep ) >= 0 ) { int shift_opnum = get_attr_shift ( insn ) ; enum attr_type attr_type = get_attr_type ( dep ) ; if ( shift_opnum != 0 && ( attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG ) ) { rtx shifted_operand ; int opno ; extract_insn ( insn ) ; shifted_operand = recog_data . operand [ shift_opnum ] ; extract_insn ( dep ) ; preprocess_constraints ( ) ; for ( opno = 0 ; opno < recog_data . n_operands ; opno ++ ) { if ( recog_data . operand_type [ opno ] == OP_IN ) continue ; if ( reg_overlap_mentioned_p ( recog_data . operand [ opno ] , shifted_operand ) ) return 2 ; } } } if ( REG_NOTE_KIND ( link ) == REG_DEP_ANTI || REG_NOTE_KIND ( link ) == REG_DEP_OUTPUT ) return 0 ; if ( REG_NOTE_KIND ( link ) == 0 && GET_CODE ( insn ) == CALL_INSN ) return 1 ; if ( ( i_pat = single_set ( insn ) ) != NULL && GET_CODE ( SET_SRC ( i_pat ) ) == MEM && ( d_pat = single_set ( dep ) ) != NULL && GET_CODE ( SET_DEST ( d_pat ) ) == MEM ) { rtx src_mem = XEXP ( SET_SRC ( i_pat ) , 0 ) ; if ( ( GET_CODE ( src_mem ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( src_mem ) ) || reg_mentioned_p ( stack_pointer_rtx , src_mem ) || reg_mentioned_p ( frame_pointer_rtx , src_mem ) || reg_mentioned_p ( hard_frame_pointer_rtx , src_mem ) ) return 1 ; } return cost ; } </s>

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


<s> int arm_apply_result_size ( void ) { int size = 16 ; if ( TARGET_ARM ) { if ( TARGET_HARD_FLOAT_ABI ) { if ( TARGET_FPA ) size += 12 ; if ( TARGET_MAVERICK ) size += 8 ; } if ( TARGET_IWMMXT_ABI ) size += 8 ; } return size ; } </s>

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


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

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