"unexpected argument to msp430_select_hwmult_lib: %s"

"unrecognised hwpy field in msp430_mcu_data[%d]: %d"

"unexpected first argument to msp430_select_hwmult_lib: %s"

"msp430_select_hwmult_lib needs one or more arguments"

Implement spec function ` msp430_hwmult_lib麓 .


"unrecognized hwpy field in msp430_mcu_data[%d]: %d"


<s> const char * msp430_get_linker_devices_include_path ( int argc ATTRIBUTE_UNUSED , const char * * argv ATTRIBUTE_UNUSED ) { char * devices_csv_path ; if ( msp430_check_env_var_for_devices ( & devices_csv_path ) ) return NULL ; return concat ( "-L" , msp430_dirname ( devices_csv_path ) , NULL ) ; } </s>

Spec function . Used to place the path to the MSP430-GCC support files on the command line , prefixed with `` -L '' , so the linker finds the linker scripts in that directory .


<s> const char * msp430_propagate_region_opt ( int argc , const char * * argv ) { if ( strcmp ( argv [ 0 ] , "lower" ) != 0 ) return argv [ 0 ] ; else if ( ( argc == 2 ) && ( strcmp ( argv [ 1 ] , "-muse-lower-region-prefix" ) == 0 ) ) return argv [ 0 ] ; return "none" ; } </s>

Spec function . Propagate -m { code , data } -region= to the linker , unless the lower region has been specified without -muse-lower-region-prefix also being used .


"expected an argument to %<msp430_select_cpu%>"

This spec function is called if the user has provided an -mmcu option without an -mcpu option . It will place the correct -mcpu option for the given -mmcu onto the command line , to ensure the correct ISA multilib is selected .


"unexpected argument to %<msp430_select_hwmult_lib%>: %s"

"unexpected first argument to %<msp430_select_hwmult_lib%>: %s"

"%<msp430_select_hwmult_lib%> needs one or more arguments"


"%<msp430_set_driver_var%> expects 2 arguments"

"unhandled arguments %qs and %qs to %<msp430_set_driver_var%>"

Spec function to set a global variable to a specific value in the driver . The first argument is the variable name , and the second is the value to set it to . Currently only `` msp430_warn_devices_csv '' and `` msp430_devices_csv_loc '' are supported . The intention is that we can take a `` Target '' option and set the variable associated with it in the driver as well . Whilst the driver sees `` Target '' options , it does not set the variables associated with that option .


<s> void msp430_register_pragmas ( void ) { c_register_addr_space ( "__near" , ADDR_SPACE_NEAR ) ; if ( msp430x ) c_register_addr_space ( "__far" , ADDR_SPACE_FAR ) ; } </s>


<s> static void canonicalize_path_dirsep ( char * * path ) { char * t_path = * path ; int len = strlen ( t_path ) ; int i ; for ( i = 0 ; i < len ; i ++ ) if ( IS_DIR_SEPARATOR ( t_path [ i ] ) ) t_path [ i ] = DIR_SEPARATOR ; } </s>

This is to canonicalize the directory separators in the path . On Windows we could have a mix of '/ ' and '\ ' in the path .


<s> static void extract_devices_dir_from_collect_gcc ( char * * devices_loc ) { char * t_devices_loc = * devices_loc ; t_devices_loc = msp430_dirname ( msp430_dirname ( t_devices_loc ) ) ; t_devices_loc = concat ( t_devices_loc , rest_of_devices_path , NULL ) ; * devices_loc = t_devices_loc ; } </s>


<s> static void extract_devices_dir_from_exec_prefix ( char * * devices_loc ) { const char * temp ; char * gcc_exec_prefix = * devices_loc ; int len = strlen ( gcc_exec_prefix ) ; if ( len > ( int ) sizeof ( "/lib/gcc/" ) - 1 && ( IS_DIR_SEPARATOR ( gcc_exec_prefix [ len - 1 ] ) ) ) { temp = gcc_exec_prefix + len - sizeof ( "/lib/gcc/" ) + 1 ; if ( IS_DIR_SEPARATOR ( * temp ) && filename_ncmp ( temp + 1 , "lib" , 3 ) == 0 && IS_DIR_SEPARATOR ( temp [ 4 ] ) && filename_ncmp ( temp + 5 , "gcc" , 3 ) == 0 ) { len -= sizeof ( "/lib/gcc/" ) - 1 ; gcc_exec_prefix [ len + 1 ] = ( char ) 0 ; * devices_loc = concat ( gcc_exec_prefix , rest_of_devices_path , NULL ) ; return ; } } } </s>

`` The default value of GCC_EXEC_PREFIX is prefix/lib/gcc '' . Strip lib/gcc from GCC_EXEC_PREFIX to get the path to the installed toolchain .


<s> int msp430_check_env_var_for_devices ( char * * local_devices_csv_loc ) { const int num_vars = 3 ; const char dirsep [ 2 ] = { DIR_SEPARATOR , 0 } ; const char * env_vars [ num_vars ] = { "MSP430_GCC_INCLUDE_DIR" , "GCC_EXEC_PREFIX" , "COLLECT_GCC" } ; enum msp430_include_vars { MSP430_GCC_INCLUDE_DIR , GCC_EXEC_PREFIX , COLLECT_GCC } ; FILE * devices_csv_file = NULL ; int i ; for ( i = MSP430_GCC_INCLUDE_DIR ; i <= COLLECT_GCC ; i ++ ) { char * t_devices_loc ; char * val = getenv ( env_vars [ i ] ) ; if ( val == NULL ) continue ; t_devices_loc = xstrdup ( val ) ; if ( i == MSP430_GCC_INCLUDE_DIR ) { if ( ! IS_DIR_SEPARATOR ( t_devices_loc [ strlen ( t_devices_loc ) - 1 ] ) ) t_devices_loc = concat ( t_devices_loc , dirsep , NULL ) ; } else if ( i == GCC_EXEC_PREFIX ) extract_devices_dir_from_exec_prefix ( & t_devices_loc ) ; else if ( i == COLLECT_GCC ) extract_devices_dir_from_collect_gcc ( & t_devices_loc ) ; t_devices_loc = concat ( t_devices_loc , "devices.csv" , NULL ) ; devices_csv_file = fopen ( t_devices_loc , "r" ) ; if ( devices_csv_file != NULL ) { fclose ( devices_csv_file ) ; * local_devices_csv_loc = t_devices_loc ; canonicalize_path_dirsep ( local_devices_csv_loc ) ; return 0 ; } } return 1 ; } </s>

The path to the MSP430-GCC support files can be specified with the environment variable `` MSP430_GCC_INCLUDE_DIR '' , or installed into the toolchain in the msp430-elf/include/devices subdirectory . We use the GCC_EXEC_PREFIX or COLLECT_GCC environment variables as a starting point for the location of the toolchain , and work out the path to the installed device data from there . Return 0 and set LOCAL_DEVICES_CSV_LOC if we find devices.csv . Return 1 if devices.csv was n't found .


<s> const char * msp430_check_path_for_devices ( int argc , const char * * argv ) { const char dirsep [ 2 ] = { DIR_SEPARATOR , 0 } ; FILE * devices_file = NULL ; char * local_devices_csv_loc = NULL ; int i ; if ( msp430_devices_csv_loc || derived_devices_csv_loc ) return NULL ; for ( i = 0 ; i < argc ; i ++ ) { char * inc_path = xstrdup ( argv [ i ] ) ; canonicalize_path_dirsep ( & inc_path ) ; if ( ! IS_DIR_SEPARATOR ( inc_path [ strlen ( inc_path ) - 1 ] ) ) inc_path = concat ( inc_path , dirsep , NULL ) ; local_devices_csv_loc = concat ( inc_path , "devices.csv" , NULL ) ; devices_file = fopen ( local_devices_csv_loc , "r" ) ; if ( devices_file != NULL ) { fclose ( devices_file ) ; derived_devices_csv_loc = local_devices_csv_loc ; return concat ( "-mdevices-csv-loc=" , local_devices_csv_loc , NULL ) ; } } return NULL ; } </s>

Spec function which searches the paths passed to the -I and -L options for the `` devices.csv '' file . If it is found then the -mdevices-csv-loc option is placed on the command line so the compiler knows the location of the file .


<s> char * msp430_dirname ( char * path ) { int last_elem = strlen ( path ) - 1 ; int i = last_elem - ( IS_DIR_SEPARATOR ( path [ last_elem ] ) ? 1 : 0 ) ; for ( ; i >= 0 ; i -- ) { if ( IS_DIR_SEPARATOR ( path [ i ] ) ) { path [ i ] = '\0' ; return path ; } } return path ; } </s>

This function returns the enclosing directory of PATH . It is inconsequential whether PATH ends in a dirsep or not . It modifies the string pointed to by PATH .


"could not locate MCU data file %<devices.csv%>"

Main entry point to load the MCU data for the given -mmcu into extracted_mcu_data . First , the `` devices.csv '' MCU data file is searched for , if it is found , and the MCU has a record in it , then that data is used . Otherwise , hard_msp430_mcu_data ( initialized at the bottom of this file ) is searched for the MCU name . This function only needs to be executed once , but it can be first called from a number of different locations .


<s> static int parse_devices_csv ( const char * mcu_name ) { if ( msp430_devices_csv_loc != NULL ) return parse_devices_csv_1 ( msp430_devices_csv_loc , mcu_name ) ; else if ( derived_devices_csv_loc != NULL ) return parse_devices_csv_1 ( derived_devices_csv_loc , mcu_name ) ; if ( msp430_check_env_var_for_devices ( & derived_devices_csv_loc ) ) return 2 ; return parse_devices_csv_1 ( derived_devices_csv_loc , mcu_name ) ; } </s>

Wrapper for the parse_devices_csv_1 work function . A return code of 0 indicates that the MCU data has been successfully extracted into extracted_mcu_data . A return code of 1 indicates that the specified MCU was n't found in devices.csv . A return code of 2 indicates that devices.csv was n't found at all .


<s> static int msp430_single_op_cost ( rtx dst , bool speed , rtx ) { enum rtx_code dst_code = GET_CODE ( dst ) ; const struct single_op_cost * cost_p ; const struct double_op_cost * double_op_cost_p ; cost_p = ( speed ? & cycle_cost_single_op : & size_cost_single_op ) ; double_op_cost_p = ( speed ? & cycle_cost_double_op : & size_cost_double_op ) ; switch ( dst_code ) { case REG : return cost_p -> reg ; case MEM : if ( msp430_is_mem_indirect ( dst ) ) return cost_p -> ind ; else return cost_p -> mem ; case CONST_INT : case CONST_FIXED : case CONST_DOUBLE : case SYMBOL_REF : case CONST : return double_op_cost_p -> imm2r + cost_p -> reg ; default : return cost_p -> mem ; } } </s>

Calculate the cost of an MSP430 single-operand instruction , for operand DST within the RTX OUTER_RTX , optimizing for speed if SPEED is true .


<s> static inline bool is_naked_func ( void ) { return is_attr_func ( "naked" ) ; } </s>

Returns true if the provided function has the `` naked '' attribute .


Generate a sequence of instructions to sign-extend an HI value into an SI value . Handles the tricky case where we are overwriting the destination . Return the number of bytes used by the emitted instructions . If RETURN_LENGTH is true then do not emit the assembly instruction sequence .


"unrecognised interrupt vector argument of %qE attribute"

"numeric argument of %qE attribute must be in range 0..63"

"argument of %qE attribute is not a string constant or number"

"%qE attribute only applies to functions"


<s> static void msp430_compute_frame_info ( void ) { int i ; cfun -> machine -> computed = 1 ; cfun -> machine -> framesize_regs = 0 ; cfun -> machine -> framesize_locals = get_frame_size ( ) ; cfun -> machine -> framesize_outgoing = crtl -> outgoing_args_size ; for ( i = 0 ; i < ARG_POINTER_REGNUM ; i ++ ) if ( msp430_preserve_reg_p ( i ) ) { cfun -> machine -> need_to_save [ i ] = 1 ; cfun -> machine -> framesize_regs += ( TARGET_LARGE ? 4 : 2 ) ; } else cfun -> machine -> need_to_save [ i ] = 0 ; if ( ( cfun -> machine -> framesize_locals + cfun -> machine -> framesize_outgoing ) & 1 ) cfun -> machine -> framesize_locals ++ ; cfun -> machine -> framesize = ( cfun -> machine -> framesize_regs + cfun -> machine -> framesize_locals + cfun -> machine -> framesize_outgoing ) ; } </s>

Compute all the frame-related fields in our machine_function structure .


<s> static void msp430_evaluate_arg ( cumulative_args_t cap , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ) { CUMULATIVE_ARGS * ca = get_cumulative_args ( cap ) ; int nregs = GET_MODE_SIZE ( mode ) ; int i ; ca -> reg_count = 0 ; ca -> mem_count = 0 ; if ( ! named ) return ; if ( mode == PSImode ) nregs = 1 ; else nregs = ( nregs + 1 ) / 2 ; if ( ca -> special_p ) { ca -> start_reg = 8 ; ca -> reg_count = 4 ; return ; } switch ( nregs ) { case 1 : for ( i = 0 ; i < 4 ; i ++ ) if ( ! ca -> reg_used [ i ] ) { ca -> reg_count = 1 ; ca -> start_reg = CA_FIRST_REG + i ; return ; } break ; case 2 : for ( i = 0 ; i < 3 ; i ++ ) if ( ! ca -> reg_used [ i ] && ! ca -> reg_used [ i + 1 ] ) { ca -> reg_count = 2 ; ca -> start_reg = CA_FIRST_REG + i ; return ; } if ( ! ca -> reg_used [ 3 ] && ca -> can_split ) { ca -> reg_count = 1 ; ca -> mem_count = 2 ; ca -> start_reg = CA_FIRST_REG + 3 ; return ; } break ; case 3 : case 4 : ca -> can_split = 0 ; if ( ! ca -> reg_used [ 0 ] && ! ca -> reg_used [ 1 ] && ! ca -> reg_used [ 2 ] && ! ca -> reg_used [ 3 ] ) { ca -> reg_count = 4 ; ca -> start_reg = CA_FIRST_REG ; return ; } break ; } } </s>

Helper function for argument passing ; this function is the common code that determines where an argument will be passed .


<s> void msp430_expand_helper ( rtx * operands , const char * helper_name , bool const_variants ) { rtx c , f ; char * helper_const = NULL ; int arg2 = 13 ; int arg1sz = 1 ; machine_mode arg0mode = GET_MODE ( operands [ 0 ] ) ; machine_mode arg1mode = GET_MODE ( operands [ 1 ] ) ; machine_mode arg2mode = GET_MODE ( operands [ 2 ] ) ; int have_430x = msp430x ? 1 : 0 ; if ( CONST_INT_P ( operands [ 2 ] ) ) { int i ; for ( i = 0 ; const_shift_helpers [ i ] . name ; i ++ ) { if ( const_shift_helpers [ i ] . need_430x <= have_430x && strcmp ( helper_name , const_shift_helpers [ i ] . name ) == 0 && INTVAL ( operands [ 2 ] ) == const_shift_helpers [ i ] . count ) { emit_insn ( const_shift_helpers [ i ] . genfunc ( operands [ 0 ] , operands [ 1 ] ) ) ; return ; } } } if ( arg1mode == VOIDmode ) arg1mode = arg0mode ; if ( arg2mode == VOIDmode ) arg2mode = arg0mode ; if ( arg1mode == SImode ) { arg2 = 14 ; arg1sz = 2 ; } if ( const_variants && CONST_INT_P ( operands [ 2 ] ) && INTVAL ( operands [ 2 ] ) >= 1 && INTVAL ( operands [ 2 ] ) <= 15 ) { int len = strlen ( helper_name ) + 4 ; helper_const = ( char * ) xmalloc ( len ) ; snprintf ( helper_const , len , "%s_%d" , helper_name , ( int ) INTVAL ( operands [ 2 ] ) ) ; } emit_move_insn ( gen_rtx_REG ( arg1mode , 12 ) , operands [ 1 ] ) ; if ( ! helper_const ) emit_move_insn ( gen_rtx_REG ( arg2mode , arg2 ) , operands [ 2 ] ) ; c = gen_call_value_internal ( gen_rtx_REG ( arg0mode , 12 ) , gen_rtx_SYMBOL_REF ( VOIDmode , helper_const ? helper_const : helper_name ) , GEN_INT ( 0 ) ) ; c = emit_call_insn ( c ) ; RTL_CONST_CALL_P ( c ) = 1 ; f = 0 ; use_regs ( & f , 12 , arg1sz ) ; if ( ! helper_const ) use_regs ( & f , arg2 , 1 ) ; add_function_usage_to ( c , f ) ; emit_move_insn ( operands [ 0 ] , gen_rtx_REG ( arg0mode , 12 ) ) ; } </s>

The MSP430 ABI defines a number of helper functions that should be used for , for example , 32-bit shifts . This function is called to emit such a function , using the table above to optimize some cases .


<s> int msp430_hard_regno_mode_ok ( int regno ATTRIBUTE_UNUSED , machine_mode mode ) { return regno <= ( ARG_POINTER_REGNUM - msp430_hard_regno_nregs ( regno , mode ) ) ; } </s>


<s> int msp430_hard_regno_nregs ( int regno ATTRIBUTE_UNUSED , machine_mode mode ) { if ( mode == PSImode && msp430x ) return 1 ; return ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; } </s>

Implements HARD_REGNO_NREGS . MSP430X registers can hold a single PSImode value , but not an SImode value .


<s> int msp430_hard_regno_nregs_has_padding ( int regno ATTRIBUTE_UNUSED , machine_mode mode ) { if ( mode == PSImode && msp430x ) return 1 ; return ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; } </s>


<s> int msp430_hard_regno_nregs_with_padding ( int regno ATTRIBUTE_UNUSED , machine_mode mode ) { if ( mode == PSImode ) return 2 ; return msp430_hard_regno_nregs ( regno , mode ) ; } </s>


<s> bool msp430_is_interrupt_func ( void ) { if ( current_function_decl == NULL ) return false ; return is_attr_func ( "interrupt" ) ; } </s>

Returns true if the current function has the `` interrupt '' attribute .


<s> const char * msp430_mcu_name ( void ) { if ( target_mcu ) { unsigned int i ; static char mcu_name [ 64 ] ; snprintf ( mcu_name , sizeof ( mcu_name ) - 1 , "__%s__" , target_mcu ) ; for ( i = strlen ( mcu_name ) ; i -- ; ) mcu_name [ i ] = TOUPPER ( mcu_name [ i ] ) ; return mcu_name ; } return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__" ; } </s>

Generate a C preprocessor symbol based upon the MCU selected by the user . If a specific MCU has not been selected then return a generic symbol instead .


<s> bool msp430_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { if ( ( mode1 == PSImode || mode2 == SImode ) || ( mode1 == SImode || mode2 == PSImode ) ) return false ; return ( ( GET_MODE_CLASS ( mode1 ) == MODE_FLOAT || GET_MODE_CLASS ( mode1 ) == MODE_COMPLEX_FLOAT ) == ( GET_MODE_CLASS ( mode2 ) == MODE_FLOAT || GET_MODE_CLASS ( mode2 ) == MODE_COMPLEX_FLOAT ) ) ; } </s>


Returns true if the current MCU does not have a hardware multiplier of any kind .


<s> void msp430_output_labelref ( FILE * file , const char * name ) { int i ; for ( i = 0 ; helper_function_name_mappings [ i ] . gcc_name ; i ++ ) if ( strcmp ( helper_function_name_mappings [ i ] . gcc_name , name ) == 0 ) { name = helper_function_name_mappings [ i ] . ti_name ; break ; } if ( msp430_hwmult_type != NONE ) { if ( strcmp ( "__mspabi_mpyi" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulhi2_f5" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulhi2" ; } else if ( strcmp ( "__mspabi_mpyl" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulsi2_f5" ; else if ( use_32bit_hwmult ( ) ) name = "__mulsi2_hw32" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulsi2" ; } } fputs ( name , file ) ; } </s>

This function does the same as the default , but it will replace GCC function names with the MSPABI-specified ones .


<s> static bool msp430_preserve_reg_p ( int regno ) { if ( regno <= 3 ) return false ; if ( crtl -> calls_eh_return ) return true ; if ( fixed_regs [ regno ] ) return false ; if ( msp430_is_interrupt_func ( ) ) return ! crtl -> is_leaf || df_regs_ever_live_p ( regno ) ; if ( ! call_used_regs [ regno ] && df_regs_ever_live_p ( regno ) ) return true ; return false ; } </s>

This is the one spot that decides if a register is to be saved and restored in the prologue/epilogue .


<s> static void msp430_print_operand_addr ( FILE * file , rtx addr ) { switch ( GET_CODE ( addr ) ) { case PLUS : msp430_print_operand_raw ( file , XEXP ( addr , 1 ) ) ; gcc_assert ( REG_P ( XEXP ( addr , 0 ) ) ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( XEXP ( addr , 0 ) ) ] ) ; return ; case REG : fprintf ( file , "@" ) ; break ; case CONST : case CONST_INT : case SYMBOL_REF : case LABEL_REF : fprintf ( file , "&" ) ; break ; default : break ; } msp430_print_operand_raw ( file , addr ) ; } </s>

Output to stdio stream FILE the assembler syntax for an instruction operand that is a memory reference whose address is ADDR .


<s> static void msp430_print_operand_raw ( FILE * file , rtx op ) { HOST_WIDE_INT i ; switch ( GET_CODE ( op ) ) { case REG : fprintf ( file , "%s" , reg_names [ REGNO ( op ) ] ) ; break ; case CONST_INT : i = INTVAL ( op ) ; if ( TARGET_ASM_HEX ) fprintf ( file , "%#" HOST_WIDE_INT_PRINT "x" , i ) ; else fprintf ( file , "%" HOST_WIDE_INT_PRINT "d" , i ) ; break ; case CONST : case PLUS : case MINUS : case SYMBOL_REF : case LABEL_REF : output_addr_const ( file , op ) ; break ; default : print_rtl ( file , op ) ; break ; } } </s>

Common code for msp430_print_operand ...


<s> static bool msp430_rtx_costs ( rtx x ATTRIBUTE_UNUSED , int code , int outer_code ATTRIBUTE_UNUSED , int opno ATTRIBUTE_UNUSED , int * total , bool speed ATTRIBUTE_UNUSED ) { switch ( code ) { case SIGN_EXTEND : if ( GET_MODE ( x ) == SImode && outer_code == SET ) { * total = COSTS_N_INSNS ( 4 ) ; return true ; } break ; case ASHIFT : case ASHIFTRT : case LSHIFTRT : if ( ! msp430x ) { * total = COSTS_N_INSNS ( 100 ) ; return true ; } break ; } return false ; } </s>

This target hook describes the relative costs of RTL expressions . The function recurses to just before the lowest level of the expression , when both of the operands of the expression can be examined at the same time . This is because the cost of the expression depends on the specific addressing mode combination of the operands . The hook returns true when all subexpressions of X have been processed , and false when rtx_cost should recurse .


<s> static bool msp430_special_register_convention_p ( const char * name ) { int i ; for ( i = 0 ; special_convention_function_names [ i ] ; i ++ ) if ( ! strcmp ( name , special_convention_function_names [ i ] ) ) return true ; return false ; } </s>

TRUE if the function passed is a `` speical '' function . Special functions pass two DImode parameters in registers .


<s> void msp430_split_movsi ( rtx * operands ) { rtx op00 , op02 , op10 , op12 ; op00 = msp430_subreg ( HImode , operands [ 0 ] , SImode , 0 ) ; op02 = msp430_subreg ( HImode , operands [ 0 ] , SImode , 2 ) ; if ( GET_CODE ( operands [ 1 ] ) == CONST || GET_CODE ( operands [ 1 ] ) == SYMBOL_REF ) { op10 = gen_rtx_ZERO_EXTRACT ( HImode , operands [ 1 ] , GEN_INT ( 16 ) , GEN_INT ( 0 ) ) ; op10 = gen_rtx_CONST ( HImode , op10 ) ; op12 = gen_rtx_ZERO_EXTRACT ( HImode , operands [ 1 ] , GEN_INT ( 16 ) , GEN_INT ( 16 ) ) ; op12 = gen_rtx_CONST ( HImode , op12 ) ; } else { op10 = msp430_subreg ( HImode , operands [ 1 ] , SImode , 0 ) ; op12 = msp430_subreg ( HImode , operands [ 1 ] , SImode , 2 ) ; } if ( rtx_equal_p ( operands [ 0 ] , operands [ 1 ] ) ) { operands [ 2 ] = op02 ; operands [ 4 ] = op12 ; operands [ 3 ] = op00 ; operands [ 5 ] = op10 ; } else if ( rtx_equal_p ( op00 , op12 ) || ( REG_P ( op00 ) && reg_mentioned_p ( op00 , op10 ) ) || ( REG_P ( op10 ) && reg_mentioned_p ( op10 , op00 ) ) ) { operands [ 2 ] = op02 ; operands [ 4 ] = op12 ; operands [ 3 ] = op00 ; operands [ 5 ] = op10 ; } else { operands [ 2 ] = op00 ; operands [ 4 ] = op10 ; operands [ 3 ] = op02 ; operands [ 5 ] = op12 ; } } </s>

Called by movsi_x to generate the HImode operands .


<s> rtx msp430_subreg ( machine_mode mode , rtx r , machine_mode omode , int byte ) { rtx rv ; if ( GET_CODE ( r ) == SUBREG && SUBREG_BYTE ( r ) == 0 ) { rtx ireg = SUBREG_REG ( r ) ; machine_mode imode = GET_MODE ( ireg ) ; if ( imode == PSImode && mode == HImode && byte == 0 ) rv = gen_rtx_SUBREG ( mode , ireg , byte ) ; else rv = simplify_gen_subreg ( mode , ireg , imode , byte ) ; } else if ( GET_CODE ( r ) == MEM ) rv = adjust_address ( r , mode , byte ) ; else rv = simplify_gen_subreg ( mode , r , omode , byte ) ; if ( ! rv ) gcc_unreachable ( ) ; return rv ; } </s>

Simplify_gen_subreg ( ) does n't handle memory references the way we need it to below , so we use this function for when we must get a valid subreg in a `` natural '' state .


<s> bool msp430_use_f5_series_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == F5SERIES ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; if ( strncasecmp ( target_mcu , "msp430f5" , 8 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430fr5" , 9 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430f6" , 8 ) == 0 ) return cached_result = true ; static const char * known_f5_mult_mcus [ ] = { "cc430f5123" , "cc430f5125" , "cc430f5133" , "cc430f5135" , "cc430f5137" , "cc430f5143" , "cc430f5145" , "cc430f5147" , "cc430f6125" , "cc430f6126" , "cc430f6127" , "cc430f6135" , "cc430f6137" , "cc430f6143" , "cc430f6145" , "cc430f6147" , "msp430bt5190" , "msp430sl5438a" , "msp430xgeneric" } ; int i ; for ( i = ARRAY_SIZE ( known_f5_mult_mcus ) ; i -- ; ) if ( strcasecmp ( target_mcu , known_f5_mult_mcus [ i ] ) == 0 ) return cached_result = true ; return cached_result = false ; } </s>

Returns true if the current MCU supports an F5xxx series hardware multiper .


<s> static bool use_32bit_hwmult ( void ) { static const char * known_32bit_mult_mcus [ ] = { "msp430f4783" , "msp430f4793" , "msp430f4784" , "msp430f4794" , "msp430f47126" , "msp430f47127" , "msp430f47163" , "msp430f47173" , "msp430f47183" , "msp430f47193" , "msp430f47166" , "msp430f47176" , "msp430f47186" , "msp430f47196" , "msp430f47167" , "msp430f47177" , "msp430f47187" , "msp430f47197" } ; static const char * cached_match = NULL ; static bool cached_result ; int i ; if ( msp430_hwmult_type == LARGE ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; for ( i = ARRAY_SIZE ( known_32bit_mult_mcus ) ; i -- ; ) if ( strcasecmp ( target_mcu , known_32bit_mult_mcus [ i ] ) == 0 ) return cached_result = true ; return cached_result = false ; } </s>

Returns true if the current MCU has a second generation 32-bit hardware multiplier .


<s> static const char * gen_prefix ( tree decl ) { if ( DECL_ONE_ONLY ( decl ) ) return NULL ; if ( has_attr ( "section" , decl ) ) return NULL ; if ( has_attr ( ATTR_LOWER , decl ) ) return lower_prefix ; if ( ! msp430x ) return NULL ; if ( has_attr ( ATTR_UPPER , decl ) ) return upper_prefix ; if ( has_attr ( ATTR_EITHER , decl ) ) return either_prefix ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { if ( msp430_code_region == LOWER ) return lower_prefix ; if ( msp430_code_region == UPPER ) return upper_prefix ; if ( msp430_code_region == EITHER ) return either_prefix ; } else { if ( msp430_data_region == LOWER ) return lower_prefix ; if ( msp430_data_region == UPPER ) return upper_prefix ; if ( msp430_data_region == EITHER ) return either_prefix ; } return NULL ; } </s>

Generate a prefix for a section name , based upon the region into which the object should be placed .


"unrecognised interrupt vector argument of %qE attribute"

"numeric argument of %qE attribute must be in range 0..63"

"argument of %qE attribute is not a string constant or number"

"%qE attribute only applies to functions"

"critical functions cannot be reentrant"

"reentrant functions cannot be critical"


<s> static bool msp430_no_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; int i ; if ( msp430_hwmult_type == NONE ) return true ; if ( msp430_hwmult_type != AUTO ) return false ; if ( target_mcu == NULL ) return true ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 0 ; return cached_result = true ; } </s>


<s> void msp430_output_aligned_decl_common ( FILE * stream , const tree decl , const char * name , unsigned HOST_WIDE_INT size , unsigned int align ) { if ( msp430_data_region == ANY ) { fprintf ( stream , COMMON_ASM_OP ) ; assemble_name ( stream , name ) ; fprintf ( stream , "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n" , size , align / BITS_PER_UNIT ) ; } else { section * sec ; if ( decl ) sec = msp430_select_section ( decl , 0 , align ) ; else switch ( msp430_data_region ) { case UPPER : sec = get_named_section ( NULL , ".upper.bss" , 0 ) ; break ; case LOWER : sec = get_named_section ( NULL , ".lower.bss" , 0 ) ; break ; case EITHER : sec = get_named_section ( NULL , ".either.bss" , 0 ) ; break ; default : gcc_unreachable ( ) ; } gcc_assert ( sec != NULL ) ; switch_to_section ( sec ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( align / BITS_PER_UNIT ) ) ; targetm . asm_out . globalize_label ( stream , name ) ; ASM_WEAKEN_LABEL ( stream , name ) ; ASM_OUTPUT_LABEL ( stream , name ) ; ASM_OUTPUT_SKIP ( stream , size ? size : 1 ) ; } } </s>

Emit a declaration of a common symbol . If a data region is in use then put the symbol into the equivalent .bss section instead . If LOCAL is 1 , then DECL is for a local common variable .


<s> static void msp430_print_operand_addr ( FILE * file , machine_mode , rtx addr ) { switch ( GET_CODE ( addr ) ) { case PLUS : msp430_print_operand_raw ( file , XEXP ( addr , 1 ) ) ; gcc_assert ( REG_P ( XEXP ( addr , 0 ) ) ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( XEXP ( addr , 0 ) ) ] ) ; return ; case REG : fprintf ( file , "@" ) ; break ; case CONST : case CONST_INT : case SYMBOL_REF : case LABEL_REF : fprintf ( file , "&" ) ; break ; default : break ; } msp430_print_operand_raw ( file , addr ) ; } </s>


<s> rtx msp430_subreg ( machine_mode mode , rtx r , machine_mode omode , int byte ) { rtx rv ; if ( GET_CODE ( r ) == SUBREG && SUBREG_BYTE ( r ) == 0 ) { rtx ireg = SUBREG_REG ( r ) ; machine_mode imode = GET_MODE ( ireg ) ; if ( imode == PSImode && mode == HImode && byte == 0 ) rv = gen_rtx_SUBREG ( mode , ireg , byte ) ; else rv = simplify_gen_subreg ( mode , ireg , imode , byte ) ; } else if ( GET_CODE ( r ) == MEM ) rv = adjust_address ( r , mode , byte ) ; else if ( GET_CODE ( r ) == SYMBOL_REF && ( byte == 0 || byte == 2 ) && mode == HImode ) { rv = gen_rtx_ZERO_EXTRACT ( HImode , r , GEN_INT ( 16 ) , GEN_INT ( 8 * byte ) ) ; rv = gen_rtx_CONST ( HImode , r ) ; } else rv = simplify_gen_subreg ( mode , r , omode , byte ) ; if ( ! rv ) gcc_unreachable ( ) ; return rv ; } </s>


<s> bool msp430_use_f5_series_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == F5SERIES ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; if ( strncasecmp ( target_mcu , "msp430f5" , 8 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430fr5" , 9 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430f6" , 8 ) == 0 ) return cached_result = true ; int i ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 8 ; return cached_result = false ; } </s>


<s> static bool use_32bit_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; int i ; if ( msp430_hwmult_type == LARGE ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 4 ; return cached_result = false ; } </s>


<s> static const char * gen_prefix ( tree decl ) { if ( DECL_ONE_ONLY ( decl ) ) return NULL ; if ( has_attr ( "section" , decl ) ) return NULL ; if ( has_attr ( ATTR_LOWER , decl ) ) return lower_prefix ; if ( ! msp430x ) return NULL ; if ( has_attr ( ATTR_UPPER , decl ) ) return upper_prefix ; if ( has_attr ( ATTR_EITHER , decl ) ) return either_prefix ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { if ( msp430_code_region == MSP430_REGION_LOWER ) return lower_prefix ; if ( msp430_code_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_code_region == MSP430_REGION_EITHER ) return either_prefix ; } else { if ( msp430_data_region == MSP430_REGION_LOWER ) return lower_prefix ; if ( msp430_data_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_data_region == MSP430_REGION_EITHER ) return either_prefix ; } return NULL ; } </s>


"unrecognized interrupt vector argument of %qE attribute"


<s> static bool msp430_no_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; int i ; if ( msp430_hwmult_type == MSP430_HWMULT_NONE ) return true ; if ( msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == NULL ) return true ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 0 ; return cached_result = true ; } </s>


<s> void msp430_output_aligned_decl_common ( FILE * stream , const tree decl , const char * name , unsigned HOST_WIDE_INT size , unsigned int align ) { if ( msp430_data_region == MSP430_REGION_ANY ) { fprintf ( stream , COMMON_ASM_OP ) ; assemble_name ( stream , name ) ; fprintf ( stream , "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n" , size , align / BITS_PER_UNIT ) ; } else { section * sec ; if ( decl ) sec = msp430_select_section ( decl , 0 , align ) ; else switch ( msp430_data_region ) { case MSP430_REGION_UPPER : sec = get_named_section ( NULL , ".upper.bss" , 0 ) ; break ; case MSP430_REGION_LOWER : sec = get_named_section ( NULL , ".lower.bss" , 0 ) ; break ; case MSP430_REGION_EITHER : sec = get_named_section ( NULL , ".either.bss" , 0 ) ; break ; default : gcc_unreachable ( ) ; } gcc_assert ( sec != NULL ) ; switch_to_section ( sec ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( align / BITS_PER_UNIT ) ) ; targetm . asm_out . globalize_label ( stream , name ) ; ASM_WEAKEN_LABEL ( stream , name ) ; ASM_OUTPUT_LABEL ( stream , name ) ; ASM_OUTPUT_SKIP ( stream , size ? size : 1 ) ; } } </s>


<s> void msp430_output_labelref ( FILE * file , const char * name ) { int i ; for ( i = 0 ; helper_function_name_mappings [ i ] . gcc_name ; i ++ ) if ( strcmp ( helper_function_name_mappings [ i ] . gcc_name , name ) == 0 ) { name = helper_function_name_mappings [ i ] . ti_name ; break ; } if ( msp430_hwmult_type != MSP430_HWMULT_NONE ) { if ( strcmp ( "__mspabi_mpyi" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulhi2_f5" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulhi2" ; } else if ( strcmp ( "__mspabi_mpyl" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulsi2_f5" ; else if ( use_32bit_hwmult ( ) ) name = "__mulsi2_hw32" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulsi2" ; } } fputs ( name , file ) ; } </s>


<s> bool msp430_use_f5_series_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_F5SERIES ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; if ( strncasecmp ( target_mcu , "msp430f5" , 8 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430fr5" , 9 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430f6" , 8 ) == 0 ) return cached_result = true ; int i ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 8 ; return cached_result = false ; } </s>


<s> static bool use_32bit_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; int i ; if ( msp430_hwmult_type == MSP430_HWMULT_LARGE ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; for ( i = ARRAY_SIZE ( msp430_mcu_data ) ; i -- ; ) if ( strcasecmp ( target_mcu , msp430_mcu_data [ i ] . name ) == 0 ) return cached_result = msp430_mcu_data [ i ] . hwmpy == 4 ; return cached_result = false ; } </s>


<s> static const char * gen_prefix ( tree decl ) { if ( DECL_ONE_ONLY ( decl ) ) return NULL ; if ( has_attr ( "section" , decl ) ) return NULL ; if ( has_section_name ( ".lowtext" , decl ) ) return NULL ; if ( has_attr ( ATTR_LOWER , decl ) ) return lower_prefix ; if ( ! msp430x ) return NULL ; if ( has_attr ( ATTR_UPPER , decl ) ) return upper_prefix ; if ( has_attr ( ATTR_EITHER , decl ) ) return either_prefix ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { if ( msp430_code_region == MSP430_REGION_LOWER ) return lower_prefix ; if ( msp430_code_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_code_region == MSP430_REGION_EITHER ) return either_prefix ; } else { if ( msp430_data_region == MSP430_REGION_LOWER ) return lower_prefix ; if ( msp430_data_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_data_region == MSP430_REGION_EITHER ) return either_prefix ; } return NULL ; } </s>


"numeric argument of %qE attribute must be in range 0..63"

"argument of %qE attribute is not a string constant or number"

"%qE attribute only applies to functions"

"critical functions cannot be reentrant"

"reentrant functions cannot be critical"


<s> int msp430_hard_regno_nregs_with_padding ( int regno ATTRIBUTE_UNUSED , machine_mode mode ) { if ( mode == PSImode ) return 2 ; if ( mode == CPSImode ) return 4 ; return msp430_hard_regno_nregs ( regno , mode ) ; } </s>


"critical attribute has no effect on interrupt functions"


<s> const char * msp430_mcu_name ( void ) { if ( target_mcu ) { unsigned int i ; unsigned int start_upper ; unsigned int end_upper ; static char mcu_name [ 64 ] ; if ( strncmp ( target_mcu , "msp430i" , 7 ) == 0 ) { snprintf ( mcu_name , sizeof ( mcu_name ) - 1 , "__MSP430i%s__" , target_mcu + 7 ) ; start_upper = 9 ; } else { snprintf ( mcu_name , sizeof ( mcu_name ) - 1 , "__%s__" , target_mcu ) ; start_upper = 2 ; } end_upper = strlen ( mcu_name ) - 2 ; for ( i = start_upper ; i < end_upper ; i ++ ) mcu_name [ i ] = TOUPPER ( mcu_name [ i ] ) ; return mcu_name ; } return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__" ; } </s>


<s> void msp430_output_labelref ( FILE * file , const char * name ) { int i ; for ( i = 0 ; helper_function_name_mappings [ i ] . gcc_name ; i ++ ) if ( strcmp ( helper_function_name_mappings [ i ] . gcc_name , name ) == 0 ) { name = helper_function_name_mappings [ i ] . ti_name ; break ; } if ( msp430_hwmult_type != MSP430_HWMULT_NONE ) { if ( strcmp ( "__mspabi_mpyi" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulhi2_f5" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulhi2" ; } else if ( strcmp ( "__mspabi_mpyl" , name ) == 0 ) { if ( msp430_use_f5_series_hwmult ( ) ) name = "__mulsi2_f5" ; else if ( use_32bit_hwmult ( ) ) name = "__mulsi2_hw32" ; else if ( ! msp430_no_hwmult ( ) ) name = "__mulsi2" ; } } if ( user_label_prefix [ 0 ] != 0 ) fputs ( user_label_prefix , file ) ; fputs ( name , file ) ; } </s>


<s> static int cg_magic_constant ( HOST_WIDE_INT c ) { switch ( c ) { case 0xffff : case - 1 : case 0 : case 1 : case 2 : case 4 : case 8 : return 1 ; default : return 0 ; } } </s>

These constants are really register reads , which are faster than regular constants .


<s> static rtx F ( rtx x ) { RTX_FRAME_RELATED_P ( x ) = 1 ; return x ; } </s>

We use this to wrap all emitted insns in the prologue , so they get the `` frame-related '' ( /f ) flag set .


<s> static const char * gen_prefix ( tree decl ) { if ( DECL_ONE_ONLY ( decl ) ) return NULL ; if ( has_attr ( "section" , decl ) ) return NULL ; if ( has_section_name ( ".lowtext" , decl ) ) return NULL ; if ( ! TARGET_LARGE ) return NULL ; if ( has_attr ( ATTR_LOWER , decl ) ) return lower_prefix ; if ( has_attr ( ATTR_UPPER , decl ) ) return upper_prefix ; if ( has_attr ( ATTR_EITHER , decl ) ) return either_prefix ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) { if ( ( msp430_code_region == MSP430_REGION_LOWER ) && TARGET_USE_LOWER_REGION_PREFIX ) return lower_prefix ; if ( msp430_code_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_code_region == MSP430_REGION_EITHER ) return either_prefix ; } else { if ( ( msp430_data_region == MSP430_REGION_LOWER ) && TARGET_USE_LOWER_REGION_PREFIX ) return lower_prefix ; if ( msp430_data_region == MSP430_REGION_UPPER ) return upper_prefix ; if ( msp430_data_region == MSP430_REGION_EITHER ) return either_prefix ; } return NULL ; } </s>


<s> static void increment_stack ( HOST_WIDE_INT amount ) { rtx inc ; rtx sp = stack_pointer_rtx ; if ( amount == 0 ) return ; if ( amount < 0 ) { inc = GEN_INT ( - amount ) ; if ( TARGET_LARGE ) F ( emit_insn ( gen_subpsi3 ( sp , sp , inc ) ) ) ; else F ( emit_insn ( gen_subhi3 ( sp , sp , inc ) ) ) ; } else { inc = GEN_INT ( amount ) ; if ( TARGET_LARGE ) F ( emit_insn ( gen_addpsi3 ( sp , sp , inc ) ) ) ; else F ( emit_insn ( gen_addhi3 ( sp , sp , inc ) ) ) ; } } </s>

Common code to change the stack pointer .


<s> static bool is_interrupt_func ( tree decl = current_function_decl ) { return has_attr ( ATTR_INTR , decl ) ; } </s>

Returns true if the provided function has the `` interrupt '' attribute .


<s> static inline bool is_naked_func ( tree decl = current_function_decl ) { return has_attr ( ATTR_NAKED , decl ) ; } </s>

Returns true if the provided function has the `` naked '' attribute .


Generate a sequence of instructions to sign-extend an HI value into an SI value . Handles the tricky case where we are overwriting the destination . Return the number of bytes used by the emitted instructions . If RETURN_LENGTH is true then do not emit the assembly instruction sequence .


<s> static rtx msp430_addr_space_convert ( rtx op , tree from_type , tree to_type ) { addr_space_t from_as = TYPE_ADDR_SPACE ( TREE_TYPE ( from_type ) ) ; addr_space_t to_as = TYPE_ADDR_SPACE ( TREE_TYPE ( to_type ) ) ; rtx result ; if ( to_as != ADDR_SPACE_FAR && from_as == ADDR_SPACE_FAR ) { if ( CONSTANT_P ( op ) ) return gen_rtx_CONST ( HImode , op ) ; result = gen_reg_rtx ( HImode ) ; emit_insn ( gen_truncpsihi2 ( result , op ) ) ; return result ; } else if ( to_as == ADDR_SPACE_FAR && from_as != ADDR_SPACE_FAR ) { if ( CONSTANT_P ( op ) ) return gen_rtx_CONST ( PSImode , op ) ; result = gen_reg_rtx ( PSImode ) ; emit_insn ( gen_zero_extendhipsi2 ( result , op ) ) ; return result ; } else gcc_unreachable ( ) ; } </s>

Convert from one address space to another .


"unrecognized interrupt vector argument of %qE attribute"

"numeric argument of %qE attribute must be in range [0-63]"

"argument of %qE attribute is not a string constant "

"%qE attribute only applies to functions"


<s> static bool msp430_check_index_not_high_mem ( rtx op ) { if ( CONST_INT_P ( op ) && IN_RANGE ( INTVAL ( op ) , HOST_WIDE_INT_M1U << 15 , ( 1 << 15 ) - 1 ) ) return true ; return false ; } </s>

We can only allow signed 15-bit indexes i.e . +/-32K .


<s> static bool msp430_check_plus_not_high_mem ( rtx op ) { if ( GET_CODE ( op ) != PLUS ) return false ; rtx op0 = XEXP ( op , 0 ) ; rtx op1 = XEXP ( op , 1 ) ; if ( SYMBOL_REF_P ( op0 ) && ( SYMBOL_REF_FLAGS ( op0 ) & SYMBOL_FLAG_LOW_MEM ) && msp430_check_index_not_high_mem ( op1 ) ) return true ; return false ; } </s>

If this returns true , we do n't need a 430X insn .


<s> static void msp430_compute_frame_info ( void ) { int i ; cfun -> machine -> computed = 1 ; cfun -> machine -> framesize_regs = 0 ; cfun -> machine -> framesize_locals = get_frame_size ( ) ; cfun -> machine -> framesize_outgoing = crtl -> outgoing_args_size ; for ( i = 0 ; i < ARG_POINTER_REGNUM ; i ++ ) if ( msp430_preserve_reg_p ( i ) ) { cfun -> machine -> need_to_save [ i ] = 1 ; cfun -> machine -> framesize_regs += ( TARGET_LARGE ? 4 : 2 ) ; } else cfun -> machine -> need_to_save [ i ] = 0 ; if ( ( cfun -> machine -> framesize_locals + cfun -> machine -> framesize_outgoing ) & 1 ) cfun -> machine -> framesize_locals ++ ; cfun -> machine -> framesize = ( cfun -> machine -> framesize_regs + cfun -> machine -> framesize_locals + cfun -> machine -> framesize_outgoing ) ; } </s>

Compute all the frame-related fields in our machine_function structure .


<s> static int msp430_costs ( rtx src , rtx dst , bool speed , rtx outer_rtx ) { enum rtx_code src_code = GET_CODE ( src ) ; enum rtx_code dst_code = GET_CODE ( dst ) ; enum rtx_code outer_code = GET_CODE ( outer_rtx ) ; machine_mode outer_mode = GET_MODE ( outer_rtx ) ; const struct double_op_cost * cost_p ; cost_p = ( speed ? & cycle_cost_double_op : & size_cost_double_op ) ; if ( outer_code == TRUNCATE && ( outer_mode == QImode || outer_mode == HImode || outer_mode == PSImode ) ) return 0 ; if ( dst_code == SYMBOL_REF || dst_code == LABEL_REF || dst_code == CONST_INT ) return 0 ; switch ( src_code ) { case REG : return ( dst_code == REG ? cost_p -> r2r : ( dst_code == PC ? cost_p -> r2pc : cost_p -> r2m ) ) ; case CONST_INT : case SYMBOL_REF : case LABEL_REF : case CONST : return ( dst_code == REG ? cost_p -> imm2r : ( dst_code == PC ? cost_p -> imm2pc : cost_p -> imm2m ) ) ; case MEM : if ( msp430_is_mem_indirect ( src ) ) return ( dst_code == REG ? cost_p -> ind2r : ( dst_code == PC ? cost_p -> ind2pc : cost_p -> ind2m ) ) ; else return ( dst_code == REG ? cost_p -> mem2r : ( dst_code == PC ? cost_p -> mem2pc : cost_p -> mem2m ) ) ; default : return cost_p -> mem2m ; } } </s>

Costs of MSP430 instructions are generally based on the addressing mode combination of the source and destination operands . Given source operand SRC ( which may be NULL to indicate a single-operand instruction ) and destination operand DST return the cost of this expression .


<s> rtx msp430_eh_return_stackadj_rtx ( void ) { if ( ! cfun -> machine -> eh_stack_adjust ) { rtx sa ; sa = gen_rtx_REG ( Pmode , 15 ) ; cfun -> machine -> eh_stack_adjust = sa ; } return cfun -> machine -> eh_stack_adjust ; } </s>

Implements EH_RETURN_STACKADJ_RTX . Saved and used later in m32c_emit_eh_epilogue .


<s> static void msp430_encode_section_info ( tree decl , rtx rtl , int first ) { rtx symbol ; default_encode_section_info ( decl , rtl , first ) ; if ( ! MEM_P ( rtl ) ) return ; symbol = XEXP ( rtl , 0 ) ; if ( GET_CODE ( symbol ) != SYMBOL_REF ) return ; if ( VAR_P ( decl ) && ( TREE_STATIC ( decl ) || DECL_EXTERNAL ( decl ) ) && msp430_var_in_low_mem ( decl ) ) SYMBOL_REF_FLAGS ( symbol ) = SYMBOL_FLAG_LOW_MEM ; } </s>

Encode whether a SYMBOL_REF is definitely in the lower memory region .


<s> static void msp430_evaluate_arg ( cumulative_args_t cap , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ) { CUMULATIVE_ARGS * ca = get_cumulative_args ( cap ) ; int nregs = GET_MODE_SIZE ( mode ) ; int i ; ca -> reg_count = 0 ; ca -> mem_count = 0 ; if ( ! named ) return ; if ( mode == PSImode ) nregs = 1 ; else nregs = ( nregs + 1 ) / 2 ; if ( ca -> special_p ) { ca -> start_reg = 8 ; ca -> reg_count = 4 ; return ; } switch ( nregs ) { case 1 : for ( i = 0 ; i < 4 ; i ++ ) if ( ! ca -> reg_used [ i ] ) { ca -> reg_count = 1 ; ca -> start_reg = CA_FIRST_REG + i ; return ; } break ; case 2 : for ( i = 0 ; i < 3 ; i ++ ) if ( ! ca -> reg_used [ i ] && ! ca -> reg_used [ i + 1 ] ) { ca -> reg_count = 2 ; ca -> start_reg = CA_FIRST_REG + i ; return ; } if ( ! ca -> reg_used [ 3 ] && ca -> can_split ) { ca -> reg_count = 1 ; ca -> mem_count = 2 ; ca -> start_reg = CA_FIRST_REG + 3 ; return ; } break ; case 3 : case 4 : ca -> can_split = 0 ; if ( ! ca -> reg_used [ 0 ] && ! ca -> reg_used [ 1 ] && ! ca -> reg_used [ 2 ] && ! ca -> reg_used [ 3 ] ) { ca -> reg_count = 4 ; ca -> start_reg = CA_FIRST_REG ; return ; } break ; } } </s>

Helper function for argument passing ; this function is the common code that determines where an argument will be passed .


<s> void msp430_expand_eh_return ( rtx eh_handler ) { rtx ap , sa , ra , tmp ; ap = arg_pointer_rtx ; sa = msp430_eh_return_stackadj_rtx ( ) ; ra = eh_handler ; tmp = ap ; tmp = gen_rtx_PLUS ( Pmode , ap , sa ) ; tmp = plus_constant ( Pmode , tmp , TARGET_LARGE ? - 4 : - 2 ) ; tmp = gen_rtx_MEM ( Pmode , tmp ) ; emit_move_insn ( tmp , ra ) ; } </s>

This function is called before reload , to `` fix '' the stack in preparation for an EH return .


<s> void msp430_expand_helper ( rtx * operands , const char * helper_name , bool const_variants ) { rtx c , fusage , fsym ; char * helper_const = NULL ; int arg1 = 12 ; int arg2 = 13 ; int arg1sz = 1 ; machine_mode arg0mode = GET_MODE ( operands [ 0 ] ) ; machine_mode arg1mode = GET_MODE ( operands [ 1 ] ) ; machine_mode arg2mode = GET_MODE ( operands [ 2 ] ) ; int expand_mpy = startswith ( helper_name , "__mspabi_mpy" ) ; gcc_assert ( ! ( expand_mpy && const_variants ) ) ; if ( arg1mode != VOIDmode && arg2mode != VOIDmode ) gcc_assert ( arg1mode == arg2mode ) ; if ( arg1mode == VOIDmode ) arg1mode = arg0mode ; if ( arg2mode == VOIDmode ) arg2mode = arg0mode ; if ( arg1mode == SImode ) { arg2 = 14 ; arg1sz = 2 ; } else if ( arg1mode == DImode ) { arg1 = 8 ; arg1sz = 4 ; arg2 = 12 ; } if ( const_variants && CONST_INT_P ( operands [ 2 ] ) && INTVAL ( operands [ 2 ] ) >= 1 && INTVAL ( operands [ 2 ] ) <= 15 ) { int len = strlen ( helper_name ) + 4 ; helper_const = ( char * ) xmalloc ( len ) ; snprintf ( helper_const , len , "%s_%d" , helper_name , ( int ) INTVAL ( operands [ 2 ] ) ) ; } emit_move_insn ( gen_rtx_REG ( arg1mode , arg1 ) , operands [ 1 ] ) ; if ( ! helper_const ) emit_move_insn ( gen_rtx_REG ( arg2mode , arg2 ) , operands [ 2 ] ) ; if ( expand_mpy ) { if ( msp430_use_f5_series_hwmult ( ) ) fsym = gen_rtx_SYMBOL_REF ( VOIDmode , concat ( helper_name , "_f5hw" , NULL ) ) ; else if ( msp430_use_32bit_hwmult ( ) ) { if ( arg1mode == HImode ) fsym = gen_rtx_SYMBOL_REF ( VOIDmode , concat ( helper_name , "_hw" , NULL ) ) ; else fsym = gen_rtx_SYMBOL_REF ( VOIDmode , concat ( helper_name , "_hw32" , NULL ) ) ; } else if ( msp430_use_16bit_hwmult ( ) ) fsym = gen_rtx_SYMBOL_REF ( VOIDmode , concat ( helper_name , "_hw" , NULL ) ) ; else fsym = gen_rtx_SYMBOL_REF ( VOIDmode , helper_name ) ; } else fsym = gen_rtx_SYMBOL_REF ( VOIDmode , helper_const ? helper_const : helper_name ) ; c = gen_call_value_internal ( gen_rtx_REG ( arg0mode , 12 ) , fsym , GEN_INT ( 0 ) ) ; c = emit_call_insn ( c ) ; RTL_CONST_CALL_P ( c ) = 1 ; fusage = NULL ; use_regs ( & fusage , arg1 , arg1sz ) ; if ( ! helper_const ) { if ( ! expand_mpy ) use_regs ( & fusage , arg2 , 1 ) ; else use_regs ( & fusage , arg2 , arg1sz ) ; } add_function_usage_to ( c , fusage ) ; emit_move_insn ( operands [ 0 ] , gen_rtx_REG ( arg0mode , 12 ) ) ; } </s>

The MSP430 ABI defines a number of helper functions that should be used for , for example , 32-bit shifts . This function is called to emit such a function , using the table above to optimize some cases .


<s> int msp430_expand_shift ( enum rtx_code code , machine_mode mode , rtx * operands ) { if ( ! CONST_INT_P ( operands [ 2 ] ) || mode == E_DImode || use_helper_for_const_shift ( mode , INTVAL ( operands [ 2 ] ) ) ) { const char * helper_name = NULL ; bool const_variant = ! optimize_size ; switch ( mode ) { case E_HImode : helper_name = ( code == ASHIFT ? "__mspabi_slli" : ( code == ASHIFTRT ? "__mspabi_srai" : ( code == LSHIFTRT ? "__mspabi_srli" : NULL ) ) ) ; break ; case E_PSImode : helper_name = ( code == ASHIFT ? "__gnu_mspabi_sllp" : ( code == ASHIFTRT ? "__gnu_mspabi_srap" : ( code == LSHIFTRT ? "__gnu_mspabi_srlp" : NULL ) ) ) ; const_variant = false ; break ; case E_SImode : helper_name = ( code == ASHIFT ? "__mspabi_slll" : ( code == ASHIFTRT ? "__mspabi_sral" : ( code == LSHIFTRT ? "__mspabi_srll" : NULL ) ) ) ; break ; case E_DImode : helper_name = ( code == ASHIFT ? "__mspabi_sllll" : ( code == ASHIFTRT ? "__mspabi_srall" : ( code == LSHIFTRT ? "__mspabi_srlll" : NULL ) ) ) ; const_variant = false ; break ; default : gcc_unreachable ( ) ; break ; } gcc_assert ( helper_name ) ; msp430_expand_helper ( operands , helper_name , const_variant ) ; return 1 ; } return 0 ; } </s>

For shift operations which will use an mspabi helper function , setup the call to msp430_expand helper . Return 1 to indicate we have finished with this insn and invoke `` DONE '' . Otherwise return 0 to indicate the insn should fallthrough . Never FAIL .


Emit MSPABI and GNU object attributes . Tags and values for MSPABI attributes are : OFBA_MSPABI_Tag_ISA 4 MSP430 1 MSP430X 2 OFBA_MSPABI_Tag_Code_Model 6 Small 1 Large 2 OFBA_MSPABI_Tag_Data_Model 8 Small 1 Large 2 Restricted 3 ( Unused by GNU ) OFBA_MSPABI_Tag_enum_size 10 ( Unused by GNU ) Note that Code_Model and Data_Model are always equal for GNU . We define a new .gnu_attribute to keep track of the data region used . Tag_GNU_MSP430_Data_Region 4 LOWER 1 ANY 2 See binutils-gdb/include/elf/msp430.h for the full details .


<s> void msp430_fixup_compare_operands ( machine_mode my_mode , rtx * operands ) { int const_op_idx = 1 ; if ( msp430_reversible_cmp_operator ( operands [ 0 ] , VOIDmode ) ) const_op_idx = 2 ; if ( GET_CODE ( operands [ const_op_idx ] ) != REG && GET_CODE ( operands [ const_op_idx ] ) != MEM ) operands [ const_op_idx ] = copy_to_mode_reg ( my_mode , operands [ const_op_idx ] ) ; } </s>

Called by cbranch < mode > 4 to coerce operands into usable forms .


<s> static rtx msp430_get_inner_dest_code ( rtx x ) { enum rtx_code code = GET_CODE ( x ) ; rtx op0 = XEXP ( x , 0 ) ; switch ( code ) { case REG : case SYMBOL_REF : case CONST_INT : case CONST : case LABEL_REF : return x ; case MEM : switch ( GET_CODE ( op0 ) ) { case REG : case SYMBOL_REF : case LABEL_REF : case CONST : case POST_INC : return x ; case PLUS : if ( GET_CODE ( XEXP ( op0 , 0 ) ) == REG ) { if ( GET_CODE ( XEXP ( op0 , 1 ) ) == CONST_INT || GET_CODE ( XEXP ( op0 , 1 ) ) == CONST || GET_CODE ( XEXP ( op0 , 1 ) ) == LABEL_REF || GET_CODE ( XEXP ( op0 , 1 ) ) == SYMBOL_REF ) return x ; else return msp430_get_inner_dest_code ( op0 ) ; } return msp430_get_inner_dest_code ( op0 ) ; default : if ( GET_RTX_FORMAT ( code ) [ 0 ] != 'e' ) return x ; return msp430_get_inner_dest_code ( op0 ) ; } break ; default : if ( op0 == NULL_RTX ) gcc_unreachable ( ) ; else { if ( GET_RTX_FORMAT ( code ) [ 0 ] != 'e' && code != ENTRY_VALUE ) return x ; return msp430_get_inner_dest_code ( op0 ) ; } } } </s>

Recurse within X to find the actual destination operand of the expression . For example : ( plus ( ashift ( minus ( ashift ( reg ) ( const_int ) ...... should return the reg RTX .


<s> static bool msp430_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { return regno <= ( ARG_POINTER_REGNUM - ( unsigned int ) msp430_hard_regno_nregs ( regno , mode ) ) ; } </s>


<s> static unsigned int msp430_hard_regno_nregs ( unsigned int , machine_mode mode ) { if ( mode == PSImode && msp430x ) return 1 ; if ( mode == CPSImode && msp430x ) return 2 ; return ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; } </s>

Implements HARD_REGNO_NREGS . MSP430X registers can hold a single PSImode value , but not an SImode value .


<s> bool msp430_has_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_NONE ) return false ; if ( msp430_hwmult_type != MSP430_HWMULT_AUTO ) return true ; if ( target_mcu == NULL ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; msp430_extract_mcu_data ( target_mcu ) ; if ( extracted_mcu_data . name != NULL ) return cached_result = extracted_mcu_data . hwmpy != 0 ; return cached_result = false ; } </s>

Returns true if the current MCU does not have a hardware multiplier of any kind .


<s> int msp430_initial_elimination_offset ( int from , int to ) { int rv = 0 ; msp430_compute_frame_info ( ) ; switch ( to ) { case STACK_POINTER_REGNUM : rv += cfun -> machine -> framesize_outgoing ; rv += cfun -> machine -> framesize_locals ; case FRAME_POINTER_REGNUM : rv += cfun -> machine -> framesize_regs ; rv += ( TARGET_LARGE ? 4 : 2 ) ; break ; default : gcc_unreachable ( ) ; } switch ( from ) { case FRAME_POINTER_REGNUM : rv -= ( TARGET_LARGE ? 4 : 2 ) ; rv -= cfun -> machine -> framesize_regs ; case ARG_POINTER_REGNUM : break ; default : gcc_unreachable ( ) ; } return rv ; } </s>


<s> void msp430_init_cumulative_args ( CUMULATIVE_ARGS * ca , tree fntype ATTRIBUTE_UNUSED , rtx libname ATTRIBUTE_UNUSED , tree fndecl ATTRIBUTE_UNUSED , int n_named_args ATTRIBUTE_UNUSED ) { const char * fname ; memset ( ca , 0 , sizeof ( * ca ) ) ; ca -> can_split = 1 ; if ( fndecl ) fname = IDENTIFIER_POINTER ( DECL_NAME ( fndecl ) ) ; else if ( libname ) fname = XSTR ( libname , 0 ) ; else fname = NULL ; if ( fname && msp430_special_register_convention_p ( fname ) ) ca -> special_p = 1 ; } </s>


<s> static struct machine_function * msp430_init_machine_status ( void ) { struct machine_function * m ; m = ggc_cleared_alloc < machine_function > ( ) ; return m ; } </s>

This is our init_machine_status , as set in msp_option_override .


<s> bool msp430_is_interrupt_func ( void ) { return is_interrupt_func ( current_function_decl ) ; } </s>

Returns true if the current function has the `` interrupt '' attribute .


<s> static bool msp430_is_mem_indirect ( rtx x ) { gcc_assert ( GET_CODE ( x ) == MEM ) ; rtx op0 = XEXP ( x , 0 ) ; return ( GET_CODE ( op0 ) == REG || GET_CODE ( op0 ) == POST_INC ) ; } </s>

For X , which must be a MEM RTX , return TRUE if it is an indirect memory reference , @ Rn or @ Rn+ .


<s> const char * msp430_mcu_name ( void ) { if ( target_mcu ) { msp430_extract_mcu_data ( target_mcu ) ; unsigned int i ; unsigned int start_upper ; unsigned int end_upper ; static char mcu_name [ 64 ] ; if ( startswith ( target_mcu , "msp430i" ) ) { snprintf ( mcu_name , sizeof ( mcu_name ) - 1 , "__MSP430i%s__" , target_mcu + 7 ) ; start_upper = 9 ; } else { snprintf ( mcu_name , sizeof ( mcu_name ) - 1 , "__%s__" , target_mcu ) ; start_upper = 2 ; } end_upper = strlen ( mcu_name ) - 2 ; for ( i = start_upper ; i < end_upper ; i ++ ) mcu_name [ i ] = TOUPPER ( mcu_name [ i ] ) ; return mcu_name ; } return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__" ; } </s>

Generate a C preprocessor symbol based upon the MCU selected by the user . If a specific MCU has not been selected then return a generic symbol instead .


<s> static int msp430_memory_move_cost ( machine_mode mode ATTRIBUTE_UNUSED , reg_class_t rclass ATTRIBUTE_UNUSED , bool in ) { int cost ; const struct double_op_cost * cost_p ; bool speed = ( ! optimize_size && optimize >= 2 ) ; cost_p = ( speed ? & cycle_cost_double_op_mov : & size_cost_double_op ) ; if ( in ) cost = cost_p -> ind2r ; else cost = cost_p -> r2m ; return 2 * cost ; } </s>

Return the cost of moving data between registers and memory . The returned cost must be relative to the default TARGET_REGISTER_MOVE_COST of 2 . IN is false if the value is to be written to memory .


<s> static bool msp430_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { if ( ( mode1 == PSImode || mode2 == SImode ) || ( mode1 == SImode || mode2 == PSImode ) ) return false ; return ( ( GET_MODE_CLASS ( mode1 ) == MODE_FLOAT || GET_MODE_CLASS ( mode1 ) == MODE_COMPLEX_FLOAT ) == ( GET_MODE_CLASS ( mode2 ) == MODE_FLOAT || GET_MODE_CLASS ( mode2 ) == MODE_COMPLEX_FLOAT ) ) ; } </s>


<s> static int msp430_muldiv_costs ( rtx src , rtx dst , bool speed , rtx outer_rtx , machine_mode outer_mode ) { enum rtx_code outer_code = GET_CODE ( outer_rtx ) ; const struct msp430_multlib_costs * cost_p ; cost_p = ( msp430_use_16bit_hwmult ( ) ? & cycle_cost_multlib_32bit : & cycle_cost_multlib_16bit ) ; int factor = 1 ; int mode_factor = 1 ; if ( outer_mode == SImode ) mode_factor = 2 ; else if ( outer_mode == PSImode ) mode_factor = 3 ; else if ( outer_mode == DImode ) mode_factor = 4 ; if ( ! speed ) { if ( outer_code != MULT ) factor = 7 ; else if ( ( ( msp430_use_16bit_hwmult ( ) && outer_mode != DImode ) || msp430_use_32bit_hwmult ( ) || msp430_use_f5_series_hwmult ( ) ) ) factor = 2 ; else factor = 5 ; return factor * mode_factor * msp430_costs ( src , dst , speed , outer_rtx ) ; } if ( outer_code != MULT || ! msp430_has_hwmult ( ) || ( outer_mode == DImode && msp430_use_16bit_hwmult ( ) ) ) { factor = ( outer_code == MULT ? 50 : 70 ) ; return factor * mode_factor * msp430_costs ( src , dst , speed , outer_rtx ) ; } switch ( outer_mode ) { case E_QImode : case E_HImode : return cost_p -> mulhi + ( 3 * msp430_costs ( src , dst , speed , outer_rtx ) ) ; case E_PSImode : factor = 2 ; case E_SImode : return factor * ( cost_p -> mulsi + ( 6 * msp430_costs ( src , dst , speed , outer_rtx ) ) ) ; case E_DImode : default : return cost_p -> muldi + ( 12 * msp430_costs ( src , dst , speed , outer_rtx ) ) ; } } </s>

Given source operand SRC and destination operand DST from the MULT/DIV/MOD RTX OUTER_RTX , return the cost of performing that operation , assuming optimization for speed when SPEED is true .


<s> bool msp430_op_not_in_high_mem ( rtx op ) { rtx op0 ; if ( ! TARGET_LARGE || ! MEM_P ( op ) ) return true ; op0 = XEXP ( op , 0 ) ; if ( SYMBOL_REF_P ( op0 ) && ( SYMBOL_REF_FLAGS ( op0 ) & SYMBOL_FLAG_LOW_MEM ) ) return true ; if ( msp430_check_plus_not_high_mem ( op0 ) || ( ( GET_CODE ( op0 ) == CONST ) && msp430_check_plus_not_high_mem ( XEXP ( op0 , 0 ) ) ) ) return true ; if ( ( CONST_INT_P ( op0 ) && ( IN_RANGE ( INTVAL ( op0 ) , 0 , ( 1 << 16 ) - 1 ) ) ) ) return true ; return false ; } </s>

Determine whether an RTX is definitely not a MEM referencing an address in the upper memory region . Returns true if we 've decided the address will be in the lower memory region , or the RTX is not a MEM . Returns false otherwise . The Ys constraint will catch ( mem ( plus ( const/reg ) ) but we catch cases involving a symbol_ref here .


<s> void msp430_output_aligned_decl_common ( FILE * stream , const tree decl , const char * name , unsigned HOST_WIDE_INT size , unsigned int align , int local ) { if ( ( msp430_data_region == MSP430_REGION_ANY || ( ( msp430_data_region == MSP430_REGION_LOWER ) && ! TARGET_USE_LOWER_REGION_PREFIX ) ) && ! ( decl != NULL_TREE && DECL_SECTION_NAME ( decl ) ) && ! has_attr ( ATTR_EITHER , decl ) && ! has_attr ( ATTR_LOWER , decl ) && ! has_attr ( ATTR_UPPER , decl ) && ! has_attr ( ATTR_PERSIST , decl ) && ! has_attr ( ATTR_NOINIT , decl ) ) { if ( local ) { fprintf ( stream , LOCAL_ASM_OP ) ; assemble_name ( stream , name ) ; fprintf ( stream , "\n" ) ; } fprintf ( stream , COMMON_ASM_OP ) ; assemble_name ( stream , name ) ; fprintf ( stream , "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n" , size , align / BITS_PER_UNIT ) ; } else { section * sec ; if ( decl ) sec = msp430_select_section ( decl , 0 , align ) ; else switch ( msp430_data_region ) { case MSP430_REGION_UPPER : sec = get_named_section ( NULL , ".upper.bss" , 0 ) ; break ; case MSP430_REGION_LOWER : sec = get_named_section ( NULL , ".lower.bss" , 0 ) ; break ; case MSP430_REGION_EITHER : sec = get_named_section ( NULL , ".either.bss" , 0 ) ; break ; default : gcc_unreachable ( ) ; } gcc_assert ( sec != NULL ) ; switch_to_section ( sec ) ; ASM_OUTPUT_ALIGN ( stream , floor_log2 ( align / BITS_PER_UNIT ) ) ; if ( ! local ) { targetm . asm_out . globalize_label ( stream , name ) ; ASM_WEAKEN_LABEL ( stream , name ) ; } ASM_OUTPUT_LABEL ( stream , name ) ; ASM_OUTPUT_SKIP ( stream , size ? size : 1 ) ; } } </s>

Emit a declaration of a common symbol . If a data region is in use then put the symbol into the equivalent .bss section instead . If LOCAL is 1 , then DECL is for a local common variable .


<s> void msp430_output_labelref ( FILE * file , const char * name ) { int i ; for ( i = 0 ; helper_function_name_mappings [ i ] . gcc_name ; i ++ ) if ( strcmp ( helper_function_name_mappings [ i ] . gcc_name , name ) == 0 ) { name = helper_function_name_mappings [ i ] . ti_name ; break ; } if ( user_label_prefix [ 0 ] != 0 ) fputs ( user_label_prefix , file ) ; fputs ( name , file ) ; } </s>

This function does the same as the default , but it will replace GCC function names with the MSPABI-specified ones .


<s> static bool msp430_preserve_reg_p ( int regno ) { if ( regno <= 3 ) return false ; if ( crtl -> calls_eh_return ) return true ; if ( fixed_regs [ regno ] ) return false ; if ( msp430_is_interrupt_func ( ) && regno >= 11 && regno <= 15 ) { if ( crtl -> is_leaf && df_regs_ever_live_p ( regno ) ) return true ; else if ( ! crtl -> is_leaf ) return true ; } if ( ! call_used_or_fixed_reg_p ( regno ) && df_regs_ever_live_p ( regno ) ) return true ; return false ; } </s>

This is the one spot that decides if a register is to be saved and restored in the prologue/epilogue .


<s> static void msp430_print_operand_addr ( FILE * file , machine_mode , rtx addr ) { switch ( GET_CODE ( addr ) ) { case PLUS : msp430_print_operand_raw ( file , XEXP ( addr , 1 ) ) ; gcc_assert ( REG_P ( XEXP ( addr , 0 ) ) ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( XEXP ( addr , 0 ) ) ] ) ; return ; case REG : fprintf ( file , "@" ) ; break ; case POST_INC : fprintf ( file , "@%s+" , reg_names [ REGNO ( XEXP ( addr , 0 ) ) ] ) ; return ; case CONST : case CONST_INT : case SYMBOL_REF : case LABEL_REF : fprintf ( file , "&" ) ; break ; default : break ; } msp430_print_operand_raw ( file , addr ) ; } </s>

Output to stdio stream FILE the assembler syntax for an instruction operand that is a memory reference whose address is ADDR .


<s> static void msp430_print_operand_raw ( FILE * file , rtx op ) { HOST_WIDE_INT i ; switch ( GET_CODE ( op ) ) { case REG : fprintf ( file , "%s" , reg_names [ REGNO ( op ) ] ) ; break ; case CONST_INT : i = INTVAL ( op ) ; if ( TARGET_ASM_HEX ) fprintf ( file , "%#" HOST_WIDE_INT_PRINT "x" , i ) ; else fprintf ( file , "%" HOST_WIDE_INT_PRINT "d" , i ) ; break ; case CONST : case PLUS : case MINUS : case SYMBOL_REF : case LABEL_REF : output_addr_const ( file , op ) ; break ; default : print_rtl ( file , op ) ; break ; } } </s>

Common code for msp430_print_operand ...


<s> void msp430_register_pre_includes ( const char * sysroot ATTRIBUTE_UNUSED , const char * iprefix ATTRIBUTE_UNUSED , int stdinc ATTRIBUTE_UNUSED ) { char * include_dir ; if ( msp430_devices_csv_loc ) include_dir = xstrdup ( msp430_devices_csv_loc ) ; else if ( msp430_check_env_var_for_devices ( & include_dir ) ) return ; include_dir = msp430_dirname ( include_dir ) ; include_dir = update_path ( include_dir , "" ) ; add_path ( include_dir , INC_SYSTEM , false , false ) ; } </s>

If the path to the MSP430-GCC support files has been found by examining an environment variable ( see msp430_check_env_var_for_devices in msp430-devices.cc ) , or -mdevices-csv-loc= , register this path as an include directory so the user can # include msp430.h without needing to specify the path to the support files with -I .


<s> rtx msp430_return_addr_rtx ( int count ) { int ra_size ; if ( count ) return NULL_RTX ; ra_size = TARGET_LARGE ? 4 : 2 ; if ( crtl -> args . pretend_args_size ) ra_size += 2 ; return gen_rtx_MEM ( Pmode , gen_rtx_PLUS ( Pmode , arg_pointer_rtx , GEN_INT ( - ra_size ) ) ) ; } </s>


<s> static int msp430_shift_costs ( rtx src , rtx dst , bool speed , rtx outer_rtx ) { int amt ; enum rtx_code src_code = GET_CODE ( src ) ; enum rtx_code dst_code = GET_CODE ( dst ) ; const struct single_op_cost * cost_p ; cost_p = ( speed ? & cycle_cost_single_op : & size_cost_single_op ) ; if ( src_code != CONST_INT ) return 2 * msp430_costs ( src , dst , speed , outer_rtx ) ; if ( use_helper_for_const_shift ( GET_MODE ( outer_rtx ) , amt = INTVAL ( src ) ) ) { return msp430_costs ( src , dst , speed , outer_rtx ) ; } if ( ! msp430x ) { switch ( dst_code ) { case REG : case CONST_INT : return amt * cost_p -> reg ; case MEM : if ( msp430_is_mem_indirect ( dst ) ) return amt * cost_p -> ind ; else return amt * cost_p -> mem ; default : return amt * cost_p -> mem ; } } return ( amt <= 4 ? ( speed ? amt : 1 ) : ( speed ? amt + 1 : 2 ) + ( dst_code == REG ? 0 : msp430_costs ( dst , gen_rtx_REG ( HImode , 10 ) , speed , outer_rtx ) ) ) ; } </s>

Given source operand SRC and destination operand DST from the shift or rotate RTX OUTER_RTX , return the cost of performing that shift , assuming optimization for speed when SPEED is true .


<s> static int msp430_single_op_cost ( rtx dst , bool speed , rtx outer_rtx ) { enum rtx_code dst_code = GET_CODE ( dst ) ; const struct single_op_cost * cost_p ; const struct double_op_cost * double_op_cost_p ; cost_p = ( speed ? & cycle_cost_single_op : & size_cost_single_op ) ; double_op_cost_p = ( speed ? & cycle_cost_double_op : & size_cost_double_op ) ; switch ( dst_code ) { case REG : return cost_p -> reg ; case MEM : if ( msp430_is_mem_indirect ( dst ) ) return cost_p -> ind ; else return cost_p -> mem ; case CONST_INT : case CONST_FIXED : case CONST_DOUBLE : case SYMBOL_REF : case CONST : return double_op_cost_p -> imm2r + cost_p -> reg ; default : return cost_p -> mem ; } } </s>

Calculate the cost of an MSP430 single-operand instruction , for operand DST within the RTX OUTER_RTX , optimizing for speed if SPEED is true .


<s> static bool msp430_special_register_convention_p ( const char * name ) { int i ; for ( i = 0 ; special_convention_function_names [ i ] ; i ++ ) if ( ! strcmp ( name , special_convention_function_names [ i ] ) ) return true ; return false ; } </s>

TRUE if the function passed is a `` speical '' function . Special functions pass two DImode parameters in registers .


<s> void msp430_split_movsi ( rtx * operands ) { rtx op00 , op02 , op10 , op12 ; op00 = msp430_subreg ( HImode , operands [ 0 ] , SImode , 0 ) ; op02 = msp430_subreg ( HImode , operands [ 0 ] , SImode , 2 ) ; if ( GET_CODE ( operands [ 1 ] ) == CONST || GET_CODE ( operands [ 1 ] ) == SYMBOL_REF ) { op10 = gen_rtx_ZERO_EXTRACT ( HImode , operands [ 1 ] , GEN_INT ( 16 ) , GEN_INT ( 0 ) ) ; op10 = gen_rtx_CONST ( HImode , op10 ) ; op12 = gen_rtx_ZERO_EXTRACT ( HImode , operands [ 1 ] , GEN_INT ( 16 ) , GEN_INT ( 16 ) ) ; op12 = gen_rtx_CONST ( HImode , op12 ) ; } else { op10 = msp430_subreg ( HImode , operands [ 1 ] , SImode , 0 ) ; op12 = msp430_subreg ( HImode , operands [ 1 ] , SImode , 2 ) ; } if ( rtx_equal_p ( operands [ 0 ] , operands [ 1 ] ) ) { operands [ 2 ] = op02 ; operands [ 4 ] = op12 ; operands [ 3 ] = op00 ; operands [ 5 ] = op10 ; } else if ( rtx_equal_p ( op00 , op12 ) || ( REG_P ( op00 ) && reg_mentioned_p ( op00 , op10 ) ) || ( REG_P ( op10 ) && reg_mentioned_p ( op10 , op00 ) ) ) { operands [ 2 ] = op02 ; operands [ 4 ] = op12 ; operands [ 3 ] = op00 ; operands [ 5 ] = op10 ; } else { operands [ 2 ] = op00 ; operands [ 4 ] = op10 ; operands [ 3 ] = op02 ; operands [ 5 ] = op12 ; } } </s>

Called by movsi_x to generate the HImode operands .


<s> rtx msp430_subreg ( machine_mode mode , rtx r , machine_mode omode , int byte ) { rtx rv ; gcc_assert ( mode == HImode ) ; if ( GET_CODE ( r ) == SUBREG && SUBREG_BYTE ( r ) == 0 ) { rtx ireg = SUBREG_REG ( r ) ; machine_mode imode = GET_MODE ( ireg ) ; if ( imode == PSImode && mode == HImode && byte == 0 ) rv = gen_rtx_SUBREG ( mode , ireg , byte ) ; else rv = simplify_gen_subreg ( mode , ireg , imode , byte ) ; } else if ( GET_CODE ( r ) == MEM ) { if ( GET_CODE ( XEXP ( r , 0 ) ) == POST_INC && byte == 2 ) byte = 0 ; rv = adjust_address ( r , mode , byte ) ; } else if ( GET_CODE ( r ) == SYMBOL_REF && ( byte == 0 || byte == 2 ) && mode == HImode ) { rv = gen_rtx_ZERO_EXTRACT ( HImode , r , GEN_INT ( 16 ) , GEN_INT ( 8 * byte ) ) ; rv = gen_rtx_CONST ( HImode , r ) ; } else rv = simplify_gen_subreg ( mode , r , omode , byte ) ; if ( ! rv ) gcc_unreachable ( ) ; return rv ; } </s>

Simplify_gen_subreg ( ) does n't handle memory references the way we need it to below , so we use this function for when we must get a valid subreg in a `` natural '' state .


<s> static bool msp430_use_16bit_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_SMALL ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; msp430_extract_mcu_data ( target_mcu ) ; if ( extracted_mcu_data . name != NULL ) return cached_result = ( extracted_mcu_data . hwmpy == 1 || extracted_mcu_data . hwmpy == 2 ) ; return cached_result = false ; } </s>

Returns true if the current MCU has a first generation 16-bit hardware multiplier .


<s> static bool msp430_use_32bit_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_LARGE ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; msp430_extract_mcu_data ( target_mcu ) ; if ( extracted_mcu_data . name != NULL ) return cached_result = extracted_mcu_data . hwmpy == 4 ; return cached_result = false ; } </s>

Returns true if the current MCU has a second generation 32-bit hardware multiplier .


<s> bool msp430_use_f5_series_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_F5SERIES ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; if ( strncasecmp ( target_mcu , "msp430f5" , 8 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430fr5" , 9 ) == 0 ) return cached_result = true ; if ( strncasecmp ( target_mcu , "msp430f6" , 8 ) == 0 ) return cached_result = true ; msp430_extract_mcu_data ( target_mcu ) ; if ( extracted_mcu_data . name != NULL ) return cached_result = extracted_mcu_data . hwmpy == 8 ; return cached_result = false ; } </s>

Returns true if the current MCU supports an F5xxx series hardware multiper .


<s> static bool msp430_var_in_low_mem ( tree decl ) { gcc_assert ( VAR_P ( decl ) ) ; if ( has_attr ( ATTR_UPPER , decl ) || has_attr ( ATTR_EITHER , decl ) || has_attr ( ATTR_PERSIST , decl ) || ( ! has_attr ( ATTR_LOWER , decl ) && ! has_attr ( ATTR_NOINIT , decl ) && ( has_attr ( "section" , decl ) || msp430_data_region == MSP430_REGION_UPPER || msp430_data_region == MSP430_REGION_EITHER || msp430_data_region == MSP430_REGION_ANY ) ) ) return false ; return true ; } </s>

Given a non-automatic VAR_DECL which can possibly have a section , return true if the variable will definitely be placed in the lower memory region ( below address 0x10000 ) .


<s> static bool use_32bit_hwmult ( void ) { static const char * cached_match = NULL ; static bool cached_result ; if ( msp430_hwmult_type == MSP430_HWMULT_LARGE ) return true ; if ( target_mcu == NULL || msp430_hwmult_type != MSP430_HWMULT_AUTO ) return false ; if ( target_mcu == cached_match ) return cached_result ; cached_match = target_mcu ; msp430_extract_mcu_data ( target_mcu ) ; if ( extracted_mcu_data . name != NULL ) return cached_result = extracted_mcu_data . hwmpy == 4 ; return cached_result = false ; } </s>


<s> static bool use_helper_for_const_shift ( machine_mode mode , HOST_WIDE_INT amt ) { const int default_inline_shift = 4 ; int user_set_max_inline = ( msp430_max_inline_shift == 65 ? 0 : 1 ) ; int max_inline = ( user_set_max_inline ? msp430_max_inline_shift : default_inline_shift ) ; int max_inline_32 = max_inline / 2 ; if ( mode == E_DImode ) return true ; if ( ( mode == E_QImode || mode == E_HImode || mode == E_PSImode ) && ( msp430x || amt <= max_inline || ( ! user_set_max_inline && ( optimize >= 2 && ! optimize_size ) ) ) ) return false ; if ( mode == E_SImode && ( amt <= max_inline_32 || ( ! user_set_max_inline && ( optimize >= 2 && ! optimize_size ) && amt <= 15 ) ) ) return false ; return true ; } </s>

Return TRUE if the helper function should be used and FALSE if the shifts insns should be emitted inline .