<s> static void alpha_expand_unaligned_load_words ( rtx * out_regs , rtx smem , HOST_WIDE_INT words , HOST_WIDE_INT ofs ) { rtx const im8 = GEN_INT ( - 8 ) ; rtx ext_tmps [ MAX_MOVE_WORDS ] , data_regs [ MAX_MOVE_WORDS + 1 ] ; rtx sreg , areg , tmp , smema ; HOST_WIDE_INT i ; smema = XEXP ( smem , 0 ) ; if ( GET_CODE ( smema ) == LO_SUM ) smema = force_reg ( Pmode , smema ) ; for ( i = 0 ; i < words ; ++ i ) { data_regs [ i ] = out_regs [ i ] ; ext_tmps [ i ] = gen_reg_rtx ( DImode ) ; } data_regs [ words ] = gen_reg_rtx ( DImode ) ; if ( ofs != 0 ) smem = adjust_address ( smem , GET_MODE ( smem ) , ofs ) ; for ( i = 0 ; i < words ; ++ i ) { tmp = change_address ( smem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , smema , 8 * i ) , im8 ) ) ; set_mem_alias_set ( tmp , 0 ) ; emit_move_insn ( data_regs [ i ] , tmp ) ; } tmp = change_address ( smem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , smema , 8 * words - 1 ) , im8 ) ) ; set_mem_alias_set ( tmp , 0 ) ; emit_move_insn ( data_regs [ words ] , tmp ) ; sreg = copy_addr_to_reg ( smema ) ; areg = expand_binop ( DImode , and_optab , sreg , GEN_INT ( 7 ) , NULL , 1 , OPTAB_WIDEN ) ; for ( i = 0 ; i < words ; ++ i ) { emit_insn ( gen_extql ( data_regs [ i ] , data_regs [ i ] , sreg ) ) ; emit_insn ( gen_extqh ( ext_tmps [ i ] , data_regs [ i + 1 ] , sreg ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , ext_tmps [ i ] , gen_rtx_IF_THEN_ELSE ( DImode , gen_rtx_EQ ( DImode , areg , const0_rtx ) , const0_rtx , ext_tmps [ i ] ) ) ) ; } for ( i = 0 ; i < words ; ++ i ) { out_regs [ i ] = expand_binop ( DImode , ior_optab , data_regs [ i ] , ext_tmps [ i ] , data_regs [ i ] , 1 , OPTAB_WIDEN ) ; } } </s>

Load an integral number of consecutive unaligned quadwords .


<s> static void alpha_extract_integer ( rtx x , HOST_WIDE_INT * p0 , HOST_WIDE_INT * p1 ) { HOST_WIDE_INT i0 , i1 ; if ( GET_CODE ( x ) == CONST_VECTOR ) x = simplify_subreg ( DImode , x , GET_MODE ( x ) , 0 ) ; if ( CONST_INT_P ( x ) ) { i0 = INTVAL ( x ) ; i1 = - ( i0 < 0 ) ; } else if ( HOST_BITS_PER_WIDE_INT >= 64 ) { i0 = CONST_DOUBLE_LOW ( x ) ; i1 = - ( i0 < 0 ) ; } else { i0 = CONST_DOUBLE_LOW ( x ) ; i1 = CONST_DOUBLE_HIGH ( x ) ; } * p0 = i0 ; * p1 = i1 ; } </s>

Given an integral CONST_INT , CONST_DOUBLE , or CONST_VECTOR , return the low 64 bits .


<s> static rtx alpha_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int basereg ; int num_args ; if ( type && AGGREGATE_TYPE_P ( type ) ) basereg = 16 ; else { gcc_assert ( ! COMPLEX_MODE_P ( mode ) ) ; if ( TARGET_FPREGS && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) basereg = 32 + 16 ; else basereg = 16 ; } { if ( mode == VOIDmode ) return alpha_arg_info_reg_val ( * cum ) ; num_args = cum -> num_args ; if ( num_args >= 6 || targetm . calls . must_pass_in_stack ( mode , type ) ) return NULL_RTX ; } { if ( * cum >= 6 ) return NULL_RTX ; num_args = * cum ; if ( type == void_type_node ) basereg = 16 ; else if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return NULL_RTX ; } return gen_rtx_REG ( mode , num_args + basereg ) ; } </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 Alpha the first 6 words of args are normally in registers and the rest are pushed .


<s> static void alpha_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; bool onstack = targetm . calls . must_pass_in_stack ( mode , type ) ; int increment = onstack ? 6 : ALPHA_ARG_SIZE ( mode , type , named ) ; * cum += increment ; if ( ! onstack && cum -> num_args < 6 ) cum -> atypes [ cum -> num_args ] = alpha_arg_type ( mode ) ; cum -> num_args += increment ; } </s>

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


<s> HOST_WIDE_INT alpha_initial_elimination_offset ( unsigned int from , unsigned int to ATTRIBUTE_UNUSED ) { HOST_WIDE_INT ret ; ret = alpha_sa_size ( ) ; ret += ALPHA_ROUND ( crtl -> outgoing_args_size ) ; switch ( from ) { case FRAME_POINTER_REGNUM : break ; case ARG_POINTER_REGNUM : ret += ( ALPHA_ROUND ( get_frame_size ( ) + crtl -> args . pretend_args_size ) - crtl -> args . pretend_args_size ) ; break ; default : gcc_unreachable ( ) ; } return ret ; } </s>

Define the offset between two registers , one to be eliminated , and the other its replacement , at the start of a routine .


<s> static bool alpha_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { if ( mode == DImode && GET_CODE ( x ) == AND && CONST_INT_P ( XEXP ( x , 1 ) ) && INTVAL ( XEXP ( x , 1 ) ) == - 8 ) x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == SUBREG && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( REG_P ( x ) && ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) ) return true ; if ( CONSTANT_ADDRESS_P ( x ) ) return true ; if ( LINKAGE_SYMBOL_REF_P ( x ) ) return true ; if ( GET_CODE ( x ) == PLUS ) { rtx ofs = XEXP ( x , 1 ) ; x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == SUBREG && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( REG_P ( x ) ) { if ( ! strict && NONSTRICT_REG_OK_FP_BASE_P ( x ) && CONST_INT_P ( ofs ) ) return true ; if ( ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) && CONSTANT_ADDRESS_P ( ofs ) ) return true ; } } else if ( TARGET_EXPLICIT_RELOCS && GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD ) { if ( small_symbolic_operand ( x , Pmode ) ) return true ; if ( GET_CODE ( x ) == LO_SUM ) { rtx ofs = XEXP ( x , 1 ) ; x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == SUBREG && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( ! ( REG_P ( x ) && ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) ) ) return false ; if ( local_symbolic_operand ( ofs , Pmode ) || dtp32_symbolic_operand ( ofs , Pmode ) || tp32_symbolic_operand ( ofs , Pmode ) ) return true ; } } return false ; } </s>

legitimate_address_p recognizes an RTL expression that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . For Alpha , we have either a constant address or the sum of a register and a constant address , or just a register . For DImode , any of those forms can be surrounded with an AND that clear the low-order three bits ; this is an `` unaligned '' access .


<s> bool alpha_legitimate_constant_p ( machine_mode mode , rtx x ) { HOST_WIDE_INT i0 , i1 ; switch ( GET_CODE ( x ) ) { case LABEL_REF : case HIGH : return true ; case CONST : if ( GET_CODE ( XEXP ( x , 0 ) ) == PLUS && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 1 ) ) == CONST_INT ) x = XEXP ( XEXP ( x , 0 ) , 0 ) ; else return true ; if ( GET_CODE ( x ) != SYMBOL_REF ) return true ; case SYMBOL_REF : return SYMBOL_REF_TLS_MODEL ( x ) == 0 ; case CONST_DOUBLE : if ( x == CONST0_RTX ( mode ) ) return true ; if ( FLOAT_MODE_P ( mode ) ) return false ; goto do_integer ; case CONST_VECTOR : if ( x == CONST0_RTX ( mode ) ) return true ; if ( GET_MODE_CLASS ( mode ) != MODE_VECTOR_INT ) return false ; if ( GET_MODE_SIZE ( mode ) != 8 ) return false ; goto do_integer ; case CONST_INT : do_integer : if ( TARGET_BUILD_CONSTANTS ) return true ; alpha_extract_integer ( x , & i0 , & i1 ) ; if ( HOST_BITS_PER_WIDE_INT >= 64 || i1 == ( - i0 < 0 ) ) return alpha_emit_set_const_1 ( x , mode , i0 , 3 , true ) != NULL ; return false ; default : return false ; } } </s>

Implement LEGITIMATE_CONSTANT_P . This is all constants for which we are willing to load the value into a register via a move pattern . Normally this is all symbolic constants , integral constants that take three or fewer instructions , and floating-point zero .


<s> rtx alpha_legitimize_reload_address ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int opnum , int type , int ind_levels ATTRIBUTE_UNUSED ) { if ( GET_CODE ( x ) == PLUS && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && REG_P ( XEXP ( XEXP ( x , 0 ) , 0 ) ) && CONST_INT_P ( XEXP ( XEXP ( x , 0 ) , 1 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { push_reload ( XEXP ( x , 0 ) , NULL_RTX , & XEXP ( x , 0 ) , NULL , BASE_REG_CLASS , GET_MODE ( x ) , VOIDmode , 0 , 0 , opnum , ( enum reload_type ) type ) ; return x ; } if ( GET_CODE ( x ) == PLUS && REG_P ( XEXP ( x , 0 ) ) && REGNO ( XEXP ( x , 0 ) ) < FIRST_PSEUDO_REGISTER && REGNO_OK_FOR_BASE_P ( REGNO ( XEXP ( x , 0 ) ) ) && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) { HOST_WIDE_INT val = INTVAL ( XEXP ( x , 1 ) ) ; HOST_WIDE_INT low = ( ( val & 0xffff ) ^ 0x8000 ) - 0x8000 ; HOST_WIDE_INT high = ( ( ( val - low ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( high + low != val ) return NULL_RTX ; x = gen_rtx_PLUS ( GET_MODE ( x ) , gen_rtx_PLUS ( GET_MODE ( x ) , XEXP ( x , 0 ) , GEN_INT ( high ) ) , GEN_INT ( low ) ) ; push_reload ( XEXP ( x , 0 ) , NULL_RTX , & XEXP ( x , 0 ) , NULL , BASE_REG_CLASS , GET_MODE ( x ) , VOIDmode , 0 , 0 , opnum , ( enum reload_type ) type ) ; return x ; } return NULL_RTX ; } </s>

Try a machine-dependent way of reloading an illegitimate address operand . If we find one , push the reload and return the new rtx .


<s> static void alpha_output_mi_thunk_osf ( FILE * file , tree thunk_fndecl ATTRIBUTE_UNUSED , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { HOST_WIDE_INT hi , lo ; rtx this_rtx , funexp ; rtx_insn * insn ; emit_insn ( gen_prologue_ldgp ( ) ) ; emit_note ( NOTE_INSN_PROLOGUE_END ) ; if ( aggregate_value_p ( TREE_TYPE ( TREE_TYPE ( function ) ) , function ) ) this_rtx = gen_rtx_REG ( Pmode , 17 ) ; else this_rtx = gen_rtx_REG ( Pmode , 16 ) ; lo = ( ( delta & 0xffff ) ^ 0x8000 ) - 0x8000 ; hi = ( ( ( delta - lo ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( hi + lo == delta ) { if ( hi ) emit_insn ( gen_adddi3 ( this_rtx , this_rtx , GEN_INT ( hi ) ) ) ; if ( lo ) emit_insn ( gen_adddi3 ( this_rtx , this_rtx , GEN_INT ( lo ) ) ) ; } else { rtx tmp = alpha_emit_set_long_const ( gen_rtx_REG ( Pmode , 0 ) , delta , - ( delta < 0 ) ) ; emit_insn ( gen_adddi3 ( this_rtx , this_rtx , tmp ) ) ; } if ( vcall_offset ) { rtx tmp , tmp2 ; tmp = gen_rtx_REG ( Pmode , 0 ) ; emit_move_insn ( tmp , gen_rtx_MEM ( Pmode , this_rtx ) ) ; lo = ( ( vcall_offset & 0xffff ) ^ 0x8000 ) - 0x8000 ; hi = ( ( ( vcall_offset - lo ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( hi + lo == vcall_offset ) { if ( hi ) emit_insn ( gen_adddi3 ( tmp , tmp , GEN_INT ( hi ) ) ) ; } else { tmp2 = alpha_emit_set_long_const ( gen_rtx_REG ( Pmode , 1 ) , vcall_offset , - ( vcall_offset < 0 ) ) ; emit_insn ( gen_adddi3 ( tmp , tmp , tmp2 ) ) ; lo = 0 ; } if ( lo ) tmp2 = gen_rtx_PLUS ( Pmode , tmp , GEN_INT ( lo ) ) ; else tmp2 = tmp ; emit_move_insn ( tmp , gen_rtx_MEM ( Pmode , tmp2 ) ) ; emit_insn ( gen_adddi3 ( this_rtx , this_rtx , tmp ) ) ; } if ( ! TREE_USED ( function ) ) { assemble_external ( function ) ; TREE_USED ( function ) = 1 ; } funexp = XEXP ( DECL_RTL ( function ) , 0 ) ; funexp = gen_rtx_MEM ( FUNCTION_MODE , funexp ) ; insn = emit_call_insn ( gen_sibcall ( funexp , const0_rtx ) ) ; SIBLING_CALL_P ( insn ) = 1 ; insn = get_insns ( ) ; shorten_branches ( insn ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; } </s>

Emit a tail call to FUNCTION after adjusting THIS by DELTA . In order to avoid the hordes of differences between generated code with and without TARGET_EXPLICIT_RELOCS , and to avoid duplicating lots of code loading up large constants , generate rtl and emit it instead of going straight to text . Not sure why this idea has n't been explored before ...


<s> static void alpha_pad_function_end ( void ) { rtx_insn * insn , * next ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) { if ( ! CALL_P ( insn ) || ! ( SIBLING_CALL_P ( insn ) || find_reg_note ( insn , REG_NORETURN , NULL_RTX ) ) ) continue ; next = NEXT_INSN ( insn ) ; if ( next == NULL ) continue ; if ( NOTE_P ( next ) && NOTE_KIND ( next ) == NOTE_INSN_CALL_ARG_LOCATION ) insn = next ; next = next_active_insn ( insn ) ; if ( next ) { rtx pat = PATTERN ( next ) ; if ( GET_CODE ( pat ) == SET && GET_CODE ( SET_SRC ( pat ) ) == UNSPEC_VOLATILE && XINT ( SET_SRC ( pat ) , 1 ) == UNSPECV_LDGP1 ) emit_insn_after ( gen_unop ( ) , insn ) ; } } } </s>

Insert an unop between sibcall or noreturn function call and GP load .


<s> static bool alpha_pass_by_reference ( cumulative_args_t ca ATTRIBUTE_UNUSED , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { return mode == TFmode || mode == TCmode ; } </s>

Return true if TYPE should be passed by invisible reference .


<s> enum reg_class alpha_preferred_reload_class ( rtx x , enum reg_class rclass ) { if ( x == CONST0_RTX ( GET_MODE ( x ) ) ) return rclass ; if ( CONST_INT_P ( x ) || GET_CODE ( x ) == CONST_DOUBLE || GET_CODE ( x ) == CONST_VECTOR ) { if ( rclass == FLOAT_REGS ) return NO_REGS ; if ( rclass == ALL_REGS ) return GENERAL_REGS ; return rclass ; } if ( CONSTANT_P ( x ) ) return ( rclass == ALL_REGS ? GENERAL_REGS : rclass ) ; return rclass ; } </s>

On the Alpha , all ( non-symbolic ) constants except zero go into a floating-point register via memory . Note that we can not return anything that is not a subset of CLASS , and that some symbolic constants can not be dropped to memory .


<s> static void alpha_reorg ( void ) { if ( current_function_has_exception_handlers ( ) ) alpha_pad_function_end ( ) ; } </s>


<s> static void alpha_sa_mask ( unsigned long * imaskP , unsigned long * fmaskP ) { unsigned long imask = 0 ; unsigned long fmask = 0 ; unsigned int i ; if ( cfun -> is_thunk ) { * imaskP = 0 ; * fmaskP = 0 ; return ; } if ( TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK ) imask |= ( 1UL << HARD_FRAME_POINTER_REGNUM ) ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( ! fixed_regs [ i ] && ! call_used_regs [ i ] && df_regs_ever_live_p ( i ) && i != REG_RA ) { if ( i < 32 ) imask |= ( 1UL << i ) ; else fmask |= ( 1UL << ( i - 32 ) ) ; } if ( crtl -> calls_eh_return ) { for ( i = 0 ; ; ++ i ) { unsigned regno = EH_RETURN_DATA_REGNO ( i ) ; if ( regno == INVALID_REGNUM ) break ; imask |= 1UL << regno ; } } if ( imask || fmask || alpha_ra_ever_killed ( ) ) imask |= ( 1UL << REG_RA ) ; * imaskP = imask ; * fmaskP = fmask ; } </s>

Compute register masks for saved registers .


<s> static bool alpha_scalar_mode_supported_p ( machine_mode mode ) { switch ( mode ) { case QImode : case HImode : case SImode : case DImode : case TImode : return true ; case SFmode : case DFmode : return true ; case TFmode : return TARGET_HAS_XFLOATING_LIBS ; default : return false ; } } </s>

The scalar modes supported differs from the default check-what-c-supports version in that sometimes TFmode is available even when long double indicates only DFmode . On unicosmk , we have the situation that HImode does n't map to any C type , but of course we still support that .


<s> static void alpha_setup_incoming_varargs ( cumulative_args_t pcum , machine_mode mode , tree type , int * pretend_size , int no_rtl ) { CUMULATIVE_ARGS cum = * get_cumulative_args ( pcum ) ; targetm . calls . function_arg_advance ( pack_cumulative_args ( & cum ) , mode , type , true ) ; if ( cum . num_args < 6 ) { if ( ! no_rtl ) { emit_move_insn ( gen_rtx_REG ( DImode , 1 ) , virtual_incoming_args_rtx ) ; emit_insn ( gen_arg_home ( ) ) ; } * pretend_size = 7 * UNITS_PER_WORD ; } if ( cum >= 6 ) return ; if ( ! no_rtl ) { int count ; alias_set_type set = get_varargs_alias_set ( ) ; rtx tmp ; count = cfun -> va_list_gpr_size / UNITS_PER_WORD ; if ( count > 6 - cum ) count = 6 - cum ; gcc_assert ( ( VA_LIST_MAX_FPR_SIZE & 3 ) == 3 ) ; if ( cfun -> va_list_fpr_size & 1 ) { tmp = gen_rtx_MEM ( BLKmode , plus_constant ( Pmode , virtual_incoming_args_rtx , ( cum + 6 ) * UNITS_PER_WORD ) ) ; MEM_NOTRAP_P ( tmp ) = 1 ; set_mem_alias_set ( tmp , set ) ; move_block_from_reg ( 16 + cum , tmp , count ) ; } if ( cfun -> va_list_fpr_size & 2 ) { tmp = gen_rtx_MEM ( BLKmode , plus_constant ( Pmode , virtual_incoming_args_rtx , cum * UNITS_PER_WORD ) ) ; MEM_NOTRAP_P ( tmp ) = 1 ; set_mem_alias_set ( tmp , set ) ; move_block_from_reg ( 16 + cum + TARGET_FPREGS * 32 , tmp , count ) ; } } * pretend_size = 12 * UNITS_PER_WORD ; } </s>

Perform any needed actions needed for a function that is receiving a variable number of arguments .


<s> void alpha_split_atomic_exchange ( rtx operands [ ] ) { rtx retval , mem , val , scratch ; enum memmodel model ; machine_mode mode ; rtx label , x , cond ; retval = operands [ 0 ] ; mem = operands [ 1 ] ; val = operands [ 2 ] ; model = ( enum memmodel ) INTVAL ( operands [ 3 ] ) ; scratch = operands [ 4 ] ; mode = GET_MODE ( mem ) ; cond = gen_lowpart ( DImode , scratch ) ; alpha_pre_atomic_barrier ( model ) ; label = gen_rtx_LABEL_REF ( DImode , gen_label_rtx ( ) ) ; emit_label ( XEXP ( label , 0 ) ) ; emit_load_locked ( mode , retval , mem ) ; emit_move_insn ( scratch , val ) ; emit_store_conditional ( mode , cond , mem , scratch ) ; x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; emit_unlikely_jump ( x , label ) ; alpha_post_atomic_barrier ( model ) ; } </s>


<s> void alpha_split_atomic_op ( enum rtx_code code , rtx mem , rtx val , rtx before , rtx after , rtx scratch , enum memmodel model ) { machine_mode mode = GET_MODE ( mem ) ; rtx label , x , cond = gen_rtx_REG ( DImode , REGNO ( scratch ) ) ; alpha_pre_atomic_barrier ( model ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; label = gen_rtx_LABEL_REF ( DImode , label ) ; if ( before == NULL ) before = scratch ; emit_load_locked ( mode , before , mem ) ; if ( code == NOT ) { x = gen_rtx_AND ( mode , before , val ) ; emit_insn ( gen_rtx_SET ( VOIDmode , val , x ) ) ; x = gen_rtx_NOT ( mode , val ) ; } else x = gen_rtx_fmt_ee ( code , mode , before , val ) ; if ( after ) emit_insn ( gen_rtx_SET ( VOIDmode , after , copy_rtx ( x ) ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , scratch , x ) ) ; emit_store_conditional ( mode , cond , mem , scratch ) ; x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; emit_unlikely_jump ( x , label ) ; alpha_post_atomic_barrier ( model ) ; } </s>

Expand an an atomic fetch-and-operate pattern . CODE is the binary operation to perform . MEM is the memory on which to operate . VAL is the second operand of the binary operator . BEFORE and AFTER are optional locations to return the value of MEM either before of after the operation . SCRATCH is a scratch register .


<s> void alpha_split_compare_and_swap ( rtx operands [ ] ) { rtx cond , retval , mem , oldval , newval ; bool is_weak ; enum memmodel mod_s , mod_f ; machine_mode mode ; rtx label1 , label2 , x ; cond = operands [ 0 ] ; retval = operands [ 1 ] ; mem = operands [ 2 ] ; oldval = operands [ 3 ] ; newval = operands [ 4 ] ; is_weak = ( operands [ 5 ] != const0_rtx ) ; mod_s = ( enum memmodel ) INTVAL ( operands [ 6 ] ) ; mod_f = ( enum memmodel ) INTVAL ( operands [ 7 ] ) ; mode = GET_MODE ( mem ) ; alpha_pre_atomic_barrier ( mod_s ) ; label1 = NULL_RTX ; if ( ! is_weak ) { label1 = gen_rtx_LABEL_REF ( DImode , gen_label_rtx ( ) ) ; emit_label ( XEXP ( label1 , 0 ) ) ; } label2 = gen_rtx_LABEL_REF ( DImode , gen_label_rtx ( ) ) ; emit_load_locked ( mode , retval , mem ) ; x = gen_lowpart ( DImode , retval ) ; if ( oldval == const0_rtx ) { emit_move_insn ( cond , const0_rtx ) ; x = gen_rtx_NE ( DImode , x , const0_rtx ) ; } else { x = gen_rtx_EQ ( DImode , x , oldval ) ; emit_insn ( gen_rtx_SET ( VOIDmode , cond , x ) ) ; x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; } emit_unlikely_jump ( x , label2 ) ; emit_move_insn ( cond , newval ) ; emit_store_conditional ( mode , cond , mem , gen_lowpart ( mode , cond ) ) ; if ( ! is_weak ) { x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; emit_unlikely_jump ( x , label1 ) ; } if ( mod_f != MEMMODEL_RELAXED ) emit_label ( XEXP ( label2 , 0 ) ) ; alpha_post_atomic_barrier ( mod_s ) ; if ( mod_f == MEMMODEL_RELAXED ) emit_label ( XEXP ( label2 , 0 ) ) ; } </s>


<s> int alpha_split_conditional_move ( enum rtx_code code , rtx dest , rtx cond , rtx t_rtx , rtx f_rtx ) { HOST_WIDE_INT t , f , diff ; machine_mode mode ; rtx target , subtarget , tmp ; mode = GET_MODE ( dest ) ; t = INTVAL ( t_rtx ) ; f = INTVAL ( f_rtx ) ; diff = t - f ; if ( ( ( code == NE || code == EQ ) && diff < 0 ) || ( code == GE || code == GT ) ) { code = reverse_condition ( code ) ; diff = t , t = f , f = diff ; diff = t - f ; } subtarget = target = dest ; if ( mode != DImode ) { target = gen_lowpart ( DImode , dest ) ; if ( can_create_pseudo_p ( ) ) subtarget = gen_reg_rtx ( DImode ) ; else subtarget = target ; } if ( f == 0 && exact_log2 ( diff ) > 0 && ( diff <= 8 || alpha_tune == PROCESSOR_EV6 ) ) { tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( VOIDmode , copy_rtx ( subtarget ) , tmp ) ) ; tmp = gen_rtx_ASHIFT ( DImode , copy_rtx ( subtarget ) , GEN_INT ( exact_log2 ( t ) ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , target , tmp ) ) ; } else if ( f == 0 && t == - 1 ) { tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( VOIDmode , copy_rtx ( subtarget ) , tmp ) ) ; emit_insn ( gen_negdi2 ( target , copy_rtx ( subtarget ) ) ) ; } else if ( diff == 1 || diff == 4 || diff == 8 ) { rtx add_op ; tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( VOIDmode , copy_rtx ( subtarget ) , tmp ) ) ; if ( diff == 1 ) emit_insn ( gen_adddi3 ( target , copy_rtx ( subtarget ) , GEN_INT ( f ) ) ) ; else { add_op = GEN_INT ( f ) ; if ( sext_add_operand ( add_op , mode ) ) { tmp = gen_rtx_MULT ( DImode , copy_rtx ( subtarget ) , GEN_INT ( diff ) ) ; tmp = gen_rtx_PLUS ( DImode , tmp , add_op ) ; emit_insn ( gen_rtx_SET ( VOIDmode , target , tmp ) ) ; } else return 0 ; } } else return 0 ; return 1 ; } </s>

Simplify a conditional move of two constants into a setcc with arithmetic . This is done with a splitter since combine would just undo the work if done during code generation . It also catches cases we would n't have before cse .


<s> bool alpha_split_const_mov ( machine_mode mode , rtx * operands ) { HOST_WIDE_INT i0 , i1 ; rtx temp = NULL_RTX ; alpha_extract_integer ( operands [ 1 ] , & i0 , & i1 ) ; if ( HOST_BITS_PER_WIDE_INT >= 64 || i1 == - ( i0 < 0 ) ) temp = alpha_emit_set_const ( operands [ 0 ] , mode , i0 , 3 , false ) ; if ( ! temp && TARGET_BUILD_CONSTANTS ) temp = alpha_emit_set_long_const ( operands [ 0 ] , i0 , i1 ) ; if ( temp ) { if ( ! rtx_equal_p ( operands [ 0 ] , temp ) ) emit_move_insn ( operands [ 0 ] , temp ) ; return true ; } return false ; } </s>

Operand 1 is known to be a constant , and should require more than one instruction to load . Emit that multi-part load .


<s> void alpha_split_tmode_pair ( rtx operands [ 4 ] , machine_mode mode , bool fixup_overlap ) { switch ( GET_CODE ( operands [ 1 ] ) ) { case REG : operands [ 3 ] = gen_rtx_REG ( DImode , REGNO ( operands [ 1 ] ) + 1 ) ; operands [ 2 ] = gen_rtx_REG ( DImode , REGNO ( operands [ 1 ] ) ) ; break ; case MEM : operands [ 3 ] = adjust_address ( operands [ 1 ] , DImode , 8 ) ; operands [ 2 ] = adjust_address ( operands [ 1 ] , DImode , 0 ) ; break ; case CONST_INT : case CONST_DOUBLE : gcc_assert ( operands [ 1 ] == CONST0_RTX ( mode ) ) ; operands [ 2 ] = operands [ 3 ] = const0_rtx ; break ; default : gcc_unreachable ( ) ; } switch ( GET_CODE ( operands [ 0 ] ) ) { case REG : operands [ 1 ] = gen_rtx_REG ( DImode , REGNO ( operands [ 0 ] ) + 1 ) ; operands [ 0 ] = gen_rtx_REG ( DImode , REGNO ( operands [ 0 ] ) ) ; break ; case MEM : operands [ 1 ] = adjust_address ( operands [ 0 ] , DImode , 8 ) ; operands [ 0 ] = adjust_address ( operands [ 0 ] , DImode , 0 ) ; break ; default : gcc_unreachable ( ) ; } if ( fixup_overlap && reg_overlap_mentioned_p ( operands [ 0 ] , operands [ 3 ] ) ) { std :: swap ( operands [ 0 ] , operands [ 1 ] ) ; std :: swap ( operands [ 2 ] , operands [ 3 ] ) ; } } </s>

Split a TImode or TFmode move from OP [ 1 ] to OP [ 0 ] into a pair of DImode moves from OP [ 2,3 ] to OP [ 0,1 ] . If FIXUP_OVERLAP is true , guarantee that the sequence set ( OP [ 0 ] OP [ 2 ] ) set ( OP [ 1 ] OP [ 3 ] ) is valid . Naturally , output operand ordering is little-endian . This is used by * movtf_internal and * movti_internal .


<s> static void alpha_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr , mem , word1 , word2 ; fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; fnaddr = convert_memory_address ( Pmode , fnaddr ) ; chain_value = convert_memory_address ( Pmode , chain_value ) ; if ( TARGET_ABI_OPEN_VMS ) { const char * fnname ; char * trname ; fnname = XSTR ( fnaddr , 0 ) ; trname = ( char * ) alloca ( strlen ( fnname ) + 5 ) ; strcpy ( trname , fnname ) ; strcat ( trname , "..tr" ) ; fnname = ggc_alloc_string ( trname , strlen ( trname ) + 1 ) ; word2 = gen_rtx_SYMBOL_REF ( Pmode , fnname ) ; word1 = force_reg ( DImode , gen_const_mem ( DImode , fnaddr ) ) ; word1 = expand_and ( DImode , word1 , GEN_INT ( HOST_WIDE_INT_C ( 0xffff0fff0000fff0 ) ) , NULL ) ; } else { word1 = GEN_INT ( HOST_WIDE_INT_C ( 0xa77b0010a43b0018 ) ) ; word2 = GEN_INT ( HOST_WIDE_INT_C ( 0x47ff041f6bfb0000 ) ) ; } mem = adjust_address ( m_tramp , DImode , 0 ) ; emit_move_insn ( mem , word1 ) ; mem = adjust_address ( m_tramp , DImode , 8 ) ; emit_move_insn ( mem , word2 ) ; mem = adjust_address ( m_tramp , Pmode , 16 ) ; emit_move_insn ( mem , fnaddr ) ; mem = adjust_address ( m_tramp , Pmode , 24 ) ; emit_move_insn ( mem , chain_value ) ; if ( TARGET_ABI_OSF ) { emit_insn ( gen_imb ( ) ) ; emit_library_call ( init_one_libfunc ( "__enable_execute_stack" ) , LCT_NORMAL , VOIDmode , 1 , XEXP ( m_tramp , 0 ) , Pmode ) ; } } </s>

Emit RTL insns to initialize the variable parts of a trampoline at M_TRAMP . FNDECL is target function 's decl . CHAIN_VALUE is an rtx for the static chain value for the function .


<s> rtx alpha_use_linkage ( rtx func , bool lflag , bool rflag ) { struct alpha_links * al = NULL ; const char * name = XSTR ( func , 0 ) ; if ( cfun -> machine -> links ) { alpha_links * * slot = cfun -> machine -> links -> get ( name ) ; if ( slot ) al = * slot ; } else cfun -> machine -> links = hash_map < const char * , alpha_links * , string_traits > :: create_ggc ( 64 ) ; if ( al == NULL ) { size_t buf_len ; char * linksym ; tree id ; if ( name [ 0 ] == '*' ) name ++ ; id = maybe_get_identifier ( name ) ; if ( id ) { while ( IDENTIFIER_TRANSPARENT_ALIAS ( id ) ) id = TREE_CHAIN ( id ) ; name = IDENTIFIER_POINTER ( id ) ; } buf_len = strlen ( name ) + 8 + 9 ; linksym = ( char * ) alloca ( buf_len ) ; snprintf ( linksym , buf_len , "$%d..%s..lk" , cfun -> funcdef_no , name ) ; al = ggc_alloc < alpha_links > ( ) ; al -> func = func ; al -> linkage = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( linksym ) ) ; cfun -> machine -> links -> put ( ggc_strdup ( name ) , al ) ; } al -> rkind = rflag ? KIND_CODEADDR : KIND_LINKAGE ; if ( lflag ) return gen_rtx_MEM ( Pmode , plus_constant ( Pmode , al -> linkage , 8 ) ) ; else return al -> linkage ; } </s>

Return a SYMBOL_REF representing the reference to the .linkage entry of function FUNC built for calls made from CFUNDECL . LFLAG is 1 if this is the reference to the linkage pointer value , 0 if this is the reference to the function entry value . RFLAG is 1 if this a reduced reference ( code address only ) , 0 if this is a full reference .


<s> static bool alpha_vms_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { alpha_sa_size ( ) ; switch ( alpha_procedure_type ) { case PT_NULL : return to == STACK_POINTER_REGNUM ; case PT_REGISTER : case PT_STACK : return ( to != STACK_POINTER_REGNUM || vms_unwind_regno != HARD_FRAME_POINTER_REGNUM ) ; } gcc_unreachable ( ) ; } </s>

Worker function for TARGET_CAN_ELIMINATE .


<s> HOST_WIDE_INT alpha_vms_initial_elimination_offset ( unsigned int from , unsigned int to ) { HOST_WIDE_INT sa_size = alpha_sa_size ( ) ; if ( alpha_procedure_type == PT_NULL ) return 0 ; { HOST_WIDE_INT offset ; HOST_WIDE_INT pv_save_size = alpha_procedure_type == PT_STACK ? 8 : 0 ; switch ( from ) { case FRAME_POINTER_REGNUM : offset = ALPHA_ROUND ( sa_size + pv_save_size ) ; break ; case ARG_POINTER_REGNUM : offset = ( ALPHA_ROUND ( sa_size + pv_save_size + get_frame_size ( ) + crtl -> args . pretend_args_size ) - crtl -> args . pretend_args_size ) ; break ; default : gcc_unreachable ( ) ; } if ( to == STACK_POINTER_REGNUM ) offset += ALPHA_ROUND ( crtl -> outgoing_args_size ) ; return offset ; } } </s>

FROM is to be eliminated for TO . Return the offset so that TO+offset designates the same location as FROM .


<s> static HOST_WIDE_INT compute_frame_size ( HOST_WIDE_INT size , HOST_WIDE_INT sa_size ) { if ( TARGET_ABI_OPEN_VMS ) return ALPHA_ROUND ( sa_size + ( alpha_procedure_type == PT_STACK ? 8 : 0 ) + size + crtl -> args . pretend_args_size ) ; else return ALPHA_ROUND ( crtl -> outgoing_args_size ) + sa_size + ALPHA_ROUND ( size + crtl -> args . pretend_args_size ) ; } </s>

Typical stack layout should looks like this after the function 's prologue : | | -- ^ | | \ | | | arguments saved | Increasing | | on the stack | addresses PARENT arg pointer - > | | / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - | | - space for argument split between regs & stack -- CHILD | | \ < -- ( return address here ) | | other call | | saved registers | | / -- frame pointer - > | | \ ___ | | local | | | variables |f | | / |r -- |a | | \ |m | | outgoing |e | | arguments | | Decreasing ( hard ) frame pointer | | / | | addresses and stack pointer - > | | / _|_ | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- V


<s> int direct_return ( void ) { return ( TARGET_ABI_OSF && reload_completed && alpha_sa_size ( ) == 0 && get_frame_size ( ) == 0 && crtl -> outgoing_args_size == 0 && crtl -> args . pretend_args_size == 0 ) ; } </s>

Return non-zero if this function is known to have a null epilogue .


<s> static void emit_frame_store_1 ( rtx value , rtx base_reg , HOST_WIDE_INT frame_bias , HOST_WIDE_INT base_ofs , rtx frame_reg ) { rtx addr , mem ; rtx_insn * insn ; addr = plus_constant ( Pmode , base_reg , base_ofs ) ; mem = gen_frame_mem ( DImode , addr ) ; insn = emit_move_insn ( mem , value ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; if ( frame_bias || value != frame_reg ) { if ( frame_bias ) { addr = plus_constant ( Pmode , stack_pointer_rtx , frame_bias + base_ofs ) ; mem = gen_rtx_MEM ( DImode , addr ) ; } add_reg_note ( insn , REG_FRAME_RELATED_EXPR , gen_rtx_SET ( VOIDmode , mem , frame_reg ) ) ; } } </s>

Generates a store with the proper unwind info attached . VALUE is stored at BASE_REG+BASE_OFS . If FRAME_BIAS is nonzero , then BASE_REG contains SP+FRAME_BIAS , and that is the unwind info that should be generated . If FRAME_REG ! = VALUE , then VALUE is being stored on behalf of FRAME_REG , and FRAME_REG should be present in the unwind .


<s> static rtx emit_insxl ( machine_mode mode , rtx op1 , rtx op2 ) { rtx ret = gen_reg_rtx ( DImode ) ; rtx ( * fn ) ( rtx , rtx , rtx ) ; switch ( mode ) { case QImode : fn = gen_insbl ; break ; case HImode : fn = gen_inswl ; break ; case SImode : fn = gen_insll ; break ; case DImode : fn = gen_insql ; break ; default : gcc_unreachable ( ) ; } op1 = force_reg ( mode , op1 ) ; emit_insn ( fn ( ret , op1 , op2 ) ) ; return ret ; } </s>

A subroutine of the atomic operation splitters . Emit an insxl instruction in MODE .


<s> static void emit_load_locked ( machine_mode mode , rtx reg , rtx mem ) { rtx ( * fn ) ( rtx , rtx ) = NULL ; if ( mode == SImode ) fn = gen_load_locked_si ; else if ( mode == DImode ) fn = gen_load_locked_di ; emit_insn ( fn ( reg , mem ) ) ; } </s>

A subroutine of the atomic operation splitters . Emit a load-locked instruction in MODE . For QI/HImode , possibly use a pattern than includes the zero_extend operation .


<s> static void emit_store_conditional ( machine_mode mode , rtx res , rtx mem , rtx val ) { rtx ( * fn ) ( rtx , rtx , rtx ) = NULL ; if ( mode == SImode ) fn = gen_store_conditional_si ; else if ( mode == DImode ) fn = gen_store_conditional_di ; emit_insn ( fn ( res , mem , val ) ) ; } </s>

A subroutine of the atomic operation splitters . Emit a store-conditional instruction in MODE .


<s> static void emit_unlikely_jump ( rtx cond , rtx label ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; rtx x ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , cond , label , pc_rtx ) ; x = emit_jump_insn ( gen_rtx_SET ( VOIDmode , pc_rtx , x ) ) ; add_int_reg_note ( x , REG_BR_PROB , very_unlikely ) ; } </s>

Mark the previous jump instruction as unlikely .


<s> rtx function_value ( const_tree valtype , const_tree func ATTRIBUTE_UNUSED , machine_mode mode ) { unsigned int regnum , dummy ATTRIBUTE_UNUSED ; enum mode_class mclass ; gcc_assert ( ! valtype || ! alpha_return_in_memory ( valtype , func ) ) ; if ( valtype ) mode = TYPE_MODE ( valtype ) ; mclass = GET_MODE_CLASS ( mode ) ; switch ( mclass ) { case MODE_INT : if ( ! ( TARGET_ABI_OPEN_VMS && valtype && AGGREGATE_TYPE_P ( valtype ) ) ) PROMOTE_MODE ( mode , dummy , valtype ) ; case MODE_COMPLEX_INT : case MODE_VECTOR_INT : regnum = 0 ; break ; case MODE_FLOAT : regnum = 32 ; break ; case MODE_COMPLEX_FLOAT : { machine_mode cmode = GET_MODE_INNER ( mode ) ; return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( cmode , 32 ) , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( cmode , 33 ) , GEN_INT ( GET_MODE_SIZE ( cmode ) ) ) ) ) ; } case MODE_RANDOM : gcc_assert ( TARGET_ABI_OPEN_VMS && mode == BLKmode ) ; regnum = 0 ; break ; default : gcc_unreachable ( ) ; } return gen_rtx_REG ( mode , regnum ) ; } </s>

Handle FUNCTION_VALUE , FUNCTION_OUTGOING_VALUE , and LIBCALL_VALUE macros . For v9 , function return values are subject to the same rules as arguments , except that up to 32 bytes may be returned in registers .


<s> void get_aligned_mem ( rtx ref , rtx * paligned_mem , rtx * pbitnum ) { rtx base ; HOST_WIDE_INT disp , offset ; gcc_assert ( MEM_P ( ref ) ) ; if ( reload_in_progress && ! memory_address_p ( GET_MODE ( ref ) , XEXP ( ref , 0 ) ) ) { base = find_replacement ( & XEXP ( ref , 0 ) ) ; gcc_assert ( memory_address_p ( GET_MODE ( ref ) , base ) ) ; } else base = XEXP ( ref , 0 ) ; if ( GET_CODE ( base ) == PLUS ) disp = INTVAL ( XEXP ( base , 1 ) ) , base = XEXP ( base , 0 ) ; else disp = 0 ; if ( MEM_ALIGN ( ref ) >= 32 ) offset = 0 ; else offset = disp & 3 ; gcc_assert ( offset + GET_MODE_SIZE ( GET_MODE ( ref ) ) <= GET_MODE_SIZE ( SImode ) ) ; * paligned_mem = widen_memory_access ( ref , SImode , - offset ) ; offset *= BITS_PER_UNIT ; * pbitnum = GEN_INT ( offset ) ; } </s>

REF is an alignable memory location . Place an aligned SImode reference into * PALIGNED_MEM and the number of bits to shift into * PBITNUM . SCRATCH is a free register for use in reloading out of range stack slots .


<s> rtx get_unaligned_address ( rtx ref ) { rtx base ; HOST_WIDE_INT offset = 0 ; gcc_assert ( MEM_P ( ref ) ) ; if ( reload_in_progress && ! memory_address_p ( GET_MODE ( ref ) , XEXP ( ref , 0 ) ) ) { base = find_replacement ( & XEXP ( ref , 0 ) ) ; gcc_assert ( memory_address_p ( GET_MODE ( ref ) , base ) ) ; } else base = XEXP ( ref , 0 ) ; if ( GET_CODE ( base ) == PLUS ) offset += INTVAL ( XEXP ( base , 1 ) ) , base = XEXP ( base , 0 ) ; return plus_constant ( Pmode , base , offset ) ; } </s>

Similar , but just get the address . Handle the two reload cases . Add EXTRA_OFFSET to the address we return .


<s>
void
print_operand_address
(
FILE
*
file
,
rtx
addr
)
{
int
basereg
=
31
;
HOST_WIDE_INT
offset
=
0
;
if
(
GET_CODE
(
addr
)
==
AND
)
addr
=
XEXP
(
addr
,
0
)
;
if
(
GET_CODE
(
addr
)
==
PLUS
&&
CONST_INT_P
(
XEXP
(
addr
,
1
)
)
)
{
offset
=
INTVAL
(
XEXP
(
addr
,
1
)
)
;
addr
=
XEXP
(
addr
,
0
)
;
}
if
(
GET_CODE
(
addr
)
==
LO_SUM
)
{
const
char
*
reloc16
,
*
reloclo
;
rtx
op1
=
XEXP
(
addr
,
1
)
;
if
(
GET_CODE
(
op1
)
==
CONST
&&
GET_CODE
(
XEXP
(
op1
,
0
)
)
==
UNSPEC
)
{
op1
=
XEXP
(
op1
,
0
)
;
switch
(
XINT
(
op1
,
1
)
)
{
case
UNSPEC_DTPREL
:
reloc16
=
;
reloclo
=
(
alpha_tls_size
==
16
"dtprel"
:
"dtprello"
)
;
break
;
case
UNSPEC_TPREL
:
reloc16
=
;
reloclo
=
(
alpha_tls_size
==
16
"tprel"
:
"tprello"
)
;
break
;
default
:
output_operand_lossage
(
"unknown relocation unspec"
)
;
return
;
}
output_addr_const
(
file
,
XVECEXP
(
op1
,
0
,
0
)
)
;
}
else
{
reloc16
=
"gprel"
;
reloclo
=
"gprellow"
;
output_addr_const
(
file
,
op1
)
;
}
if
(
offset
)
fprintf
(
file
,
"+"
HOST_WIDE_INT_PRINT_DEC
,
offset
)
;
addr
=
XEXP
(
addr
,
0
)
;
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
basereg
=
REGNO
(
addr
)
;
break
;
case
SUBREG
:
basereg
=
subreg_regno
(
addr
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
fprintf
(
file
,
"($%d)\t\t!%s"
,
basereg
,
(
basereg
==
29
reloc16
:
reloclo
)
)
;
return
;
}
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
basereg
=
REGNO
(
addr
)
;
break
;
case
SUBREG
:
basereg
=
subreg_regno
(
addr
)
;
break
;
case
CONST_INT
:
offset
=
INTVAL
(
addr
)
;
break
;
case
SYMBOL_REF
:
gcc_assert
(
TARGET_ABI_OPEN_VMS
||
this_is_asm_operands
)
;
fprintf
(
file
,
"%s"
,
XSTR
(
addr
,
0
)
)
;
return
;
case
CONST
:
gcc_assert
(
TARGET_ABI_OPEN_VMS
||
this_is_asm_operands
)
;
gcc_assert
(
GET_CODE
(
XEXP
(
addr
,
0
)
)
==
PLUS
&&
GET_CODE
(
XEXP
(
XEXP
(
addr
,
0
)
,
0
)
)
==
SYMBOL_REF
)
;
fprintf
(
file
,
"%s+"
HOST_WIDE_INT_PRINT_DEC
,
XSTR
(
XEXP
(
XEXP
(
addr
,
0
)
,
0
)
,
0
)
,
INTVAL
(
XEXP
(
XEXP
(
addr
,
0
)
,
1
)
)
)
;
return
;
default
:
output_operand_lossage
(
"invalid operand address"
)
;
return
;
}
fprintf
(
file
,
HOST_WIDE_INT_PRINT_DEC
"($%d)"
,
offset
,
basereg
)
;
}
</s>

Print the operand address represented by the rtx addr


<s> rtx resolve_reload_operand ( rtx op ) { if ( reload_in_progress ) { rtx tmp = op ; if ( GET_CODE ( tmp ) == SUBREG ) tmp = SUBREG_REG ( tmp ) ; if ( REG_P ( tmp ) && REGNO ( tmp ) >= FIRST_PSEUDO_REGISTER ) { op = reg_equiv_memory_loc ( REGNO ( tmp ) ) ; if ( op == 0 ) return 0 ; } } return op ; } </s>

Used by aligned_memory_operand and unaligned_memory_operand to resolve what reload is going to do with OP if it 's a register .


<s> static gimple va_list_skip_additions ( tree lhs ) { gimple stmt ; for ( ; ; ) { enum tree_code code ; stmt = SSA_NAME_DEF_STMT ( lhs ) ; if ( gimple_code ( stmt ) == GIMPLE_PHI ) return stmt ; if ( ! is_gimple_assign ( stmt ) || gimple_assign_lhs ( stmt ) != lhs ) return NULL ; if ( TREE_CODE ( gimple_assign_rhs1 ( stmt ) ) != SSA_NAME ) return stmt ; code = gimple_assign_rhs_code ( stmt ) ; if ( ! CONVERT_EXPR_CODE_P ( code ) && ( ( code != PLUS_EXPR && code != POINTER_PLUS_EXPR ) || TREE_CODE ( gimple_assign_rhs2 ( stmt ) ) != INTEGER_CST || ! tree_fits_uhwi_p ( gimple_assign_rhs2 ( stmt ) ) ) ) return stmt ; lhs = gimple_assign_rhs1 ( stmt ) ; } } </s>

Helper function for alpha_stdarg_optimize_hook . Skip over casts and constant additions .


<s> static void alpha_emit_xfloating_libcall ( rtx func , rtx target , rtx operands [ ] , int noperands , rtx equiv ) { rtx usage = NULL_RTX , tmp , reg ; int regno = 16 , i ; start_sequence ( ) ; for ( i = 0 ; i < noperands ; ++ i ) { switch ( GET_MODE ( operands [ i ] ) ) { case TFmode : reg = gen_rtx_REG ( TFmode , regno ) ; regno += 2 ; break ; case DFmode : reg = gen_rtx_REG ( DFmode , regno + 32 ) ; regno += 1 ; break ; case VOIDmode : gcc_assert ( CONST_INT_P ( operands [ i ] ) ) ; case DImode : reg = gen_rtx_REG ( DImode , regno ) ; regno += 1 ; break ; default : gcc_unreachable ( ) ; } emit_move_insn ( reg , operands [ i ] ) ; use_reg ( & usage , reg ) ; } switch ( GET_MODE ( target ) ) { case TFmode : reg = gen_rtx_REG ( TFmode , 16 ) ; break ; case DFmode : reg = gen_rtx_REG ( DFmode , 32 ) ; break ; case DImode : reg = gen_rtx_REG ( DImode , 0 ) ; break ; default : gcc_unreachable ( ) ; } tmp = gen_rtx_MEM ( QImode , func ) ; tmp = emit_call_insn ( gen_call_value ( reg , tmp , const0_rtx , const0_rtx , const0_rtx ) ) ; CALL_INSN_FUNCTION_USAGE ( tmp ) = usage ; RTL_CONST_CALL_P ( tmp ) = 1 ; tmp = get_insns ( ) ; end_sequence ( ) ; emit_libcall_block ( tmp , target , reg , equiv ) ; } </s>

Emit an X_floating library function call . Note that these functions do not follow normal calling conventions : TFmode arguments are passed in two integer registers ( as opposed to indirect ) ; TFmode return values appear in R16+R17 . FUNC is the function name to call . TARGET is where the output belongs . OPERANDS are the inputs . NOPERANDS is the count of inputs . EQUIV is the expression equivalent for the function .


<s> static rtx alpha_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int basereg ; int num_args ; if ( type && AGGREGATE_TYPE_P ( type ) ) basereg = 16 ; else { gcc_checking_assert ( ! COMPLEX_MODE_P ( mode ) ) ; if ( TARGET_FPREGS && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) basereg = 32 + 16 ; else basereg = 16 ; } { if ( mode == VOIDmode ) return alpha_arg_info_reg_val ( * cum ) ; num_args = cum -> num_args ; if ( num_args >= 6 || targetm . calls . must_pass_in_stack ( mode , type ) ) return NULL_RTX ; } { if ( * cum >= 6 ) return NULL_RTX ; num_args = * cum ; if ( type == void_type_node ) basereg = 16 ; else if ( targetm . calls . must_pass_in_stack ( mode , type ) ) return NULL_RTX ; } return gen_rtx_REG ( mode , num_args + basereg ) ; } </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 Alpha the first 6 words of args are normally in registers and the rest are pushed .


<s> static void alpha_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; bool onstack = targetm . calls . must_pass_in_stack ( mode , type ) ; int increment = onstack ? 6 : ALPHA_ARG_SIZE ( mode , type ) ; * cum += increment ; if ( ! onstack && cum -> num_args < 6 ) cum -> atypes [ cum -> num_args ] = alpha_arg_type ( mode ) ; cum -> num_args += increment ; } </s>

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


<s> static void alpha_output_mi_thunk_osf ( FILE * file , tree thunk_fndecl ATTRIBUTE_UNUSED , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { HOST_WIDE_INT hi , lo ; rtx this_rtx , funexp ; rtx_insn * insn ; emit_insn ( gen_prologue_ldgp ( ) ) ; emit_note ( NOTE_INSN_PROLOGUE_END ) ; if ( aggregate_value_p ( TREE_TYPE ( TREE_TYPE ( function ) ) , function ) ) this_rtx = gen_rtx_REG ( Pmode , 17 ) ; else this_rtx = gen_rtx_REG ( Pmode , 16 ) ; lo = ( ( delta & 0xffff ) ^ 0x8000 ) - 0x8000 ; hi = ( ( ( delta - lo ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( hi + lo == delta ) { if ( hi ) emit_insn ( gen_adddi3 ( this_rtx , this_rtx , GEN_INT ( hi ) ) ) ; if ( lo ) emit_insn ( gen_adddi3 ( this_rtx , this_rtx , GEN_INT ( lo ) ) ) ; } else { rtx tmp = alpha_emit_set_long_const ( gen_rtx_REG ( Pmode , 0 ) , delta ) ; emit_insn ( gen_adddi3 ( this_rtx , this_rtx , tmp ) ) ; } if ( vcall_offset ) { rtx tmp , tmp2 ; tmp = gen_rtx_REG ( Pmode , 0 ) ; emit_move_insn ( tmp , gen_rtx_MEM ( Pmode , this_rtx ) ) ; lo = ( ( vcall_offset & 0xffff ) ^ 0x8000 ) - 0x8000 ; hi = ( ( ( vcall_offset - lo ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( hi + lo == vcall_offset ) { if ( hi ) emit_insn ( gen_adddi3 ( tmp , tmp , GEN_INT ( hi ) ) ) ; } else { tmp2 = alpha_emit_set_long_const ( gen_rtx_REG ( Pmode , 1 ) , vcall_offset ) ; emit_insn ( gen_adddi3 ( tmp , tmp , tmp2 ) ) ; lo = 0 ; } if ( lo ) tmp2 = gen_rtx_PLUS ( Pmode , tmp , GEN_INT ( lo ) ) ; else tmp2 = tmp ; emit_move_insn ( tmp , gen_rtx_MEM ( Pmode , tmp2 ) ) ; emit_insn ( gen_adddi3 ( this_rtx , this_rtx , tmp ) ) ; } if ( ! TREE_USED ( function ) ) { assemble_external ( function ) ; TREE_USED ( function ) = 1 ; } funexp = XEXP ( DECL_RTL ( function ) , 0 ) ; funexp = gen_rtx_MEM ( FUNCTION_MODE , funexp ) ; insn = emit_call_insn ( gen_sibcall ( funexp , const0_rtx ) ) ; SIBLING_CALL_P ( insn ) = 1 ; insn = get_insns ( ) ; shorten_branches ( insn ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; } </s>

Emit a tail call to FUNCTION after adjusting THIS by DELTA . In order to avoid the hordes of differences between generated code with and without TARGET_EXPLICIT_RELOCS , and to avoid duplicating lots of code loading up large constants , generate rtl and emit it instead of going straight to text . Not sure why this idea has n't been explored before ...


<s> static void alpha_override_options_after_change ( void ) { if ( optimize > 0 ) { if ( align_loops <= 0 ) align_loops = 16 ; if ( align_jumps <= 0 ) align_jumps = 16 ; } if ( align_functions <= 0 ) align_functions = 16 ; } </s>


<s> void alpha_split_atomic_op ( enum rtx_code code , rtx mem , rtx val , rtx before , rtx after , rtx scratch , enum memmodel model ) { machine_mode mode = GET_MODE ( mem ) ; rtx label , x , cond = gen_rtx_REG ( DImode , REGNO ( scratch ) ) ; alpha_pre_atomic_barrier ( model ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; label = gen_rtx_LABEL_REF ( DImode , label ) ; if ( before == NULL ) before = scratch ; emit_load_locked ( mode , before , mem ) ; if ( code == NOT ) { x = gen_rtx_AND ( mode , before , val ) ; emit_insn ( gen_rtx_SET ( val , x ) ) ; x = gen_rtx_NOT ( mode , val ) ; } else x = gen_rtx_fmt_ee ( code , mode , before , val ) ; if ( after ) emit_insn ( gen_rtx_SET ( after , copy_rtx ( x ) ) ) ; emit_insn ( gen_rtx_SET ( scratch , x ) ) ; emit_store_conditional ( mode , cond , mem , scratch ) ; x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; emit_unlikely_jump ( x , label ) ; alpha_post_atomic_barrier ( model ) ; } </s>

Expand an an atomic fetch-and-operate pattern . CODE is the binary operation to perform . MEM is the memory on which to operate . VAL is the second operand of the binary operator . BEFORE and AFTER are optional locations to return the value of MEM either before of after the operation . SCRATCH is a scratch register .


<s> void alpha_split_compare_and_swap ( rtx operands [ ] ) { rtx cond , retval , mem , oldval , newval ; bool is_weak ; enum memmodel mod_s , mod_f ; machine_mode mode ; rtx label1 , label2 , x ; cond = operands [ 0 ] ; retval = operands [ 1 ] ; mem = operands [ 2 ] ; oldval = operands [ 3 ] ; newval = operands [ 4 ] ; is_weak = ( operands [ 5 ] != const0_rtx ) ; mod_s = memmodel_from_int ( INTVAL ( operands [ 6 ] ) ) ; mod_f = memmodel_from_int ( INTVAL ( operands [ 7 ] ) ) ; mode = GET_MODE ( mem ) ; alpha_pre_atomic_barrier ( mod_s ) ; label1 = NULL_RTX ; if ( ! is_weak ) { label1 = gen_rtx_LABEL_REF ( DImode , gen_label_rtx ( ) ) ; emit_label ( XEXP ( label1 , 0 ) ) ; } label2 = gen_rtx_LABEL_REF ( DImode , gen_label_rtx ( ) ) ; emit_load_locked ( mode , retval , mem ) ; x = gen_lowpart ( DImode , retval ) ; if ( oldval == const0_rtx ) { emit_move_insn ( cond , const0_rtx ) ; x = gen_rtx_NE ( DImode , x , const0_rtx ) ; } else { x = gen_rtx_EQ ( DImode , x , oldval ) ; emit_insn ( gen_rtx_SET ( cond , x ) ) ; x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; } emit_unlikely_jump ( x , label2 ) ; emit_move_insn ( cond , newval ) ; emit_store_conditional ( mode , cond , mem , gen_lowpart ( mode , cond ) ) ; if ( ! is_weak ) { x = gen_rtx_EQ ( DImode , cond , const0_rtx ) ; emit_unlikely_jump ( x , label1 ) ; } if ( ! is_mm_relaxed ( mod_f ) ) emit_label ( XEXP ( label2 , 0 ) ) ; alpha_post_atomic_barrier ( mod_s ) ; if ( is_mm_relaxed ( mod_f ) ) emit_label ( XEXP ( label2 , 0 ) ) ; } </s>


<s> int alpha_split_conditional_move ( enum rtx_code code , rtx dest , rtx cond , rtx t_rtx , rtx f_rtx ) { HOST_WIDE_INT t , f , diff ; machine_mode mode ; rtx target , subtarget , tmp ; mode = GET_MODE ( dest ) ; t = INTVAL ( t_rtx ) ; f = INTVAL ( f_rtx ) ; diff = t - f ; if ( ( ( code == NE || code == EQ ) && diff < 0 ) || ( code == GE || code == GT ) ) { code = reverse_condition ( code ) ; diff = t , t = f , f = diff ; diff = t - f ; } subtarget = target = dest ; if ( mode != DImode ) { target = gen_lowpart ( DImode , dest ) ; if ( can_create_pseudo_p ( ) ) subtarget = gen_reg_rtx ( DImode ) ; else subtarget = target ; } if ( f == 0 && exact_log2 ( diff ) > 0 && ( diff <= 8 || alpha_tune == PROCESSOR_EV6 ) ) { tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( copy_rtx ( subtarget ) , tmp ) ) ; tmp = gen_rtx_ASHIFT ( DImode , copy_rtx ( subtarget ) , GEN_INT ( exact_log2 ( t ) ) ) ; emit_insn ( gen_rtx_SET ( target , tmp ) ) ; } else if ( f == 0 && t == - 1 ) { tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( copy_rtx ( subtarget ) , tmp ) ) ; emit_insn ( gen_negdi2 ( target , copy_rtx ( subtarget ) ) ) ; } else if ( diff == 1 || diff == 4 || diff == 8 ) { rtx add_op ; tmp = gen_rtx_fmt_ee ( code , DImode , cond , const0_rtx ) ; emit_insn ( gen_rtx_SET ( copy_rtx ( subtarget ) , tmp ) ) ; if ( diff == 1 ) emit_insn ( gen_adddi3 ( target , copy_rtx ( subtarget ) , GEN_INT ( f ) ) ) ; else { add_op = GEN_INT ( f ) ; if ( sext_add_operand ( add_op , mode ) ) { tmp = gen_rtx_MULT ( DImode , copy_rtx ( subtarget ) , GEN_INT ( diff ) ) ; tmp = gen_rtx_PLUS ( DImode , tmp , add_op ) ; emit_insn ( gen_rtx_SET ( target , tmp ) ) ; } else return 0 ; } } else return 0 ; return 1 ; } </s>

Simplify a conditional move of two constants into a setcc with arithmetic . This is done with a splitter since combine would just undo the work if done during code generation . It also catches cases we would n't have before cse .


<s> static void emit_unlikely_jump ( rtx cond , rtx label ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; rtx x ; x = gen_rtx_IF_THEN_ELSE ( VOIDmode , cond , label , pc_rtx ) ; x = emit_jump_insn ( gen_rtx_SET ( pc_rtx , x ) ) ; add_int_reg_note ( x , REG_BR_PROB , very_unlikely ) ; } </s>


<s> static void alpha_emit_xfloating_libcall ( rtx func , rtx target , rtx operands [ ] , int noperands , rtx equiv ) { rtx usage = NULL_RTX , reg ; int regno = 16 , i ; start_sequence ( ) ; for ( i = 0 ; i < noperands ; ++ i ) { switch ( GET_MODE ( operands [ i ] ) ) { case TFmode : reg = gen_rtx_REG ( TFmode , regno ) ; regno += 2 ; break ; case DFmode : reg = gen_rtx_REG ( DFmode , regno + 32 ) ; regno += 1 ; break ; case VOIDmode : gcc_assert ( CONST_INT_P ( operands [ i ] ) ) ; case DImode : reg = gen_rtx_REG ( DImode , regno ) ; regno += 1 ; break ; default : gcc_unreachable ( ) ; } emit_move_insn ( reg , operands [ i ] ) ; use_reg ( & usage , reg ) ; } switch ( GET_MODE ( target ) ) { case TFmode : reg = gen_rtx_REG ( TFmode , 16 ) ; break ; case DFmode : reg = gen_rtx_REG ( DFmode , 32 ) ; break ; case DImode : reg = gen_rtx_REG ( DImode , 0 ) ; break ; default : gcc_unreachable ( ) ; } rtx mem = gen_rtx_MEM ( QImode , func ) ; rtx_insn * tmp = emit_call_insn ( gen_call_value ( reg , mem , const0_rtx , const0_rtx , const0_rtx ) ) ; CALL_INSN_FUNCTION_USAGE ( tmp ) = usage ; RTL_CONST_CALL_P ( tmp ) = 1 ; tmp = get_insns ( ) ; end_sequence ( ) ; emit_libcall_block ( tmp , target , reg , equiv ) ; } </s>


<s> static bool alpha_pass_by_reference ( cumulative_args_t ca ATTRIBUTE_UNUSED , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ) { if ( mode == SFmode || mode == SCmode ) return ! named ; return mode == TFmode || mode == TCmode ; } </s>

Return true if TYPE should be passed by invisible reference .


<s> static void emit_unlikely_jump ( rtx cond , rtx label ) { int very_unlikely = REG_BR_PROB_BASE / 100 - 1 ; rtx x = gen_rtx_IF_THEN_ELSE ( VOIDmode , cond , label , pc_rtx ) ; rtx_insn * insn = emit_jump_insn ( gen_rtx_SET ( pc_rtx , x ) ) ; add_int_reg_note ( insn , REG_BR_PROB , very_unlikely ) ; } </s>


<s> static rtx_insn * alphaev4_next_group ( rtx_insn * insn , int * pin_use , int * plen ) { int len , in_use ; len = in_use = 0 ; if ( ! INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || GET_CODE ( PATTERN ( insn ) ) == USE ) goto next_and_done ; while ( 1 ) { enum alphaev4_pipe pipe ; pipe = alphaev4_insn_pipe ( insn ) ; switch ( pipe ) { case EV4_STOP : if ( in_use ) goto done ; if ( recog_memoized ( insn ) < 0 ) len = - 1 ; else len = get_attr_length ( insn ) ; goto next_and_done ; case EV4_IBX : if ( in_use & EV4_IB0 ) { if ( in_use & EV4_IB1 ) goto done ; in_use |= EV4_IB1 ; } else in_use |= EV4_IB0 | EV4_IBX ; break ; case EV4_IB0 : if ( in_use & EV4_IB0 ) { if ( ! ( in_use & EV4_IBX ) || ( in_use & EV4_IB1 ) ) goto done ; in_use |= EV4_IB1 ; } in_use |= EV4_IB0 ; break ; case EV4_IB1 : if ( in_use & EV4_IB1 ) goto done ; in_use |= EV4_IB1 ; break ; default : gcc_unreachable ( ) ; } len += 4 ; if ( JUMP_P ( insn ) ) goto next_and_done ; next : insn = next_nonnote_insn ( insn ) ; if ( ! insn || ! INSN_P ( insn ) ) goto done ; if ( GET_MODE ( insn ) == TImode ) goto done ; if ( GET_CODE ( insn ) == CLOBBER || GET_CODE ( insn ) == USE ) goto next ; } next_and_done : insn = next_nonnote_insn ( insn ) ; done : * plen = len ; * pin_use = in_use ; return insn ; } </s>

IN_USE is a mask of the slots currently filled within the insn group . The mask bits come from alphaev4_pipe above . If EV4_IBX is set , then the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1 . LEN is , of course , the length of the group in bytes .


<s> static rtx_insn * alphaev5_next_group ( rtx_insn * insn , int * pin_use , int * plen ) { int len , in_use ; len = in_use = 0 ; if ( ! INSN_P ( insn ) || GET_CODE ( PATTERN ( insn ) ) == CLOBBER || GET_CODE ( PATTERN ( insn ) ) == USE ) goto next_and_done ; while ( 1 ) { enum alphaev5_pipe pipe ; pipe = alphaev5_insn_pipe ( insn ) ; switch ( pipe ) { case EV5_STOP : if ( in_use ) goto done ; if ( recog_memoized ( insn ) < 0 ) len = - 1 ; else len = get_attr_length ( insn ) ; goto next_and_done ; case EV5_E01 : if ( in_use & EV5_E0 ) { if ( in_use & EV5_E1 ) goto done ; in_use |= EV5_E1 ; } else in_use |= EV5_E0 | EV5_E01 ; break ; case EV5_E0 : if ( in_use & EV5_E0 ) { if ( ! ( in_use & EV5_E01 ) || ( in_use & EV5_E1 ) ) goto done ; in_use |= EV5_E1 ; } in_use |= EV5_E0 ; break ; case EV5_E1 : if ( in_use & EV5_E1 ) goto done ; in_use |= EV5_E1 ; break ; case EV5_FAM : if ( in_use & EV5_FA ) { if ( in_use & EV5_FM ) goto done ; in_use |= EV5_FM ; } else in_use |= EV5_FA | EV5_FAM ; break ; case EV5_FA : if ( in_use & EV5_FA ) goto done ; in_use |= EV5_FA ; break ; case EV5_FM : if ( in_use & EV5_FM ) goto done ; in_use |= EV5_FM ; break ; case EV5_NONE : break ; default : gcc_unreachable ( ) ; } len += 4 ; if ( JUMP_P ( insn ) ) goto next_and_done ; next : insn = next_nonnote_insn ( insn ) ; if ( ! insn || ! INSN_P ( insn ) ) goto done ; if ( GET_MODE ( insn ) == TImode ) goto done ; if ( GET_CODE ( insn ) == CLOBBER || GET_CODE ( insn ) == USE ) goto next ; } next_and_done : insn = next_nonnote_insn ( insn ) ; done : * plen = len ; * pin_use = in_use ; return insn ; } </s>

IN_USE is a mask of the slots currently filled within the insn group . The mask bits come from alphaev5_pipe above . If EV5_E01 is set , then the insn in EV5_E0 can be swapped by the hardware into EV5_E1 . LEN is , of course , the length of the group in bytes .


<s> static void alpha_add_builtins ( const struct alpha_builtin_def * p , size_t count , tree ftype ) { size_t i ; for ( i = 0 ; i < count ; ++ i , ++ p ) if ( ( target_flags & p -> target_mask ) == p -> target_mask ) alpha_builtin_function ( p -> name , ftype , p -> code , ( p -> is_const ? ECF_CONST : 0 ) | ECF_NOTHROW ) ; } </s>

Helper function of alpha_init_builtins . Add the COUNT built-in functions pointed to by P , with function type FTYPE .


<s> static int alpha_adjust_cost ( rtx_insn * insn , int dep_type , rtx_insn * dep_insn , int cost , unsigned int ) { enum attr_type dep_insn_type ; if ( dep_type != 0 ) return cost ; if ( recog_memoized ( insn ) < 0 || recog_memoized ( dep_insn ) < 0 ) return cost ; dep_insn_type = get_attr_type ( dep_insn ) ; if ( dep_insn_type == TYPE_ILD || dep_insn_type == TYPE_FLD || dep_insn_type == TYPE_LDSYM ) cost += alpha_memory_latency - 1 ; return cost ; } </s>

Adjust the cost of a scheduling dependency . Return the new cost of a dependency LINK or INSN on DEP_INSN . COST is the current cost .


<s> static void alpha_align_insns ( void ) { if ( alpha_tune == PROCESSOR_EV4 ) alpha_align_insns_1 ( 8 , alphaev4_next_group , alphaev4_next_nop ) ; else if ( alpha_tune == PROCESSOR_EV5 ) alpha_align_insns_1 ( 16 , alphaev5_next_group , alphaev5_next_nop ) ; else gcc_unreachable ( ) ; } </s>

The instruction group alignment main loop .


<s> rtx alpha_arg_info_reg_val ( CUMULATIVE_ARGS cum ) { unsigned HOST_WIDE_INT regval = cum . num_args ; int i ; for ( i = 0 ; i < 6 ; i ++ ) regval |= ( ( int ) cum . atypes [ i ] ) << ( i * 3 + 8 ) ; return GEN_INT ( regval ) ; } </s>

Return an rtx for an integer representing the VMS Argument Information register value .


<s> enum avms_arg_type alpha_arg_type ( machine_mode mode ) { switch ( mode ) { case E_SFmode : return TARGET_FLOAT_VAX ? FF : FS ; case E_DFmode : return TARGET_FLOAT_VAX ? FD : FT ; default : return I64 ; } } </s>

Return the VMS argument type corresponding to MODE .


<s> static tree alpha_builtin_decl ( unsigned code , bool initialize_p ATTRIBUTE_UNUSED ) { if ( code >= ALPHA_BUILTIN_max ) return error_mark_node ; return alpha_builtins [ code ] ; } </s>


<s> static void alpha_builtin_function ( const char * name , tree ftype , enum alpha_builtin code , unsigned ecf ) { tree decl = add_builtin_function ( name , ftype , ( int ) code , BUILT_IN_MD , NULL , NULL_TREE ) ; if ( ecf & ECF_CONST ) TREE_READONLY ( decl ) = 1 ; if ( ecf & ECF_NOTHROW ) TREE_NOTHROW ( decl ) = 1 ; alpha_builtins [ ( int ) code ] = decl ; } </s>

Helper function of alpha_init_builtins . Add the built-in specified by NAME , TYPE , CODE , and ECF .


<s> static bool alpha_cannot_copy_insn_p ( rtx_insn * insn ) { if ( ! reload_completed || ! TARGET_EXPLICIT_RELOCS ) return false ; if ( recog_memoized ( insn ) >= 0 ) return get_attr_cannot_copy ( insn ) ; else return false ; } </s>

Indicate that INSN can not be duplicated . This is true for any insn that we 've marked with gpdisp relocs , since those have to stay in 1-1 correspondence with one another . Technically we could copy them if we could set up a mapping from one sequence number to another , across the set of insns to be duplicated . This seems overly complicated and error-prone since interblock motion from sched-ebb could move one of the pair of insns to a different block . Also can not allow jsr insns to be duplicated . If they throw exceptions , then they 'll be in a different block from their ldgp . Which could lead the bb reorder code to think that it would be ok to copy just the block containing the call and branch to the block containing the ldgp .


<s> static bool alpha_cannot_force_const_mem ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { enum rtx_code code = GET_CODE ( x ) ; return code == SYMBOL_REF || code == LABEL_REF || code == CONST ; } </s>

Primarily this is required for TLS symbols , but given that our move patterns * ought * to be able to handle any symbol at any time , we should never be spilling symbolic operands to the constant pool , ever .


<s> static void alpha_canonicalize_comparison ( int * code , rtx * op0 , rtx * op1 , bool op0_preserve_value ) { if ( ! op0_preserve_value && ( * code == GE || * code == GT || * code == GEU || * code == GTU ) && ( REG_P ( * op1 ) || * op1 == const0_rtx ) ) { std :: swap ( * op0 , * op1 ) ; * code = ( int ) swap_condition ( ( enum rtx_code ) * code ) ; } if ( ( * code == LT || * code == LTU ) && CONST_INT_P ( * op1 ) && INTVAL ( * op1 ) == 256 ) { * code = * code == LT ? LE : LEU ; * op1 = GEN_INT ( 255 ) ; } } </s>

Canonicalize a comparison from one we do n't have to one we do have .


<s> static bool alpha_can_change_mode_class ( machine_mode from , machine_mode to , reg_class_t rclass ) { return ( GET_MODE_SIZE ( from ) == GET_MODE_SIZE ( to ) || ! reg_classes_intersect_p ( FLOAT_REGS , rclass ) ) ; } </s>


<s> static void alpha_compute_frame_layout ( void ) { unsigned HOST_WIDE_INT sa_mask = 0 ; HOST_WIDE_INT frame_size ; int sa_size ; if ( ! cfun -> is_thunk ) { if ( TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK ) sa_mask |= HOST_WIDE_INT_1U << HARD_FRAME_POINTER_REGNUM ; for ( unsigned i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( ! call_used_or_fixed_reg_p ( i ) && df_regs_ever_live_p ( i ) && i != REG_RA ) sa_mask |= HOST_WIDE_INT_1U << i ; if ( crtl -> calls_eh_return ) { for ( unsigned i = 0 ; ; ++ i ) { unsigned regno = EH_RETURN_DATA_REGNO ( i ) ; if ( regno == INVALID_REGNUM ) break ; sa_mask |= HOST_WIDE_INT_1U << regno ; } } if ( sa_mask || alpha_ra_ever_killed ( ) ) sa_mask |= HOST_WIDE_INT_1U << REG_RA ; } sa_size = popcount_hwi ( sa_mask ) ; frame_size = get_frame_size ( ) ; if ( TARGET_ABI_OPEN_VMS ) { if ( ( sa_mask >> REG_RA ) & 1 || frame_pointer_needed ) alpha_procedure_type = PT_STACK ; else if ( frame_size != 0 ) alpha_procedure_type = PT_REGISTER ; else alpha_procedure_type = PT_NULL ; if ( alpha_procedure_type == PT_STACK ) sa_size -= 2 ; vms_base_regno = ( frame_pointer_needed || cfun -> has_nonlocal_label || alpha_procedure_type == PT_STACK || crtl -> outgoing_args_size ) ? REG_PV : HARD_FRAME_POINTER_REGNUM ; vms_save_fp_regno = - 1 ; if ( vms_base_regno == HARD_FRAME_POINTER_REGNUM ) for ( unsigned i = 0 ; i < 32 ; i ++ ) if ( ! fixed_regs [ i ] && call_used_or_fixed_reg_p ( i ) && ! df_regs_ever_live_p ( i ) ) { vms_save_fp_regno = i ; break ; } if ( ( vms_save_fp_regno == - 1 && alpha_procedure_type == PT_REGISTER ) || cfun -> machine -> uses_condition_handler ) vms_base_regno = REG_PV , alpha_procedure_type = PT_STACK ; else if ( alpha_procedure_type == PT_NULL ) vms_base_regno = REG_PV ; vms_unwind_regno = ( vms_base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ) ; if ( alpha_procedure_type == PT_STACK ) sa_size += 2 + cfun -> machine -> uses_condition_handler ; } else { if ( sa_size & 1 ) sa_size ++ ; } sa_size *= 8 ; if ( TARGET_ABI_OPEN_VMS ) frame_size = ALPHA_ROUND ( sa_size + ( alpha_procedure_type == PT_STACK ? 8 : 0 ) + frame_size + crtl -> args . pretend_args_size ) ; else frame_size = ( ALPHA_ROUND ( crtl -> outgoing_args_size ) + sa_size + ALPHA_ROUND ( frame_size + crtl -> args . pretend_args_size ) ) ; cfun -> machine -> sa_mask = sa_mask ; cfun -> machine -> sa_size = sa_size ; cfun -> machine -> frame_size = frame_size ; } </s>

Compute register masks for saved registers , register save area size , and total frame size .


<s> static int alpha_compute_xfloating_mode_arg ( enum rtx_code code , enum alpha_fp_rounding_mode round ) { int mode ; switch ( round ) { case ALPHA_FPRM_NORM : mode = 2 ; break ; case ALPHA_FPRM_MINF : mode = 1 ; break ; case ALPHA_FPRM_CHOP : mode = 0 ; break ; case ALPHA_FPRM_DYN : mode = 4 ; break ; default : gcc_unreachable ( ) ; } if ( code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N ) mode |= 0x10000 ; return mode ; } </s>

Most X_floating operations take the rounding mode as an argument . Compute that here .


<s> static void alpha_conditional_register_usage ( void ) { int i ; if ( ! TARGET_FPREGS ) for ( i = 32 ; i < 63 ; i ++ ) fixed_regs [ i ] = call_used_regs [ i ] = 1 ; } </s>

On the Alpha , we use this to disable the floating-point registers when they do n't exist .


<s> static int alpha_elf_reloc_rw_mask ( void ) { return flag_pic ? 3 : 2 ; } </s>

Since we do n't have a .dynbss section , we should not allow global relocations in the .rodata section .


<s> static section * alpha_elf_select_rtx_section ( machine_mode mode , rtx x , unsigned HOST_WIDE_INT align ) { if ( TARGET_SMALL_DATA && GET_MODE_SIZE ( mode ) <= g_switch_value ) return sdata_section ; else return default_elf_select_rtx_section ( mode , x , align ) ; } </s>

Switch to the section to which we should output X . The only thing special we do here is to honor small data .


<s> bool alpha_emit_setcc ( rtx operands [ ] , machine_mode cmp_mode ) { enum rtx_code cmp_code ; enum rtx_code code = GET_CODE ( operands [ 1 ] ) ; rtx op0 = operands [ 2 ] , op1 = operands [ 3 ] ; rtx tmp ; if ( cmp_mode == TFmode ) { op0 = alpha_emit_xfloating_compare ( & code , op0 , op1 ) ; op1 = const0_rtx ; cmp_mode = DImode ; } if ( cmp_mode == DFmode && ! TARGET_FIX ) return 0 ; cmp_code = UNKNOWN ; switch ( code ) { case EQ : case LE : case LT : case LEU : case LTU : case UNORDERED : if ( cmp_mode == DFmode ) cmp_code = code , code = NE ; break ; case NE : if ( cmp_mode == DImode && op1 == const0_rtx ) break ; case ORDERED : cmp_code = reverse_condition ( code ) ; code = EQ ; break ; case GE : case GT : case GEU : case GTU : if ( cmp_mode == DImode && op1 == const0_rtx ) break ; code = swap_condition ( code ) ; if ( cmp_mode == DFmode ) cmp_code = code , code = NE ; std :: swap ( op0 , op1 ) ; break ; default : gcc_unreachable ( ) ; } if ( cmp_mode == DImode ) { if ( ! register_operand ( op0 , DImode ) ) op0 = force_reg ( DImode , op0 ) ; if ( ! reg_or_8bit_operand ( op1 , DImode ) ) op1 = force_reg ( DImode , op1 ) ; } if ( cmp_code != UNKNOWN ) { tmp = gen_reg_rtx ( cmp_mode ) ; emit_insn ( gen_rtx_SET ( tmp , gen_rtx_fmt_ee ( cmp_code , cmp_mode , op0 , op1 ) ) ) ; op0 = cmp_mode != DImode ? gen_lowpart ( DImode , tmp ) : tmp ; op1 = const0_rtx ; } emit_insn ( gen_rtx_SET ( operands [ 0 ] , gen_rtx_fmt_ee ( code , DImode , op0 , op1 ) ) ) ; return true ; } </s>

Certain simplifications can be done to make invalid setcc operations valid . Return the final comparison , or NULL if we ca n't work .


<s> static rtx alpha_emit_set_const ( rtx target , machine_mode mode , HOST_WIDE_INT c , int n , bool no_output ) { machine_mode orig_mode = mode ; rtx orig_target = target ; rtx result = 0 ; int i ; if ( ! can_create_pseudo_p ( ) && mode == SImode && REG_P ( target ) && REGNO ( target ) < FIRST_PSEUDO_REGISTER ) { result = alpha_emit_set_const_1 ( target , mode , c , 1 , no_output ) ; if ( result ) return result ; target = no_output ? NULL : gen_lowpart ( DImode , target ) ; mode = DImode ; } else if ( mode == V8QImode || mode == V4HImode || mode == V2SImode ) { target = no_output ? NULL : gen_lowpart ( DImode , target ) ; mode = DImode ; } for ( i = 1 ; i <= n ; i ++ ) { result = alpha_emit_set_const_1 ( target , mode , c , i , no_output ) ; if ( result ) { rtx_insn * insn ; rtx set ; if ( no_output ) return result ; insn = get_last_insn ( ) ; set = single_set ( insn ) ; if ( ! CONSTANT_P ( SET_SRC ( set ) ) ) set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , GEN_INT ( c ) ) ; break ; } } if ( result ) { if ( result == target ) result = orig_target ; else if ( mode != orig_mode ) result = gen_lowpart ( orig_mode , result ) ; } return result ; } </s>

Try to output insns to set TARGET equal to the constant C if it can be done in less than N insns . Do all computations in MODE . Returns the place where the output has been placed if it can be done and the insns have been emitted . If it would take more than N insns , zero is returned and no insns and emitted .


<s> static rtx alpha_emit_set_long_const ( rtx target , HOST_WIDE_INT c1 ) { HOST_WIDE_INT d1 , d2 , d3 , d4 ; d1 = ( ( c1 & 0xffff ) ^ 0x8000 ) - 0x8000 ; c1 -= d1 ; d2 = ( ( c1 & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; c1 = ( c1 - d2 ) >> 32 ; d3 = ( ( c1 & 0xffff ) ^ 0x8000 ) - 0x8000 ; c1 -= d3 ; d4 = ( ( c1 & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; gcc_assert ( c1 == d4 ) ; if ( d4 ) { emit_move_insn ( target , GEN_INT ( d4 ) ) ; if ( d3 ) emit_move_insn ( target , gen_rtx_PLUS ( DImode , target , GEN_INT ( d3 ) ) ) ; } else emit_move_insn ( target , GEN_INT ( d3 ) ) ; emit_move_insn ( target , gen_rtx_ASHIFT ( DImode , target , GEN_INT ( 32 ) ) ) ; if ( d2 ) emit_move_insn ( target , gen_rtx_PLUS ( DImode , target , GEN_INT ( d2 ) ) ) ; if ( d1 ) emit_move_insn ( target , gen_rtx_PLUS ( DImode , target , GEN_INT ( d1 ) ) ) ; return target ; } </s>

Having failed to find a 3 insn sequence in alpha_emit_set_const , fall back to a straight forward decomposition . We do this to avoid exponential run times encountered when looking for longer sequences with alpha_emit_set_const .


<s> void alpha_emit_xfloating_arith ( enum rtx_code code , rtx operands [ ] ) { rtx func ; int mode ; rtx out_operands [ 3 ] ; func = alpha_lookup_xfloating_lib_func ( code ) ; mode = alpha_compute_xfloating_mode_arg ( code , alpha_fprm ) ; out_operands [ 0 ] = operands [ 1 ] ; out_operands [ 1 ] = operands [ 2 ] ; out_operands [ 2 ] = GEN_INT ( mode ) ; alpha_emit_xfloating_libcall ( func , operands [ 0 ] , out_operands , 3 , gen_rtx_fmt_ee ( code , TFmode , operands [ 1 ] , operands [ 2 ] ) ) ; } </s>

Emit an X_floating library function call for arithmetic ( + , - , * , / ) .


<s> static rtx alpha_emit_xfloating_compare ( enum rtx_code * pcode , rtx op0 , rtx op1 ) { enum rtx_code cmp_code , res_code ; rtx func , out , operands [ 2 ] , note ; cmp_code = * pcode ; switch ( cmp_code ) { case UNORDERED : cmp_code = EQ ; res_code = LT ; break ; case ORDERED : cmp_code = EQ ; res_code = GE ; break ; case NE : res_code = NE ; break ; case EQ : case LT : case GT : case LE : case GE : res_code = GT ; break ; default : gcc_unreachable ( ) ; } * pcode = res_code ; func = alpha_lookup_xfloating_lib_func ( cmp_code ) ; operands [ 0 ] = op0 ; operands [ 1 ] = op1 ; out = gen_reg_rtx ( DImode ) ; note = gen_rtx_fmt_ee ( cmp_code , VOIDmode , op0 , op1 ) ; note = gen_rtx_UNSPEC ( DImode , gen_rtvec ( 1 , note ) , UNSPEC_XFLT_COMPARE ) ; alpha_emit_xfloating_libcall ( func , out , operands , 2 , note ) ; return out ; } </s>

Emit an X_floating library function call for a comparison .


<s> void alpha_emit_xfloating_cvt ( enum rtx_code orig_code , rtx operands [ ] ) { int noperands = 1 , mode ; rtx out_operands [ 2 ] ; rtx func ; enum rtx_code code = orig_code ; if ( code == UNSIGNED_FIX ) code = FIX ; func = alpha_lookup_xfloating_lib_func ( code ) ; out_operands [ 0 ] = operands [ 1 ] ; switch ( code ) { case FIX : mode = alpha_compute_xfloating_mode_arg ( code , ALPHA_FPRM_CHOP ) ; out_operands [ 1 ] = GEN_INT ( mode ) ; noperands = 2 ; break ; case FLOAT_TRUNCATE : mode = alpha_compute_xfloating_mode_arg ( code , alpha_fprm ) ; out_operands [ 1 ] = GEN_INT ( mode ) ; noperands = 2 ; break ; default : break ; } alpha_emit_xfloating_libcall ( func , operands [ 0 ] , out_operands , noperands , gen_rtx_fmt_e ( orig_code , GET_MODE ( operands [ 0 ] ) , operands [ 1 ] ) ) ; } </s>

Emit an X_floating library function call for a conversion .


<s> static void alpha_emit_xfloating_libcall ( rtx func , rtx target , rtx operands [ ] , int noperands , rtx equiv ) { rtx usage = NULL_RTX , reg ; int regno = 16 , i ; start_sequence ( ) ; for ( i = 0 ; i < noperands ; ++ i ) { switch ( GET_MODE ( operands [ i ] ) ) { case E_TFmode : reg = gen_rtx_REG ( TFmode , regno ) ; regno += 2 ; break ; case E_DFmode : reg = gen_rtx_REG ( DFmode , regno + 32 ) ; regno += 1 ; break ; case E_VOIDmode : gcc_assert ( CONST_INT_P ( operands [ i ] ) ) ; case E_DImode : reg = gen_rtx_REG ( DImode , regno ) ; regno += 1 ; break ; default : gcc_unreachable ( ) ; } emit_move_insn ( reg , operands [ i ] ) ; use_reg ( & usage , reg ) ; } switch ( GET_MODE ( target ) ) { case E_TFmode : reg = gen_rtx_REG ( TFmode , 16 ) ; break ; case E_DFmode : reg = gen_rtx_REG ( DFmode , 32 ) ; break ; case E_DImode : reg = gen_rtx_REG ( DImode , 0 ) ; break ; default : gcc_unreachable ( ) ; } rtx mem = gen_rtx_MEM ( QImode , func ) ; rtx_insn * tmp = emit_call_insn ( gen_call_value ( reg , mem , const0_rtx , const0_rtx , const0_rtx ) ) ; CALL_INSN_FUNCTION_USAGE ( tmp ) = usage ; RTL_CONST_CALL_P ( tmp ) = 1 ; tmp = get_insns ( ) ; end_sequence ( ) ; emit_libcall_block ( tmp , target , reg , equiv ) ; } </s>

Emit an X_floating library function call . Note that these functions do not follow normal calling conventions : TFmode arguments are passed in two integer registers ( as opposed to indirect ) ; TFmode return values appear in R16+R17 . FUNC is the function name to call . TARGET is where the output belongs . OPERANDS are the inputs . NOPERANDS is the count of inputs . EQUIV is the expression equivalent for the function .


<s>
void
alpha_end_function
(
FILE
*
file
,
const
char
*
fnname
,
tree
decl
ATTRIBUTE_UNUSED
)
{
rtx_insn
*
insn
;
insn
=
get_last_insn
(
)
;
if
(
!
INSN_P
(
insn
)
)
insn
=
prev_active_insn
(
insn
)
;
if
(
insn
&&
CALL_P
(
insn
)
)
output_asm_insn
(
get_insn_template
(
CODE_FOR_nop
,
)
,
)
;
alpha_write_linkage
(
file
,
fnname
)
;
if
(
TARGET_ABI_OPEN_VMS
||
!
flag_inhibit_size_directive
)
{
fputs
(
"\t.end "
,
file
)
;
assemble_name
(
file
,
fnname
)
;
putc
(
'\n'
,
file
)
;
}
inside_function
=
FALSE
;
}
</s>

Output the rest of the textual info surrounding the epilogue .


<s>
static
rtx
alpha_expand_builtin
(
tree
exp
,
rtx
target
,
rtx
subtarget
ATTRIBUTE_UNUSED
,
machine_mode
mode
ATTRIBUTE_UNUSED
,
int
ignore
ATTRIBUTE_UNUSED
)
{
tree
fndecl
=
TREE_OPERAND
(
CALL_EXPR_FN
(
exp
)
,
0
)
;
unsigned
int
fcode
=
DECL_MD_FUNCTION_CODE
(
fndecl
)
;
tree
arg
;
call_expr_arg_iterator
iter
;
enum
insn_code
icode
;
rtx
op
[
MAX_ARGS
]
,
pat
;
int
arity
;
bool
nonvoid
;
if
(
fcode
>=
ALPHA_BUILTIN_max
)
internal_error
(
"bad builtin fcode"
)
;
icode
=
code_for_builtin
[
fcode
]
;
if
(
icode
==
0
)
internal_error
(
"bad builtin fcode"
)
;
nonvoid
=
TREE_TYPE
(
TREE_TYPE
(
fndecl
)
)
!=
void_type_node
;
arity
=
0
;
FOR_EACH_CALL_EXPR_ARG
(
arg
,
iter
,
exp
)
{
const
struct
insn_operand_data
*
insn_op
;
if
(
arg
==
error_mark_node
)
return
NULL_RTX
;
if
(
arity
>
MAX_ARGS
)
return
NULL_RTX
;
insn_op
=
&
insn_data
[
icode
]
.
operand
[
arity
+
nonvoid
]
;
op
[
arity
]
=
expand_expr
(
arg
,
NULL_RTX
,
insn_op
->
mode
,
EXPAND_NORMAL
)
;
if
(
!
(
*
insn_op
->
predicate
)
(
op
[
arity
]
,
insn_op
->
mode
)
)
op
[
arity
]
=
copy_to_mode_reg
(
insn_op
->
mode
,
op
[
arity
]
)
;
arity
++
;
}
if
(
nonvoid
)
{
machine_mode
tmode
=
insn_data
[
icode
]
.
operand
[
0
]
.
mode
;
if
(
!
target
||
GET_MODE
(
target
)
!=
tmode
||
!
(
*
insn_data
[
icode
]
.
operand
[
0
]
.
predicate
)
(
target
,
tmode
)
)
target
=
gen_reg_rtx
(
tmode
)
;
}
switch
(
arity
)
{
case
0
:
pat
=
GEN_FCN
(
icode
)
(
target
)
;
break
;
case
1
:
if
(
nonvoid
)
pat
=
GEN_FCN
(
icode
)
(
target
,
op
[
0
]
)
;
else
pat
=
GEN_FCN
(
icode
)
(
op
[
0
]
)
;
break
;
case
2
:
pat
=
GEN_FCN
(
icode
)
(
target
,
op
[
0
]
,
op
[
1
]
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
if
(
!
pat
)
return
NULL_RTX
;
emit_insn
(
pat
)
;
if
(
nonvoid
)
return
target
;
else
return
const0_rtx
;
}
</s>

Expand an expression EXP that calls a built-in function , with result going to TARGET if that 's convenient ( and in mode MODE if that 's convenient ) . SUBTARGET may be used as the target for computing one of EXP 's operands . IGNORE is nonzero if the value is to be ignored .


Expand code to store the currently installed user VMS condition handler into TARGET and install HANDLER as the new condition handler .


Expand code to store the current VMS condition handler into TARGET and nullify it .


<s> bool alpha_expand_mov ( machine_mode mode , rtx * operands ) { rtx tmp ; if ( MEM_P ( operands [ 0 ] ) && ! reg_or_0_operand ( operands [ 1 ] , mode ) ) operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; if ( mode == Pmode && symbolic_operand ( operands [ 1 ] , mode ) ) { tmp = alpha_legitimize_address_1 ( operands [ 1 ] , operands [ 0 ] , mode ) ; if ( tmp ) { if ( tmp == operands [ 0 ] ) return true ; operands [ 1 ] = tmp ; return false ; } } if ( ! CONSTANT_P ( operands [ 1 ] ) || input_operand ( operands [ 1 ] , mode ) ) return false ; if ( CONST_INT_P ( operands [ 1 ] ) || GET_CODE ( operands [ 1 ] ) == CONST_VECTOR ) { if ( alpha_split_const_mov ( mode , operands ) ) return true ; } tmp = force_const_mem ( mode , operands [ 1 ] ) ; if ( tmp == NULL_RTX ) return false ; if ( reload_in_progress ) { emit_move_insn ( operands [ 0 ] , XEXP ( tmp , 0 ) ) ; operands [ 1 ] = replace_equiv_address ( tmp , operands [ 0 ] ) ; } else operands [ 1 ] = validize_mem ( tmp ) ; return false ; } </s>

Expand a move instruction ; return true if all work is done . We do n't handle non-bwx subword loads here .


<s> void alpha_expand_movmisalign ( machine_mode mode , rtx * operands ) { if ( MEM_P ( operands [ 1 ] ) ) { rtx tmp ; if ( register_operand ( operands [ 0 ] , mode ) ) tmp = operands [ 0 ] ; else tmp = gen_reg_rtx ( mode ) ; alpha_expand_unaligned_load ( tmp , operands [ 1 ] , 8 , 0 , 0 ) ; if ( tmp != operands [ 0 ] ) emit_move_insn ( operands [ 0 ] , tmp ) ; } else if ( MEM_P ( operands [ 0 ] ) ) { if ( ! reg_or_0_operand ( operands [ 1 ] , mode ) ) operands [ 1 ] = force_reg ( mode , operands [ 1 ] ) ; alpha_expand_unaligned_store ( operands [ 0 ] , operands [ 1 ] , 8 , 0 ) ; } else gcc_unreachable ( ) ; } </s>

Implement the movmisalign patterns . One of the operands is a memory that is not naturally aligned . Emit instructions to load it .


<s> static void alpha_expand_unaligned_load_words ( rtx * out_regs , rtx smem , HOST_WIDE_INT words , HOST_WIDE_INT ofs ) { rtx const im8 = GEN_INT ( - 8 ) ; rtx ext_tmps [ MAX_MOVE_WORDS ] , data_regs [ MAX_MOVE_WORDS + 1 ] ; rtx sreg , areg , tmp , smema ; HOST_WIDE_INT i ; smema = XEXP ( smem , 0 ) ; if ( GET_CODE ( smema ) == LO_SUM ) smema = force_reg ( Pmode , smema ) ; for ( i = 0 ; i < words ; ++ i ) { data_regs [ i ] = out_regs [ i ] ; ext_tmps [ i ] = gen_reg_rtx ( DImode ) ; } data_regs [ words ] = gen_reg_rtx ( DImode ) ; if ( ofs != 0 ) smem = adjust_address ( smem , GET_MODE ( smem ) , ofs ) ; for ( i = 0 ; i < words ; ++ i ) { tmp = change_address ( smem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , smema , 8 * i ) , im8 ) ) ; set_mem_alias_set ( tmp , 0 ) ; emit_move_insn ( data_regs [ i ] , tmp ) ; } tmp = change_address ( smem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , smema , 8 * words - 1 ) , im8 ) ) ; set_mem_alias_set ( tmp , 0 ) ; emit_move_insn ( data_regs [ words ] , tmp ) ; sreg = copy_addr_to_reg ( smema ) ; areg = expand_binop ( DImode , and_optab , sreg , GEN_INT ( 7 ) , NULL , 1 , OPTAB_WIDEN ) ; for ( i = 0 ; i < words ; ++ i ) { emit_insn ( gen_extql ( data_regs [ i ] , data_regs [ i ] , sreg ) ) ; emit_insn ( gen_extqh ( ext_tmps [ i ] , data_regs [ i + 1 ] , sreg ) ) ; emit_insn ( gen_rtx_SET ( ext_tmps [ i ] , gen_rtx_IF_THEN_ELSE ( DImode , gen_rtx_EQ ( DImode , areg , const0_rtx ) , const0_rtx , ext_tmps [ i ] ) ) ) ; } for ( i = 0 ; i < words ; ++ i ) { out_regs [ i ] = expand_binop ( DImode , ior_optab , data_regs [ i ] , ext_tmps [ i ] , data_regs [ i ] , 1 , OPTAB_WIDEN ) ; } } </s>

Load an integral number of consecutive unaligned quadwords .


<s> static void alpha_expand_unaligned_store_words ( rtx * data_regs , rtx dmem , HOST_WIDE_INT words , HOST_WIDE_INT ofs ) { rtx const im8 = GEN_INT ( - 8 ) ; rtx ins_tmps [ MAX_MOVE_WORDS ] ; rtx st_tmp_1 , st_tmp_2 , dreg ; rtx st_addr_1 , st_addr_2 , dmema ; HOST_WIDE_INT i ; dmema = XEXP ( dmem , 0 ) ; if ( GET_CODE ( dmema ) == LO_SUM ) dmema = force_reg ( Pmode , dmema ) ; if ( data_regs != NULL ) for ( i = 0 ; i < words ; ++ i ) ins_tmps [ i ] = gen_reg_rtx ( DImode ) ; st_tmp_1 = gen_reg_rtx ( DImode ) ; st_tmp_2 = gen_reg_rtx ( DImode ) ; if ( ofs != 0 ) dmem = adjust_address ( dmem , GET_MODE ( dmem ) , ofs ) ; st_addr_2 = change_address ( dmem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , dmema , words * 8 - 1 ) , im8 ) ) ; set_mem_alias_set ( st_addr_2 , 0 ) ; st_addr_1 = change_address ( dmem , DImode , gen_rtx_AND ( DImode , dmema , im8 ) ) ; set_mem_alias_set ( st_addr_1 , 0 ) ; emit_move_insn ( st_tmp_2 , st_addr_2 ) ; emit_move_insn ( st_tmp_1 , st_addr_1 ) ; dreg = copy_addr_to_reg ( dmema ) ; if ( data_regs != NULL ) { for ( i = words - 1 ; i >= 0 ; -- i ) { emit_insn ( gen_insqh ( ins_tmps [ i ] , data_regs [ i ] , dreg ) ) ; emit_insn ( gen_insql ( data_regs [ i ] , data_regs [ i ] , dreg ) ) ; } for ( i = words - 1 ; i > 0 ; -- i ) { ins_tmps [ i - 1 ] = expand_binop ( DImode , ior_optab , data_regs [ i ] , ins_tmps [ i - 1 ] , ins_tmps [ i - 1 ] , 1 , OPTAB_WIDEN ) ; } } emit_insn ( gen_mskqh ( st_tmp_2 , st_tmp_2 , dreg ) ) ; emit_insn ( gen_mskql ( st_tmp_1 , st_tmp_1 , dreg ) ) ; if ( data_regs != NULL ) { st_tmp_2 = expand_binop ( DImode , ior_optab , st_tmp_2 , ins_tmps [ words - 1 ] , st_tmp_2 , 1 , OPTAB_WIDEN ) ; st_tmp_1 = expand_binop ( DImode , ior_optab , st_tmp_1 , data_regs [ 0 ] , st_tmp_1 , 1 , OPTAB_WIDEN ) ; } emit_move_insn ( st_addr_2 , st_tmp_2 ) ; for ( i = words - 1 ; i > 0 ; -- i ) { rtx tmp = change_address ( dmem , DImode , gen_rtx_AND ( DImode , plus_constant ( DImode , dmema , i * 8 ) , im8 ) ) ; set_mem_alias_set ( tmp , 0 ) ; emit_move_insn ( tmp , data_regs ? ins_tmps [ i - 1 ] : const0_rtx ) ; } emit_move_insn ( st_addr_1 , st_tmp_1 ) ; } </s>

Store an integral number of consecutive unaligned quadwords . DATA_REGS may be NULL to store zeros .


<s> rtx alpha_expand_zap_mask ( HOST_WIDE_INT value ) { rtx result ; int i ; HOST_WIDE_INT mask = 0 ; for ( i = 7 ; i >= 0 ; -- i ) { mask <<= 8 ; if ( ! ( ( value >> i ) & 1 ) ) mask |= 0xff ; } result = gen_int_mode ( mask , DImode ) ; return result ; } </s>

Returns a mask so that zap ( x , value ) == x & mask .


<s> static HOST_WIDE_INT alpha_extract_integer ( rtx x ) { if ( GET_CODE ( x ) == CONST_VECTOR ) x = simplify_subreg ( DImode , x , GET_MODE ( x ) , 0 ) ; gcc_assert ( CONST_INT_P ( x ) ) ; return INTVAL ( x ) ; } </s>

Given an integral CONST_INT , CONST_DOUBLE , or CONST_VECTOR , return the low 64 bits .


<s> static tree alpha_fold_builtin_cmpbge ( unsigned HOST_WIDE_INT opint [ ] , long op_const ) { if ( op_const == 3 ) { int i , val ; for ( i = 0 , val = 0 ; i < 8 ; ++ i ) { unsigned HOST_WIDE_INT c0 = ( opint [ 0 ] >> ( i * 8 ) ) & 0xff ; unsigned HOST_WIDE_INT c1 = ( opint [ 1 ] >> ( i * 8 ) ) & 0xff ; if ( c0 >= c1 ) val |= 1 << i ; } return build_int_cst ( alpha_dimode_u , val ) ; } else if ( op_const == 2 && opint [ 1 ] == 0 ) return build_int_cst ( alpha_dimode_u , 0xff ) ; return NULL ; } </s>

Fold the builtin for the CMPBGE instruction . This is a vector comparison with an 8 bit output vector . OPINT contains the integer operands ; bit N of OP_CONST is set if OPINT [ N ] is valid .


<s> static tree alpha_fold_builtin_extxx ( tree op [ ] , unsigned HOST_WIDE_INT opint [ ] , long op_const , unsigned HOST_WIDE_INT bytemask , bool is_high ) { long zap_const = 2 ; tree * zap_op = NULL ; if ( op_const & 2 ) { unsigned HOST_WIDE_INT loc ; loc = opint [ 1 ] & 7 ; loc *= BITS_PER_UNIT ; if ( loc != 0 ) { if ( op_const & 1 ) { unsigned HOST_WIDE_INT temp = opint [ 0 ] ; if ( is_high ) temp <<= loc ; else temp >>= loc ; opint [ 0 ] = temp ; zap_const = 3 ; } } else zap_op = op ; } opint [ 1 ] = bytemask ; return alpha_fold_builtin_zapnot ( zap_op , opint , zap_const ) ; } </s>

Fold the builtins for the EXT family of instructions .


<s> static tree alpha_fold_builtin_insxx ( tree op [ ] , unsigned HOST_WIDE_INT opint [ ] , long op_const , unsigned HOST_WIDE_INT bytemask , bool is_high ) { if ( ( op_const & 1 ) && opint [ 0 ] == 0 ) return build_int_cst ( alpha_dimode_u , 0 ) ; if ( op_const & 2 ) { unsigned HOST_WIDE_INT temp , loc , byteloc ; tree * zap_op = NULL ; loc = opint [ 1 ] & 7 ; bytemask <<= loc ; temp = opint [ 0 ] ; if ( is_high ) { byteloc = ( 64 - ( loc * 8 ) ) & 0x3f ; if ( byteloc == 0 ) zap_op = op ; else temp >>= byteloc ; bytemask >>= 8 ; } else { byteloc = loc * 8 ; if ( byteloc == 0 ) zap_op = op ; else temp <<= byteloc ; } opint [ 0 ] = temp ; opint [ 1 ] = bytemask ; return alpha_fold_builtin_zapnot ( zap_op , opint , op_const ) ; } return NULL ; } </s>

Fold the builtins for the INS family of instructions .


<s> static tree alpha_fold_builtin_zapnot ( tree * op , unsigned HOST_WIDE_INT opint [ ] , long op_const ) { if ( op_const & 2 ) { unsigned HOST_WIDE_INT mask = 0 ; int i ; for ( i = 0 ; i < 8 ; ++ i ) if ( ( opint [ 1 ] >> i ) & 1 ) mask |= ( unsigned HOST_WIDE_INT ) 0xff << ( i * 8 ) ; if ( op_const & 1 ) return build_int_cst ( alpha_dimode_u , opint [ 0 ] & mask ) ; if ( op ) return fold_build2 ( BIT_AND_EXPR , alpha_dimode_u , op [ 0 ] , build_int_cst ( alpha_dimode_u , mask ) ) ; } else if ( ( op_const & 1 ) && opint [ 0 ] == 0 ) return build_int_cst ( alpha_dimode_u , 0 ) ; return NULL ; } </s>

Fold the builtin for the ZAPNOT instruction . This is essentially a specialized form of an AND operation . Other byte manipulation instructions are defined in terms of this instruction , so this is also used as a subroutine for other builtins . OP contains the tree operands ; OPINT contains the extracted integer values . Bit N of OP_CONST it set if OPINT [ N ] is valid . OP may be null if only OPINT may be considered .


<s> static rtx alpha_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; int basereg ; int num_args ; if ( arg . aggregate_type_p ( ) ) basereg = 16 ; else { gcc_checking_assert ( ! COMPLEX_MODE_P ( arg . mode ) ) ; if ( TARGET_FPREGS && GET_MODE_CLASS ( arg . mode ) == MODE_FLOAT ) basereg = 32 + 16 ; else basereg = 16 ; } { if ( arg . end_marker_p ( ) ) return alpha_arg_info_reg_val ( * cum ) ; num_args = cum -> num_args ; if ( num_args >= 6 || targetm . calls . must_pass_in_stack ( arg ) ) return NULL_RTX ; } { if ( * cum >= 6 ) return NULL_RTX ; num_args = * cum ; if ( arg . end_marker_p ( ) ) basereg = 16 ; else if ( targetm . calls . must_pass_in_stack ( arg ) ) return NULL_RTX ; } return gen_rtx_REG ( arg . mode , num_args + basereg ) ; } </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 Alpha the first 6 words of args are normally in registers and the rest are pushed .


<s> static void alpha_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; bool onstack = targetm . calls . must_pass_in_stack ( arg ) ; int increment = onstack ? 6 : ALPHA_ARG_SIZE ( arg . mode , arg . type ) ; * cum += increment ; if ( ! onstack && cum -> num_args < 6 ) cum -> atypes [ cum -> num_args ] = alpha_arg_type ( arg . mode ) ; cum -> num_args += increment ; } </s>

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


<s> static bool alpha_function_ok_for_sibcall ( tree decl , tree exp ATTRIBUTE_UNUSED ) { if ( ! decl ) return false ; return decl_has_samegp ( decl ) ; } </s>

We do not allow indirect calls to be optimized into sibling calls , nor can we allow a call to a function with a different GP to be optimized into a sibcall .


<s> static rtx alpha_function_value ( const_tree valtype , const_tree fn_decl_or_type , bool ) { return alpha_function_value_1 ( valtype , fn_decl_or_type , VOIDmode ) ; } </s>


<s> static rtx alpha_function_value_1 ( const_tree valtype , const_tree func ATTRIBUTE_UNUSED , machine_mode mode ) { unsigned int regnum , dummy ATTRIBUTE_UNUSED ; enum mode_class mclass ; gcc_assert ( ! valtype || ! alpha_return_in_memory ( valtype , func ) ) ; if ( valtype ) mode = TYPE_MODE ( valtype ) ; mclass = GET_MODE_CLASS ( mode ) ; switch ( mclass ) { case MODE_INT : if ( ! ( TARGET_ABI_OPEN_VMS && valtype && AGGREGATE_TYPE_P ( valtype ) ) ) PROMOTE_MODE ( mode , dummy , valtype ) ; case MODE_COMPLEX_INT : case MODE_VECTOR_INT : regnum = 0 ; break ; case MODE_FLOAT : regnum = 32 ; break ; case MODE_COMPLEX_FLOAT : { machine_mode cmode = GET_MODE_INNER ( mode ) ; return gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( cmode , 32 ) , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( cmode , 33 ) , GEN_INT ( GET_MODE_SIZE ( cmode ) ) ) ) ) ; } case MODE_RANDOM : gcc_assert ( TARGET_ABI_OPEN_VMS && mode == BLKmode ) ; regnum = 0 ; break ; default : gcc_unreachable ( ) ; } return gen_rtx_REG ( mode , regnum ) ; } </s>

Define how to find the value returned by a function . VALTYPE is the data type of the value ( as a tree ) . If the precise function being called is known , FUNC is its FUNCTION_DECL ; otherwise , FUNC is 0 . MODE is set instead of VALTYPE for libcalls . On Alpha the value is found in $ 0 for integer functions and $ f0 for floating-point functions .


<s> static bool alpha_function_value_regno_p ( const unsigned int regno ) { return ( regno == 0 || regno == 1 || regno == 32 || regno == 33 ) ; } </s>

Implement TARGET_FUNCTION_VALUE_REGNO_P . On the Alpha , $ 0 $ 1 and $ f0 $ f1 are the only register thus used .


<s> rtx alpha_gp_save_rtx ( void ) { rtx_insn * seq ; rtx m = cfun -> machine -> gp_save_rtx ; if ( m == NULL ) { start_sequence ( ) ; m = assign_stack_local ( DImode , UNITS_PER_WORD , BITS_PER_WORD ) ; m = validize_mem ( m ) ; emit_move_insn ( m , pic_offset_table_rtx ) ; seq = get_insns ( ) ; end_sequence ( ) ; insert_insn_on_edge ( seq , single_succ_edge ( ENTRY_BLOCK_PTR_FOR_FN ( cfun ) ) ) ; cfun -> machine -> gp_save_rtx = m ; } return m ; } </s>

Return or create a pseudo containing the gp value for the current function . Needed only if TARGET_LD_BUGGY_LDGP .


<s> static bool alpha_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( IN_RANGE ( regno , 32 , 62 ) ) return ( mode == SFmode || mode == DFmode || mode == DImode || mode == SCmode || mode == DCmode ) ; return true ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . On Alpha , the integer registers can hold any mode . The floating-point registers can hold 64-bit integers as well , but not smaller values .


<s> HOST_WIDE_INT alpha_initial_elimination_offset ( unsigned int from , unsigned int to ATTRIBUTE_UNUSED ) { HOST_WIDE_INT ret ; ret = cfun -> machine -> sa_size ; ret += ALPHA_ROUND ( crtl -> outgoing_args_size ) ; switch ( from ) { case FRAME_POINTER_REGNUM : break ; case ARG_POINTER_REGNUM : ret += ( ALPHA_ROUND ( get_frame_size ( ) + crtl -> args . pretend_args_size ) - crtl -> args . pretend_args_size ) ; break ; default : gcc_unreachable ( ) ; } return ret ; } </s>

Define the offset between two registers , one to be eliminated , and the other its replacement , at the start of a routine .


<s> static bool alpha_in_small_data_p ( const_tree exp ) { if ( TREE_CODE ( exp ) == STRING_CST ) return false ; if ( TREE_CODE ( exp ) == FUNCTION_DECL ) return false ; if ( TREE_CODE ( exp ) == VAR_DECL && DECL_COMMON ( exp ) ) return false ; if ( TREE_CODE ( exp ) == VAR_DECL && DECL_SECTION_NAME ( exp ) ) { const char * section = DECL_SECTION_NAME ( exp ) ; if ( strcmp ( section , ".sdata" ) == 0 || strcmp ( section , ".sbss" ) == 0 ) return true ; } else { HOST_WIDE_INT size = int_size_in_bytes ( TREE_TYPE ( exp ) ) ; if ( size > 0 && size <= g_switch_value ) return true ; } return false ; } </s>

Return true if EXP should be placed in the small data section .


<s> static int alpha_issue_rate ( void ) { return ( alpha_tune == PROCESSOR_EV4 ? 2 : 4 ) ; } </s>

Function to initialize the issue rate used by the scheduler .


<s> static bool alpha_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { if ( mode == DImode && GET_CODE ( x ) == AND && CONST_INT_P ( XEXP ( x , 1 ) ) && INTVAL ( XEXP ( x , 1 ) ) == - 8 ) x = XEXP ( x , 0 ) ; if ( SUBREG_P ( x ) && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( REG_P ( x ) && ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) ) return true ; if ( CONSTANT_ADDRESS_P ( x ) ) return true ; if ( LINKAGE_SYMBOL_REF_P ( x ) ) return true ; if ( GET_CODE ( x ) == PLUS ) { rtx ofs = XEXP ( x , 1 ) ; x = XEXP ( x , 0 ) ; if ( SUBREG_P ( x ) && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( REG_P ( x ) ) { if ( ! strict && NONSTRICT_REG_OK_FP_BASE_P ( x ) && CONST_INT_P ( ofs ) ) return true ; if ( ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) && CONSTANT_ADDRESS_P ( ofs ) ) return true ; } } else if ( TARGET_EXPLICIT_RELOCS && GET_MODE_SIZE ( mode ) <= UNITS_PER_WORD ) { if ( small_symbolic_operand ( x , Pmode ) ) return true ; if ( GET_CODE ( x ) == LO_SUM ) { rtx ofs = XEXP ( x , 1 ) ; x = XEXP ( x , 0 ) ; if ( SUBREG_P ( x ) && ( GET_MODE_SIZE ( GET_MODE ( x ) ) < GET_MODE_SIZE ( GET_MODE ( SUBREG_REG ( x ) ) ) ) ) x = SUBREG_REG ( x ) ; if ( ! ( REG_P ( x ) && ( strict ? STRICT_REG_OK_FOR_BASE_P ( x ) : NONSTRICT_REG_OK_FOR_BASE_P ( x ) ) ) ) return false ; if ( local_symbolic_operand ( ofs , Pmode ) || dtp32_symbolic_operand ( ofs , Pmode ) || tp32_symbolic_operand ( ofs , Pmode ) ) return true ; } } return false ; } </s>

legitimate_address_p recognizes an RTL expression that is a valid memory address for an instruction . The MODE argument is the machine mode for the MEM expression that wants to use this address . For Alpha , we have either a constant address or the sum of a register and a constant address , or just a register . For DImode , any of those forms can be surrounded with an AND that clear the low-order three bits ; this is an `` unaligned '' access .


<s> bool alpha_legitimate_constant_p ( machine_mode mode , rtx x ) { HOST_WIDE_INT i0 ; switch ( GET_CODE ( x ) ) { case LABEL_REF : case HIGH : return true ; case CONST : if ( GET_CODE ( XEXP ( x , 0 ) ) == PLUS && CONST_INT_P ( XEXP ( XEXP ( x , 0 ) , 1 ) ) ) x = XEXP ( XEXP ( x , 0 ) , 0 ) ; else return true ; if ( GET_CODE ( x ) != SYMBOL_REF ) return true ; case SYMBOL_REF : return SYMBOL_REF_TLS_MODEL ( x ) == 0 ; case CONST_WIDE_INT : if ( TARGET_BUILD_CONSTANTS ) return true ; if ( x == CONST0_RTX ( mode ) ) return true ; mode = DImode ; gcc_assert ( CONST_WIDE_INT_NUNITS ( x ) == 2 ) ; i0 = CONST_WIDE_INT_ELT ( x , 1 ) ; if ( alpha_emit_set_const_1 ( NULL_RTX , mode , i0 , 3 , true ) == NULL ) return false ; i0 = CONST_WIDE_INT_ELT ( x , 0 ) ; goto do_integer ; case CONST_DOUBLE : if ( x == CONST0_RTX ( mode ) ) return true ; return false ; case CONST_VECTOR : if ( x == CONST0_RTX ( mode ) ) return true ; if ( GET_MODE_CLASS ( mode ) != MODE_VECTOR_INT ) return false ; if ( GET_MODE_SIZE ( mode ) != 8 ) return false ; case CONST_INT : if ( TARGET_BUILD_CONSTANTS ) return true ; i0 = alpha_extract_integer ( x ) ; do_integer : return alpha_emit_set_const_1 ( NULL_RTX , mode , i0 , 3 , true ) != NULL ; default : return false ; } } </s>

Implement LEGITIMATE_CONSTANT_P . This is all constants for which we are willing to load the value into a register via a move pattern . Normally this is all symbolic constants , integral constants that take three or fewer instructions , and floating-point zero .


<s> static rtx alpha_legitimize_address ( rtx x , rtx oldx ATTRIBUTE_UNUSED , machine_mode mode ) { rtx new_x = alpha_legitimize_address_1 ( x , NULL_RTX , mode ) ; return new_x ? new_x : x ; } </s>

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


<s> rtx alpha_legitimize_reload_address ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int opnum , int type , int ind_levels ATTRIBUTE_UNUSED ) { if ( GET_CODE ( x ) == PLUS && GET_CODE ( XEXP ( x , 0 ) ) == PLUS && REG_P ( XEXP ( XEXP ( x , 0 ) , 0 ) ) && CONST_INT_P ( XEXP ( XEXP ( x , 0 ) , 1 ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { push_reload ( XEXP ( x , 0 ) , NULL_RTX , & XEXP ( x , 0 ) , NULL , BASE_REG_CLASS , GET_MODE ( x ) , VOIDmode , 0 , 0 , opnum , ( enum reload_type ) type ) ; return x ; } if ( GET_CODE ( x ) == PLUS && REG_P ( XEXP ( x , 0 ) ) && REGNO ( XEXP ( x , 0 ) ) < FIRST_PSEUDO_REGISTER && REGNO_OK_FOR_BASE_P ( REGNO ( XEXP ( x , 0 ) ) ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) { HOST_WIDE_INT val = INTVAL ( XEXP ( x , 1 ) ) ; HOST_WIDE_INT low = ( ( val & 0xffff ) ^ 0x8000 ) - 0x8000 ; HOST_WIDE_INT high = ( ( ( val - low ) & 0xffffffff ) ^ 0x80000000 ) - 0x80000000 ; if ( high + low != val ) return NULL_RTX ; x = gen_rtx_PLUS ( GET_MODE ( x ) , gen_rtx_PLUS ( GET_MODE ( x ) , XEXP ( x , 0 ) , GEN_INT ( high ) ) , GEN_INT ( low ) ) ; push_reload ( XEXP ( x , 0 ) , NULL_RTX , & XEXP ( x , 0 ) , NULL , BASE_REG_CLASS , GET_MODE ( x ) , VOIDmode , 0 , 0 , opnum , ( enum reload_type ) type ) ; return x ; } return NULL_RTX ; } </s>

Try a machine-dependent way of reloading an illegitimate address operand . If we find one , push the reload and return the new rtx .


<s> static rtx alpha_libcall_value ( machine_mode mode , const_rtx ) { return alpha_function_value_1 ( NULL_TREE , NULL_TREE , mode ) ; } </s>


<s> static rtx alpha_lookup_xfloating_lib_func ( enum rtx_code code ) { struct xfloating_op * ops = xfloating_ops ; long n = ARRAY_SIZE ( xfloating_ops ) ; long i ; gcc_assert ( TARGET_HAS_XFLOATING_LIBS ) ; if ( TARGET_FLOAT_VAX && ( code == FLOAT_EXTEND || code == FLOAT_TRUNCATE ) ) { ops = vax_cvt_ops ; n = ARRAY_SIZE ( vax_cvt_ops ) ; } for ( i = 0 ; i < n ; ++ i , ++ ops ) if ( ops -> code == code ) { rtx func = ops -> libcall ; if ( ! func ) { func = init_one_libfunc ( TARGET_ABI_OPEN_VMS ? ops -> vms_func : ops -> osf_func ) ; ops -> libcall = func ; } return func ; } gcc_unreachable ( ) ; } </s>

Look up the function X_floating library function name for the given operation .


<s> static const char * alpha_mangle_type ( const_tree type ) { if ( TYPE_MAIN_VARIANT ( type ) == long_double_type_node && TARGET_LONG_DOUBLE_128 ) return "g" ; return NULL ; } </s>


<s> static int alpha_memory_move_cost ( machine_mode , reg_class_t , bool ) { return 2 * alpha_memory_latency ; } </s>

Return the cost of moving data of MODE from a register to or from memory . On the Alpha , bump this up a bit .


Implement TARGET_MODES_TIEABLE_P . This asymmetric test is true when MODE1 could be put in an FP register but MODE2 could not .