<s> static bool arm_assemble_integer ( rtx x , unsigned int size , int aligned_p ) { if ( size == UNITS_PER_WORD && aligned_p ) { fputs ( "\t.word\t" , asm_out_file ) ; output_addr_const ( asm_out_file , x ) ; if ( NEED_GOT_RELOC && flag_pic && making_const_table && ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) ) { if ( GET_CODE ( x ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( x ) || SYMBOL_REF_LOCAL_P ( x ) ) ) fputs ( "(GOTOFF)" , asm_out_file ) ; else if ( GET_CODE ( x ) == LABEL_REF ) fputs ( "(GOTOFF)" , asm_out_file ) ; else fputs ( "(GOT)" , asm_out_file ) ; } fputc ( '\n' , asm_out_file ) ; return true ; } if ( arm_vector_mode_supported_p ( GET_MODE ( x ) ) ) { int i , units ; gcc_assert ( GET_CODE ( x ) == CONST_VECTOR ) ; units = CONST_VECTOR_NUNITS ( x ) ; switch ( GET_MODE ( x ) ) { case V2SImode : size = 4 ; break ; case V4HImode : size = 2 ; break ; case V8QImode : size = 1 ; break ; default : gcc_unreachable ( ) ; } for ( i = 0 ; i < units ; i ++ ) { rtx elt ; elt = CONST_VECTOR_ELT ( x , i ) ; assemble_integer ( elt , size , i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT , 1 ) ; } return true ; } return default_assemble_integer ( x , size , aligned_p ) ; } </s>

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


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

Return the cost of forcibly inserting a barrier after INSN .


<s> static bool arm_cannot_copy_insn_p ( rtx insn ) { rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) == PARALLEL && GET_CODE ( XVECEXP ( pat , 0 , 0 ) ) == SET ) { rtx rhs = SET_SRC ( XVECEXP ( pat , 0 , 0 ) ) ; if ( GET_CODE ( rhs ) == UNSPEC && XINT ( rhs , 1 ) == UNSPEC_PIC_BASE ) return TRUE ; if ( GET_CODE ( rhs ) == MEM && GET_CODE ( XEXP ( rhs , 0 ) ) == UNSPEC && XINT ( XEXP ( rhs , 0 ) , 1 ) == UNSPEC_PIC_BASE ) return TRUE ; } return FALSE ; } </s>

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


<s> enum rtx_code arm_canonicalize_comparison ( enum rtx_code code , enum machine_mode mode , rtx * op1 ) { unsigned HOST_WIDE_INT i = INTVAL ( * op1 ) ; unsigned HOST_WIDE_INT maxval ; maxval = ( ( ( unsigned HOST_WIDE_INT ) 1 ) << ( GET_MODE_BITSIZE ( mode ) - 1 ) ) - 1 ; switch ( code ) { case EQ : case NE : return code ; case GT : case LE : if ( i != maxval && ( const_ok_for_arm ( i + 1 ) || const_ok_for_arm ( - ( i + 1 ) ) ) ) { * op1 = GEN_INT ( i + 1 ) ; return code == GT ? GE : LT ; } break ; case GE : case LT : if ( i != ~ maxval && ( const_ok_for_arm ( i - 1 ) || const_ok_for_arm ( - ( i - 1 ) ) ) ) { * op1 = GEN_INT ( i - 1 ) ; return code == GE ? GT : LE ; } break ; case GTU : case LEU : if ( i != ~ ( ( unsigned HOST_WIDE_INT ) 0 ) && ( const_ok_for_arm ( i + 1 ) || const_ok_for_arm ( - ( i + 1 ) ) ) ) { * op1 = GEN_INT ( i + 1 ) ; return code == GTU ? GEU : LTU ; } break ; case GEU : case LTU : if ( i != 0 && ( const_ok_for_arm ( i - 1 ) || const_ok_for_arm ( - ( i - 1 ) ) ) ) { * op1 = GEN_INT ( i - 1 ) ; return code == GEU ? GTU : LEU ; } break ; default : gcc_unreachable ( ) ; } return code ; } </s>

Canonicalize a comparison so that we are more likely to recognize it . This can be done for a few constant compares , where we can make the immediate value easier to load .


<s> static bool arm_cirrus_insn_p ( rtx insn ) { enum attr_cirrus attr ; if ( ! insn || GET_CODE ( insn ) != INSN || GET_CODE ( PATTERN ( insn ) ) == USE || GET_CODE ( PATTERN ( insn ) ) == CLOBBER ) return 0 ; attr = get_attr_cirrus ( insn ) ; return attr != CIRRUS_NOT ; } </s>

Return TRUE if INSN is a Cirrus instruction .


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

Computes the type of the current function .


<s> HOST_WIDE_INT arm_compute_initial_elimination_offset ( unsigned int from , unsigned int to ) { arm_stack_offsets * offsets ; offsets = arm_get_frame_offsets ( ) ; switch ( from ) { case ARG_POINTER_REGNUM : switch ( to ) { case THUMB_HARD_FRAME_POINTER_REGNUM : return 0 ; case FRAME_POINTER_REGNUM : return offsets -> soft_frame - offsets -> saved_args ; case ARM_HARD_FRAME_POINTER_REGNUM : if ( offsets -> frame == offsets -> saved_regs ) return 0 ; return ( frame_pointer_needed && cfun -> static_chain_decl != NULL && ! cfun -> machine -> uses_anonymous_args ) ? 4 : 0 ; case STACK_POINTER_REGNUM : return offsets -> outgoing_args - ( offsets -> saved_args + 4 ) ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; case FRAME_POINTER_REGNUM : switch ( to ) { case THUMB_HARD_FRAME_POINTER_REGNUM : return 0 ; case ARM_HARD_FRAME_POINTER_REGNUM : return offsets -> frame - offsets -> soft_frame ; case STACK_POINTER_REGNUM : return offsets -> outgoing_args - offsets -> soft_frame ; default : gcc_unreachable ( ) ; } gcc_unreachable ( ) ; default : gcc_unreachable ( ) ; } } </s>

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


<s> static unsigned long arm_compute_save_reg0_reg12_mask ( void ) { unsigned long func_type = arm_current_func_type ( ) ; unsigned long save_reg_mask = 0 ; unsigned int reg ; if ( IS_INTERRUPT ( func_type ) ) { unsigned int max_reg ; if ( ARM_FUNC_TYPE ( func_type ) == ARM_FT_FIQ ) max_reg = 7 ; else max_reg = 12 ; for ( reg = 0 ; reg <= max_reg ; reg ++ ) if ( regs_ever_live [ reg ] || ( ! current_function_is_leaf && call_used_regs [ reg ] ) ) save_reg_mask |= ( 1 << reg ) ; if ( flag_pic && ! TARGET_SINGLE_PIC_BASE && current_function_uses_pic_offset_table ) save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; } 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 ] || current_function_uses_pic_offset_table ) ) save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; } if ( current_function_calls_eh_return ) { unsigned int i ; for ( i = 0 ; ; i ++ ) { reg = EH_RETURN_DATA_REGNO ( i ) ; if ( reg == INVALID_REGNUM ) break ; save_reg_mask |= 1 << reg ; } } return save_reg_mask ; } </s>

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


<s> static unsigned long arm_compute_save_reg_mask ( void ) { 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 && ! current_function_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 ( current_function_pretend_args_size ) ) % 2 ) != 0 ) { unsigned int reg ; 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 ) ; } } 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> static int arm_comp_type_attributes ( tree type1 , tree type2 ) { int l1 , l2 , s1 , s2 ; if ( TREE_CODE ( type1 ) != FUNCTION_TYPE ) return 1 ; l1 = lookup_attribute ( "long_call" , TYPE_ATTRIBUTES ( type1 ) ) != NULL ; l2 = lookup_attribute ( "long_call" , TYPE_ATTRIBUTES ( type2 ) ) != NULL ; s1 = lookup_attribute ( "short_call" , TYPE_ATTRIBUTES ( type1 ) ) != NULL ; s2 = lookup_attribute ( "short_call" , TYPE_ATTRIBUTES ( type2 ) ) != NULL ; if ( l1 | l2 | s1 | s2 ) { if ( ( l1 != l2 ) || ( s1 != s2 ) ) return 0 ; if ( ( l1 & s2 ) || ( l2 & s1 ) ) return 0 ; } l1 = lookup_attribute ( "isr" , TYPE_ATTRIBUTES ( type1 ) ) != NULL ; if ( ! l1 ) l1 = lookup_attribute ( "interrupt" , TYPE_ATTRIBUTES ( type1 ) ) != NULL ; l2 = lookup_attribute ( "isr" , TYPE_ATTRIBUTES ( type2 ) ) != NULL ; if ( ! l2 ) l1 = lookup_attribute ( "interrupt" , TYPE_ATTRIBUTES ( type2 ) ) != NULL ; if ( l1 != l2 ) return 0 ; return 1 ; } </s>

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


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

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


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

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


<s> int arm_const_double_rtx ( rtx x ) { REAL_VALUE_TYPE r ; int i ; if ( ! fp_consts_inited ) init_fp_table ( ) ; REAL_VALUE_FROM_CONST_DOUBLE ( r , x ) ; if ( REAL_VALUE_MINUS_ZERO ( r ) ) return 0 ; for ( i = 0 ; i < fp_consts_inited ; i ++ ) if ( REAL_VALUES_EQUAL ( r , values_fp [ i ] ) ) return 1 ; return 0 ; } </s>

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


<s> int arm_coproc_mem_operand ( rtx op , bool wb ) { rtx ind ; if ( ! ( reload_in_progress || reload_completed ) && ( reg_mentioned_p ( frame_pointer_rtx , op ) || reg_mentioned_p ( arg_pointer_rtx , op ) || reg_mentioned_p ( virtual_incoming_args_rtx , op ) || reg_mentioned_p ( virtual_outgoing_args_rtx , op ) || reg_mentioned_p ( virtual_stack_dynamic_rtx , op ) || reg_mentioned_p ( virtual_stack_vars_rtx , op ) ) ) return FALSE ; if ( GET_CODE ( op ) != MEM ) return FALSE ; ind = XEXP ( op , 0 ) ; if ( reload_completed && ( GET_CODE ( ind ) == LABEL_REF || ( GET_CODE ( ind ) == CONST && GET_CODE ( XEXP ( ind , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( ind , 0 ) , 0 ) ) == LABEL_REF && GET_CODE ( XEXP ( XEXP ( ind , 0 ) , 1 ) ) == CONST_INT ) ) ) return TRUE ; if ( GET_CODE ( ind ) == REG ) return arm_address_register_rtx_p ( ind , 0 ) ; if ( wb && ( GET_CODE ( ind ) == PRE_INC || GET_CODE ( ind ) == POST_INC || GET_CODE ( ind ) == PRE_DEC || GET_CODE ( ind ) == POST_DEC ) ) return arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) ; if ( wb && ( GET_CODE ( ind ) == POST_MODIFY || GET_CODE ( ind ) == PRE_MODIFY ) && arm_address_register_rtx_p ( XEXP ( ind , 0 ) , 0 ) && GET_CODE ( XEXP ( ind , 1 ) ) == PLUS && rtx_equal_p ( XEXP ( XEXP ( ind , 1 ) , 0 ) , XEXP ( ind , 0 ) ) ) ind = XEXP ( ind , 1 ) ; if ( GET_CODE ( ind ) == PLUS && GET_CODE ( XEXP ( ind , 0 ) ) == REG && REG_MODE_OK_FOR_BASE_P ( XEXP ( ind , 0 ) , VOIDmode ) && GET_CODE ( XEXP ( ind , 1 ) ) == CONST_INT && INTVAL ( XEXP ( ind , 1 ) ) > - 1024 && INTVAL ( XEXP ( ind , 1 ) ) < 1024 && ( INTVAL ( XEXP ( ind , 1 ) ) & 3 ) == 0 ) return TRUE ; return FALSE ; } </s>

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


<s> unsigned int arm_dbx_register_number ( unsigned int regno ) { if ( regno < 16 ) return regno ; if ( IS_FPA_REGNUM ( regno ) ) return ( TARGET_AAPCS_BASED ? 96 : 16 ) + regno - FIRST_FPA_REGNUM ; if ( IS_VFP_REGNUM ( regno ) ) return 64 + regno - FIRST_VFP_REGNUM ; if ( IS_IWMMXT_GR_REGNUM ( regno ) ) return 104 + regno - FIRST_IWMMXT_GR_REGNUM ; if ( IS_IWMMXT_REGNUM ( regno ) ) return 112 + regno - FIRST_IWMMXT_REGNUM ; gcc_unreachable ( ) ; } </s>

Map internal gcc register numbers to DWARF2 register numbers .


"unable to compute real location of stacked parameter"

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


<s> static bool arm_default_short_enums ( void ) { return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX ; } </s>

AAPCS based ABIs use short enums by default .


Add a function to the list of static constructors .


<s> void arm_encode_call_attribute ( tree decl , int flag ) { const char * str = XSTR ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) ; int len = strlen ( str ) ; char * newstr ; if ( DECL_WEAK ( decl ) && flag == SHORT_CALL_FLAG_CHAR ) return ; newstr = alloca ( len + 2 ) ; newstr [ 0 ] = flag ; strcpy ( newstr + 1 , str ) ; newstr = ( char * ) ggc_alloc_string ( newstr , len + 1 ) ; XSTR ( XEXP ( DECL_RTL ( decl ) , 0 ) , 0 ) = newstr ; } </s>

Encode long_call or short_call attribute by prefixing symbol name in DECL with a special character FLAG .


<s> static void arm_encode_section_info ( tree decl , rtx rtl , int first ) { if ( optimize > 0 && TREE_CONSTANT ( decl ) ) SYMBOL_REF_FLAG ( XEXP ( rtl , 0 ) ) = 1 ; if ( first && DECL_P ( decl ) ) { if ( TREE_CODE ( decl ) == FUNCTION_DECL && DECL_WEAK ( decl ) ) arm_encode_call_attribute ( decl , LONG_CALL_FLAG_CHAR ) ; else if ( ! TREE_PUBLIC ( decl ) ) arm_encode_call_attribute ( decl , SHORT_CALL_FLAG_CHAR ) ; } default_encode_section_info ( decl , rtl , first ) ; } </s>

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


<s> static rtx arm_expand_binop_builtin ( enum insn_code icode , tree arglist , rtx target ) { rtx pat ; tree arg0 = TREE_VALUE ( arglist ) ; tree arg1 = TREE_VALUE ( TREE_CHAIN ( arglist ) ) ; rtx op0 = expand_expr ( arg0 , NULL_RTX , VOIDmode , 0 ) ; rtx op1 = expand_expr ( arg1 , NULL_RTX , VOIDmode , 0 ) ; enum machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; enum machine_mode mode0 = insn_data [ icode ] . operand [ 1 ] . mode ; enum 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 ( op1 ) == mode1 ) ; 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_unop_builtin ( enum insn_code icode , tree arglist , rtx target , int do_load ) { rtx pat ; tree arg0 = TREE_VALUE ( arglist ) ; rtx op0 = expand_expr ( arg0 , NULL_RTX , VOIDmode , 0 ) ; enum machine_mode tmode = insn_data [ icode ] . operand [ 0 ] . mode ; enum 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>

Subroutine of arm_expand_builtin to take care of unop insns .


<s> static bool arm_fastmul_rtx_costs ( rtx x , int code , int outer_code , int * total ) { enum machine_mode mode = GET_MODE ( x ) ; if ( TARGET_THUMB ) { * 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 = 8 ; return true ; } if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || mode == DImode ) { * total = 30 ; return true ; } if ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) { unsigned HOST_WIDE_INT i = ( INTVAL ( XEXP ( x , 1 ) ) & ( unsigned HOST_WIDE_INT ) 0xffffffff ) ; int cost , const_ok = const_ok_for_arm ( i ) ; int j , booth_unit_size ; cost = const_ok ? 4 : 8 ; booth_unit_size = 8 ; for ( j = 0 ; i && j < 32 ; j += booth_unit_size ) { i >>= booth_unit_size ; cost += 2 ; } * total = cost ; return true ; } * total = 8 + ( REG_OR_SUBREG_REG ( XEXP ( x , 0 ) ) ? 0 : 4 ) + ( REG_OR_SUBREG_REG ( XEXP ( x , 1 ) ) ? 0 : 4 ) ; return true ; default : * total = arm_rtx_costs_1 ( x , code , outer_code ) ; return true ; } } </s>

RTX cost for cores with a fast multiply unit ( M variants ) .


<s> int arm_float_words_big_endian ( void ) { if ( TARGET_MAVERICK ) return 0 ; if ( TARGET_FPA ) { return 1 ; } if ( TARGET_VFP ) return ( TARGET_BIG_END ? 1 : 0 ) ; return 1 ; } </s>

Indicate whether or not words of a double are in big-endian order .


<s> rtx arm_function_arg ( CUMULATIVE_ARGS * pcum , enum machine_mode mode , tree type , int named ) { int nregs ; if ( TARGET_IWMMXT_ABI && arm_vector_mode_supported_p ( mode ) && pcum -> named_count > pcum -> nargs + 1 ) { if ( pcum -> iwmmxt_nregs <= 9 ) return gen_rtx_REG ( mode , pcum -> iwmmxt_nregs + FIRST_IWMMXT_REGNUM ) ; else { pcum -> can_split = false ; return NULL_RTX ; } } if ( pcum -> nregs & 1 && ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align ( mode , type ) ) pcum -> nregs ++ ; if ( mode == VOIDmode ) return GEN_INT ( pcum -> call_cookie ) ; if ( pcum -> can_split ) nregs = 1 ; else nregs = ARM_NUM_REGS2 ( mode , type ) ; if ( ! named || pcum -> nregs + nregs > NUM_ARG_REGS ) return NULL_RTX ; return gen_rtx_REG ( mode , pcum -> nregs ) ; } </s>

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


<s> static bool arm_function_ok_for_sibcall ( tree decl , tree exp ATTRIBUTE_UNUSED ) { int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL ; if ( cfun -> machine -> sibcall_blocked ) return false ; if ( decl == NULL || TARGET_THUMB ) return false ; if ( lookup_attribute ( "short_call" , TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ) ) call_type = CALL_SHORT ; else if ( lookup_attribute ( "long_call" , TYPE_ATTRIBUTES ( TREE_TYPE ( decl ) ) ) ) call_type = CALL_LONG ; if ( call_type == CALL_LONG && ( flag_pic || ! TREE_ASM_WRITTEN ( decl ) ) ) return false ; if ( TARGET_INTERWORK && TREE_PUBLIC ( decl ) && ! TREE_ASM_WRITTEN ( decl ) ) return false ; if ( IS_INTERRUPT ( arm_current_func_type ( ) ) ) return false ; return true ; } </s>

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


<s> rtx arm_function_value ( tree type , tree func ATTRIBUTE_UNUSED ) { enum machine_mode mode ; int unsignedp ATTRIBUTE_UNUSED ; rtx r ATTRIBUTE_UNUSED ; mode = TYPE_MODE ( type ) ; if ( INTEGRAL_TYPE_P ( type ) ) PROMOTE_FUNCTION_MODE ( mode , unsignedp , type ) ; if ( arm_return_in_msb ( type ) ) { HOST_WIDE_INT size = int_size_in_bytes ( type ) ; if ( size % UNITS_PER_WORD != 0 ) { size += UNITS_PER_WORD - size % UNITS_PER_WORD ; mode = mode_for_size ( size * BITS_PER_UNIT , MODE_INT , 0 ) ; } } return LIBCALL_VALUE ( mode ) ; } </s>

Define how to find the value returned by a function .


<s> rtx arm_gen_compare_reg ( enum rtx_code code , rtx x , rtx y ) { enum machine_mode mode = SELECT_CC_MODE ( code , x , y ) ; rtx cc_reg = gen_rtx_REG ( mode , CC_REGNUM ) ; emit_insn ( gen_rtx_SET ( VOIDmode , cc_reg , gen_rtx_COMPARE ( mode , x , y ) ) ) ; return cc_reg ; } </s>

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


<s> rtx arm_gen_load_multiple ( int base_regno , int count , rtx from , int up , int write_back , rtx basemem , HOST_WIDE_INT * offsetp ) { HOST_WIDE_INT offset = * offsetp ; int i = 0 , j ; rtx result ; int sign = up ? 1 : - 1 ; rtx mem , addr ; if ( arm_tune_xscale && count <= 2 && ! optimize_size ) { rtx seq ; start_sequence ( ) ; for ( i = 0 ; i < count ; i ++ ) { addr = plus_constant ( from , i * 4 * sign ) ; mem = adjust_automodify_address ( basemem , SImode , addr , offset ) ; emit_move_insn ( gen_rtx_REG ( SImode , base_regno + i ) , mem ) ; offset += 4 * sign ; } if ( write_back ) { emit_move_insn ( from , plus_constant ( from , count * 4 * sign ) ) ; * offsetp = offset ; } seq = get_insns ( ) ; end_sequence ( ) ; return seq ; } result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count + ( write_back ? 1 : 0 ) ) ) ; if ( write_back ) { XVECEXP ( result , 0 , 0 ) = gen_rtx_SET ( GET_MODE ( from ) , from , plus_constant ( from , count * 4 * sign ) ) ; i = 1 ; count ++ ; } for ( j = 0 ; i < count ; i ++ , j ++ ) { addr = plus_constant ( from , j * 4 * sign ) ; mem = adjust_automodify_address_nv ( basemem , SImode , addr , offset ) ; XVECEXP ( result , 0 , i ) = gen_rtx_SET ( VOIDmode , gen_rtx_REG ( SImode , base_regno + j ) , mem ) ; offset += 4 * sign ; } if ( write_back ) * offsetp = offset ; return result ; } </s>


<s> static arm_stack_offsets * arm_get_frame_offsets ( void ) { struct arm_stack_offsets * offsets ; unsigned long func_type ; int leaf ; int saved ; HOST_WIDE_INT frame_size ; offsets = & cfun -> machine -> stack_offsets ; if ( reload_completed ) return offsets ; frame_size = ROUND_UP_WORD ( get_frame_size ( ) ) ; leaf = leaf_function_p ( ) ; offsets -> saved_args = current_function_pretend_args_size ; offsets -> frame = offsets -> saved_args + ( frame_pointer_needed ? 4 : 0 ) ; if ( TARGET_ARM ) { unsigned int regno ; saved = bit_count ( arm_compute_save_reg_mask ( ) ) * 4 ; if ( TARGET_REALLY_IWMMXT ) { for ( regno = FIRST_IWMMXT_REGNUM ; regno <= LAST_IWMMXT_REGNUM ; regno ++ ) if ( regs_ever_live [ regno ] && ! call_used_regs [ regno ] ) saved += 8 ; } func_type = arm_current_func_type ( ) ; if ( ! IS_VOLATILE ( func_type ) ) { for ( regno = FIRST_FPA_REGNUM ; regno <= LAST_FPA_REGNUM ; regno ++ ) if ( regs_ever_live [ regno ] && ! call_used_regs [ regno ] ) saved += 12 ; if ( TARGET_HARD_FLOAT && TARGET_VFP ) saved += arm_get_vfp_saved_size ( ) ; } } else { saved = bit_count ( thumb_compute_save_reg_mask ( ) ) * 4 ; if ( TARGET_BACKTRACE ) saved += 16 ; } offsets -> saved_regs = offsets -> saved_args + saved ; offsets -> soft_frame = offsets -> saved_regs + CALLER_INTERWORKING_SLOT_SIZE ; if ( leaf && frame_size == 0 ) { offsets -> outgoing_args = offsets -> soft_frame ; return offsets ; } if ( ARM_DOUBLEWORD_ALIGN && ( offsets -> soft_frame & 7 ) ) offsets -> soft_frame += 4 ; offsets -> locals_base = offsets -> soft_frame + frame_size ; offsets -> outgoing_args = ( offsets -> locals_base + current_function_outgoing_args_size ) ; if ( ARM_DOUBLEWORD_ALIGN ) { if ( offsets -> outgoing_args & 7 ) offsets -> outgoing_args += 4 ; gcc_assert ( ! ( offsets -> outgoing_args & 7 ) ) ; } return offsets ; } </s>

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


<s> static int arm_get_vfp_saved_size ( void ) { unsigned int regno ; int count ; int saved ; saved = 0 ; if ( TARGET_HARD_FLOAT && TARGET_VFP ) { count = 0 ; for ( regno = FIRST_VFP_REGNUM ; regno < LAST_VFP_REGNUM ; regno += 2 ) { if ( ( ! regs_ever_live [ regno ] || call_used_regs [ regno ] ) && ( ! regs_ever_live [ regno + 1 ] || call_used_regs [ regno + 1 ] ) ) { if ( count > 0 ) { if ( count == 2 && ! arm_arch6 ) count ++ ; saved += count * 8 + 4 ; } count = 0 ; } else count ++ ; } if ( count > 0 ) { if ( count == 2 && ! arm_arch6 ) count ++ ; saved += count * 8 + 4 ; } } return saved ; } </s>

Return the number of bytes required to save VFP registers .


"%qs attribute only applies to functions"

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


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


<s> static bool arm_handle_option ( size_t code , const char * arg , int value ATTRIBUTE_UNUSED ) { switch ( code ) { case OPT_march_ : arm_select [ 1 ] . string = arg ; return true ; case OPT_mcpu_ : arm_select [ 0 ] . string = arg ; return true ; case OPT_mhard_float : target_float_abi_name = "hard" ; return true ; case OPT_msoft_float : target_float_abi_name = "soft" ; return true ; case OPT_mtune_ : arm_select [ 2 ] . string = arg ; return true ; default : return true ; } } </s>


<s> int arm_hard_regno_mode_ok ( unsigned int regno , enum machine_mode mode ) { if ( GET_MODE_CLASS ( mode ) == MODE_CC ) return ( regno == CC_REGNUM || ( TARGET_HARD_FLOAT && TARGET_VFP && regno == VFPCC_REGNUM ) ) ; if ( TARGET_THUMB ) return ( ARM_NUM_REGS ( mode ) < 2 ) || ( regno < LAST_LO_REGNUM ) ; if ( TARGET_HARD_FLOAT && TARGET_MAVERICK && IS_CIRRUS_REGNUM ( regno ) ) return ( GET_MODE_CLASS ( mode ) == MODE_FLOAT ) || ( mode == DImode ) ; if ( TARGET_HARD_FLOAT && TARGET_VFP && IS_VFP_REGNUM ( regno ) ) { if ( mode == SFmode || mode == SImode ) return TRUE ; if ( mode == DFmode ) return ( ( regno - FIRST_VFP_REGNUM ) & 1 ) == 0 ; 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 ) return ! ( TARGET_LDRD && 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 ( TARGET_HARD_FLOAT && TARGET_FPA && GET_MODE_CLASS ( mode ) == MODE_FLOAT && regno >= FIRST_FPA_REGNUM && regno <= LAST_FPA_REGNUM ) ; } </s>

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


<s> void arm_init_cumulative_args ( CUMULATIVE_ARGS * pcum , tree fntype , rtx libname ATTRIBUTE_UNUSED , tree fndecl ATTRIBUTE_UNUSED ) { pcum -> nregs = ( ( fntype && aggregate_value_p ( TREE_TYPE ( fntype ) , fntype ) ) ? 1 : 0 ) ; pcum -> iwmmxt_nregs = 0 ; pcum -> can_split = true ; pcum -> call_cookie = CALL_NORMAL ; if ( TARGET_LONG_CALLS ) pcum -> call_cookie = CALL_LONG ; if ( fntype ) { if ( lookup_attribute ( "short_call" , TYPE_ATTRIBUTES ( fntype ) ) ) pcum -> call_cookie = CALL_SHORT ; else if ( lookup_attribute ( "long_call" , TYPE_ATTRIBUTES ( fntype ) ) ) pcum -> call_cookie = CALL_LONG ; } pcum -> named_count = 0 ; pcum -> nargs = 0 ; if ( TARGET_REALLY_IWMMXT && fntype ) { tree fn_arg ; for ( fn_arg = TYPE_ARG_TYPES ( fntype ) ; fn_arg ; fn_arg = TREE_CHAIN ( fn_arg ) ) pcum -> named_count += 1 ; if ( ! pcum -> named_count ) pcum -> named_count = INT_MAX ; } } </s>

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


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

Functions to save and restore machine-specific function data .


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

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


<s> int arm_is_longcall_p ( rtx sym_ref , int call_cookie , int call_symbol ) { if ( ! call_symbol ) { if ( GET_CODE ( sym_ref ) != MEM ) return 0 ; sym_ref = XEXP ( sym_ref , 0 ) ; } if ( GET_CODE ( sym_ref ) != SYMBOL_REF ) return 0 ; if ( call_cookie & CALL_SHORT ) return 0 ; if ( TARGET_LONG_CALLS ) { if ( flag_function_sections || DECL_SECTION_NAME ( current_function_decl ) ) return 1 ; } if ( current_file_function_operand ( sym_ref ) ) return 0 ; return ( call_cookie & CALL_LONG ) || ENCODED_LONG_CALL_ATTR_P ( XSTR ( sym_ref , 0 ) ) || TARGET_LONG_CALLS ; } </s>

Return nonzero if a 32 bit `` long_call '' should be generated for this call . We generate a long_call if the function : a. has an __attribute__ ( ( long call ) ) or b. is within the scope of a # pragma long_calls or c. the -mlong-calls command line switch has been specified . and either : 1 . -ffunction-sections is in effect or 2. the current function has __attribute__ ( ( section ) ) or 3. the target function has __attribute__ ( ( section ) ) However we do not generate a long call if the function : d. has an __attribute__ ( ( short_call ) ) or e. is inside the scope of a # pragma no_long_calls or f. is defined within the current compilation unit . This function will be called by C fragments contained in the machine description file . SYM_REF and CALL_COOKIE correspond to the matched rtl operands . CALL_SYMBOL is used to distinguish between two different callers of the function . It is set to 1 in the `` call_symbol '' and `` call_symbol_value '' patterns and to 0 in the `` call '' and `` call_value '' patterns . This is because of the difference in the SYM_REFs passed by these patterns .


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

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


<s> static int arm_legitimate_index_p ( enum machine_mode mode , rtx index , RTX_CODE outer , int strict_p ) { HOST_WIDE_INT range ; enum rtx_code code = GET_CODE ( index ) ; if ( TARGET_HARD_FLOAT && ( TARGET_FPA || TARGET_MAVERICK ) && ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || ( TARGET_MAVERICK && mode == DImode ) ) ) return ( code == CONST_INT && INTVAL ( index ) < 1024 && INTVAL ( index ) > - 1024 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE ( mode ) ) return ( code == CONST_INT && INTVAL ( index ) < 1024 && INTVAL ( index ) > - 1024 && ( INTVAL ( index ) & 3 ) == 0 ) ; if ( arm_address_register_rtx_p ( index , strict_p ) && ( GET_MODE_SIZE ( mode ) <= 4 ) ) return 1 ; if ( mode == DImode || mode == DFmode ) { if ( code == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( index ) ; if ( TARGET_LDRD ) return val > - 256 && val < 256 ; else return val > - 4096 && val < 4092 ; } return TARGET_LDRD && arm_address_register_rtx_p ( index , strict_p ) ; } if ( GET_MODE_SIZE ( mode ) <= 4 && ! ( arm_arch4 && ( mode == HImode || ( mode == QImode && outer == SIGN_EXTEND ) ) ) ) { if ( code == MULT ) { rtx xiop0 = XEXP ( index , 0 ) ; rtx xiop1 = XEXP ( index , 1 ) ; return ( ( arm_address_register_rtx_p ( xiop0 , strict_p ) && power_of_two_operand ( xiop1 , SImode ) ) || ( arm_address_register_rtx_p ( xiop1 , strict_p ) && power_of_two_operand ( xiop0 , SImode ) ) ) ; } else if ( code == LSHIFTRT || code == ASHIFTRT || code == ASHIFT || code == ROTATERT ) { rtx op = XEXP ( index , 1 ) ; return ( arm_address_register_rtx_p ( XEXP ( index , 0 ) , strict_p ) && GET_CODE ( op ) == CONST_INT && INTVAL ( op ) > 0 && INTVAL ( op ) <= 31 ) ; } } if ( arm_arch4 ) { if ( mode == HImode || ( outer == SIGN_EXTEND && mode == QImode ) ) range = 256 ; else range = 4096 ; } else range = ( mode == HImode ) ? 4095 : 4096 ; return ( code == CONST_INT && INTVAL ( index ) < range && INTVAL ( index ) > - range ) ; } </s>

Return nonzero if INDEX is valid for an address index operand in ARM state .


<s> void arm_load_pic_register ( unsigned long saved_regs ATTRIBUTE_UNUSED ) { rtx l1 , labelno , pic_tmp , pic_tmp2 , pic_rtx ; rtx global_offset_table ; if ( current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE ) return ; gcc_assert ( flag_pic ) ; labelno = GEN_INT ( pic_labelno ++ ) ; l1 = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_PIC_LABEL ) ; l1 = gen_rtx_CONST ( VOIDmode , l1 ) ; global_offset_table = gen_rtx_SYMBOL_REF ( Pmode , "_GLOBAL_OFFSET_TABLE_" ) ; pic_tmp = plus_constant ( l1 , TARGET_ARM ? 8 : 4 ) ; if ( GOT_PCREL ) pic_tmp2 = gen_rtx_CONST ( VOIDmode , gen_rtx_PLUS ( Pmode , global_offset_table , pc_rtx ) ) ; else pic_tmp2 = gen_rtx_CONST ( VOIDmode , global_offset_table ) ; pic_rtx = gen_rtx_CONST ( Pmode , gen_rtx_MINUS ( Pmode , pic_tmp2 , pic_tmp ) ) ; if ( TARGET_ARM ) { emit_insn ( gen_pic_load_addr_arm ( pic_offset_table_rtx , pic_rtx ) ) ; emit_insn ( gen_pic_add_dot_plus_eight ( pic_offset_table_rtx , pic_offset_table_rtx , labelno ) ) ; } else { if ( REGNO ( pic_offset_table_rtx ) > LAST_LO_REGNUM ) { pic_tmp = gen_rtx_REG ( SImode , thumb_find_work_register ( saved_regs ) ) ; emit_insn ( gen_pic_load_addr_thumb ( pic_tmp , pic_rtx ) ) ; emit_insn ( gen_movsi ( pic_offset_table_rtx , pic_tmp ) ) ; } else emit_insn ( gen_pic_load_addr_thumb ( pic_offset_table_rtx , pic_rtx ) ) ; emit_insn ( gen_pic_add_dot_plus_four ( pic_offset_table_rtx , pic_offset_table_rtx , labelno ) ) ; } emit_insn ( gen_rtx_USE ( VOIDmode , pic_offset_table_rtx ) ) ; } </s>

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


<s> static bool arm_memory_load_p ( rtx insn ) { rtx body , lhs , rhs ; ; if ( insn == NULL_RTX || GET_CODE ( insn ) != INSN ) return false ; body = PATTERN ( insn ) ; if ( GET_CODE ( body ) != SET ) return false ; lhs = XEXP ( body , 0 ) ; rhs = XEXP ( body , 1 ) ; lhs = REG_OR_SUBREG_RTX ( lhs ) ; if ( GET_CODE ( lhs ) != REG || REGNO_REG_CLASS ( REGNO ( lhs ) ) != GENERAL_REGS ) return false ; return ( GET_CODE ( rhs ) == MEM || GET_CODE ( rhs ) == SYMBOL_REF || note_invalid_constants ( insn , - 1 , false ) ) ; } </s>

Returns TRUE if INSN is an `` LDR REG , ADDR '' instruction . Use by the Cirrus Maverick code which has to workaround a hardware bug triggered by such instructions .


<s> static bool arm_must_pass_in_stack ( enum machine_mode mode , tree type ) { if ( TARGET_AAPCS_BASED ) return must_pass_in_stack_var_size ( mode , type ) ; else return must_pass_in_stack_var_size_or_pad ( mode , type ) ; } </s>

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


<s> bool arm_needs_doubleword_align ( enum machine_mode mode , tree type ) { return ( GET_MODE_ALIGNMENT ( mode ) > PARM_BOUNDARY || ( type && TYPE_ALIGN ( type ) > PARM_BOUNDARY ) ) ; } </s>

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


<s> int arm_no_early_alu_shift_dep ( rtx producer , rtx consumer ) { rtx value = PATTERN ( producer ) ; rtx op = PATTERN ( consumer ) ; rtx early_op ; if ( GET_CODE ( value ) == COND_EXEC ) value = COND_EXEC_CODE ( value ) ; if ( GET_CODE ( value ) == PARALLEL ) value = XVECEXP ( value , 0 , 0 ) ; value = XEXP ( value , 0 ) ; if ( GET_CODE ( op ) == COND_EXEC ) op = COND_EXEC_CODE ( op ) ; if ( GET_CODE ( op ) == PARALLEL ) op = XVECEXP ( op , 0 , 0 ) ; op = XEXP ( op , 1 ) ; early_op = XEXP ( op , 0 ) ; if ( GET_CODE ( early_op ) == REG ) early_op = op ; return ! reg_overlap_mentioned_p ( value , early_op ) ; } </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 arm_no_early_alu_shift_value_dep ( rtx producer , rtx consumer ) { rtx value = PATTERN ( producer ) ; rtx op = PATTERN ( consumer ) ; rtx early_op ; if ( GET_CODE ( value ) == COND_EXEC ) value = COND_EXEC_CODE ( value ) ; if ( GET_CODE ( value ) == PARALLEL ) value = XVECEXP ( value , 0 , 0 ) ; value = XEXP ( value , 0 ) ; if ( GET_CODE ( op ) == COND_EXEC ) op = COND_EXEC_CODE ( op ) ; if ( GET_CODE ( op ) == PARALLEL ) op = XVECEXP ( op , 0 , 0 ) ; op = XEXP ( op , 1 ) ; early_op = XEXP ( op , 0 ) ; if ( GET_CODE ( early_op ) != REG ) early_op = XEXP ( early_op , 0 ) ; return ! reg_overlap_mentioned_p ( value , early_op ) ; } </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 = PATTERN ( producer ) ; rtx op = PATTERN ( consumer ) ; if ( GET_CODE ( value ) == COND_EXEC ) value = COND_EXEC_CODE ( value ) ; if ( GET_CODE ( value ) == PARALLEL ) value = XVECEXP ( value , 0 , 0 ) ; value = XEXP ( value , 0 ) ; if ( GET_CODE ( op ) == COND_EXEC ) op = COND_EXEC_CODE ( op ) ; if ( GET_CODE ( op ) == PARALLEL ) op = XVECEXP ( op , 0 , 0 ) ; op = XEXP ( op , 1 ) ; return ( GET_CODE ( op ) == PLUS && ! reg_overlap_mentioned_p ( value , XEXP ( op , 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 = PATTERN ( producer ) ; rtx addr = PATTERN ( consumer ) ; if ( GET_CODE ( value ) == COND_EXEC ) value = COND_EXEC_CODE ( value ) ; if ( GET_CODE ( value ) == PARALLEL ) value = XVECEXP ( value , 0 , 0 ) ; value = XEXP ( value , 0 ) ; if ( GET_CODE ( addr ) == COND_EXEC ) addr = COND_EXEC_CODE ( addr ) ; if ( GET_CODE ( addr ) == PARALLEL ) addr = XVECEXP ( addr , 0 , 0 ) ; addr = XEXP ( addr , 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_output_addr_const_extra ( FILE * fp , rtx x ) { if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) return arm_emit_tls_decoration ( fp , x ) ; else if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_PIC_LABEL ) { char label [ 256 ] ; int labelno = INTVAL ( XVECEXP ( x , 0 , 0 ) ) ; ASM_GENERATE_INTERNAL_LABEL ( label , "LPIC" , labelno ) ; assemble_name_raw ( fp , label ) ; return TRUE ; } else if ( GET_CODE ( x ) == CONST_VECTOR ) return arm_emit_vector_const ( fp , x ) ; return FALSE ; } </s>


<s>
static
void
arm_output_fldmx
(
FILE
*
stream
,
unsigned
int
base
,
int
reg
,
int
count
)
{
int
i
;
if
(
count
==
2
&&
!
arm_arch6
)
{
if
(
reg
==
15
)
reg
;
count
++
;
}
fputc
(
'\t'
,
stream
)
;
asm_fprintf
(
stream
,
"fldmfdx\t%r!, {"
,
base
)
;
for
(
i
=
reg
;
i
<
reg
+
count
;
i
++
)
{
if
(
i
>
reg
)
fputs
(
", "
,
stream
)
;
asm_fprintf
(
stream
,
"d%d"
,
i
)
;
}
fputs
(
"}\n"
,
stream
)
;
}
</s>

Output a FLDMX instruction to STREAM . BASE if the register containing the address . REG and COUNT specify the register range . Extra registers may be added to avoid hardware bugs .


<s> void arm_output_fn_unwind ( FILE * f , bool prologue ) { if ( ! ARM_EABI_UNWIND_TABLES ) return ; if ( prologue ) fputs ( "\t.fnstart\n" , f ) ; else fputs ( "\t.fnend\n" , f ) ; } </s>

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


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

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

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

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

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

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

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

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


<s>
static
void
arm_output_mi_thunk
(
FILE
*
file
,
tree
thunk
ATTRIBUTE_UNUSED
,
HOST_WIDE_INT
delta
,
HOST_WIDE_INT
vcall_offset
ATTRIBUTE_UNUSED
,
tree
function
)
{
static
int
thunk_label
=
0
;
char
label
[
256
]
;
int
mi_delta
=
delta
;
const
char
*
const
mi_op
=
mi_delta
<
0
"sub"
:
"add"
;
int
shift
=
0
;
int
this_regno
=
(
aggregate_value_p
(
TREE_TYPE
(
TREE_TYPE
(
function
)
)
,
function
)
1
:
0
)
;
if
(
mi_delta
<
0
)
mi_delta
=
mi_delta
;
if
(
TARGET_THUMB
)
{
int
labelno
=
thunk_label
++
;
ASM_GENERATE_INTERNAL_LABEL
(
label
,
"LTHUMBFUNC"
,
labelno
)
;
fputs
(
"\tldr\tr12, "
,
file
)
;
assemble_name
(
file
,
label
)
;
fputc
(
'\n'
,
file
)
;
}
while
(
mi_delta
!=
0
)
{
if
(
(
mi_delta
&
(
3
<<
shift
)
)
==
0
)
shift
+=
2
;
else
{
asm_fprintf
(
file
,
"\t%s\t%r, %r, #%d\n"
,
mi_op
,
this_regno
,
this_regno
,
mi_delta
&
(
0xff
<<
shift
)
)
;
mi_delta
&=
~
(
0xff
<<
shift
)
;
shift
+=
8
;
}
}
if
(
TARGET_THUMB
)
{
fprintf
(
file
,
"\tbx\tr12\n"
)
;
ASM_OUTPUT_ALIGN
(
file
,
2
)
;
assemble_name
(
file
,
label
)
;
fputs
(
":\n"
,
file
)
;
assemble_integer
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
4
,
BITS_PER_WORD
,
1
)
;
}
else
{
fputs
(
"\tb\t"
,
file
)
;
assemble_name
(
file
,
XSTR
(
XEXP
(
DECL_RTL
(
function
)
,
0
)
,
0
)
)
;
if
(
NEED_PLT_RELOC
)
fputs
(
"(PLT)"
,
file
)
;
fputc
(
'\n'
,
file
)
;
}
}
</s>

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


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

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


<s> bool arm_pad_arg_upward ( enum machine_mode mode , tree type ) { if ( ! TARGET_AAPCS_BASED ) return DEFAULT_FUNCTION_ARG_PADDING ( mode , type ) == upward ; if ( type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P ( type ) ) return false ; return true ; } </s>

For use by FUNCTION_ARG_PADDING ( MODE , TYPE ) . Return true if an argument passed on the stack should be padded upwards , i.e . if the least-significant byte has useful data . For legacy APCS ABIs we use the default . For AAPCS based ABIs small aggregate types are placed in the lowest memory address .


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

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


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

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


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

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


<s> int arm_regno_class ( int regno ) { if ( TARGET_THUMB ) { 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 ( regno <= LAST_ARM_REGNUM || regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM ) return GENERAL_REGS ; if ( regno == CC_REGNUM || regno == VFPCC_REGNUM ) return NO_REGS ; if ( IS_CIRRUS_REGNUM ( regno ) ) return CIRRUS_REGS ; if ( IS_VFP_REGNUM ( regno ) ) return VFP_REGS ; if ( IS_IWMMXT_REGNUM ( regno ) ) return IWMMXT_REGS ; if ( IS_IWMMXT_GR_REGNUM ( regno ) ) return IWMMXT_GR_REGS ; return FPA_REGS ; } </s>

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


<s> static void arm_reorg ( void ) { rtx insn ; HOST_WIDE_INT address = 0 ; Mfix * fix ; minipool_fix_head = minipool_fix_tail = NULL ; insn = get_insns ( ) ; gcc_assert ( GET_CODE ( insn ) == NOTE ) ; for ( insn = next_nonnote_insn ( insn ) ; insn ; insn = next_nonnote_insn ( insn ) ) { if ( TARGET_CIRRUS_FIX_INVALID_INSNS && ( arm_cirrus_insn_p ( insn ) || GET_CODE ( insn ) == JUMP_INSN || arm_memory_load_p ( insn ) ) ) cirrus_reorg ( insn ) ; if ( GET_CODE ( insn ) == BARRIER ) push_minipool_barrier ( insn , address ) ; else if ( INSN_P ( insn ) ) { rtx table ; note_invalid_constants ( insn , address , true ) ; address += get_attr_length ( insn ) ; if ( ( table = is_jump_table ( insn ) ) != NULL ) { address += get_jump_table_size ( table ) ; insn = table ; } } } fix = minipool_fix_head ; while ( fix ) { Mfix * ftmp ; Mfix * fdel ; Mfix * last_added_fix ; Mfix * last_barrier = NULL ; Mfix * this_fix ; while ( fix && GET_CODE ( fix -> insn ) == BARRIER ) fix = fix -> next ; if ( fix == NULL ) break ; last_added_fix = NULL ; for ( ftmp = fix ; ftmp ; ftmp = ftmp -> next ) { if ( GET_CODE ( ftmp -> insn ) == BARRIER ) { if ( ftmp -> address >= minipool_vector_head -> max_address ) break ; last_barrier = ftmp ; } else if ( ( ftmp -> minipool = add_minipool_forward_ref ( ftmp ) ) == NULL ) break ; last_added_fix = ftmp ; } if ( last_barrier != NULL ) { for ( fdel = last_barrier -> next ; fdel && fdel != ftmp ; fdel = fdel -> next ) { fdel -> minipool -> refcount -- ; fdel -> minipool = NULL ; } ftmp = last_barrier ; } else { HOST_WIDE_INT max_address ; gcc_assert ( ftmp ) ; max_address = minipool_vector_head -> max_address ; if ( ftmp -> address < max_address ) max_address = ftmp -> address ; last_barrier = create_fix_barrier ( last_added_fix , max_address ) ; } assign_minipool_offsets ( last_barrier ) ; while ( ftmp ) { if ( GET_CODE ( ftmp -> insn ) != BARRIER && ( ( ftmp -> minipool = add_minipool_backward_ref ( ftmp ) ) == NULL ) ) break ; ftmp = ftmp -> next ; } for ( this_fix = fix ; this_fix && ftmp != this_fix ; this_fix = this_fix -> next ) if ( GET_CODE ( this_fix -> insn ) != BARRIER ) { rtx addr = plus_constant ( gen_rtx_LABEL_REF ( VOIDmode , minipool_vector_label ) , this_fix -> minipool -> offset ) ; * this_fix -> loc = gen_rtx_MEM ( this_fix -> mode , addr ) ; } dump_minipool ( last_barrier -> insn ) ; fix = ftmp ; } after_arm_reorg = 1 ; obstack_free ( & minipool_obstack , minipool_startobj ) ; } </s>

Gcc puts the pool in the wrong place for ARM , since we can only load addresses a limited distance around the pc . We do some special munging to move the constant pool values to the correct point in the code .


<s> int arm_return_in_memory ( tree type ) { HOST_WIDE_INT size ; if ( ! AGGREGATE_TYPE_P ( type ) && ( TREE_CODE ( type ) != VECTOR_TYPE ) && ! ( TARGET_AAPCS_BASED && TREE_CODE ( type ) == COMPLEX_TYPE ) ) return 0 ; size = int_size_in_bytes ( type ) ; if ( arm_abi != ARM_ABI_APCS ) { return ( size < 0 || size > UNITS_PER_WORD ) ; } if ( TREE_CODE ( type ) == VECTOR_TYPE ) return ( size < 0 || size > ( 4 * UNITS_PER_WORD ) ) ; if ( size < 0 || size > UNITS_PER_WORD ) return 1 ; if ( TREE_CODE ( type ) == RECORD_TYPE ) { tree field ; for ( field = TYPE_FIELDS ( type ) ; field && TREE_CODE ( field ) != FIELD_DECL ; field = TREE_CHAIN ( field ) ) continue ; if ( field == NULL ) return 0 ; if ( FLOAT_TYPE_P ( TREE_TYPE ( field ) ) ) return 1 ; if ( RETURN_IN_MEMORY ( TREE_TYPE ( field ) ) ) return 1 ; for ( field = TREE_CHAIN ( field ) ; field ; field = TREE_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( ! DECL_BIT_FIELD_TYPE ( field ) ) return 1 ; } return 0 ; } if ( TREE_CODE ( type ) == UNION_TYPE ) { tree field ; for ( field = TYPE_FIELDS ( type ) ; field ; field = TREE_CHAIN ( field ) ) { if ( TREE_CODE ( field ) != FIELD_DECL ) continue ; if ( FLOAT_TYPE_P ( TREE_TYPE ( field ) ) ) return 1 ; if ( RETURN_IN_MEMORY ( TREE_TYPE ( field ) ) ) return 1 ; } return 0 ; } return 1 ; } </s>

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


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

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


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

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


<s> static void arm_setup_incoming_varargs ( CUMULATIVE_ARGS * cum , enum machine_mode mode ATTRIBUTE_UNUSED , tree type ATTRIBUTE_UNUSED , int * pretend_size , int second_time ATTRIBUTE_UNUSED ) { cfun -> machine -> uses_anonymous_args = 1 ; if ( cum -> nregs < NUM_ARG_REGS ) * pretend_size = ( NUM_ARG_REGS - cum -> nregs ) * UNITS_PER_WORD ; } </s>

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 unsigned HOST_WIDE_INT arm_shift_truncation_mask ( enum machine_mode mode ) { return mode == SImode ? 255 : 0 ; } </s>

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


<s> static int arm_size_return_regs ( void ) { enum machine_mode mode ; if ( current_function_return_rtx != 0 ) mode = GET_MODE ( current_function_return_rtx ) ; else mode = DECL_MODE ( DECL_RESULT ( current_function_decl ) ) ; return GET_MODE_SIZE ( mode ) ; } </s>

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


<s> static bool arm_slowmul_rtx_costs ( rtx x , int code , int outer_code , int * total ) { enum machine_mode mode = GET_MODE ( x ) ; if ( TARGET_THUMB ) { * total = thumb_rtx_costs ( x , code , outer_code ) ; return true ; } switch ( code ) { case MULT : if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || mode == DImode ) { * total = 30 ; return true ; } if ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) { unsigned HOST_WIDE_INT i = ( INTVAL ( XEXP ( x , 1 ) ) & ( unsigned HOST_WIDE_INT ) 0xffffffff ) ; int cost , const_ok = const_ok_for_arm ( i ) ; int j , booth_unit_size ; cost = const_ok ? 4 : 8 ; booth_unit_size = 2 ; for ( j = 0 ; i && j < 32 ; j += booth_unit_size ) { i >>= booth_unit_size ; cost += 2 ; } * total = cost ; return true ; } * total = 30 + ( REG_OR_SUBREG_REG ( XEXP ( x , 0 ) ) ? 0 : 4 ) + ( REG_OR_SUBREG_REG ( XEXP ( x , 1 ) ) ? 0 : 4 ) ; return true ; default : * total = arm_rtx_costs_1 ( x , code , outer_code ) ; return true ; } } </s>

RTX costs for cores with a slow MUL implementation . Thumb-2 is not supported on any `` slowmul '' cores , so it can be ignored .


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

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


<s> static int arm_tls_operand_p_1 ( rtx * x , void * data ATTRIBUTE_UNUSED ) { if ( GET_CODE ( * x ) == SYMBOL_REF ) return SYMBOL_REF_TLS_MODEL ( * x ) != 0 ; if ( GET_CODE ( * x ) == UNSPEC && XINT ( * x , 1 ) == UNSPEC_TLS ) return - 1 ; return 0 ; } </s>


<s> bool arm_tls_referenced_p ( rtx x ) { if ( ! TARGET_HAVE_TLS ) return false ; return for_each_rtx ( & x , arm_tls_operand_p_1 , NULL ) ; } </s>

Return TRUE if X contains any TLS symbol references .


<s> static bool arm_tls_symbol_p ( rtx x ) { if ( ! TARGET_HAVE_TLS ) return false ; if ( GET_CODE ( x ) != SYMBOL_REF ) return false ; return SYMBOL_REF_TLS_MODEL ( x ) != 0 ; } </s>

Return TRUE if X is a thread-local symbol .


<s> static void arm_unwind_emit ( FILE * asm_out_file , rtx insn ) { rtx pat ; if ( ! ARM_EABI_UNWIND_TABLES ) return ; if ( GET_CODE ( insn ) == NOTE || ! RTX_FRAME_RELATED_P ( insn ) ) return ; pat = find_reg_note ( insn , REG_FRAME_RELATED_EXPR , NULL_RTX ) ; if ( pat ) pat = XEXP ( pat , 0 ) ; else pat = PATTERN ( insn ) ; switch ( GET_CODE ( pat ) ) { case SET : arm_unwind_emit_set ( asm_out_file , pat ) ; break ; case SEQUENCE : arm_unwind_emit_stm ( asm_out_file , pat ) ; break ; default : abort ( ) ; } } </s>

Emit unwind directives for the given insn .


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


<s>
static
void
arm_unwind_emit_stm
(
FILE
*
asm_out_file
,
rtx
p
)
{
int
i
;
HOST_WIDE_INT
offset
;
HOST_WIDE_INT
nregs
;
int
reg_size
;
unsigned
reg
;
unsigned
lastreg
;
rtx
e
;
e
=
XVECEXP
(
p
,
0
,
0
)
;
if
(
GET_CODE
(
e
)
!=
SET
||
GET_CODE
(
XEXP
(
e
,
0
)
)
!=
REG
||
REGNO
(
XEXP
(
e
,
0
)
)
!=
SP_REGNUM
||
GET_CODE
(
XEXP
(
e
,
1
)
)
!=
PLUS
)
abort
(
)
;
offset
=
INTVAL
(
XEXP
(
XEXP
(
e
,
1
)
,
1
)
)
;
nregs
=
XVECLEN
(
p
,
0
)
1
;
reg
=
REGNO
(
XEXP
(
XVECEXP
(
p
,
0
,
1
)
,
1
)
)
;
if
(
reg
<
16
)
{
if
(
nregs
*
4
==
offset
4
)
{
fprintf
(
asm_out_file
,
"\t.pad #4\n"
)
;
offset
-=
4
;
}
reg_size
=
4
;
}
else
if
(
IS_VFP_REGNUM
(
reg
)
)
{
offset
-=
4
;
reg_size
=
8
;
}
else
if
(
reg
>=
FIRST_FPA_REGNUM
&&
reg
<=
LAST_FPA_REGNUM
)
{
asm_fprintf
(
asm_out_file
,
"\t.save %r, %wd\n"
,
reg
,
nregs
)
;
return
;
}
else
abort
(
)
;
if
(
offset
!=
nregs
*
reg_size
)
abort
(
)
;
fprintf
(
asm_out_file
,
"\t.save {"
)
;
offset
=
0
;
lastreg
=
0
;
for
(
i
=
1
;
i
<=
nregs
;
i
++
)
{
e
=
XVECEXP
(
p
,
0
,
i
)
;
if
(
GET_CODE
(
e
)
!=
SET
||
GET_CODE
(
XEXP
(
e
,
0
)
)
!=
MEM
||
GET_CODE
(
XEXP
(
e
,
1
)
)
!=
REG
)
abort
(
)
;
reg
=
REGNO
(
XEXP
(
e
,
1
)
)
;
if
(
reg
<
lastreg
)
abort
(
)
;
if
(
i
!=
1
)
fprintf
(
asm_out_file
,
", "
)
;
if
(
IS_VFP_REGNUM
(
reg
)
)
asm_fprintf
(
asm_out_file
,
"d%d"
,
(
reg
FIRST_VFP_REGNUM
)
/
2
)
;
else
asm_fprintf
(
asm_out_file
,
"%r"
,
reg
)
;
e
=
XEXP
(
XEXP
(
e
,
0
)
,
0
)
;
if
(
GET_CODE
(
e
)
==
PLUS
)
{
offset
+=
reg_size
;
if
(
GET_CODE
(
XEXP
(
e
,
0
)
)
!=
REG
||
REGNO
(
XEXP
(
e
,
0
)
)
!=
SP_REGNUM
||
GET_CODE
(
XEXP
(
e
,
1
)
)
!=
CONST_INT
||
offset
!=
INTVAL
(
XEXP
(
e
,
1
)
)
)
abort
(
)
;
}
else
if
(
i
!=
1
||
GET_CODE
(
e
)
!=
REG
||
REGNO
(
e
)
!=
SP_REGNUM
)
abort
(
)
;
}
fprintf
(
asm_out_file
,
"}\n"
)
;
}
</s>

Emit unwind directives for a store-multiple instruction . This should only ever be generated by the function prologue code , so we expect it to have a particular form .


<s> bool arm_vector_mode_supported_p ( enum machine_mode mode ) { if ( ( mode == V2SImode ) || ( mode == V4HImode ) || ( mode == V8QImode ) ) return true ; return false ; } </s>

Implements target hook vector_mode_supported_p .


<s> static bool arm_xscale_rtx_costs ( rtx x , int code , int outer_code , int * total ) { enum machine_mode mode = GET_MODE ( x ) ; if ( TARGET_THUMB ) { * 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 = 8 ; return true ; } if ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || mode == DImode ) { * total = 30 ; return true ; } if ( GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) { unsigned HOST_WIDE_INT i = ( INTVAL ( XEXP ( x , 1 ) ) & ( unsigned HOST_WIDE_INT ) 0xffffffff ) ; int cost , const_ok = const_ok_for_arm ( i ) ; unsigned HOST_WIDE_INT masked_const ; cost = 2 ; if ( ! const_ok ) cost += 1 ; masked_const = i & 0xffff8000 ; if ( masked_const != 0 && masked_const != 0xffff8000 ) { masked_const = i & 0xf8000000 ; if ( masked_const == 0 || masked_const == 0xf8000000 ) cost += 1 ; else cost += 2 ; } * total = cost ; return true ; } * total = 8 + ( REG_OR_SUBREG_REG ( XEXP ( x , 0 ) ) ? 0 : 4 ) + ( REG_OR_SUBREG_REG ( XEXP ( x , 1 ) ) ? 0 : 4 ) ; return true ; case COMPARE : if ( GET_CODE ( XEXP ( x , 0 ) ) == MULT ) * total = 4 + rtx_cost ( XEXP ( x , 0 ) , code ) ; else * total = arm_rtx_costs_1 ( x , code , outer_code ) ; return true ; default : * total = arm_rtx_costs_1 ( x , code , outer_code ) ; return true ; } } </s>

RTX cost for XScale CPUs . Thumb-2 is not supported on any xscale cores , so it can be ignored .


<s> int cirrus_memory_offset ( rtx op ) { if ( ! ( reload_in_progress || reload_completed ) && ( reg_mentioned_p ( frame_pointer_rtx , op ) || reg_mentioned_p ( arg_pointer_rtx , op ) || reg_mentioned_p ( virtual_incoming_args_rtx , op ) || reg_mentioned_p ( virtual_outgoing_args_rtx , op ) || reg_mentioned_p ( virtual_stack_dynamic_rtx , op ) || reg_mentioned_p ( virtual_stack_vars_rtx , op ) ) ) return 0 ; if ( GET_CODE ( op ) == MEM ) { rtx ind ; ind = XEXP ( op , 0 ) ; if ( GET_CODE ( ind ) == REG ) return 1 ; if ( GET_CODE ( ind ) == PLUS && GET_CODE ( XEXP ( ind , 0 ) ) == REG && REG_MODE_OK_FOR_BASE_P ( XEXP ( ind , 0 ) , VOIDmode ) && GET_CODE ( XEXP ( ind , 1 ) ) == CONST_INT ) return 1 ; } return 0 ; } </s>

Return nonzero if OP is a valid Cirrus memory address pattern .


<s> static void cirrus_reorg ( rtx first ) { enum attr_cirrus attr ; rtx body = PATTERN ( first ) ; rtx t ; int nops ; if ( GET_CODE ( first ) == JUMP_INSN && GET_CODE ( body ) != RETURN ) { nops = 0 ; t = next_nonnote_insn ( first ) ; if ( arm_cirrus_insn_p ( t ) ) ++ nops ; if ( arm_cirrus_insn_p ( next_nonnote_insn ( t ) ) ) ++ nops ; while ( nops -- ) emit_insn_after ( gen_nop ( ) , first ) ; return ; } if ( GET_CODE ( body ) == PARALLEL && XVECLEN ( body , 0 ) > 0 ) body = XVECEXP ( body , 0 , 0 ) ; if ( GET_CODE ( body ) == SET ) { rtx lhs = XEXP ( body , 0 ) , rhs = XEXP ( body , 1 ) ; if ( get_attr_cirrus ( first ) == CIRRUS_DOUBLE ) { if ( arm_cirrus_insn_p ( next_nonnote_insn ( first ) ) ) emit_insn_after ( gen_nop ( ) , first ) ; return ; } else if ( arm_memory_load_p ( first ) ) { unsigned int arm_regno ; if ( GET_CODE ( lhs ) == REG ) arm_regno = REGNO ( lhs ) ; else { gcc_assert ( GET_CODE ( rhs ) == REG ) ; arm_regno = REGNO ( rhs ) ; } first = next_nonnote_insn ( first ) ; if ( ! arm_cirrus_insn_p ( first ) ) return ; body = PATTERN ( first ) ; if ( GET_CODE ( body ) == PARALLEL && XVECLEN ( body , 0 ) ) body = XVECEXP ( body , 0 , 0 ) ; if ( GET_CODE ( body ) == FLOAT ) body = XEXP ( body , 0 ) ; if ( get_attr_cirrus ( first ) == CIRRUS_MOVE && GET_CODE ( XEXP ( body , 1 ) ) == REG && arm_regno == REGNO ( XEXP ( body , 1 ) ) ) emit_insn_after ( gen_nop ( ) , first ) ; return ; } } if ( ! first || GET_CODE ( first ) != INSN || GET_CODE ( PATTERN ( first ) ) == USE || GET_CODE ( PATTERN ( first ) ) == CLOBBER ) return ; attr = get_attr_cirrus ( first ) ; if ( attr == CIRRUS_COMPARE ) { nops = 0 ; t = next_nonnote_insn ( first ) ; if ( arm_cirrus_insn_p ( t ) ) ++ nops ; if ( arm_cirrus_insn_p ( next_nonnote_insn ( t ) ) ) ++ nops ; while ( nops -- ) emit_insn_after ( gen_nop ( ) , first ) ; return ; } } </s>

Cirrus reorg for invalid instruction combinations .


<s> int const_ok_for_arm ( HOST_WIDE_INT i ) { int lowbit ; if ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) != 0 && ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) != ( ( ~ ( unsigned HOST_WIDE_INT ) 0 ) & ~ ( unsigned HOST_WIDE_INT ) 0xffffffff ) ) ) return FALSE ; i &= ( unsigned HOST_WIDE_INT ) 0xffffffff ; if ( ( i & ~ ( unsigned HOST_WIDE_INT ) 0xff ) == 0 ) return TRUE ; lowbit = ( ffs ( ( int ) i ) - 1 ) & ~ 1 ; if ( ( i & ~ ( ( ( unsigned HOST_WIDE_INT ) 0xff ) << lowbit ) ) == 0 ) return TRUE ; else if ( lowbit <= 4 && ( ( i & ~ 0xc000003f ) == 0 || ( i & ~ 0xf000000f ) == 0 || ( i & ~ 0xfc000003 ) == 0 ) ) return TRUE ; return FALSE ; } </s>

Return TRUE if int I is a valid immediate ARM constant .


<s> static int const_ok_for_op ( HOST_WIDE_INT i , enum rtx_code code ) { if ( const_ok_for_arm ( i ) ) return 1 ; switch ( code ) { case PLUS : return const_ok_for_arm ( ARM_SIGN_EXTEND ( - i ) ) ; case MINUS : case XOR : case IOR : return 0 ; case AND : return const_ok_for_arm ( ARM_SIGN_EXTEND ( ~ i ) ) ; default : gcc_unreachable ( ) ; } } </s>

Return true if I is a valid constant for the operation CODE .


<s> static Mfix * create_fix_barrier ( Mfix * fix , HOST_WIDE_INT max_address ) { HOST_WIDE_INT count = 0 ; rtx barrier ; rtx from = fix -> insn ; rtx selected = from ; int selected_cost ; HOST_WIDE_INT selected_address ; Mfix * new_fix ; HOST_WIDE_INT max_count = max_address - fix -> address ; rtx label = gen_label_rtx ( ) ; selected_cost = arm_barrier_cost ( from ) ; selected_address = fix -> address ; while ( from && count < max_count ) { rtx tmp ; int new_cost ; gcc_assert ( GET_CODE ( from ) != BARRIER ) ; count += get_attr_length ( from ) ; tmp = is_jump_table ( from ) ; if ( tmp != NULL ) { count += get_jump_table_size ( tmp ) ; new_cost = arm_barrier_cost ( from ) ; if ( count < max_count && new_cost <= selected_cost ) { selected = tmp ; selected_cost = new_cost ; selected_address = fix -> address + count ; } from = NEXT_INSN ( tmp ) ; continue ; } new_cost = arm_barrier_cost ( from ) ; if ( count < max_count && new_cost <= selected_cost ) { selected = from ; selected_cost = new_cost ; selected_address = fix -> address + count ; } from = NEXT_INSN ( from ) ; } from = emit_jump_insn_after ( gen_jump ( label ) , selected ) ; JUMP_LABEL ( from ) = label ; barrier = emit_barrier_after ( from ) ; emit_label_after ( label , barrier ) ; new_fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * new_fix ) ) ; new_fix -> insn = barrier ; new_fix -> address = selected_address ; new_fix -> next = fix -> next ; fix -> next = new_fix ; return new_fix ; } </s>

Find the best place in the insn stream in the range ( FIX- > address , MAX_ADDRESS ) to forcibly insert a minipool barrier . Create the barrier by inserting a jump and add a new fix entry for it .


<s> static int current_file_function_operand ( rtx sym_ref ) { if ( ENCODED_SHORT_CALL_ATTR_P ( XSTR ( sym_ref , 0 ) ) ) return 1 ; if ( sym_ref == XEXP ( DECL_RTL ( current_function_decl ) , 0 ) && ! DECL_WEAK ( current_function_decl ) ) return 1 ; return 0 ; } </s>

Return 1 if the operand is a SYMBOL_REF for a function known to be in this file and the function is not weakly defined .


";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n"


<s> static rtx emit_multi_reg_push ( unsigned long mask ) { int num_regs = 0 ; int num_dwarf_regs ; int i , j ; rtx par ; rtx dwarf ; int dwarf_par_index ; rtx tmp , reg ; for ( i = 0 ; i <= LAST_ARM_REGNUM ; i ++ ) if ( mask & ( 1 << i ) ) num_regs ++ ; gcc_assert ( num_regs && num_regs <= 16 ) ; num_dwarf_regs = num_regs ; if ( mask & ( 1 << PC_REGNUM ) ) num_dwarf_regs -- ; 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 ) ) { reg = gen_rtx_REG ( SImode , i ) ; XVECEXP ( par , 0 , 0 ) = gen_rtx_SET ( VOIDmode , gen_frame_mem ( BLKmode , gen_rtx_PRE_DEC ( BLKmode , stack_pointer_rtx ) ) , gen_rtx_UNSPEC ( BLKmode , gen_rtvec ( 1 , reg ) , UNSPEC_PUSH_MULT ) ) ; if ( i != PC_REGNUM ) { tmp = gen_rtx_SET ( VOIDmode , gen_frame_mem ( SImode , stack_pointer_rtx ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ) = tmp ; dwarf_par_index ++ ; } break ; } } for ( j = 1 , i ++ ; j < num_regs ; i ++ ) { if ( mask & ( 1 << i ) ) { reg = gen_rtx_REG ( SImode , i ) ; XVECEXP ( par , 0 , j ) = gen_rtx_USE ( VOIDmode , reg ) ; if ( i != PC_REGNUM ) { tmp = gen_rtx_SET ( VOIDmode , gen_frame_mem ( SImode , plus_constant ( stack_pointer_rtx , 4 * j ) ) , reg ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , dwarf_par_index ++ ) = tmp ; } j ++ ; } } par = emit_insn ( par ) ; tmp = gen_rtx_SET ( SImode , stack_pointer_rtx , gen_rtx_PLUS ( SImode , stack_pointer_rtx , GEN_INT ( - 4 * num_regs ) ) ) ; RTX_FRAME_RELATED_P ( tmp ) = 1 ; XVECEXP ( dwarf , 0 , 0 ) = tmp ; REG_NOTES ( par ) = gen_rtx_EXPR_LIST ( REG_FRAME_RELATED_EXPR , dwarf , REG_NOTES ( par ) ) ; 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> static const char * fp_const_from_val ( REAL_VALUE_TYPE * r ) { int i ; if ( ! fp_consts_inited ) init_fp_table ( ) ; for ( i = 0 ; i < 8 ; i ++ ) if ( REAL_VALUES_EQUAL ( * r , values_fp [ i ] ) ) return strings_fp [ i ] ; gcc_unreachable ( ) ; } </s>

As for fp_immediate_constant , but value is passed directly , not in rtx .


<s> const char * fp_immediate_constant ( rtx x ) { REAL_VALUE_TYPE r ; int i ; if ( ! fp_consts_inited ) init_fp_table ( ) ; REAL_VALUE_FROM_CONST_DOUBLE ( r , x ) ; for ( i = 0 ; i < 8 ; i ++ ) if ( REAL_VALUES_EQUAL ( r , values_fp [ i ] ) ) return strings_fp [ i ] ; gcc_unreachable ( ) ; } </s>

If the rtx is the correct value then return the string of the number . In this way we can ensure that valid double constants are generated even when cross compiling .


<s> static HOST_WIDE_INT int_log2 ( HOST_WIDE_INT power ) { HOST_WIDE_INT shift = 0 ; while ( ( ( ( HOST_WIDE_INT ) 1 << shift ) & power ) == 0 ) { gcc_assert ( shift <= 31 ) ; shift ++ ; } return shift ; } </s>

Obtain the shift from the POWER of two .


<s> int is_called_in_ARM_mode ( tree func ) { gcc_assert ( TREE_CODE ( func ) == FUNCTION_DECL ) ; if ( TARGET_CALLEE_INTERWORKING && TREE_PUBLIC ( func ) ) return TRUE ; return lookup_attribute ( "interfacearm" , DECL_ATTRIBUTES ( func ) ) != NULL_TREE ; return FALSE ; } </s>

Return non-zero if FUNC must be entered in ARM mode .


<s> static rtx is_jump_table ( rtx insn ) { rtx table ; if ( GET_CODE ( insn ) == JUMP_INSN && JUMP_LABEL ( insn ) != NULL && ( ( table = next_real_insn ( JUMP_LABEL ( insn ) ) ) == next_real_insn ( insn ) ) && table != NULL && GET_CODE ( table ) == JUMP_INSN && ( GET_CODE ( PATTERN ( table ) ) == ADDR_VEC || GET_CODE ( PATTERN ( table ) ) == ADDR_DIFF_VEC ) ) return table ; return NULL_RTX ; } </s>

Determines if INSN is the start of a jump table . Returns the end of the TABLE or NULL_RTX .


<s> int legitimate_pic_operand_p ( rtx x ) { if ( CONSTANT_P ( x ) && flag_pic && ( GET_CODE ( x ) == SYMBOL_REF || ( GET_CODE ( x ) == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == SYMBOL_REF ) ) ) return 0 ; return 1 ; } </s>

Return true if OP is a legitimate general operand when generating PIC code . It is given that flag_pic is on and that OP satisfies CONSTANT_P or is a CONST_DOUBLE .


<s> rtx legitimize_pic_address ( rtx orig , enum machine_mode mode , rtx reg ) { if ( GET_CODE ( orig ) == SYMBOL_REF || GET_CODE ( orig ) == LABEL_REF ) { rtx pic_ref , address ; rtx insn ; int subregs = 0 ; if ( reg == 0 ) { gcc_assert ( ! no_new_pseudos ) ; reg = gen_reg_rtx ( Pmode ) ; subregs = 1 ; } insn = emit_insn ( gen_pic_load_addr_based ( reg , orig ) ) ; if ( subregs ) address = gen_reg_rtx ( Pmode ) ; else address = reg ; if ( TARGET_ARM ) emit_insn ( gen_pic_load_addr_arm ( address , orig ) ) ; else emit_insn ( gen_pic_load_addr_thumb ( address , orig ) ) ; if ( ( GET_CODE ( orig ) == LABEL_REF || ( GET_CODE ( orig ) == SYMBOL_REF && SYMBOL_REF_LOCAL_P ( orig ) ) ) && NEED_GOT_RELOC ) pic_ref = gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , address ) ; else { pic_ref = gen_const_mem ( Pmode , gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , address ) ) ; } insn = emit_move_insn ( reg , pic_ref ) ; current_function_uses_pic_offset_table = 1 ; REG_NOTES ( insn ) = gen_rtx_EXPR_LIST ( REG_EQUAL , orig , REG_NOTES ( insn ) ) ; return reg ; } else if ( GET_CODE ( orig ) == CONST ) { rtx base , offset ; if ( GET_CODE ( XEXP ( orig , 0 ) ) == PLUS && XEXP ( XEXP ( orig , 0 ) , 0 ) == pic_offset_table_rtx ) return orig ; if ( GET_CODE ( XEXP ( orig , 0 ) ) == UNSPEC && XINT ( XEXP ( orig , 0 ) , 1 ) == UNSPEC_TLS ) return orig ; if ( reg == 0 ) { gcc_assert ( ! no_new_pseudos ) ; reg = gen_reg_rtx ( Pmode ) ; } gcc_assert ( GET_CODE ( XEXP ( orig , 0 ) ) == PLUS ) ; base = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 0 ) , Pmode , reg ) ; offset = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 1 ) , Pmode , base == reg ? 0 : reg ) ; if ( GET_CODE ( offset ) == CONST_INT ) { if ( ! arm_legitimate_index_p ( mode , offset , SET , 0 ) ) { gcc_assert ( ! no_new_pseudos ) ; offset = force_reg ( Pmode , offset ) ; } if ( GET_CODE ( offset ) == CONST_INT ) return plus_constant ( base , INTVAL ( offset ) ) ; } if ( GET_MODE_SIZE ( mode ) > 4 && ( GET_MODE_CLASS ( mode ) == MODE_INT || TARGET_SOFT_FLOAT ) ) { emit_insn ( gen_addsi3 ( reg , base , offset ) ) ; return reg ; } return gen_rtx_PLUS ( Pmode , base , offset ) ; } return orig ; } </s>

Legitimize PIC addresses . If the address is already position-independent , we return ORIG . Newly generated position-independent addresses go into a reg . This is REG if nonzero , otherwise we allocate register ( s ) as necessary .


<s> rtx legitimize_tls_address ( rtx x , rtx reg ) { rtx dest , tp , label , labelno , sum , insns , ret , eqv , addend ; unsigned int model = SYMBOL_REF_TLS_MODEL ( x ) ; switch ( model ) { case TLS_MODEL_GLOBAL_DYNAMIC : insns = arm_call_tls_get_addr ( x , reg , & ret , TLS_GD32 ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , ret , x ) ; return dest ; case TLS_MODEL_LOCAL_DYNAMIC : insns = arm_call_tls_get_addr ( x , reg , & ret , TLS_LDM32 ) ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const1_rtx ) , UNSPEC_TLS ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , ret , eqv ) ; addend = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( TLS_LDO32 ) ) , UNSPEC_TLS ) ; addend = force_reg ( SImode , gen_rtx_CONST ( SImode , addend ) ) ; return gen_rtx_PLUS ( Pmode , dest , addend ) ; case TLS_MODEL_INITIAL_EXEC : labelno = GEN_INT ( pic_labelno ++ ) ; label = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , labelno ) , UNSPEC_PIC_LABEL ) ; label = gen_rtx_CONST ( VOIDmode , label ) ; sum = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 4 , x , GEN_INT ( TLS_IE32 ) , label , GEN_INT ( TARGET_ARM ? 8 : 4 ) ) , UNSPEC_TLS ) ; reg = load_tls_operand ( sum , reg ) ; if ( TARGET_ARM ) emit_insn ( gen_tls_load_dot_plus_eight ( reg , reg , labelno ) ) ; else { emit_insn ( gen_pic_add_dot_plus_four ( reg , reg , labelno ) ) ; emit_move_insn ( reg , gen_const_mem ( SImode , reg ) ) ; } tp = arm_load_tp ( NULL_RTX ) ; return gen_rtx_PLUS ( Pmode , tp , reg ) ; case TLS_MODEL_LOCAL_EXEC : tp = arm_load_tp ( NULL_RTX ) ; reg = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( TLS_LE32 ) ) , UNSPEC_TLS ) ; reg = force_reg ( SImode , gen_rtx_CONST ( SImode , reg ) ) ; return gen_rtx_PLUS ( Pmode , tp , reg ) ; default : abort ( ) ; } } </s>

ADDR contains a thread-local SYMBOL_REF . Generate code to compute this ( thread-local ) address .


<s> int neg_const_double_rtx_ok_for_fpa ( rtx x ) { REAL_VALUE_TYPE r ; int i ; if ( ! fp_consts_inited ) init_fp_table ( ) ; REAL_VALUE_FROM_CONST_DOUBLE ( r , x ) ; r = REAL_VALUE_NEGATE ( r ) ; if ( REAL_VALUE_MINUS_ZERO ( r ) ) return 0 ; for ( i = 0 ; i < 8 ; i ++ ) if ( REAL_VALUES_EQUAL ( r , values_fp [ i ] ) ) return 1 ; return 0 ; } </s>

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


<s> static bool note_invalid_constants ( rtx insn , HOST_WIDE_INT address , int do_pushes ) { bool result = false ; int opno ; extract_insn ( insn ) ; if ( ! constrain_operands ( 1 ) ) fatal_insn_not_found ( insn ) ; if ( recog_data . n_alternatives == 0 ) return false ; preprocess_constraints ( ) ; for ( opno = 0 ; opno < recog_data . n_operands ; opno ++ ) { if ( recog_data . operand_type [ opno ] != OP_IN ) continue ; if ( recog_op_alt [ opno ] [ which_alternative ] . memory_ok ) { rtx op = recog_data . operand [ opno ] ; if ( CONSTANT_P ( op ) ) { if ( do_pushes ) push_minipool_fix ( insn , address , recog_data . operand_loc [ opno ] , recog_data . operand_mode [ opno ] , op ) ; result = true ; } else if ( GET_CODE ( op ) == MEM && GET_CODE ( XEXP ( op , 0 ) ) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P ( XEXP ( op , 0 ) ) ) { if ( do_pushes ) { rtx cop = avoid_constant_pool_reference ( op ) ; if ( op == cop ) cop = get_pool_constant ( XEXP ( op , 0 ) ) ; push_minipool_fix ( insn , address , recog_data . operand_loc [ opno ] , recog_data . operand_mode [ opno ] , cop ) ; } result = true ; } } } return result ; } </s>

Scan INSN and note any of its operands that need fixing . If DO_PUSHES is false we do not actually push any of the fixups needed . The function returns TRUE if any fixups were needed/pushed . This is used by arm_memory_load_p ( ) which needs to know about loads of constants that will be converted into minipool loads .


<s> inline static int number_of_first_bit_set ( unsigned mask ) { int bit ; for ( bit = 0 ; ( mask & ( 1 << bit ) ) == 0 ; ++ bit ) continue ; return bit ; } </s>

Return the number ( counting from 0 ) of the least significant set bit in MASK .


<s>
const
char
*
output_call
(
rtx
*
operands
)
{
gcc_assert
(
!
arm_arch5
)
;
if
(
REGNO
(
operands
[
0
]
)
==
LR_REGNUM
)
{
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
IP_REGNUM
)
;
output_asm_insn
(
"mov%?\t%0, %|lr"
,
operands
)
;
}
output_asm_insn
(
"mov%?\t%|lr, %|pc"
,
operands
)
;
if
(
TARGET_INTERWORK
||
arm_arch4t
)
output_asm_insn
(
"bx%?\t%0"
,
operands
)
;
else
output_asm_insn
(
"mov%?\t%|pc, %0"
,
operands
)
;
return
""
;
}
</s>

INSN is either a function call or a millicode call . It may have an unconditional jump in its delay slot . CALL_DEST is the routine we are calling .


<s>
const
char
*
output_call_mem
(
rtx
*
operands
)
{
if
(
TARGET_INTERWORK
&&
!
arm_arch5
)
{
output_asm_insn
(
"ldr%?\t%|ip, %0"
,
operands
)
;
output_asm_insn
(
"mov%?\t%|lr, %|pc"
,
operands
)
;
output_asm_insn
(
"bx%?\t%|ip"
,
operands
)
;
}
else
if
(
regno_use_in
(
LR_REGNUM
,
operands
[
0
]
)
)
{
output_asm_insn
(
"ldr%?\t%|ip, %0"
,
operands
)
;
if
(
arm_arch5
)
output_asm_insn
(
"blx%?\t%|ip"
,
operands
)
;
else
{
output_asm_insn
(
"mov%?\t%|lr, %|pc"
,
operands
)
;
if
(
arm_arch4t
)
output_asm_insn
(
"bx%?\t%|ip"
,
operands
)
;
else
output_asm_insn
(
"mov%?\t%|pc, %|ip"
,
operands
)
;
}
}
else
{
output_asm_insn
(
"mov%?\t%|lr, %|pc"
,
operands
)
;
output_asm_insn
(
"ldr%?\t%|pc, %0"
,
operands
)
;
}
return
""
;
}
</s>

Output a 'call ' insn that is a reference in memory . This is disabled for ARMv5 and we prefer a blx instead because otherwise there 's a significant performance overhead .


<s>
const
char
*
output_mov_double_arm_from_fpa
(
rtx
*
operands
)
{
int
arm_reg0
=
REGNO
(
operands
[
0
]
)
;
rtx
ops
[
2
]
;
gcc_assert
(
arm_reg0
!=
IP_REGNUM
)
;
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
arm_reg0
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
1
+
arm_reg0
)
;
output_asm_insn
(
"stf%?d\t%1, [%|sp, #-8]!"
,
operands
)
;
output_asm_insn
(
"ldm%?fd\t%|sp!, {%0, %1}"
,
ops
)
;
return
""
;
}
</s>

Output a move from an fpa register to arm registers . OPERANDS [ 0 ] is the first registers of an arm register pair . OPERANDS [ 1 ] is an fpa register .


<s>
const
char
*
output_mov_double_fpa_from_arm
(
rtx
*
operands
)
{
int
arm_reg0
=
REGNO
(
operands
[
1
]
)
;
rtx
ops
[
2
]
;
gcc_assert
(
arm_reg0
!=
IP_REGNUM
)
;
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
arm_reg0
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
1
+
arm_reg0
)
;
output_asm_insn
(
"stm%?fd\t%|sp!, {%0, %1}"
,
ops
)
;
output_asm_insn
(
"ldf%?d\t%0, [%|sp], #8"
,
operands
)
;
return
""
;
}
</s>

Output a move from arm registers to an fpa registers . OPERANDS [ 0 ] is an fpa register . OPERANDS [ 1 ] is the first registers of an arm register pair .


<s>
const
char
*
output_mov_long_double_arm_from_fpa
(
rtx
*
operands
)
{
int
arm_reg0
=
REGNO
(
operands
[
0
]
)
;
rtx
ops
[
3
]
;
gcc_assert
(
arm_reg0
!=
IP_REGNUM
)
;
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
arm_reg0
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
1
+
arm_reg0
)
;
ops
[
2
]
=
gen_rtx_REG
(
SImode
,
2
+
arm_reg0
)
;
output_asm_insn
(
"stf%?e\t%1, [%|sp, #-12]!"
,
operands
)
;
output_asm_insn
(
"ldm%?fd\t%|sp!, {%0, %1, %2}"
,
ops
)
;
return
""
;
}
</s>


<s>
const
char
*
output_mov_long_double_fpa_from_arm
(
rtx
*
operands
)
{
int
arm_reg0
=
REGNO
(
operands
[
1
]
)
;
rtx
ops
[
3
]
;
gcc_assert
(
arm_reg0
!=
IP_REGNUM
)
;
ops
[
0
]
=
gen_rtx_REG
(
SImode
,
arm_reg0
)
;
ops
[
1
]
=
gen_rtx_REG
(
SImode
,
1
+
arm_reg0
)
;
ops
[
2
]
=
gen_rtx_REG
(
SImode
,
2
+
arm_reg0
)
;
output_asm_insn
(
"stm%?fd\t%|sp!, {%0, %1, %2}"
,
ops
)
;
output_asm_insn
(
"ldf%?e\t%0, [%|sp], #12"
,
operands
)
;
return
""
;
}
</s>


<s>
static
void
print_multi_reg
(
FILE
*
stream
,
const
char
*
instr
,
unsigned
reg
,
unsigned
long
mask
)
{
unsigned
i
;
bool
not_first
=
FALSE
;
fputc
(
'\t'
,
stream
)
;
asm_fprintf
(
stream
,
instr
,
reg
)
;
fputs
(
", {"
,
stream
)
;
for
(
i
=
0
;
i
<=
LAST_ARM_REGNUM
;
i
++
)
if
(
mask
&
(
1
<<
i
)
)
{
if
(
not_first
)
fprintf
(
stream
,
", "
)
;
asm_fprintf
(
stream
,
"%r"
,
i
)
;
not_first
=
TRUE
;
}
fprintf
(
stream
,
"}\n"
)
;
}
</s>

Output the operands of a LDM/STM instruction to STREAM . MASK is the ARM register set mask of which only bits 0-15 are important . REG is the base register , either the frame pointer or the stack pointer , INSTR is the possibly suffixed load or store instruction .


<s> static void push_minipool_barrier ( rtx insn , HOST_WIDE_INT address ) { Mfix * fix = ( Mfix * ) obstack_alloc ( & minipool_obstack , sizeof ( * fix ) ) ; fix -> insn = insn ; fix -> address = address ; fix -> next = NULL ; if ( minipool_fix_head != NULL ) minipool_fix_tail -> next = fix ; else minipool_fix_head = fix ; minipool_fix_tail = fix ; } </s>

Record that there is a natural barrier in the insn stream at ADDRESS .


";; %smode fixup for i%d; addr %lu, range (%ld,%ld): "

Record INSN , which will need fixing up to load a value from the minipool . ADDRESS is the offset of the insn since the start of the function ; LOC is a pointer to the part of the insn which requires fixing ; VALUE is the constant that must be loaded , which is of type MODE .


<s> static rtx safe_vector_operand ( rtx x , enum 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 .


<s> static const char * shift_op ( rtx op , HOST_WIDE_INT * amountp ) { const char * mnem ; enum rtx_code code = GET_CODE ( op ) ; switch ( GET_CODE ( XEXP ( op , 1 ) ) ) { case REG : case SUBREG : * amountp = - 1 ; break ; case CONST_INT : * amountp = INTVAL ( XEXP ( op , 1 ) ) ; break ; default : gcc_unreachable ( ) ; } switch ( code ) { case ASHIFT : mnem = "asl" ; break ; case ASHIFTRT : mnem = "asr" ; break ; case LSHIFTRT : mnem = "lsr" ; break ; case ROTATE : gcc_assert ( * amountp != - 1 ) ; * amountp = 32 - * amountp ; case ROTATERT : mnem = "ror" ; break ; case MULT : gcc_assert ( * amountp != - 1 ) ; * amountp = int_log2 ( * amountp ) ; return "asl" ; default : gcc_unreachable ( ) ; } if ( * amountp != - 1 ) { if ( code == ROTATERT ) * amountp &= 31 ; else if ( * amountp != ( * amountp & 31 ) ) { if ( code == ASHIFT ) mnem = "lsr" ; * amountp = 32 ; } if ( * amountp == 0 ) return NULL ; } return mnem ; } </s>

Ensure valid constant shifts and return the appropriate shift mnemonic for the operation code . The returned result should not be overwritten . OP is the rtx code of the shift . On exit , * AMOUNTP will be -1 if the shift is by a register , or a constant shift .


<s> static int thumb_base_register_rtx_p ( rtx x , enum machine_mode mode , int strict_p ) { int regno ; if ( GET_CODE ( x ) != REG ) return 0 ; regno = REGNO ( x ) ; if ( strict_p ) return THUMB_REGNO_MODE_OK_FOR_BASE_P ( regno , mode ) ; return ( regno <= LAST_LO_REGNUM || regno > LAST_VIRTUAL_REGISTER || regno == FRAME_POINTER_REGNUM || ( GET_MODE_SIZE ( mode ) >= 4 && ( regno == STACK_POINTER_REGNUM || regno >= FIRST_PSEUDO_REGISTER || x == hard_frame_pointer_rtx || x == arg_pointer_rtx ) ) ) ; } </s>

Return nonzero if X is valid as a Thumb state base register .


<s> const char * thumb_call_via_reg ( rtx reg ) { int regno = REGNO ( reg ) ; rtx * labelp ; gcc_assert ( regno < LR_REGNUM ) ; if ( in_text_section ( ) ) { thumb_call_reg_needed = 1 ; if ( thumb_call_via_label [ regno ] == NULL ) thumb_call_via_label [ regno ] = gen_label_rtx ( ) ; labelp = thumb_call_via_label + regno ; } else { if ( cfun -> machine -> call_via [ regno ] == NULL ) cfun -> machine -> call_via [ regno ] = gen_label_rtx ( ) ; labelp = cfun -> machine -> call_via + regno ; } output_asm_insn ( "bl\t%a0" , labelp ) ; return "" ; } </s>

Output a call-via instruction for thumb state .


<s> static unsigned long thumb_compute_save_reg_mask ( void ) { unsigned long mask ; unsigned reg ; mask = 0 ; for ( reg = 0 ; reg < 12 ; reg ++ ) if ( regs_ever_live [ reg ] && ! call_used_regs [ reg ] ) mask |= 1 << reg ; if ( flag_pic && ! TARGET_SINGLE_PIC_BASE && current_function_uses_pic_offset_table ) mask |= 1 << PIC_OFFSET_TABLE_REGNUM ; if ( ! frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0 ) mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM ; if ( mask & 0xff || thumb_force_lr_save ( ) ) mask |= ( 1 << LR_REGNUM ) ; if ( ( mask & 0xff ) == 0 && ( ( mask & 0x0f00 ) || TARGET_BACKTRACE ) ) { reg = thumb_find_work_register ( 1 << LAST_LO_REGNUM ) ; if ( ! call_used_regs [ reg ] ) mask |= 1 << reg ; } return mask ; } </s>

Compute a bit mask of which registers need to be saved on the stack for the current function .


<s> void thumb_expand_movmemqi ( rtx * operands ) { rtx out = copy_to_mode_reg ( SImode , XEXP ( operands [ 0 ] , 0 ) ) ; rtx in = copy_to_mode_reg ( SImode , XEXP ( operands [ 1 ] , 0 ) ) ; HOST_WIDE_INT len = INTVAL ( operands [ 2 ] ) ; HOST_WIDE_INT offset = 0 ; while ( len >= 12 ) { emit_insn ( gen_movmem12b ( out , in , out , in ) ) ; len -= 12 ; } if ( len >= 8 ) { emit_insn ( gen_movmem8b ( out , in , out , in ) ) ; len -= 8 ; } if ( len >= 4 ) { rtx reg = gen_reg_rtx ( SImode ) ; emit_insn ( gen_movsi ( reg , gen_rtx_MEM ( SImode , in ) ) ) ; emit_insn ( gen_movsi ( gen_rtx_MEM ( SImode , out ) , reg ) ) ; len -= 4 ; offset += 4 ; } if ( len >= 2 ) { rtx reg = gen_reg_rtx ( HImode ) ; emit_insn ( gen_movhi ( reg , gen_rtx_MEM ( HImode , plus_constant ( in , offset ) ) ) ) ; emit_insn ( gen_movhi ( gen_rtx_MEM ( HImode , plus_constant ( out , offset ) ) , reg ) ) ; len -= 2 ; offset += 2 ; } if ( len ) { rtx reg = gen_reg_rtx ( QImode ) ; emit_insn ( gen_movqi ( reg , gen_rtx_MEM ( QImode , plus_constant ( in , offset ) ) ) ) ; emit_insn ( gen_movqi ( gen_rtx_MEM ( QImode , plus_constant ( out , offset ) ) , reg ) ) ; } } </s>


<s> static int thumb_far_jump_used_p ( void ) { rtx insn ; if ( cfun -> machine -> far_jump_used ) return 1 ; if ( ! ( ARM_DOUBLEWORD_ALIGN || reload_completed ) ) { 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 int thumb_find_work_register ( unsigned long pushed_regs_mask ) { int reg ; for ( reg = LAST_ARG_REGNUM ; reg >= 0 ; reg -- ) if ( ! regs_ever_live [ reg ] ) return reg ; if ( cfun -> machine -> uses_anonymous_args && current_function_pretend_args_size > 0 ) return LAST_ARG_REGNUM ; if ( ! cfun -> machine -> uses_anonymous_args && current_function_args_size >= 0 && current_function_args_size <= ( LAST_ARG_REGNUM * UNITS_PER_WORD ) && cfun -> args_info . nregs < 4 ) return LAST_ARG_REGNUM ; for ( reg = LAST_LO_REGNUM ; reg > LAST_ARG_REGNUM ; reg -- ) if ( pushed_regs_mask & ( 1 << reg ) ) return reg ; gcc_unreachable ( ) ; } </s>

Find a spare low register to use during the prolog of a function .


<s> static bool thumb_force_lr_save ( void ) { return ! cfun -> machine -> lr_save_eliminated && ( ! leaf_function_p ( ) || thumb_far_jump_used_p ( ) || regs_ever_live [ LR_REGNUM ] ) ; } </s>

Return true if the current function needs to save/restore LR .


<s> inline static int thumb_index_register_rtx_p ( rtx x , int strict_p ) { return thumb_base_register_rtx_p ( x , QImode , strict_p ) ; } </s>

Return nonzero if x is a legitimate index register . This is the case for any base register that can access a QImode object .


<s> int thumb_legitimate_offset_p ( enum machine_mode mode , HOST_WIDE_INT val ) { switch ( GET_MODE_SIZE ( mode ) ) { case 1 : return val >= 0 && val < 32 ; case 2 : return val >= 0 && val < 64 && ( val & 1 ) == 0 ; default : return ( val >= 0 && ( val + GET_MODE_SIZE ( mode ) ) <= 128 && ( val & 3 ) == 0 ) ; } } </s>

Return nonzero if VAL can be used as an offset in a Thumb-state address instruction of mode MODE .


<s> rtx thumb_legitimize_address ( rtx x , rtx orig_x , enum machine_mode mode ) { if ( arm_tls_symbol_p ( x ) ) return legitimize_tls_address ( x , NULL_RTX ) ; if ( GET_CODE ( x ) == PLUS && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && ( INTVAL ( XEXP ( x , 1 ) ) >= 32 * GET_MODE_SIZE ( mode ) || INTVAL ( XEXP ( x , 1 ) ) < 0 ) ) { rtx xop0 = XEXP ( x , 0 ) ; rtx xop1 = XEXP ( x , 1 ) ; HOST_WIDE_INT offset = INTVAL ( xop1 ) ; if ( optimize_size && offset >= 0 && offset < 256 + 31 * GET_MODE_SIZE ( mode ) ) { HOST_WIDE_INT delta ; if ( offset >= 256 ) delta = offset - ( 256 - GET_MODE_SIZE ( mode ) ) ; else if ( offset < 32 * GET_MODE_SIZE ( mode ) + 8 ) delta = 31 * GET_MODE_SIZE ( mode ) ; else delta = offset & ( ~ 31 * GET_MODE_SIZE ( mode ) ) ; xop0 = force_operand ( plus_constant ( xop0 , offset - delta ) , NULL_RTX ) ; x = plus_constant ( xop0 , delta ) ; } else if ( offset < 0 && offset > - 256 ) x = force_operand ( x , NULL_RTX ) ; else { xop1 = force_reg ( SImode , xop1 ) ; x = gen_rtx_PLUS ( SImode , xop0 , xop1 ) ; } } else if ( GET_CODE ( x ) == PLUS && s_register_operand ( XEXP ( x , 1 ) , SImode ) && ! s_register_operand ( XEXP ( x , 0 ) , SImode ) ) { rtx xop0 = force_operand ( XEXP ( x , 0 ) , NULL_RTX ) ; x = gen_rtx_PLUS ( SImode , xop0 , XEXP ( x , 1 ) ) ; } if ( flag_pic ) { rtx new_x = legitimize_pic_address ( orig_x , mode , NULL_RTX ) ; if ( new_x != orig_x ) x = new_x ; } return x ; } </s>

Try machine-dependent ways of modifying an illegitimate Thumb address to be legitimate . If we find one , return the new , valid address .