<s>
static
void
mips_output_function_prologue
(
FILE
*
file
,
HOST_WIDE_INT
size
ATTRIBUTE_UNUSED
)
{
const
char
*
fnname
;
HOST_WIDE_INT
tsize
=
cfun
->
machine
->
frame
.
total_size
;
if
(
debug_info_level
!=
DINFO_LEVEL_TERSE
&&
write_symbols
==
SDB_DEBUG
)
SDB_OUTPUT_SOURCE_LINE
(
file
,
DECL_SOURCE_LINE
(
current_function_decl
)
)
;
if
(
TARGET_MIPS16
&&
!
TARGET_SOFT_FLOAT
&&
current_function_args_info
.
fp_code
!=
0
)
build_mips16_function_stub
(
file
)
;
if
(
!
FUNCTION_NAME_ALREADY_DECLARED
)
{
fnname
=
XSTR
(
XEXP
(
DECL_RTL
(
current_function_decl
)
,
0
)
,
0
)
;
if
(
!
flag_inhibit_size_directive
)
{
fputs
(
"\t.ent\t"
,
file
)
;
assemble_name
(
file
,
fnname
)
;
fputs
(
"\n"
,
file
)
;
}
assemble_name
(
file
,
fnname
)
;
fputs
(
":\n"
,
file
)
;
}
if
(
TARGET_IRIX
&&
mips_abi
==
ABI_32
)
TREE_ASM_WRITTEN
(
DECL_NAME
(
cfun
->
decl
)
)
=
1
;
if
(
!
flag_inhibit_size_directive
)
{
fprintf
(
file
,
"\t.frame\t%s,"
HOST_WIDE_INT_PRINT_DEC
",%s\t\t"
"# vars= "
HOST_WIDE_INT_PRINT_DEC
", regs= %d/%d"
", args= "
HOST_WIDE_INT_PRINT_DEC
", gp= "
HOST_WIDE_INT_PRINT_DEC
"\n"
,
(
reg_names
[
(
frame_pointer_needed
)
HARD_FRAME_POINTER_REGNUM
:
STACK_POINTER_REGNUM
]
)
,
(
(
frame_pointer_needed
&&
TARGET_MIPS16
)
tsize
cfun
->
machine
->
frame
.
args_size
:
tsize
)
,
reg_names
[
GP_REG_FIRST
+
31
]
,
cfun
->
machine
->
frame
.
var_size
,
cfun
->
machine
->
frame
.
num_gp
,
cfun
->
machine
->
frame
.
num_fp
,
cfun
->
machine
->
frame
.
args_size
,
cfun
->
machine
->
frame
.
cprestore_size
)
;
fprintf
(
file
,
"\t.mask\t0x%08x,"
HOST_WIDE_INT_PRINT_DEC
"\n"
,
cfun
->
machine
->
frame
.
mask
,
cfun
->
machine
->
frame
.
gp_save_offset
)
;
fprintf
(
file
,
"\t.fmask\t0x%08x,"
HOST_WIDE_INT_PRINT_DEC
"\n"
,
cfun
->
machine
->
frame
.
fmask
,
cfun
->
machine
->
frame
.
fp_save_offset
)
;
}
if
(
TARGET_ABICALLS
&&
!
TARGET_NEWABI
&&
cfun
->
machine
->
global_pointer
>
0
)
{
if
(
!
cfun
->
machine
->
all_noreorder_p
)
output_asm_insn
(
"%(.cpload\t%^%)"
,
0
)
;
else
output_asm_insn
(
"%(.cpload\t%^\n\t%<"
,
0
)
;
}
else
if
(
cfun
->
machine
->
all_noreorder_p
)
output_asm_insn
(
"%(%<"
,
0
)
;
mips_output_cplocal
(
)
;
}
</s>

Set up the stack and frame ( if desired ) for the function .


Return an asm sequence to start a noat block and load the address of a label into $ 1 .


<s> static void mips_output_mi_thunk ( FILE * file , tree thunk_fndecl ATTRIBUTE_UNUSED , HOST_WIDE_INT delta , HOST_WIDE_INT vcall_offset , tree function ) { rtx this , temp1 , temp2 , insn , fnaddr ; no_new_pseudos = 1 ; reload_completed = 1 ; reset_block_changes ( ) ; if ( TARGET_ABICALLS ) cfun -> machine -> global_pointer = REGNO ( pic_offset_table_rtx ) = TARGET_NEWABI ? 15 : GLOBAL_POINTER_REGNUM ; mips_emit_loadgp ( ) ; temp1 = gen_rtx_REG ( Pmode , 2 ) ; temp2 = gen_rtx_REG ( Pmode , 3 ) ; if ( aggregate_value_p ( TREE_TYPE ( TREE_TYPE ( function ) ) , function ) ) this = gen_rtx_REG ( Pmode , GP_ARG_FIRST + 1 ) ; else this = gen_rtx_REG ( Pmode , GP_ARG_FIRST ) ; if ( delta != 0 ) { rtx offset = GEN_INT ( delta ) ; if ( ! SMALL_OPERAND ( delta ) ) { emit_move_insn ( temp1 , offset ) ; offset = temp1 ; } emit_insn ( gen_add3_insn ( this , this , offset ) ) ; } if ( vcall_offset != 0 ) { rtx addr ; emit_move_insn ( temp1 , gen_rtx_MEM ( Pmode , this ) ) ; addr = mips_add_offset ( temp2 , temp1 , vcall_offset ) ; emit_move_insn ( temp1 , gen_rtx_MEM ( Pmode , addr ) ) ; emit_insn ( gen_add3_insn ( this , this , temp1 ) ) ; } fnaddr = XEXP ( DECL_RTL ( function ) , 0 ) ; if ( TARGET_MIPS16 || TARGET_ABICALLS || TARGET_LONG_CALLS ) { if ( TARGET_ABICALLS && ! mips_dangerous_for_la25_p ( fnaddr ) ) temp1 = gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) ; mips_load_call_address ( temp1 , fnaddr , true ) ; if ( TARGET_ABICALLS && REGNO ( temp1 ) != PIC_FUNCTION_ADDR_REGNUM ) emit_move_insn ( gen_rtx_REG ( Pmode , PIC_FUNCTION_ADDR_REGNUM ) , temp1 ) ; emit_jump_insn ( gen_indirect_jump ( temp1 ) ) ; } else { insn = emit_call_insn ( gen_sibcall_internal ( fnaddr , const0_rtx ) ) ; SIBLING_CALL_P ( insn ) = 1 ; } insn = get_insns ( ) ; insn_locators_initialize ( ) ; split_all_insns_noflow ( ) ; if ( TARGET_MIPS16 ) mips16_lay_out_constants ( ) ; shorten_branches ( insn ) ; final_start_function ( insn , file , 1 ) ; final ( insn , file , 1 ) ; final_end_function ( ) ; reload_completed = 0 ; no_new_pseudos = 0 ; } </s>

Implement TARGET_ASM_OUTPUT_MI_THUNK . Generate rtl rather than asm text in order to avoid duplicating too much logic from elsewhere .


<s> bool mips_pad_arg_upward ( enum machine_mode mode , tree type ) { if ( ! BYTES_BIG_ENDIAN ) return true ; if ( type != 0 ? INTEGRAL_TYPE_P ( type ) || POINTER_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_INT ) return false ; if ( mips_abi == ABI_O64 ) if ( type != 0 ? FLOAT_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_FLOAT ) return false ; if ( mips_abi != ABI_EABI ) return true ; if ( mode != BLKmode ) return ( GET_MODE_BITSIZE ( mode ) >= PARM_BOUNDARY ) ; else return ( int_size_in_bytes ( type ) >= ( PARM_BOUNDARY / BITS_PER_UNIT ) ) ; } </s>

Return true if FUNCTION_ARG_PADDING ( MODE , TYPE ) should return upward rather than downward . In other words , return true if the first byte of the stack slot has useful data , false if the last byte does .


<s> bool mips_pad_reg_upward ( enum machine_mode mode , tree type ) { if ( type != 0 ? FLOAT_TYPE_P ( type ) : GET_MODE_CLASS ( mode ) == MODE_FLOAT ) return ! BYTES_BIG_ENDIAN ; return mips_pad_arg_upward ( mode , type ) ; } </s>

Likewise BLOCK_REG_PADDING ( MODE , TYPE , ... ) . Return ! BYTES_BIG_ENDIAN if the least significant byte of the register has useful data . Return the opposite if the most significant byte does .


<s>
static
const
struct
mips_cpu_info
*
mips_parse_cpu
(
const
char
*
cpu_string
)
{
const
struct
mips_cpu_info
*
p
;
const
char
*
s
;
for
(
s
=
cpu_string
;
*
s
!=
0
;
s
++
)
if
(
ISUPPER
(
*
s
)
)
{
warning
(
0
,
"the cpu name must be lower case"
)
;
break
;
}
if
(
strcasecmp
(
cpu_string
,
"from-abi"
)
==
0
)
return
mips_cpu_info_from_isa
(
ABI_NEEDS_32BIT_REGS
1
:
ABI_NEEDS_64BIT_REGS
3
:
(
TARGET_64BIT
3
:
1
)
)
;
if
(
strcasecmp
(
cpu_string
,
"default"
)
==
0
)
return
0
;
for
(
p
=
mips_cpu_info_table
;
p
->
name
!=
0
;
p
++
)
if
(
mips_matching_cpu_name_p
(
p
->
name
,
cpu_string
)
)
return
p
;
return
0
;
}
</s>

Return the mips_cpu_info entry for the processor or ISA given by CPU_STRING . Return null if the string is n't recognized . A similar function exists in GAS .


<s> enum reg_class mips_preferred_reload_class ( rtx x , enum reg_class class ) { if ( mips_dangerous_for_la25_p ( x ) && reg_class_subset_p ( LEA_REGS , class ) ) return LEA_REGS ; if ( TARGET_HARD_FLOAT && FLOAT_MODE_P ( GET_MODE ( x ) ) && reg_class_subset_p ( FP_REGS , class ) ) return FP_REGS ; if ( reg_class_subset_p ( GR_REGS , class ) ) class = GR_REGS ; if ( TARGET_MIPS16 && reg_class_subset_p ( M16_REGS , class ) ) class = M16_REGS ; return class ; } </s>


<s>
static
rtx
mips_prepare_builtin_arg
(
enum
insn_code
icode
,
unsigned
int
op
,
tree
*
arglist
)
{
rtx
value
;
enum
machine_mode
mode
;
value
=
expand_expr
(
TREE_VALUE
(
*
arglist
)
,
NULL_RTX
,
VOIDmode
,
0
)
;
mode
=
insn_data
[
icode
]
.
operand
[
op
]
.
mode
;
if
(
!
insn_data
[
icode
]
.
operand
[
op
]
.
predicate
(
value
,
mode
)
)
{
value
=
copy_to_mode_reg
(
mode
,
value
)
;
if
(
!
insn_data
[
icode
]
.
operand
[
op
]
.
predicate
(
value
,
mode
)
)
{
error
(
"invalid argument to builtin function"
)
;
return
const0_rtx
;
}
}
*
arglist
=
TREE_CHAIN
(
*
arglist
)
;
return
value
;
}
</s>

Take the head of argument list * ARGLIST and convert it into a form suitable for input operand OP of instruction ICODE . Return the value and point * ARGLIST at the next element of the list .

mips
0
"invalid argument to builtin function"


<s> static rtx mips_prepare_builtin_target ( enum insn_code icode , unsigned int op , rtx target ) { enum machine_mode mode ; mode = insn_data [ icode ] . operand [ op ] . mode ; if ( target == 0 || ! insn_data [ icode ] . operand [ op ] . predicate ( target , mode ) ) target = gen_reg_rtx ( mode ) ; return target ; } </s>

Return an rtx suitable for output operand OP of instruction ICODE . If TARGET is non-null , try to use it where possible .


<s> static void mips_promote_ready ( rtx * ready , int lower , int higher ) { rtx new_head ; int i ; new_head = ready [ lower ] ; for ( i = lower ; i < higher ; i ++ ) ready [ i ] = ready [ i + 1 ] ; ready [ i ] = new_head ; } </s>

Remove the instruction at index LOWER from ready queue READY and reinsert it in front of the instruction at index HIGHER . LOWER must be < = HIGHER .


<s> int mips_register_move_cost ( enum machine_mode mode ATTRIBUTE_UNUSED , enum reg_class to , enum reg_class from ) { if ( from == M16_REGS && GR_REG_CLASS_P ( to ) ) return 2 ; else if ( from == M16_NA_REGS && GR_REG_CLASS_P ( to ) ) return 2 ; else if ( GR_REG_CLASS_P ( from ) ) { if ( to == M16_REGS ) return 2 ; else if ( to == M16_NA_REGS ) return 2 ; else if ( GR_REG_CLASS_P ( to ) ) { if ( TARGET_MIPS16 ) return 4 ; else return 2 ; } else if ( to == FP_REGS ) return 4 ; else if ( reg_class_subset_p ( to , ACC_REGS ) ) { if ( TARGET_MIPS16 ) return 12 ; else return 6 ; } else if ( COP_REG_CLASS_P ( to ) ) { return 5 ; } } else if ( from == FP_REGS ) { if ( GR_REG_CLASS_P ( to ) ) return 4 ; else if ( to == FP_REGS ) return 2 ; else if ( to == ST_REGS ) return 8 ; } else if ( reg_class_subset_p ( from , ACC_REGS ) ) { if ( GR_REG_CLASS_P ( to ) ) { if ( TARGET_MIPS16 ) return 12 ; else return 6 ; } } else if ( from == ST_REGS && GR_REG_CLASS_P ( to ) ) return 4 ; else if ( COP_REG_CLASS_P ( from ) ) { return 5 ; } return 12 ; } </s>

Implement TARGET_REGISTER_MOVE_COST . Return 0 for classes that are the maximum of the move costs for subclasses ; regclass will work out the maximum for us .


<s> static bool mips_relational_operand_ok_p ( enum rtx_code code , rtx cmp1 ) { switch ( code ) { case GT : case GTU : return reg_or_0_operand ( cmp1 , VOIDmode ) ; case GE : case GEU : return ! TARGET_MIPS16 && cmp1 == const1_rtx ; case LT : case LTU : return arith_operand ( cmp1 , VOIDmode ) ; case LE : return sle_operand ( cmp1 , VOIDmode ) ; case LEU : return sleu_operand ( cmp1 , VOIDmode ) ; default : gcc_unreachable ( ) ; } } </s>

Return true if CMP1 is a suitable second operand for relational operator CODE . See also the * sCC patterns in mips.md .


<s> static void mips_reorg ( void ) { if ( TARGET_MIPS16 ) mips16_lay_out_constants ( ) ; else if ( TARGET_EXPLICIT_RELOCS ) { if ( mips_flag_delayed_branch ) dbr_schedule ( get_insns ( ) , dump_file ) ; mips_avoid_hazards ( ) ; if ( TUNE_MIPS4130 && TARGET_VR4130_ALIGN ) vr4130_align_insns ( ) ; } } </s>


<s> void mips_restore_gp ( void ) { rtx address , slot ; gcc_assert ( TARGET_ABICALLS && TARGET_OLDABI ) ; address = mips_add_offset ( pic_offset_table_rtx , frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx , current_function_outgoing_args_size ) ; slot = gen_rtx_MEM ( Pmode , address ) ; emit_move_insn ( pic_offset_table_rtx , slot ) ; if ( ! TARGET_EXPLICIT_RELOCS ) emit_insn ( gen_blockage ( ) ) ; } </s>

Restore $ gp from its save slot . Valid only when using o32 or o64 abicalls .


<s> static void mips_restore_reg ( rtx reg , rtx mem ) { if ( TARGET_MIPS16 && REGNO ( reg ) == GP_REG_FIRST + 31 ) reg = gen_rtx_REG ( GET_MODE ( reg ) , 7 ) ; if ( TARGET_MIPS16 && ! M16_REG_P ( REGNO ( reg ) ) ) { emit_move_insn ( MIPS_EPILOGUE_TEMP ( GET_MODE ( reg ) ) , mem ) ; emit_move_insn ( reg , MIPS_EPILOGUE_TEMP ( GET_MODE ( reg ) ) ) ; } else emit_move_insn ( reg , mem ) ; } </s>

Emit instructions to restore register REG from slot MEM .


<s> rtx mips_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return const0_rtx ; return get_hard_reg_initial_val ( Pmode , GP_REG_FIRST + 31 ) ; } </s>

Implement RETURN_ADDR_RTX . Note , we do not support moving back to a previous frame .


<s> static rtx mips_return_fpr_pair ( enum machine_mode mode , enum machine_mode mode1 , HOST_WIDE_INT offset1 , enum machine_mode mode2 , HOST_WIDE_INT offset2 ) { int inc ; inc = ( TARGET_NEWABI ? 2 : FP_INC ) ; return gen_rtx_PARALLEL ( mode , gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode1 , FP_RETURN ) , GEN_INT ( offset1 ) ) , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode2 , FP_RETURN + inc ) , GEN_INT ( offset2 ) ) ) ) ; } </s>

Return a composite value in a pair of floating-point registers . MODE1 and OFFSET1 are the mode and byte offset for the first value , likewise MODE2 and OFFSET2 for the second . MODE is the mode of the complete value . For n32 & n64 , $ f0 always holds the first value and $ f2 the second . Otherwise the values are packed together as closely as possible .


<s> static bool mips_return_in_memory ( tree type , tree fndecl ATTRIBUTE_UNUSED ) { if ( TARGET_OLDABI ) return ( TYPE_MODE ( type ) == BLKmode ) ; else return ( ( int_size_in_bytes ( type ) > ( 2 * UNITS_PER_WORD ) ) || ( int_size_in_bytes ( type ) == - 1 ) ) ; } </s>

Implement TARGET_RETURN_IN_MEMORY . Under the old ( i.e. , 32 and O64 ABIs ) all BLKmode objects are returned in memory . Under the new ( N32 and 64-bit MIPS ABIs ) small structures are returned in a register . Objects with varying size must still be returned in memory , of course .


<s> static bool mips_return_in_msb ( tree valtype ) { tree fields [ 2 ] ; return ( TARGET_NEWABI && TARGET_BIG_ENDIAN && AGGREGATE_TYPE_P ( valtype ) && mips_fpr_return_fields ( valtype , fields ) == 0 ) ; } </s>

Implement TARGET_RETURN_IN_MSB . For n32 & n64 , we should return a value in the most significant part of $ 2/ $ 3 if : - the target is big-endian ; - the value has a structure or union type ( we generalize this to cover aggregates from other languages too ) ; and - the structure is not returned in floating-point registers .


<s> rtx mips_rewrite_small_data ( rtx op ) { op = copy_insn ( op ) ; for_each_rtx ( & op , mips_rewrite_small_data_1 , 0 ) ; return op ; } </s>

If possible , rewrite OP so that it refers to small data using explicit relocations .


<s> static int mips_rewrite_small_data_1 ( rtx * loc , void * data ATTRIBUTE_UNUSED ) { if ( mips_rewrite_small_data_p ( * loc ) ) * loc = gen_rtx_LO_SUM ( Pmode , pic_offset_table_rtx , * loc ) ; if ( GET_CODE ( * loc ) == LO_SUM ) return - 1 ; return 0 ; } </s>

A for_each_rtx callback , used by mips_rewrite_small_data .


<s> static bool mips_rewrite_small_data_p ( rtx x ) { enum mips_symbol_type symbol_type ; return ( TARGET_EXPLICIT_RELOCS && mips_symbolic_constant_p ( x , & symbol_type ) && symbol_type == SYMBOL_SMALL_DATA ) ; } </s>

Return true if X is a small data address that can be rewritten as a LO_SUM .


<s> static void mips_save_reg ( rtx reg , rtx mem ) { if ( GET_MODE ( reg ) == DFmode && ! TARGET_FLOAT64 ) { rtx x1 , x2 ; if ( mips_split_64bit_move_p ( mem , reg ) ) mips_split_64bit_move ( mem , reg ) ; else emit_move_insn ( mem , reg ) ; x1 = mips_frame_set ( mips_subword ( mem , 0 ) , mips_subword ( reg , 0 ) ) ; x2 = mips_frame_set ( mips_subword ( mem , 1 ) , mips_subword ( reg , 1 ) ) ; mips_set_frame_expr ( gen_rtx_PARALLEL ( VOIDmode , gen_rtvec ( 2 , x1 , x2 ) ) ) ; } else { if ( TARGET_MIPS16 && REGNO ( reg ) != GP_REG_FIRST + 31 && ! M16_REG_P ( REGNO ( reg ) ) ) { emit_move_insn ( MIPS_PROLOGUE_TEMP ( GET_MODE ( reg ) ) , reg ) ; emit_move_insn ( mem , MIPS_PROLOGUE_TEMP ( GET_MODE ( reg ) ) ) ; } else emit_move_insn ( mem , reg ) ; mips_set_frame_expr ( mips_frame_set ( mem , reg ) ) ; } } </s>

Save register REG to MEM . Make the instruction frame-related .


<s> static bool mips_save_reg_p ( unsigned int regno ) { if ( regno == GLOBAL_POINTER_REGNUM ) return ( TARGET_ABICALLS && TARGET_NEWABI && cfun -> machine -> global_pointer == regno ) ; if ( regs_ever_live [ regno ] && ! call_used_regs [ regno ] ) return true ; if ( regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed ) return true ; if ( regno == GP_REG_FIRST + 31 && regs_ever_live [ regno ] ) return true ; if ( TARGET_MIPS16 ) { tree return_type ; return_type = DECL_RESULT ( current_function_decl ) ; if ( regno == GP_REG_FIRST + 18 && regs_ever_live [ regno ] ) return true ; if ( regno == GP_REG_FIRST + 31 && mips16_hard_float && ! aggregate_value_p ( return_type , current_function_decl ) && GET_MODE_CLASS ( DECL_MODE ( return_type ) ) == MODE_FLOAT && GET_MODE_SIZE ( DECL_MODE ( return_type ) ) <= UNITS_PER_FPVALUE ) return true ; } return false ; } </s>

Return true if the current function must save REGNO .


<s> static void mips_save_restore_reg ( enum machine_mode mode , int regno , HOST_WIDE_INT offset , mips_save_restore_fn fn ) { rtx mem ; mem = gen_rtx_MEM ( mode , plus_constant ( stack_pointer_rtx , offset ) ) ; fn ( gen_rtx_REG ( mode , regno ) , mem ) ; } </s>

Use FN to save or restore register REGNO . MODE is the register 's mode and OFFSET is the offset of its save slot from the current stack pointer .


<s> enum reg_class mips_secondary_reload_class ( enum reg_class class , enum machine_mode mode , rtx x , int in_p ) { enum reg_class gr_regs = TARGET_MIPS16 ? M16_REGS : GR_REGS ; int regno = - 1 ; int gp_reg_p ; if ( REG_P ( x ) || GET_CODE ( x ) == SUBREG ) regno = true_regnum ( x ) ; gp_reg_p = TARGET_MIPS16 ? M16_REG_P ( regno ) : GP_REG_P ( regno ) ; if ( mips_dangerous_for_la25_p ( x ) ) { gr_regs = LEA_REGS ; if ( TEST_HARD_REG_BIT ( reg_class_contents [ ( int ) class ] , 25 ) ) return gr_regs ; } if ( reg_class_subset_p ( class , ACC_REGS ) ) { if ( TARGET_MIPS16 && in_p ) { return M16_REGS ; } return gp_reg_p ? NO_REGS : gr_regs ; } if ( ACC_REG_P ( regno ) ) { if ( TARGET_MIPS16 && ! in_p ) { return M16_REGS ; } return class == gr_regs ? NO_REGS : gr_regs ; } if ( class == ST_REGS ) { if ( in_p ) return FP_REGS ; return gp_reg_p ? NO_REGS : gr_regs ; } if ( ST_REG_P ( regno ) ) { if ( ! in_p ) return FP_REGS ; return class == gr_regs ? NO_REGS : gr_regs ; } if ( class == FP_REGS ) { if ( MEM_P ( x ) ) { return NO_REGS ; } else if ( CONSTANT_P ( x ) && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) { return NO_REGS ; } else if ( gp_reg_p || x == CONST0_RTX ( mode ) ) { return NO_REGS ; } else if ( FP_REG_P ( regno ) ) { return NO_REGS ; } else { return gr_regs ; } } </s>

This function returns the register class required for a secondary register when copying between one of the registers in CLASS , and X , using MODE . If IN_P is nonzero , the copy is going from X to the register , otherwise the register is the source . A return value of NO_REGS means that no secondary register is required .


<s> static void mips_select_rtx_section ( enum machine_mode mode , rtx x , unsigned HOST_WIDE_INT align ) { if ( TARGET_MIPS16 ) { function_section ( current_function_decl ) ; } else if ( TARGET_EMBEDDED_DATA ) { mergeable_constant_section ( mode , align , 0 ) ; } else { if ( GET_MODE_SIZE ( mode ) <= ( unsigned ) mips_section_threshold && mips_section_threshold > 0 ) named_section ( 0 , ".sdata" , 0 ) ; else if ( flag_pic && symbolic_expression_p ( x ) ) named_section ( 0 , ".data.rel.ro" , 3 ) ; else mergeable_constant_section ( mode , align , 0 ) ; } } </s>

Choose the section to use for the constant rtx expression X that has mode MODE .


<s> static void mips_setup_incoming_varargs ( CUMULATIVE_ARGS * cum , enum machine_mode mode , tree type , int * pretend_size ATTRIBUTE_UNUSED , int no_rtl ) { CUMULATIVE_ARGS local_cum ; int gp_saved , fp_saved ; local_cum = * cum ; FUNCTION_ARG_ADVANCE ( local_cum , mode , type , 1 ) ; gp_saved = MAX_ARGS_IN_REGISTERS - local_cum . num_gprs ; fp_saved = ( EABI_FLOAT_VARARGS_P ? MAX_ARGS_IN_REGISTERS - local_cum . num_fprs : 0 ) ; if ( ! no_rtl ) { if ( gp_saved > 0 ) { rtx ptr , mem ; ptr = plus_constant ( virtual_incoming_args_rtx , REG_PARM_STACK_SPACE ( cfun -> decl ) - gp_saved * UNITS_PER_WORD ) ; mem = gen_rtx_MEM ( BLKmode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; move_block_from_reg ( local_cum . num_gprs + GP_ARG_FIRST , mem , gp_saved ) ; } if ( fp_saved > 0 ) { enum machine_mode mode ; int off , i ; off = - gp_saved * UNITS_PER_WORD ; off &= ~ ( UNITS_PER_FPVALUE - 1 ) ; off -= fp_saved * UNITS_PER_FPREG ; mode = TARGET_SINGLE_FLOAT ? SFmode : DFmode ; for ( i = local_cum . num_fprs ; i < MAX_ARGS_IN_REGISTERS ; i += FP_INC ) { rtx ptr , mem ; ptr = plus_constant ( virtual_incoming_args_rtx , off ) ; mem = gen_rtx_MEM ( mode , ptr ) ; set_mem_alias_set ( mem , get_varargs_alias_set ( ) ) ; emit_move_insn ( mem , gen_rtx_REG ( mode , FP_ARG_FIRST + i ) ) ; off += UNITS_PER_HWFPVALUE ; } } } if ( REG_PARM_STACK_SPACE ( cfun -> decl ) == 0 ) cfun -> machine -> varargs_size = ( gp_saved * UNITS_PER_WORD + fp_saved * UNITS_PER_FPREG ) ; } </s>


<s> static void mips_set_architecture ( const struct mips_cpu_info * info ) { if ( info != 0 ) { mips_arch_info = info ; mips_arch = info -> cpu ; mips_isa = info -> isa ; } } </s>

Set up globals to generate code for the ISA or processor described by INFO .


<s> static void mips_set_frame_expr ( rtx frame_pattern ) { rtx insn ; insn = get_last_insn ( ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; REG_NOTES ( insn ) = alloc_EXPR_LIST ( REG_FRAME_RELATED_EXPR , frame_pattern , REG_NOTES ( insn ) ) ; } </s>

Make the last instruction frame related and note that it performs the operation described by FRAME_PATTERN .


<s> void mips_set_return_address ( rtx address , rtx scratch ) { rtx slot_address ; compute_frame_size ( get_frame_size ( ) ) ; gcc_assert ( ( cfun -> machine -> frame . mask >> 31 ) & 1 ) ; slot_address = mips_add_offset ( scratch , stack_pointer_rtx , cfun -> machine -> frame . gp_sp_offset ) ; emit_move_insn ( gen_rtx_MEM ( GET_MODE ( address ) , slot_address ) , address ) ; } </s>

Emit code to change the current function 's return address to ADDRESS . SCRATCH is available as a scratch register , if needed . ADDRESS and SCRATCH are both word-mode GPRs .


<s> static void mips_sim_finish_insn ( struct mips_sim * state , rtx insn ) { if ( JUMP_P ( insn ) ) mips_sim_issue_nop ( state ) ; switch ( GET_CODE ( SEQ_BEGIN ( insn ) ) ) { case CODE_LABEL : case CALL_INSN : mips_sim_reset ( state ) ; break ; case JUMP_INSN : if ( INSN_ANNULLED_BRANCH_P ( SEQ_BEGIN ( insn ) ) ) mips_sim_reset ( state ) ; break ; default : break ; } } </s>

Update simulation state STATE so that it 's ready to accept the instruction after INSN . INSN should be part of the main rtl chain , not a member of a SEQUENCE .


<s> static void mips_sim_init ( struct mips_sim * state , state_t dfa_state ) { state -> issue_rate = mips_issue_rate ( ) ; state -> dfa_state = dfa_state ; mips_sim_reset ( state ) ; } </s>

Initialize STATE before its first use . DFA_STATE points to an allocated but uninitialized DFA state .


<s> static void mips_sim_issue_insn ( struct mips_sim * state , rtx insn ) { state_transition ( state -> dfa_state , insn ) ; state -> insns_left -- ; mips_sim_insn = insn ; note_stores ( PATTERN ( insn ) , mips_sim_record_set , state ) ; } </s>

Issue instruction INSN in scheduler state STATE . Assume that INSN can issue immediately ( i.e. , that mips_sim_wait_insn has already been called ) .


<s> static void mips_sim_next_cycle ( struct mips_sim * state ) { state -> time ++ ; state -> insns_left = state -> issue_rate ; state_transition ( state -> dfa_state , 0 ) ; } </s>


<s> static void mips_sim_record_set ( rtx x , rtx pat ATTRIBUTE_UNUSED , void * data ) { struct mips_sim * state ; unsigned int i ; state = data ; if ( REG_P ( x ) ) for ( i = 0 ; i < HARD_REGNO_NREGS ( REGNO ( x ) , GET_MODE ( x ) ) ; i ++ ) { state -> last_set [ REGNO ( x ) + i ] . insn = mips_sim_insn ; state -> last_set [ REGNO ( x ) + i ] . time = state -> time ; } } </s>

mips_sim_insn has just set X. Update the LAST_SET array in simulation state DATA .


<s> static void mips_sim_reset ( struct mips_sim * state ) { state -> time = 0 ; state -> insns_left = state -> issue_rate ; memset ( & state -> last_set , 0 , sizeof ( state -> last_set ) ) ; state_reset ( state -> dfa_state ) ; } </s>

Reset STATE to the initial simulation state .


<s> static void mips_sim_wait_insn ( struct mips_sim * state , rtx insn ) { mips_sim_wait_regs ( state , insn ) ; mips_sim_wait_units ( state , insn ) ; } </s>

Advance simulation state STATE until INSN is ready to issue .


<s> static void mips_sim_wait_reg ( struct mips_sim * state , rtx insn , rtx reg ) { unsigned int i ; for ( i = 0 ; i < HARD_REGNO_NREGS ( REGNO ( reg ) , GET_MODE ( reg ) ) ; i ++ ) if ( state -> last_set [ REGNO ( reg ) + i ] . insn != 0 ) { unsigned int t ; t = state -> last_set [ REGNO ( reg ) + i ] . time ; t += insn_latency ( state -> last_set [ REGNO ( reg ) + i ] . insn , insn ) ; while ( state -> time < t ) mips_sim_next_cycle ( state ) ; } } </s>

Advance simulation state STATE until instruction INSN can read register REG .


<s> static void mips_sim_wait_regs ( struct mips_sim * state , rtx insn ) { mips_sim_insn = insn ; note_uses ( & PATTERN ( insn ) , mips_sim_wait_regs_1 , state ) ; } </s>

Advance simulation state STATE until all of INSN 's register dependencies are satisfied .


<s> static void mips_sim_wait_regs_1 ( rtx * x , void * data ) { for_each_rtx ( x , mips_sim_wait_regs_2 , data ) ; } </s>

Call mips_sim_wait_regs_2 ( R , DATA ) for each register R mentioned in * X .


<s> static int mips_sim_wait_regs_2 ( rtx * x , void * data ) { if ( REG_P ( * x ) ) mips_sim_wait_reg ( data , mips_sim_insn , * x ) ; return 0 ; } </s>

A for_each_rtx callback . If * X is a register , advance simulation state DATA until mips_sim_insn can read the register 's value .


<s> static void mips_sim_wait_units ( struct mips_sim * state , rtx insn ) { state_t tmp_state ; tmp_state = alloca ( state_size ( ) ) ; while ( state -> insns_left == 0 || ( memcpy ( tmp_state , state -> dfa_state , state_size ( ) ) , state_transition ( tmp_state , insn ) >= 0 ) ) mips_sim_next_cycle ( state ) ; } </s>

Advance simulation state STATE until the units required by instruction INSN are available .


<s> static int mips_small_data_pattern_1 ( rtx * loc , void * data ATTRIBUTE_UNUSED ) { if ( GET_CODE ( * loc ) == LO_SUM ) return - 1 ; return mips_rewrite_small_data_p ( * loc ) ; } </s>

A for_each_rtx callback for mips_small_data_pattern_p .


<s> bool mips_small_data_pattern_p ( rtx op ) { return for_each_rtx ( & op , mips_small_data_pattern_1 , 0 ) ; } </s>

Return true if OP refers to small data symbols directly , not through a LO_SUM .


<s> void mips_split_64bit_move ( rtx dest , rtx src ) { if ( FP_REG_RTX_P ( dest ) ) { emit_insn ( gen_load_df_low ( copy_rtx ( dest ) , mips_subword ( src , 0 ) ) ) ; emit_insn ( gen_load_df_high ( dest , mips_subword ( src , 1 ) , copy_rtx ( dest ) ) ) ; } else if ( FP_REG_RTX_P ( src ) ) { emit_move_insn ( mips_subword ( dest , 0 ) , mips_subword ( src , 0 ) ) ; emit_insn ( gen_store_df_high ( mips_subword ( dest , 1 ) , src ) ) ; } else { rtx low_dest ; low_dest = mips_subword ( dest , 0 ) ; if ( REG_P ( low_dest ) && reg_overlap_mentioned_p ( low_dest , src ) ) { emit_move_insn ( mips_subword ( dest , 1 ) , mips_subword ( src , 1 ) ) ; emit_move_insn ( low_dest , mips_subword ( src , 0 ) ) ; } else { emit_move_insn ( low_dest , mips_subword ( src , 0 ) ) ; emit_move_insn ( mips_subword ( dest , 1 ) , mips_subword ( src , 1 ) ) ; } } } </s>

Split a 64-bit move from SRC to DEST assuming that mips_split_64bit_move_p holds . Moves into and out of FPRs cause some difficulty here . Such moves will always be DFmode , since paired FPRs are not allowed to store DImode values . The most natural representation would be two separate 32-bit moves , such as : ( set ( reg : SI $ f0 ) ( mem : SI ... ) ) ( set ( reg : SI $ f1 ) ( mem : SI ... ) ) However , the second insn is invalid because odd-numbered FPRs are not allowed to store independent values . Use the patterns load_df_low , load_df_high and store_df_high instead .


<s> bool mips_split_64bit_move_p ( rtx dest , rtx src ) { if ( TARGET_64BIT ) return false ; if ( FP_REG_RTX_P ( src ) && FP_REG_RTX_P ( dest ) ) return false ; if ( mips_isa > 1 ) { if ( FP_REG_RTX_P ( dest ) && MEM_P ( src ) ) return false ; if ( FP_REG_RTX_P ( src ) && MEM_P ( dest ) ) return false ; } return true ; } </s>

Return true if a 64-bit move from SRC to DEST should be split into two .


<s> static bool mips_strict_matching_cpu_name_p ( const char * canonical , const char * given ) { while ( * given != 0 && TOLOWER ( * given ) == TOLOWER ( * canonical ) ) given ++ , canonical ++ ; return ( ( * given == 0 && * canonical == 0 ) || ( strcmp ( canonical , "000" ) == 0 && strcasecmp ( given , "k" ) == 0 ) ) ; } </s>

Return true if GIVEN is the same as CANONICAL , or if it is CANONICAL with a final `` 000 '' replaced by `` k '' . Ignore case . Note : this function is shared between GCC and GAS .


<s> rtx mips_subword ( rtx op , int high_p ) { unsigned int byte ; enum machine_mode mode ; mode = GET_MODE ( op ) ; if ( mode == VOIDmode ) mode = DImode ; if ( TARGET_BIG_ENDIAN ? ! high_p : high_p ) byte = UNITS_PER_WORD ; else byte = 0 ; if ( REG_P ( op ) ) { if ( FP_REG_P ( REGNO ( op ) ) ) return gen_rtx_REG ( word_mode , high_p ? REGNO ( op ) + 1 : REGNO ( op ) ) ; if ( ACC_HI_REG_P ( REGNO ( op ) ) ) return gen_rtx_REG ( word_mode , high_p ? REGNO ( op ) : REGNO ( op ) + 1 ) ; } if ( MEM_P ( op ) ) return mips_rewrite_small_data ( adjust_address ( op , word_mode , byte ) ) ; return simplify_gen_subreg ( word_mode , op , mode , byte ) ; } </s>

Return one word of double-word value OP , taking into account the fixed endianness of certain registers . HIGH_P is true to select the high part , false to select the low part .


<s> bool mips_use_ins_ext_p ( rtx op , rtx size , rtx position ) { HOST_WIDE_INT len , pos ; if ( ! ISA_HAS_EXT_INS || ! register_operand ( op , VOIDmode ) || GET_MODE_BITSIZE ( GET_MODE ( op ) ) > BITS_PER_WORD ) return false ; len = INTVAL ( size ) ; pos = INTVAL ( position ) ; if ( len <= 0 || len >= GET_MODE_BITSIZE ( GET_MODE ( op ) ) || pos < 0 || pos + len > GET_MODE_BITSIZE ( GET_MODE ( op ) ) ) return false ; return true ; } </s>

Return true if ( zero_extract OP SIZE POSITION ) can be used as the source of an `` ext '' instruction or the destination of an `` ins '' instruction . OP must be a register operand and the following conditions must hold : 0 < = POSITION < GET_MODE_BITSIZE ( GET_MODE ( op ) ) 0 < SIZE < = GET_MODE_BITSIZE ( GET_MODE ( op ) ) 0 < POSITION + SIZE < = GET_MODE_BITSIZE ( GET_MODE ( op ) ) Also reject lengths equal to a word as they are better handled by the move patterns .


<s> static bool mips_valid_pointer_mode ( enum machine_mode mode ) { return ( mode == SImode || ( TARGET_64BIT && mode == DImode ) ) ; } </s>


<s> void mips_va_start ( tree valist , rtx nextarg ) { if ( EABI_FLOAT_VARARGS_P ) { const CUMULATIVE_ARGS * cum ; tree f_ovfl , f_gtop , f_ftop , f_goff , f_foff ; tree ovfl , gtop , ftop , goff , foff ; tree t ; int gpr_save_area_size ; int fpr_save_area_size ; int fpr_offset ; cum = & current_function_args_info ; gpr_save_area_size = ( MAX_ARGS_IN_REGISTERS - cum -> num_gprs ) * UNITS_PER_WORD ; fpr_save_area_size = ( MAX_ARGS_IN_REGISTERS - cum -> num_fprs ) * UNITS_PER_FPREG ; f_ovfl = TYPE_FIELDS ( va_list_type_node ) ; f_gtop = TREE_CHAIN ( f_ovfl ) ; f_ftop = TREE_CHAIN ( f_gtop ) ; f_goff = TREE_CHAIN ( f_ftop ) ; f_foff = TREE_CHAIN ( f_goff ) ; ovfl = build ( COMPONENT_REF , TREE_TYPE ( f_ovfl ) , valist , f_ovfl , NULL_TREE ) ; gtop = build ( COMPONENT_REF , TREE_TYPE ( f_gtop ) , valist , f_gtop , NULL_TREE ) ; ftop = build ( COMPONENT_REF , TREE_TYPE ( f_ftop ) , valist , f_ftop , NULL_TREE ) ; goff = build ( COMPONENT_REF , TREE_TYPE ( f_goff ) , valist , f_goff , NULL_TREE ) ; foff = build ( COMPONENT_REF , TREE_TYPE ( f_foff ) , valist , f_foff , NULL_TREE ) ; t = make_tree ( TREE_TYPE ( ovfl ) , virtual_incoming_args_rtx ) ; if ( cum -> stack_words > 0 ) t = build ( PLUS_EXPR , TREE_TYPE ( ovfl ) , t , build_int_cst ( NULL_TREE , cum -> stack_words * UNITS_PER_WORD ) ) ; t = build ( MODIFY_EXPR , TREE_TYPE ( ovfl ) , ovfl , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( gtop ) , virtual_incoming_args_rtx ) ; t = build ( MODIFY_EXPR , TREE_TYPE ( gtop ) , gtop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = make_tree ( TREE_TYPE ( ftop ) , virtual_incoming_args_rtx ) ; fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1 ; fpr_offset &= ~ ( UNITS_PER_FPVALUE - 1 ) ; if ( fpr_offset ) t = build ( PLUS_EXPR , TREE_TYPE ( ftop ) , t , build_int_cst ( NULL_TREE , - fpr_offset ) ) ; t = build ( MODIFY_EXPR , TREE_TYPE ( ftop ) , ftop , t ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build ( MODIFY_EXPR , TREE_TYPE ( goff ) , goff , build_int_cst ( NULL_TREE , gpr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; t = build ( MODIFY_EXPR , TREE_TYPE ( foff ) , foff , build_int_cst ( NULL_TREE , fpr_save_area_size ) ) ; expand_expr ( t , const0_rtx , VOIDmode , EXPAND_NORMAL ) ; } else { nextarg = plus_constant ( nextarg , - cfun -> machine -> varargs_size ) ; std_expand_builtin_va_start ( valist , nextarg ) ; } } </s>


<s> static bool mips_vector_mode_supported_p ( enum machine_mode mode ) { switch ( mode ) { case V2SFmode : return TARGET_PAIRED_SINGLE_FLOAT ; case V2HImode : case V4QImode : return TARGET_DSP ; default : return false ; } } </s>

Target hook for vector_mode_supported_p .


<s> void print_operand_address ( FILE * file , rtx x ) { struct mips_address_info addr ; if ( mips_classify_address ( & addr , x , word_mode , true ) ) switch ( addr . type ) { case ADDRESS_REG : print_operand ( file , addr . offset , 0 ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( addr . reg ) ] ) ; return ; case ADDRESS_LO_SUM : print_operand ( file , addr . offset , 'R' ) ; fprintf ( file , "(%s)" , reg_names [ REGNO ( addr . reg ) ] ) ; return ; case ADDRESS_CONST_INT : output_addr_const ( file , x ) ; fprintf ( file , "(%s)" , reg_names [ 0 ] ) ; return ; case ADDRESS_SYMBOLIC : output_addr_const ( file , x ) ; return ; } gcc_unreachable ( ) ; } </s>

Print the operand address represented by the rtx addr


"PRINT_OPERAND, invalid operand for relocation"

Print symbolic operand OP , which is part of a HIGH or LO_SUM . RELOCS is the array of relocations to use .


<s> static int symbolic_expression_p ( rtx x ) { if ( GET_CODE ( x ) == SYMBOL_REF ) return 1 ; if ( GET_CODE ( x ) == CONST ) return symbolic_expression_p ( XEXP ( x , 0 ) ) ; if ( UNARY_P ( x ) ) return symbolic_expression_p ( XEXP ( x , 0 ) ) ; if ( ARITHMETIC_P ( x ) ) return ( symbolic_expression_p ( XEXP ( x , 0 ) ) || symbolic_expression_p ( XEXP ( x , 1 ) ) ) ; return 0 ; } </s>

Return 1 if X contains a symbolic expression . We know these expressions will have one of a few well defined forms , so we need only check those forms .


<s> static void vr4130_align_insns ( void ) { struct mips_sim state ; rtx insn , subinsn , last , last2 , next ; bool aligned_p ; dfa_start ( ) ; last = 0 ; last2 = 0 ; aligned_p = true ; mips_sim_init ( & state , alloca ( state_size ( ) ) ) ; for ( insn = get_insns ( ) ; insn != 0 ; insn = next ) { unsigned int length ; next = NEXT_INSN ( insn ) ; vr4130_avoid_branch_rt_conflict ( insn ) ; if ( USEFUL_INSN_P ( insn ) ) FOR_EACH_SUBINSN ( subinsn , insn ) { mips_sim_wait_insn ( & state , subinsn ) ; if ( state . insns_left != state . issue_rate && ! CALL_P ( subinsn ) ) { if ( subinsn == SEQ_BEGIN ( insn ) && aligned_p ) { emit_insn_after ( gen_nop ( ) , last2 ) ; aligned_p = false ; } else if ( subinsn != SEQ_BEGIN ( insn ) && ! aligned_p ) { emit_insn_after ( gen_nop ( ) , last ) ; aligned_p = true ; } } mips_sim_issue_insn ( & state , subinsn ) ; } mips_sim_finish_insn ( & state , insn ) ; length = get_attr_length ( insn ) ; if ( length > 0 ) { if ( NONJUMP_INSN_P ( SEQ_BEGIN ( insn ) ) && ( recog_memoized ( insn ) < 0 || length >= 8 ) ) { next = emit_insn_after ( gen_align ( GEN_INT ( 3 ) ) , insn ) ; next = NEXT_INSN ( next ) ; mips_sim_next_cycle ( & state ) ; aligned_p = true ; } else if ( length & 4 ) aligned_p = ! aligned_p ; last2 = last ; last = insn ; } if ( LABEL_P ( insn ) && label_to_alignment ( insn ) >= 3 ) aligned_p = true ; } dfa_finish ( ) ; } </s>

Implement -mvr4130-align . Go through each basic block and simulate the processor pipeline . If we find that a pair of instructions could execute in parallel , and the first of those instruction is not 8-byte aligned , insert a nop to make it aligned .


<s> static void vr4130_avoid_branch_rt_conflict ( rtx insn ) { rtx first , second ; first = SEQ_BEGIN ( insn ) ; second = SEQ_END ( insn ) ; if ( JUMP_P ( first ) && NONJUMP_INSN_P ( second ) && GET_CODE ( PATTERN ( first ) ) == SET && GET_CODE ( SET_DEST ( PATTERN ( first ) ) ) == PC && GET_CODE ( SET_SRC ( PATTERN ( first ) ) ) == IF_THEN_ELSE ) { rtx cond = XEXP ( SET_SRC ( PATTERN ( first ) ) , 0 ) ; if ( ( GET_CODE ( cond ) == EQ || GET_CODE ( cond ) == NE ) && REG_P ( XEXP ( cond , 0 ) ) && REG_P ( XEXP ( cond , 1 ) ) && reg_referenced_p ( XEXP ( cond , 1 ) , PATTERN ( second ) ) && ! reg_referenced_p ( XEXP ( cond , 0 ) , PATTERN ( second ) ) ) { rtx tmp = XEXP ( cond , 0 ) ; XEXP ( cond , 0 ) = XEXP ( cond , 1 ) ; XEXP ( cond , 1 ) = tmp ; } } } </s>

The VR4130 pipeline issues aligned pairs of instructions together , but it stalls the second instruction if it depends on the first . In order to cut down the amount of logic required , this dependence check is not based on a full instruction decode . Instead , any non-SPECIAL instruction is assumed to modify the register specified by bits 20-16 ( which is usually the `` rt '' field ) . In beq , beql , bne and bnel instructions , the rt field is actually an input , so we can end up with a false dependence between the branch and its delay slot . If this situation occurs in instruction INSN , try to avoid it by swapping rs and rt .


<s> static void vr4130_reorder ( rtx * ready , int nready ) { if ( vr4130_swap_insns_p ( ready [ nready - 1 ] , ready [ nready - 2 ] ) ) mips_promote_ready ( ready , nready - 2 , nready - 1 ) ; } </s>

A TUNE_MIPS4130 helper function . ( READY , NREADY ) describes a ready queue with at least two instructions . Swap the first two if vr4130_swap_insns_p says that it could be worthwhile .


<s> static bool vr4130_swap_insns_p ( rtx insn1 , rtx insn2 ) { rtx dep ; for ( dep = INSN_DEPEND ( insn1 ) ; dep != 0 ; dep = XEXP ( dep , 1 ) ) if ( REG_NOTE_KIND ( dep ) == REG_DEP_ANTI && INSN_PRIORITY ( XEXP ( dep , 0 ) ) > INSN_PRIORITY ( insn2 ) && recog_memoized ( XEXP ( dep , 0 ) ) >= 0 && get_attr_vr4130_class ( XEXP ( dep , 0 ) ) == VR4130_CLASS_ALU ) return false ; if ( vr4130_last_insn != 0 && recog_memoized ( insn1 ) >= 0 && recog_memoized ( insn2 ) >= 0 ) { enum attr_vr4130_class class1 = get_attr_vr4130_class ( insn1 ) ; enum attr_vr4130_class class2 = get_attr_vr4130_class ( insn2 ) ; if ( class1 != class2 || class1 == VR4130_CLASS_ALU ) { bool dep1 = vr4130_true_reg_dependence_p ( insn1 ) ; bool dep2 = vr4130_true_reg_dependence_p ( insn2 ) ; if ( dep1 != dep2 ) return dep1 ; if ( class1 != VR4130_CLASS_ALU && recog_memoized ( vr4130_last_insn ) >= 0 && class1 == get_attr_vr4130_class ( vr4130_last_insn ) ) return true ; } } return false ; } </s>

A TUNE_MIPS4130 helper function . Given that INSN1 is at the head of the ready queue and that INSN2 is the instruction after it , return true if it is worth promoting INSN2 ahead of INSN1 . Look for cases in which INSN1 and INSN2 can probably issue in parallel , but for which ( INSN2 , INSN1 ) should be less sensitive to instruction alignment than ( INSN1 , INSN2 ) . See 4130.md for more details .


<s> static bool vr4130_true_reg_dependence_p ( rtx insn ) { note_stores ( PATTERN ( vr4130_last_insn ) , vr4130_true_reg_dependence_p_1 , & insn ) ; return insn == 0 ; } </s>

Return true if there is true register dependence between vr4130_last_insn and INSN .


<s> static void vr4130_true_reg_dependence_p_1 ( rtx x , rtx pat ATTRIBUTE_UNUSED , void * data ) { rtx * insn_ptr = data ; if ( REG_P ( x ) && * insn_ptr != 0 && reg_referenced_p ( x , PATTERN ( * insn_ptr ) ) ) * insn_ptr = 0 ; } </s>

A note_stores callback used by vr4130_true_reg_dependence_p . DATA points to an rtx that is initially an instruction . Nullify the rtx if the instruction uses the value of register X .


<s> bool and_operands_ok ( machine_mode mode , rtx op1 , rtx op2 ) { return ( memory_operand ( op1 , mode ) ? and_load_operand ( op2 , mode ) : and_reg_operand ( op2 , mode ) ) ; } </s>

Return true iff OP1 and OP2 are valid operands together for the * and < MODE > 3 and * and < MODE > 3_mips16 patterns . For the cases to consider , see the table in the comment before the pattern .


<s> inline bool mips_lo_sum_offset_hasher :: equal ( const value_type * entry , const compare_type * value ) { return rtx_equal_p ( entry -> base , value ) ; } </s>


<s> inline hashval_t mips_lo_sum_offset_hasher :: hash ( const value_type * entry ) { return mips_hash_base ( entry -> base ) ; } </s>

Hash function for builtin functions with up to 3 arguments and a return type .


<s> static bool mflip_mips16_use_mips16_p ( tree decl ) { const char * name ; bool base_is_mips16 = ( mips_base_compression_flags & MASK_MIPS16 ) != 0 ; if ( ! DECL_NAME ( decl ) ) return ! base_is_mips16 ; if ( ! mflip_mips16_htab ) mflip_mips16_htab = hash_map < const char * , bool , mips16_flip_traits > :: create_ggc ( 37 ) ; name = IDENTIFIER_POINTER ( DECL_NAME ( decl ) ) ; bool existed ; bool * slot = & mflip_mips16_htab -> get_or_insert ( name , & existed ) ; if ( ! existed ) { mips16_flipper = ! mips16_flipper ; * slot = mips16_flipper ? ! base_is_mips16 : base_is_mips16 ; } return * slot ; } </s>

DECL is a function that needs a default `` mips16 '' or `` nomips16 '' attribute for -mflip-mips16 . Return true if it should use `` mips16 '' and false if it should use `` nomips16 '' .


<s> static rtx mips16e_build_save_restore ( bool restore_p , unsigned int * mask_ptr , HOST_WIDE_INT * offset_ptr , unsigned int nargs , HOST_WIDE_INT size ) { rtx pattern , set ; HOST_WIDE_INT offset , top_offset ; unsigned int i , regno ; int n ; gcc_assert ( cfun -> machine -> frame . num_fp == 0 ) ; n = 1 + nargs ; for ( i = 0 ; i < ARRAY_SIZE ( mips16e_save_restore_regs ) ; i ++ ) if ( BITSET_P ( * mask_ptr , mips16e_save_restore_regs [ i ] ) ) n ++ ; pattern = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( n ) ) ; n = 0 ; set = gen_rtx_SET ( VOIDmode , stack_pointer_rtx , plus_constant ( Pmode , stack_pointer_rtx , restore_p ? size : - size ) ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; XVECEXP ( pattern , 0 , n ++ ) = set ; top_offset = restore_p ? size : 0 ; for ( i = 0 ; i < nargs ; i ++ ) { offset = top_offset + i * UNITS_PER_WORD ; set = mips16e_save_restore_reg ( restore_p , true , offset , GP_ARG_FIRST + i ) ; XVECEXP ( pattern , 0 , n ++ ) = set ; } offset = top_offset ; for ( i = 0 ; i < ARRAY_SIZE ( mips16e_save_restore_regs ) ; i ++ ) { regno = mips16e_save_restore_regs [ i ] ; if ( BITSET_P ( * mask_ptr , regno ) ) { offset -= UNITS_PER_WORD ; set = mips16e_save_restore_reg ( restore_p , false , offset , regno ) ; XVECEXP ( pattern , 0 , n ++ ) = set ; * mask_ptr &= ~ ( 1 << regno ) ; } } * offset_ptr = size + ( offset - top_offset ) ; gcc_assert ( n == XVECLEN ( pattern , 0 ) ) ; return pattern ; } </s>

Return RTL for a MIPS16e SAVE or RESTORE instruction ; RESTORE_P says which . The instruction must : - Allocate or deallocate SIZE bytes in total ; SIZE is known to be nonzero . - Save or restore as many registers in * MASK_PTR as possible . The instruction saves the first registers at the top of the allocated area , with the other registers below it . - Save NARGS argument registers above the allocated area . ( NARGS is always zero if RESTORE_P . ) The SAVE and RESTORE instructions can not save and restore all general registers , so there may be some registers left over for the caller to handle . Destructively modify * MASK_PTR so that it contains the registers that still need to be saved or restored . The caller can save these registers in the memory immediately below * OFFSET_PTR , which is a byte offset from the bottom of the allocated stack area .


<s> static rtx mips16e_save_restore_reg ( bool restore_p , bool reg_parm_p , HOST_WIDE_INT offset , unsigned int regno ) { rtx reg , mem ; mem = gen_frame_mem ( SImode , plus_constant ( Pmode , stack_pointer_rtx , offset ) ) ; reg = gen_rtx_REG ( SImode , regno ) ; if ( restore_p ) { mips_add_cfa_restore ( reg ) ; return gen_rtx_SET ( VOIDmode , reg , mem ) ; } if ( reg_parm_p ) return gen_rtx_SET ( VOIDmode , mem , reg ) ; return mips_frame_set ( mem , reg ) ; } </s>

Return a move between register REGNO and memory location SP + OFFSET . REG_PARM_P is true if SP + OFFSET belongs to REG_PARM_STACK_SPACE . Make the move a load if RESTORE_P , otherwise make it a store .


<s> static void mips16_emit_constants ( struct mips16_constant * constants , rtx_insn * insn ) { struct mips16_constant * c , * next ; int align ; align = 0 ; for ( c = constants ; c != NULL ; c = next ) { if ( align < GET_MODE_SIZE ( c -> mode ) ) { int align_log = floor_log2 ( GET_MODE_SIZE ( c -> mode ) ) ; insn = emit_insn_after ( gen_align ( GEN_INT ( align_log ) ) , insn ) ; } align = GET_MODE_SIZE ( c -> mode ) ; insn = emit_label_after ( c -> label , insn ) ; insn = mips16_emit_constants_1 ( c -> mode , c -> value , insn ) ; next = c -> next ; free ( c ) ; } emit_barrier_after ( insn ) ; } </s>

Dump out the constants in CONSTANTS after INSN .


<s> static void mips16_load_branch_target ( rtx dest , rtx src ) { if ( TARGET_ABICALLS && ! TARGET_ABSOLUTE_ABICALLS ) { rtx page , low ; if ( mips_cfun_has_cprestore_slot_p ( ) ) mips_emit_move ( dest , mips_cprestore_slot ( dest , true ) ) ; else mips_emit_move ( dest , pic_offset_table_rtx ) ; page = mips_unspec_address ( src , SYMBOL_GOTOFF_PAGE ) ; low = mips_unspec_address ( src , SYMBOL_GOT_PAGE_OFST ) ; emit_insn ( gen_rtx_SET ( VOIDmode , dest , PMODE_INSN ( gen_unspec_got , ( dest , page ) ) ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , dest , gen_rtx_LO_SUM ( Pmode , dest , low ) ) ) ; } else { src = mips_unspec_address ( src , SYMBOL_ABSOLUTE ) ; mips_emit_move ( dest , src ) ; } } </s>

Emit code to load LABEL_REF SRC into MIPS16 register DEST . This is called very late in mips_reorg , but the caller is required to run mips16_lay_out_constants on the result .


<s> static rtx mips16_local_alias ( rtx func ) { if ( mips16_local_aliases == NULL ) mips16_local_aliases = hash_map < rtx , rtx , local_alias_traits > :: create_ggc ( 37 ) ; bool existed ; rtx * slot = & mips16_local_aliases -> get_or_insert ( func , & existed ) ; gcc_assert ( slot != NULL ) ; if ( ! existed ) { const char * func_name , * local_name ; rtx local ; func_name = targetm . strip_name_encoding ( XSTR ( func , 0 ) ) ; local_name = ACONCAT ( ( "__fn_local_" , func_name , NULL ) ) ; local = gen_rtx_SYMBOL_REF ( Pmode , ggc_strdup ( local_name ) ) ; SYMBOL_REF_FLAGS ( local ) = SYMBOL_REF_FLAGS ( func ) | SYMBOL_FLAG_LOCAL ; * slot = local ; } return * slot ; } </s>

FUNC is the symbol for a locally-defined hard-float MIPS16 function . Return a local alias for it , creating a new one if necessary .


<s> static void mips16_split_long_branches ( void ) { bool something_changed ; if ( ! TARGET_MIPS16 ) return ; do { rtx_insn * insn ; shorten_branches ( get_insns ( ) ) ; something_changed = false ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) if ( JUMP_P ( insn ) && get_attr_length ( insn ) > 4 && ( any_condjump_p ( insn ) || any_uncondjump_p ( insn ) ) ) { rtx old_label , temp , saved_temp ; rtx_code_label * new_label ; rtx target ; rtx_insn * jump , * jump_sequence ; start_sequence ( ) ; saved_temp = gen_rtx_REG ( Pmode , AT_REGNUM ) ; temp = gen_rtx_REG ( Pmode , GP_REG_FIRST + 2 ) ; emit_move_insn ( saved_temp , temp ) ; old_label = JUMP_LABEL ( insn ) ; target = gen_rtx_LABEL_REF ( Pmode , old_label ) ; mips16_load_branch_target ( temp , target ) ; jump = emit_jump_insn ( PMODE_INSN ( gen_indirect_jump_and_restore , ( temp , temp , saved_temp ) ) ) ; JUMP_LABEL ( jump ) = old_label ; LABEL_NUSES ( old_label ) ++ ; mips16_lay_out_constants ( false ) ; if ( simplejump_p ( insn ) ) new_label = NULL ; else { new_label = gen_label_rtx ( ) ; emit_label ( new_label ) ; } jump_sequence = get_insns ( ) ; end_sequence ( ) ; emit_insn_after ( jump_sequence , insn ) ; if ( new_label ) invert_jump ( insn , new_label , false ) ; else delete_insn ( insn ) ; something_changed = true ; } } while ( something_changed ) ; } </s>

If we 're compiling a MIPS16 function , look for and split any long branches . This must be called after all other instruction modifications in mips_reorg .


<s> int mips_address_insns ( rtx x , machine_mode mode , bool might_split_p ) { struct mips_address_info addr ; int factor ; if ( mode != BLKmode && might_split_p ) factor = ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; else factor = 1 ; if ( mips_classify_address ( & addr , x , mode , false ) ) switch ( addr . type ) { case ADDRESS_REG : if ( TARGET_MIPS16 && ! mips16_unextended_reference_p ( mode , addr . reg , UINTVAL ( addr . offset ) ) ) return factor * 2 ; return factor ; case ADDRESS_LO_SUM : return TARGET_MIPS16 ? factor * 2 : factor ; case ADDRESS_CONST_INT : return factor ; case ADDRESS_SYMBOLIC : return factor * mips_symbol_insns ( addr . symbol_type , mode ) ; } return 0 ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at X . Return 0 if X is n't valid for MODE . For mips16 code , count extended instructions as two instructions .


<s> int mips_adjust_insn_length ( rtx_insn * insn , int length ) { if ( length == MAX_PIC_BRANCH_LENGTH && JUMP_P ( insn ) && INSN_CODE ( insn ) >= 0 && get_attr_type ( insn ) == TYPE_BRANCH ) { length = simplejump_p ( insn ) ? 0 : 8 ; length += BASE_INSN_LENGTH * mips_load_label_num_insns ( ) ; length += TARGET_COMPRESSION ? 2 : 4 ; } if ( CALL_P ( insn ) || ( TARGET_MIPS16 ? simplejump_p ( insn ) : JUMP_P ( insn ) ) ) length += TARGET_MIPS16 ? 2 : 4 ; if ( ! cfun -> machine -> ignore_hazard_length_p && INSN_P ( insn ) && INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_DELAY : length += NOP_INSN_LENGTH ; break ; case HAZARD_HILO : length += NOP_INSN_LENGTH * 2 ; break ; } return length ; } </s>

Return the length of INSN . LENGTH is the initial length computed by attributes in the machine-description file .


<s> static int mips_arg_partial_bytes ( cumulative_args_t cum , machine_mode mode , tree type , bool named ) { struct mips_arg_info info ; mips_get_arg_info ( & info , get_cumulative_args ( cum ) , mode , type , named ) ; return info . stack_words > 0 ? info . reg_words * UNITS_PER_WORD : 0 ; } </s>


<s> static void mips_avoid_hazard ( rtx_insn * after , rtx_insn * insn , int * hilo_delay , rtx * delayed_reg , rtx lo_reg ) { rtx pattern , set ; int nops , ninsns ; pattern = PATTERN ( insn ) ; if ( GET_CODE ( pattern ) == ASM_INPUT || asm_noperands ( pattern ) >= 0 ) cfun -> machine -> all_noreorder_p = false ; ninsns = get_attr_length ( insn ) / 4 ; if ( ninsns == 0 ) return ; if ( * hilo_delay < 2 && reg_set_p ( lo_reg , pattern ) ) nops = 2 - * hilo_delay ; else if ( * delayed_reg != 0 && reg_referenced_p ( * delayed_reg , pattern ) ) nops = 1 ; else nops = 0 ; * hilo_delay += nops ; while ( nops -- > 0 ) emit_insn_after ( gen_hazard_nop ( ) , after ) ; * hilo_delay += ninsns ; * delayed_reg = 0 ; if ( INSN_CODE ( insn ) >= 0 ) switch ( get_attr_hazard ( insn ) ) { case HAZARD_NONE : break ; case HAZARD_HILO : * hilo_delay = 0 ; break ; case HAZARD_DELAY : set = single_set ( insn ) ; gcc_assert ( set ) ; * delayed_reg = SET_DEST ( set ) ; break ; } } </s>

Subroutine of mips_reorg . If there is a hazard between INSN and a previous instruction , avoid it by inserting nops after instruction AFTER . * DELAYED_REG and * HILO_DELAY describe the hazards that apply at this point . If * DELAYED_REG is non-null , INSN must wait a cycle before using the value of that register . * HILO_DELAY counts the number of instructions since the last hilo hazard ( that is , the number of instructions since the last mflo or mfhi ) . After inserting nops for INSN , update * DELAYED_REG and * HILO_DELAY for the next instruction . LO_REG is an rtx for the LO register , used in dependence checking .


<s> static int mips_binary_cost ( rtx x , int single_cost , int double_cost , bool speed ) { int cost ; if ( GET_MODE_SIZE ( GET_MODE ( x ) ) == UNITS_PER_WORD * 2 ) cost = double_cost ; else cost = single_cost ; return ( cost + set_src_cost ( XEXP ( x , 0 ) , speed ) + rtx_cost ( XEXP ( x , 1 ) , GET_CODE ( x ) , 1 , speed ) ) ; } </s>

Return the cost of binary operation X , given that the instruction sequence for a word-sized or smaller operation has cost SINGLE_COST and that the sequence of a double-word operation has cost DOUBLE_COST . If SPEED is true , optimize for speed otherwise optimize for size .


<s> static void mips_block_move_loop ( rtx dest , rtx src , HOST_WIDE_INT length , HOST_WIDE_INT bytes_per_iter ) { rtx_code_label * label ; rtx src_reg , dest_reg , final_src , test ; HOST_WIDE_INT leftover ; leftover = length % bytes_per_iter ; length -= leftover ; mips_adjust_block_mem ( src , bytes_per_iter , & src_reg , & src ) ; mips_adjust_block_mem ( dest , bytes_per_iter , & dest_reg , & dest ) ; final_src = expand_simple_binop ( Pmode , PLUS , src_reg , GEN_INT ( length ) , 0 , 0 , OPTAB_WIDEN ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; mips_block_move_straight ( dest , src , bytes_per_iter ) ; mips_emit_move ( src_reg , plus_constant ( Pmode , src_reg , bytes_per_iter ) ) ; mips_emit_move ( dest_reg , plus_constant ( Pmode , dest_reg , bytes_per_iter ) ) ; test = gen_rtx_NE ( VOIDmode , src_reg , final_src ) ; if ( Pmode == DImode ) emit_jump_insn ( gen_cbranchdi4 ( test , src_reg , final_src , label ) ) ; else emit_jump_insn ( gen_cbranchsi4 ( test , src_reg , final_src , label ) ) ; if ( leftover ) mips_block_move_straight ( dest , src , leftover ) ; } </s>

Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES per iteration . LENGTH must be at least MAX_MOVE_BYTES . Assume that the memory regions do not overlap .


<s> static void mips_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; machine_mode mode ; rtx * regs ; if ( MEM_ALIGN ( src ) == BITS_PER_WORD / 2 && MEM_ALIGN ( dest ) == BITS_PER_WORD / 2 ) bits = BITS_PER_WORD / 2 ; else bits = BITS_PER_WORD ; mode = mode_for_size ( bits , MODE_INT , 0 ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( rtx , length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; if ( MEM_ALIGN ( src ) >= bits ) mips_emit_move ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; else { rtx part = adjust_address ( src , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ext_as_unaligned_load ( regs [ i ] , part , bits , 0 , 0 ) ) gcc_unreachable ( ) ; } } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) if ( MEM_ALIGN ( dest ) >= bits ) mips_emit_move ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; else { rtx part = adjust_address ( dest , BLKmode , offset ) ; set_mem_size ( part , delta ) ; if ( ! mips_expand_ins_as_unaligned_store ( part , regs [ i ] , bits , 0 ) ) gcc_unreachable ( ) ; } if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , 0 ) ; } } </s>

Emit straight-line code to move LENGTH bytes from SRC to DEST . Assume that the areas do not overlap .


<s> static bool mips_callee_copies ( cumulative_args_t cum ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , const_tree type ATTRIBUTE_UNUSED , bool named ) { return mips_abi == ABI_EABI && named ; } </s>


<s> static rtx mips_call_tls_get_addr ( rtx sym , enum mips_symbol_type type , rtx v0 ) { rtx insn , loc , a0 ; a0 = gen_rtx_REG ( Pmode , GP_ARG_FIRST ) ; if ( ! mips_tls_symbol ) mips_tls_symbol = init_one_libfunc ( "__tls_get_addr" ) ; loc = mips_unspec_address ( sym , type ) ; start_sequence ( ) ; emit_insn ( gen_rtx_SET ( Pmode , a0 , gen_rtx_LO_SUM ( Pmode , pic_offset_table_rtx , loc ) ) ) ; insn = mips_expand_call ( MIPS_CALL_NORMAL , v0 , mips_tls_symbol , const0_rtx , NULL_RTX , false ) ; RTL_CONST_CALL_P ( insn ) = 1 ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insn ) , a0 ) ; insn = get_insns ( ) ; end_sequence ( ) ; return insn ; } </s>

Return an instruction sequence that calls __tls_get_addr . SYM is the TLS symbol we are referencing and TYPE is the symbol type to use ( either global dynamic or local dynamic ) . V0 is an RTX for the return value location .


<s> bool mips_cannot_change_mode_class ( machine_mode from , machine_mode to , enum reg_class rclass ) { if ( GET_MODE_SIZE ( from ) == 8 && GET_MODE_SIZE ( to ) == 8 && INTEGRAL_MODE_P ( from ) && INTEGRAL_MODE_P ( to ) ) return false ; return reg_classes_intersect_p ( FP_REGS , rclass ) ; } </s>


<s> static bool mips_cannot_force_const_mem ( machine_mode mode , rtx x ) { enum mips_symbol_type type ; rtx base , offset ; if ( GET_CODE ( x ) == HIGH ) return true ; if ( CONST_INT_P ( x ) && mips_legitimate_constant_p ( mode , x ) ) return true ; split_const ( x , & base , & offset ) ; if ( mips_symbolic_constant_p ( base , SYMBOL_CONTEXT_LEA , & type ) ) { if ( mips_use_pcrel_pool_p [ ( int ) type ] ) return false ; if ( SMALL_INT ( offset ) && mips_symbol_insns ( type , MAX_MACHINE_MODE ) > 0 ) return true ; if ( TARGET_MIPS16_PCREL_LOADS && mips_got_symbol_type_p ( type ) ) return true ; } if ( tls_referenced_p ( x ) ) return true ; return false ; } </s>

Return true if X can not be forced into a constant pool .


<s> bool mips_can_use_return_insn ( void ) { if ( cfun -> machine -> interrupt_handler_p ) return false ; if ( ! reload_completed ) return false ; if ( crtl -> profile ) return false ; if ( mips16_cfun_returns_in_fpr_p ( ) ) return false ; return cfun -> machine -> frame . total_size == 0 ; } </s>

Return nonzero if this function is known to have a null epilogue . This allows the optimizer to omit jumps to jumps if no stack was created .


<s> static bool mips_cfun_call_saved_reg_p ( unsigned int regno ) { if ( global_regs [ regno ] ) return false ; if ( cfun -> machine -> interrupt_handler_p && mips_interrupt_extra_call_saved_reg_p ( regno ) ) return true ; return ( regno == GLOBAL_POINTER_REGNUM ? TARGET_CALL_SAVED_GP : ! call_really_used_regs [ regno ] ) ; } </s>

Return true if the current function should treat register REGNO as call-saved .


<s> int mips_class_max_nregs ( enum reg_class rclass , machine_mode mode ) { int size ; HARD_REG_SET left ; size = 0x8000 ; COPY_HARD_REG_SET ( left , reg_class_contents [ ( int ) rclass ] ) ; if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) ST_REGS ] ) ) { if ( HARD_REGNO_MODE_OK ( ST_REG_FIRST , mode ) ) size = MIN ( size , 4 ) ; AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) ST_REGS ] ) ; } if ( hard_reg_set_intersect_p ( left , reg_class_contents [ ( int ) FP_REGS ] ) ) { if ( HARD_REGNO_MODE_OK ( FP_REG_FIRST , mode ) ) size = MIN ( size , UNITS_PER_FPREG ) ; AND_COMPL_HARD_REG_SET ( left , reg_class_contents [ ( int ) FP_REGS ] ) ; } if ( ! hard_reg_set_empty_p ( left ) ) size = MIN ( size , UNITS_PER_WORD ) ; return ( GET_MODE_SIZE ( mode ) + size - 1 ) / size ; } </s>

Implement CLASS_MAX_NREGS . Usually all registers are word-sized . The only supported exception is -mgp64 -msingle-float , which has 64-bit words but 32-bit float registers . A word-based calculation is correct even in that case , since -msingle-float disallows multi-FPR values . The FP status registers are an exception to this rule . They are always 4 bytes wide as they only hold condition code modes , and CCmode is always considered to be 4 bytes wide .


<s> static void mips_conditional_register_usage ( void ) { if ( ISA_HAS_DSP ) { global_regs [ CCDSP_PO_REGNUM ] = 1 ; global_regs [ CCDSP_SC_REGNUM ] = 1 ; } else AND_COMPL_HARD_REG_SET ( accessible_reg_set , reg_class_contents [ ( int ) DSP_ACC_REGS ] ) ; if ( ! ISA_HAS_HILO ) AND_COMPL_HARD_REG_SET ( accessible_reg_set , reg_class_contents [ ( int ) MD_REGS ] ) ; if ( ! TARGET_HARD_FLOAT ) { AND_COMPL_HARD_REG_SET ( accessible_reg_set , reg_class_contents [ ( int ) FP_REGS ] ) ; AND_COMPL_HARD_REG_SET ( accessible_reg_set , reg_class_contents [ ( int ) ST_REGS ] ) ; } else if ( ! ISA_HAS_8CC ) { AND_COMPL_HARD_REG_SET ( accessible_reg_set , reg_class_contents [ ( int ) ST_REGS ] ) ; if ( ! ISA_HAS_CCF ) SET_HARD_REG_BIT ( accessible_reg_set , FPSW_REGNUM ) ; fixed_regs [ FPSW_REGNUM ] = call_used_regs [ FPSW_REGNUM ] = 1 ; } if ( TARGET_MIPS16 ) { fixed_regs [ 18 ] = call_used_regs [ 18 ] = 1 ; fixed_regs [ 19 ] = call_used_regs [ 19 ] = 1 ; fixed_regs [ 20 ] = call_used_regs [ 20 ] = 1 ; fixed_regs [ 21 ] = call_used_regs [ 21 ] = 1 ; fixed_regs [ 22 ] = call_used_regs [ 22 ] = 1 ; fixed_regs [ 23 ] = call_used_regs [ 23 ] = 1 ; fixed_regs [ 26 ] = call_used_regs [ 26 ] = 1 ; fixed_regs [ 27 ] = call_used_regs [ 27 ] = 1 ; fixed_regs [ 30 ] = call_used_regs [ 30 ] = 1 ; if ( optimize_size ) { fixed_regs [ 8 ] = call_used_regs [ 8 ] = 1 ; fixed_regs [ 9 ] = call_used_regs [ 9 ] = 1 ; fixed_regs [ 10 ] = call_used_regs [ 10 ] = 1 ; fixed_regs [ 11 ] = call_used_regs [ 11 ] = 1 ; fixed_regs [ 12 ] = call_used_regs [ 12 ] = 1 ; fixed_regs [ 13 ] = call_used_regs [ 13 ] = 1 ; fixed_regs [ 14 ] = call_used_regs [ 14 ] = 1 ; fixed_regs [ 15 ] = call_used_regs [ 15 ] = 1 ; } AND_COMPL_HARD_REG_SET ( operand_reg_set , reg_class_contents [ ( int ) MD_REGS ] ) ; } if ( mips_abi == ABI_64 ) { int regno ; for ( regno = FP_REG_FIRST + 20 ; regno < FP_REG_FIRST + 24 ; regno ++ ) call_really_used_regs [ regno ] = call_used_regs [ regno ] = 1 ; } if ( mips_abi == ABI_N32 || ( mips_abi == ABI_32 && TARGET_FLOAT64 ) ) { int regno ; for ( regno = FP_REG_FIRST + 21 ; regno <= FP_REG_FIRST + 31 ; regno += 2 ) call_really_used_regs [ regno ] = call_used_regs [ regno ] = 1 ; } if ( TARGET_LITTLE_ENDIAN ) { unsigned int regno ; mips_swap_registers ( MD_REG_FIRST ) ; for ( regno = DSP_ACC_REG_FIRST ; regno <= DSP_ACC_REG_LAST ; regno += 2 ) mips_swap_registers ( regno ) ; } } </s>


<s> int mips_const_insns ( rtx x ) { struct mips_integer_op codes [ MIPS_MAX_INTEGER_OPS ] ; enum mips_symbol_type symbol_type ; rtx offset ; switch ( GET_CODE ( x ) ) { case HIGH : if ( ! mips_symbolic_constant_p ( XEXP ( x , 0 ) , SYMBOL_CONTEXT_LEA , & symbol_type ) || ! mips_split_p [ symbol_type ] ) return 0 ; return TARGET_MIPS16 ? 4 : 1 ; case CONST_INT : if ( TARGET_MIPS16 ) return ( IN_RANGE ( INTVAL ( x ) , 0 , 255 ) ? 1 : SMALL_OPERAND_UNSIGNED ( INTVAL ( x ) ) ? 2 : IN_RANGE ( - INTVAL ( x ) , 0 , 255 ) ? 2 : SMALL_OPERAND_UNSIGNED ( - INTVAL ( x ) ) ? 3 : 0 ) ; return mips_build_integer ( codes , INTVAL ( x ) ) ; case CONST_DOUBLE : case CONST_VECTOR : return ! TARGET_MIPS16 && x == CONST0_RTX ( GET_MODE ( x ) ) ? 1 : 0 ; case CONST : if ( CONST_GP_P ( x ) ) return 1 ; if ( mips_symbolic_constant_p ( x , SYMBOL_CONTEXT_LEA , & symbol_type ) ) return mips_symbol_insns ( symbol_type , MAX_MACHINE_MODE ) ; split_const ( x , & x , & offset ) ; if ( offset != 0 ) { int n = mips_const_insns ( x ) ; if ( n != 0 ) { if ( SMALL_INT ( offset ) ) return n + 1 ; else if ( ! targetm . cannot_force_const_mem ( GET_MODE ( x ) , x ) ) return n + 1 + mips_build_integer ( codes , INTVAL ( offset ) ) ; } } return 0 ; case SYMBOL_REF : case LABEL_REF : return mips_symbol_insns ( mips_classify_symbol ( x , SYMBOL_CONTEXT_LEA ) , MAX_MACHINE_MODE ) ; default : return 0 ; } } </s>


<s> static machine_mode mips_dwarf_frame_reg_mode ( int regno ) { machine_mode mode = default_dwarf_frame_reg_mode ( regno ) ; if ( FP_REG_P ( regno ) && mips_abi == ABI_32 && TARGET_FLOAT64 ) mode = SImode ; return mode ; } </s>


<s> void mips_emit_binary ( enum rtx_code code , rtx target , rtx op0 , rtx op1 ) { emit_insn ( gen_rtx_SET ( VOIDmode , target , gen_rtx_fmt_ee ( code , GET_MODE ( target ) , op0 , op1 ) ) ) ; } </s>

Emit an instruction of the form ( set TARGET ( CODE OP0 OP1 ) ) .


<s> static void mips_emit_compare ( enum rtx_code * code , rtx * op0 , rtx * op1 , bool need_eq_ne_p ) { rtx cmp_op0 = * op0 ; rtx cmp_op1 = * op1 ; if ( GET_MODE_CLASS ( GET_MODE ( * op0 ) ) == MODE_INT ) { if ( ! need_eq_ne_p && * op1 == const0_rtx ) ; else if ( * code == EQ || * code == NE ) { if ( need_eq_ne_p ) { * op0 = mips_zero_if_equal ( cmp_op0 , cmp_op1 ) ; * op1 = const0_rtx ; } else * op1 = force_reg ( GET_MODE ( cmp_op0 ) , cmp_op1 ) ; } else { bool invert = false ; * op0 = gen_reg_rtx ( GET_MODE ( cmp_op0 ) ) ; mips_emit_int_order_test ( * code , & invert , * op0 , cmp_op0 , cmp_op1 ) ; * code = ( invert ? EQ : NE ) ; * op1 = const0_rtx ; } } else if ( ALL_FIXED_POINT_MODE_P ( GET_MODE ( cmp_op0 ) ) ) { * op0 = gen_rtx_REG ( CCDSPmode , CCDSP_CC_REGNUM ) ; mips_emit_binary ( * code , * op0 , cmp_op0 , cmp_op1 ) ; * code = NE ; * op1 = const0_rtx ; } else { enum rtx_code cmp_code ; cmp_code = * code ; if ( ISA_HAS_CCF ) { * code = NE ; * op0 = gen_reg_rtx ( CCFmode ) ; } else { * code = mips_reversed_fp_cond ( & cmp_code ) ? EQ : NE ; if ( ISA_HAS_8CC ) * op0 = mips_allocate_fcc ( CCmode ) ; else * op0 = gen_rtx_REG ( CCmode , FPSW_REGNUM ) ; } * op1 = const0_rtx ; mips_emit_binary ( cmp_code , * op0 , cmp_op0 , cmp_op1 ) ; } } </s>

Convert a comparison into something that can be used in a branch or conditional move . On entry , * OP0 and * OP1 are the values being compared and * CODE is the code used to compare them . Update * CODE , * OP0 and * OP1 so that they describe the final comparison . If NEED_EQ_NE_P , then only EQ or NE comparisons against zero are possible , otherwise any standard branch condition can be used . The standard branch conditions are : - EQ or NE between two registers . - any comparison between a register and zero .


<s> static void mips_emit_move_or_split ( rtx dest , rtx src , enum mips_split_type split_type ) { if ( mips_split_move_p ( dest , src , split_type ) ) mips_split_move ( dest , src , split_type ) ; else mips_emit_move ( dest , src ) ; } </s>

Emit a move from SRC to DEST , splitting compound moves into individual instructions . SPLIT_TYPE is the type of split to perform .


"-fstack-check=specific not implemented for MIPS16"

Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE , inclusive . These are offsets from the current stack pointer .


<s> void mips_emit_save_slot_move ( rtx dest , rtx src , rtx temp ) { unsigned int regno ; rtx mem ; if ( REG_P ( src ) ) { regno = REGNO ( src ) ; mem = dest ; } else { regno = REGNO ( dest ) ; mem = src ; } if ( regno == cfun -> machine -> global_pointer && ! mips_must_initialize_gp_p ( ) ) { if ( TARGET_64BIT ) emit_insn ( gen_move_gpdi ( dest , src ) ) ; else emit_insn ( gen_move_gpsi ( dest , src ) ) ; return ; } if ( regno == HI_REGNUM ) { if ( REG_P ( dest ) ) { mips_emit_move ( temp , src ) ; if ( TARGET_64BIT ) emit_insn ( gen_mthisi_di ( gen_rtx_REG ( TImode , MD_REG_FIRST ) , temp , gen_rtx_REG ( DImode , LO_REGNUM ) ) ) ; else emit_insn ( gen_mthisi_di ( gen_rtx_REG ( DImode , MD_REG_FIRST ) , temp , gen_rtx_REG ( SImode , LO_REGNUM ) ) ) ; } else { if ( TARGET_64BIT ) emit_insn ( gen_mfhidi_ti ( temp , gen_rtx_REG ( TImode , MD_REG_FIRST ) ) ) ; else emit_insn ( gen_mfhisi_di ( temp , gen_rtx_REG ( DImode , MD_REG_FIRST ) ) ) ; mips_emit_move ( dest , temp ) ; } } else if ( mips_direct_save_slot_move_p ( regno , mem , mem == src ) ) mips_emit_move ( dest , src ) ; else { gcc_assert ( ! reg_overlap_mentioned_p ( dest , temp ) ) ; mips_emit_move ( temp , src ) ; mips_emit_move ( dest , temp ) ; } if ( MEM_P ( dest ) ) mips_set_frame_expr ( mips_frame_set ( dest , src ) ) ; } </s>

Emit a move from SRC to DEST , given that one of them is a register save slot and that the other is a register . TEMP is a temporary GPR of the same mode that is available if need be .


<s> static void mips_emit_unary ( enum rtx_code code , rtx target , rtx op0 ) { emit_insn ( gen_rtx_SET ( VOIDmode , target , gen_rtx_fmt_e ( code , GET_MODE ( op0 ) , op0 ) ) ) ; } </s>

Emit an instruction of the form ( set TARGET ( CODE OP0 ) ) .


<s> static rtx_insn * mips_epilogue_emit_cfa_restores ( void ) { rtx_insn * insn ; insn = get_last_insn ( ) ; gcc_assert ( insn && ! REG_NOTES ( insn ) ) ; if ( mips_epilogue . cfa_restores ) { RTX_FRAME_RELATED_P ( insn ) = 1 ; REG_NOTES ( insn ) = mips_epilogue . cfa_restores ; mips_epilogue . cfa_restores = 0 ; } return insn ; } </s>

Attach all pending register saves to the previous instruction . Return that instruction .


<s> void mips_expand_atomic_qihi ( union mips_gen_fn_ptrs generator , rtx result , rtx mem , rtx oldval , rtx newval ) { rtx orig_addr , memsi_addr , memsi , shift , shiftsi , unshifted_mask ; rtx unshifted_mask_reg , mask , inverted_mask , si_op ; rtx res = NULL ; machine_mode mode ; mode = GET_MODE ( mem ) ; orig_addr = force_reg ( Pmode , XEXP ( mem , 0 ) ) ; memsi_addr = mips_force_binary ( Pmode , AND , orig_addr , force_reg ( Pmode , GEN_INT ( - 4 ) ) ) ; memsi = gen_rtx_MEM ( SImode , memsi_addr ) ; set_mem_alias_set ( memsi , ALIAS_SET_MEMORY_BARRIER ) ; MEM_VOLATILE_P ( memsi ) = MEM_VOLATILE_P ( mem ) ; shift = mips_force_binary ( Pmode , AND , orig_addr , GEN_INT ( 3 ) ) ; if ( TARGET_BIG_ENDIAN ) mips_emit_binary ( XOR , shift , shift , GEN_INT ( mode == QImode ? 3 : 2 ) ) ; mips_emit_binary ( ASHIFT , shift , shift , GEN_INT ( 3 ) ) ; shiftsi = force_reg ( SImode , gen_lowpart ( SImode , shift ) ) ; unshifted_mask = GEN_INT ( GET_MODE_MASK ( mode ) ) ; unshifted_mask_reg = force_reg ( SImode , unshifted_mask ) ; mask = mips_force_binary ( SImode , ASHIFT , unshifted_mask_reg , shiftsi ) ; inverted_mask = gen_reg_rtx ( SImode ) ; emit_insn ( gen_rtx_SET ( VOIDmode , inverted_mask , gen_rtx_NOT ( SImode , mask ) ) ) ; if ( oldval != const0_rtx ) { oldval = convert_modes ( SImode , mode , oldval , true ) ; oldval = force_reg ( SImode , oldval ) ; oldval = mips_force_binary ( SImode , ASHIFT , oldval , shiftsi ) ; } if ( newval && newval != const0_rtx ) { newval = convert_modes ( SImode , mode , newval , true ) ; newval = force_reg ( SImode , newval ) ; newval = mips_force_binary ( SImode , ASHIFT , newval , shiftsi ) ; } if ( result ) res = gen_reg_rtx ( SImode ) ; if ( newval ) si_op = generator . fn_6 ( res , memsi , mask , inverted_mask , oldval , newval ) ; else if ( result ) si_op = generator . fn_5 ( res , memsi , mask , inverted_mask , oldval ) ; else si_op = generator . fn_4 ( memsi , mask , inverted_mask , oldval ) ; emit_insn ( si_op ) ; if ( result ) { mips_emit_binary ( AND , res , res , mask ) ; mips_emit_binary ( LSHIFTRT , res , res , shiftsi ) ; mips_emit_move ( result , gen_lowpart ( GET_MODE ( result ) , res ) ) ; } } </s>

Expand a QI or HI mode atomic memory operation . GENERATOR contains a pointer to the gen_ * function that generates the SI mode underlying atomic operation using masks that we calculate . RESULT is the return register for the operation . Its value is NULL if unused . MEM is the location of the atomic access . OLDVAL is the first operand for the operation . NEWVAL is the optional second operand for the operation . Its value is NULL if unused .


<s> bool mips_expand_block_move ( rtx dest , rtx src , rtx length ) { if ( ! ISA_HAS_LWL_LWR ) return false ; if ( CONST_INT_P ( length ) ) { if ( INTVAL ( length ) <= MIPS_MAX_MOVE_BYTES_STRAIGHT ) { mips_block_move_straight ( dest , src , INTVAL ( length ) ) ; return true ; } else if ( optimize ) { mips_block_move_loop ( dest , src , INTVAL ( length ) , MIPS_MAX_MOVE_BYTES_PER_LOOP_ITER ) ; return true ; } } return false ; } </s>

Expand a movmemsi instruction , which copies LENGTH bytes from memory reference SRC to memory reference DEST .


"built-in function %qE not supported for MIPS16"

Expand builtin functions . This is called from TARGET_EXPAND_BUILTIN .


<s>
static
rtx
mips_expand_builtin_insn
(
enum
insn_code
icode
,
unsigned
int
nops
,
struct
expand_operand
*
ops
,
bool
has_target_p
)
{
if
(
!
maybe_expand_insn
(
icode
,
nops
,
ops
)
)
{
error
(
"invalid argument to built-in function"
)
;
return
has_target_p
gen_reg_rtx
(
ops
[
0
]
.
mode
)
:
const0_rtx
;
}
return
has_target_p
ops
[
0
]
.
value
:
const0_rtx
;
}
</s>

Expand instruction ICODE as part of a built-in function sequence . Use the first NOPS elements of OPS as the instruction 's operands . HAS_TARGET_P is true if operand 0 is a target ; it is false if the instruction has no target . Return the target rtx if HAS_TARGET_P , otherwise return const0_rtx .


<s> void mips_expand_conditional_move ( rtx * operands ) { rtx cond ; enum rtx_code code = GET_CODE ( operands [ 1 ] ) ; rtx op0 = XEXP ( operands [ 1 ] , 0 ) ; rtx op1 = XEXP ( operands [ 1 ] , 1 ) ; mips_emit_compare ( & code , & op0 , & op1 , true ) ; cond = gen_rtx_fmt_ee ( code , GET_MODE ( op0 ) , op0 , op1 ) ; if ( ISA_HAS_SEL && INTEGRAL_MODE_P ( GET_MODE ( operands [ 2 ] ) ) && register_operand ( operands [ 2 ] , VOIDmode ) && register_operand ( operands [ 3 ] , VOIDmode ) ) { machine_mode mode = GET_MODE ( operands [ 0 ] ) ; rtx temp = gen_reg_rtx ( mode ) ; rtx temp2 = gen_reg_rtx ( mode ) ; emit_insn ( gen_rtx_SET ( VOIDmode , temp , gen_rtx_IF_THEN_ELSE ( mode , cond , operands [ 2 ] , const0_rtx ) ) ) ; cond = gen_rtx_fmt_ee ( ( code == EQ ) ? NE : EQ , GET_MODE ( op0 ) , op0 , op1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , temp2 , gen_rtx_IF_THEN_ELSE ( mode , cond , operands [ 3 ] , const0_rtx ) ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , operands [ 0 ] , gen_rtx_IOR ( mode , temp , temp2 ) ) ) ; } else { if ( FLOAT_MODE_P ( GET_MODE ( operands [ 2 ] ) ) && ! ISA_HAS_SEL ) { operands [ 2 ] = force_reg ( GET_MODE ( operands [ 0 ] ) , operands [ 2 ] ) ; operands [ 3 ] = force_reg ( GET_MODE ( operands [ 0 ] ) , operands [ 3 ] ) ; } emit_insn ( gen_rtx_SET ( VOIDmode , operands [ 0 ] , gen_rtx_IF_THEN_ELSE ( GET_MODE ( operands [ 0 ] ) , cond , operands [ 2 ] , operands [ 3 ] ) ) ) ; } } </s>

Perform the comparison in OPERANDS [ 1 ] . Move OPERANDS [ 2 ] into OPERANDS [ 0 ] if the condition holds , otherwise move OPERANDS [ 3 ] into OPERANDS [ 0 ] .


<s> bool mips_expand_ins_as_unaligned_store ( rtx dest , rtx src , HOST_WIDE_INT width , HOST_WIDE_INT bitpos ) { rtx left , right ; machine_mode mode ; if ( ! mips_get_unaligned_mem ( dest , width , bitpos , & left , & right ) ) return false ; mode = mode_for_size ( width , MODE_INT , 0 ) ; src = gen_lowpart ( mode , src ) ; if ( mode == DImode ) { emit_insn ( gen_mov_sdl ( dest , src , left ) ) ; emit_insn ( gen_mov_sdr ( copy_rtx ( dest ) , copy_rtx ( src ) , right ) ) ; } else { emit_insn ( gen_mov_swl ( dest , src , left ) ) ; emit_insn ( gen_mov_swr ( copy_rtx ( dest ) , copy_rtx ( src ) , right ) ) ; } return true ; } </s>

Try to use left/right stores to expand an `` ins '' pattern . DEST , WIDTH , BITPOS and SRC are the operands passed to the expander ; the operation is the equivalent of : ( set ( zero_extract DEST WIDTH BITPOS ) SRC ) Return true on success .


<s> void mips_expand_vector_init ( rtx target , rtx vals ) { machine_mode vmode = GET_MODE ( target ) ; machine_mode imode = GET_MODE_INNER ( vmode ) ; unsigned i , nelt = GET_MODE_NUNITS ( vmode ) ; unsigned nvar = 0 , one_var = - 1u ; bool all_same = true ; rtx x ; for ( i = 0 ; i < nelt ; ++ i ) { x = XVECEXP ( vals , 0 , i ) ; if ( ! mips_constant_elt_p ( x ) ) nvar ++ , one_var = i ; if ( i > 0 && ! rtx_equal_p ( x , XVECEXP ( vals , 0 , 0 ) ) ) all_same = false ; } if ( nvar == 0 ) { emit_move_insn ( target , gen_rtx_CONST_VECTOR ( vmode , XVEC ( vals , 0 ) ) ) ; return ; } if ( nelt == 2 ) { rtx op0 = force_reg ( imode , XVECEXP ( vals , 0 , 0 ) ) ; rtx op1 = force_reg ( imode , XVECEXP ( vals , 0 , 1 ) ) ; x = gen_rtx_VEC_CONCAT ( vmode , op0 , op1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , target , x ) ) ; return ; } gcc_assert ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ; if ( all_same ) { mips_expand_vi_broadcast ( vmode , target , XVECEXP ( vals , 0 , 0 ) ) ; return ; } if ( nvar == 1 && vmode == V4HImode ) { mips_expand_vi_loongson_one_pinsrh ( target , vals , one_var ) ; return ; } mips_expand_vi_general ( vmode , imode , nelt , nvar , target , vals ) ; } </s>


<s> void mips_expand_vec_minmax ( rtx target , rtx op0 , rtx op1 , rtx ( * cmp ) ( rtx , rtx , rtx ) , bool min_p ) { machine_mode vmode = GET_MODE ( target ) ; rtx tc , t0 , t1 , x ; tc = gen_reg_rtx ( vmode ) ; t0 = gen_reg_rtx ( vmode ) ; t1 = gen_reg_rtx ( vmode ) ; emit_insn ( cmp ( tc , op0 , op1 ) ) ; x = gen_rtx_AND ( vmode , tc , ( min_p ? op1 : op0 ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , t0 , x ) ) ; x = gen_rtx_NOT ( vmode , tc ) ; x = gen_rtx_AND ( vmode , x , ( min_p ? op0 : op1 ) ) ; emit_insn ( gen_rtx_SET ( VOIDmode , t1 , x ) ) ; x = gen_rtx_IOR ( vmode , t0 , t1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , target , x ) ) ; } </s>


<s> bool mips_expand_vec_perm_const ( rtx operands [ 4 ] ) { struct expand_vec_perm_d d ; int i , nelt , which ; unsigned char orig_perm [ MAX_VECT_LEN ] ; rtx sel ; bool ok ; d . target = operands [ 0 ] ; d . op0 = operands [ 1 ] ; d . op1 = operands [ 2 ] ; sel = operands [ 3 ] ; d . vmode = GET_MODE ( d . target ) ; gcc_assert ( VECTOR_MODE_P ( d . vmode ) ) ; d . nelt = nelt = GET_MODE_NUNITS ( d . vmode ) ; d . testing_p = false ; for ( i = which = 0 ; i < nelt ; ++ i ) { rtx e = XVECEXP ( sel , 0 , i ) ; int ei = INTVAL ( e ) & ( 2 * nelt - 1 ) ; which |= ( ei < nelt ? 1 : 2 ) ; orig_perm [ i ] = ei ; } memcpy ( d . perm , orig_perm , MAX_VECT_LEN ) ; switch ( which ) { default : gcc_unreachable ( ) ; case 3 : d . one_vector_p = false ; if ( ! rtx_equal_p ( d . op0 , d . op1 ) ) break ; case 2 : for ( i = 0 ; i < nelt ; ++ i ) d . perm [ i ] &= nelt - 1 ; d . op0 = d . op1 ; d . one_vector_p = true ; break ; case 1 : d . op1 = d . op0 ; d . one_vector_p = true ; break ; } ok = mips_expand_vec_perm_const_1 ( & d ) ; if ( ! ok && which == 3 ) { d . op0 = operands [ 1 ] ; d . op1 = operands [ 2 ] ; d . one_vector_p = false ; memcpy ( d . perm , orig_perm , MAX_VECT_LEN ) ; ok = mips_expand_vec_perm_const_1 ( & d ) ; } return ok ; } </s>


<s> void mips_expand_vec_reduc ( rtx target , rtx in , rtx ( * gen ) ( rtx , rtx , rtx ) ) { machine_mode vmode = GET_MODE ( in ) ; unsigned char perm2 [ 2 ] ; rtx last , next , fold , x ; bool ok ; last = in ; fold = gen_reg_rtx ( vmode ) ; switch ( vmode ) { case V2SFmode : perm2 [ 0 ] = 1 ; perm2 [ 1 ] = 2 ; ok = mips_expand_vselect_vconcat ( fold , last , last , perm2 , 2 ) ; gcc_assert ( ok ) ; break ; case V2SImode : emit_insn ( gen_loongson_punpckhwd ( fold , last , last ) ) ; break ; case V4HImode : emit_insn ( gen_loongson_punpckhwd_hi ( fold , last , last ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 16 ) ) ; emit_insn ( gen_vec_shr_v4hi ( fold , last , x ) ) ; break ; case V8QImode : emit_insn ( gen_loongson_punpckhwd_qi ( fold , last , last ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 16 ) ) ; emit_insn ( gen_vec_shr_v8qi ( fold , last , x ) ) ; next = gen_reg_rtx ( vmode ) ; emit_insn ( gen ( next , last , fold ) ) ; last = next ; fold = gen_reg_rtx ( vmode ) ; x = force_reg ( SImode , GEN_INT ( 8 ) ) ; emit_insn ( gen_vec_shr_v8qi ( fold , last , x ) ) ; break ; default : gcc_unreachable ( ) ; } emit_insn ( gen ( target , last , fold ) ) ; } </s>


<s> void mips_expand_vec_unpack ( rtx operands [ 2 ] , bool unsigned_p , bool high_p ) { machine_mode imode = GET_MODE ( operands [ 1 ] ) ; rtx ( * unpack ) ( rtx , rtx , rtx ) ; rtx ( * cmpgt ) ( rtx , rtx , rtx ) ; rtx tmp , dest , zero ; switch ( imode ) { case V8QImode : if ( high_p ) unpack = gen_loongson_punpckhbh ; else unpack = gen_loongson_punpcklbh ; cmpgt = gen_loongson_pcmpgtb ; break ; case V4HImode : if ( high_p ) unpack = gen_loongson_punpckhhw ; else unpack = gen_loongson_punpcklhw ; cmpgt = gen_loongson_pcmpgth ; break ; default : gcc_unreachable ( ) ; } zero = force_reg ( imode , CONST0_RTX ( imode ) ) ; if ( unsigned_p ) tmp = zero ; else { tmp = gen_reg_rtx ( imode ) ; emit_insn ( cmpgt ( tmp , zero , operands [ 1 ] ) ) ; } dest = gen_reg_rtx ( imode ) ; emit_insn ( unpack ( dest , operands [ 1 ] , tmp ) ) ; emit_move_insn ( operands [ 0 ] , gen_lowpart ( GET_MODE ( operands [ 0 ] ) , dest ) ) ; } </s>

Expand an integral vector unpack operation .


<s> static void mips_expand_vi_broadcast ( machine_mode vmode , rtx target , rtx elt ) { struct expand_vec_perm_d d ; rtx t1 ; bool ok ; if ( elt != const0_rtx ) elt = force_reg ( GET_MODE_INNER ( vmode ) , elt ) ; if ( REG_P ( elt ) ) elt = gen_lowpart ( DImode , elt ) ; t1 = gen_reg_rtx ( vmode ) ; switch ( vmode ) { case V8QImode : emit_insn ( gen_loongson_vec_init1_v8qi ( t1 , elt ) ) ; break ; case V4HImode : emit_insn ( gen_loongson_vec_init1_v4hi ( t1 , elt ) ) ; break ; default : gcc_unreachable ( ) ; } memset ( & d , 0 , sizeof ( d ) ) ; d . target = target ; d . op0 = t1 ; d . op1 = t1 ; d . vmode = vmode ; d . nelt = GET_MODE_NUNITS ( vmode ) ; d . one_vector_p = true ; ok = mips_expand_vec_perm_const_1 ( & d ) ; gcc_assert ( ok ) ; } </s>

A subroutine of mips_expand_vec_init , expand via broadcast .


<s> static void mips_expand_vi_constant ( machine_mode vmode , unsigned nelt , rtx target , rtx vals ) { rtvec vec = shallow_copy_rtvec ( XVEC ( vals , 0 ) ) ; unsigned i ; for ( i = 0 ; i < nelt ; ++ i ) { if ( ! mips_constant_elt_p ( RTVEC_ELT ( vec , i ) ) ) RTVEC_ELT ( vec , i ) = const0_rtx ; } emit_move_insn ( target , gen_rtx_CONST_VECTOR ( vmode , vec ) ) ; } </s>

A subroutine of mips_expand_vec_init , replacing all of the non-constant elements of VALS with zeros , copy the constant vector to TARGET .


<s> static bool mips_expand_vpc_loongson_bcast ( struct expand_vec_perm_d * d ) { unsigned i , elt ; rtx t0 , t1 ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ) return false ; if ( d -> vmode != V8QImode ) return false ; if ( ! d -> one_vector_p ) return false ; elt = d -> perm [ 0 ] ; for ( i = 1 ; i < 8 ; ++ i ) if ( d -> perm [ i ] != elt ) return false ; if ( d -> testing_p ) return true ; t0 = gen_reg_rtx ( V8QImode ) ; if ( elt < 4 ) emit_insn ( gen_loongson_punpcklbh ( t0 , d -> op0 , d -> op0 ) ) ; else emit_insn ( gen_loongson_punpckhbh ( t0 , d -> op0 , d -> op0 ) ) ; elt &= 3 ; elt *= 0x55 ; t1 = gen_reg_rtx ( V4HImode ) ; emit_insn ( gen_loongson_pshufh ( t1 , gen_lowpart ( V4HImode , t0 ) , force_reg ( SImode , GEN_INT ( elt ) ) ) ) ; emit_move_insn ( d -> target , gen_lowpart ( V8QImode , t1 ) ) ; return true ; } </s>

Recognize broadcast patterns for the Loongson .


<s> static bool mips_expand_vpc_loongson_even_odd ( struct expand_vec_perm_d * d ) { unsigned i , odd , nelt = d -> nelt ; rtx t0 , t1 , t2 , t3 ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ) return false ; if ( nelt < 4 ) return false ; odd = d -> perm [ 0 ] ; if ( odd > 1 ) return false ; for ( i = 1 ; i < nelt ; ++ i ) if ( d -> perm [ i ] != i * 2 + odd ) return false ; if ( d -> testing_p ) return true ; t0 = gen_reg_rtx ( d -> vmode ) ; t1 = gen_reg_rtx ( d -> vmode ) ; switch ( d -> vmode ) { case V4HImode : emit_insn ( gen_loongson_punpckhhw ( t0 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpcklhw ( t1 , d -> op0 , d -> op1 ) ) ; if ( odd ) emit_insn ( gen_loongson_punpckhhw ( d -> target , t1 , t0 ) ) ; else emit_insn ( gen_loongson_punpcklhw ( d -> target , t1 , t0 ) ) ; break ; case V8QImode : t2 = gen_reg_rtx ( d -> vmode ) ; t3 = gen_reg_rtx ( d -> vmode ) ; emit_insn ( gen_loongson_punpckhbh ( t0 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpcklbh ( t1 , d -> op0 , d -> op1 ) ) ; emit_insn ( gen_loongson_punpckhbh ( t2 , t1 , t0 ) ) ; emit_insn ( gen_loongson_punpcklbh ( t3 , t1 , t0 ) ) ; if ( odd ) emit_insn ( gen_loongson_punpckhbh ( d -> target , t3 , t2 ) ) ; else emit_insn ( gen_loongson_punpcklbh ( d -> target , t3 , t2 ) ) ; break ; default : gcc_unreachable ( ) ; } return true ; } </s>

Recognize patterns for even-odd extraction .


<s> static bool mips_expand_vpc_loongson_pshufh ( struct expand_vec_perm_d * d ) { unsigned i , mask ; rtx rmask ; if ( ! ( TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS ) ) return false ; if ( d -> vmode != V4HImode ) return false ; if ( d -> testing_p ) return true ; for ( i = mask = 0 ; i < 4 ; i ++ ) mask |= ( d -> perm [ i ] & 3 ) << ( i * 2 ) ; rmask = force_reg ( SImode , GEN_INT ( mask ) ) ; if ( d -> one_vector_p ) emit_insn ( gen_loongson_pshufh ( d -> target , d -> op0 , rmask ) ) ; else { rtx t0 , t1 , x , merge , rmerge [ 4 ] ; t0 = gen_reg_rtx ( V4HImode ) ; t1 = gen_reg_rtx ( V4HImode ) ; emit_insn ( gen_loongson_pshufh ( t1 , d -> op1 , rmask ) ) ; emit_insn ( gen_loongson_pshufh ( t0 , d -> op0 , rmask ) ) ; for ( i = 0 ; i < 4 ; ++ i ) rmerge [ i ] = ( d -> perm [ i ] & 4 ? constm1_rtx : const0_rtx ) ; merge = gen_rtx_CONST_VECTOR ( V4HImode , gen_rtvec_v ( 4 , rmerge ) ) ; merge = force_reg ( V4HImode , merge ) ; x = gen_rtx_AND ( V4HImode , merge , t1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , t1 , x ) ) ; x = gen_rtx_NOT ( V4HImode , merge ) ; x = gen_rtx_AND ( V4HImode , x , t0 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , t0 , x ) ) ; x = gen_rtx_IOR ( V4HImode , t0 , t1 ) ; emit_insn ( gen_rtx_SET ( VOIDmode , d -> target , x ) ) ; } return true ; } </s>

Recognize patterns for the Loongson PSHUFH instruction .


<s> static bool mips_expand_vselect ( rtx target , rtx op0 , const unsigned char * perm , unsigned nelt ) { rtx rperm [ MAX_VECT_LEN ] , x ; rtx_insn * insn ; unsigned i ; for ( i = 0 ; i < nelt ; ++ i ) rperm [ i ] = GEN_INT ( perm [ i ] ) ; x = gen_rtx_PARALLEL ( VOIDmode , gen_rtvec_v ( nelt , rperm ) ) ; x = gen_rtx_VEC_SELECT ( GET_MODE ( target ) , op0 , x ) ; x = gen_rtx_SET ( VOIDmode , target , x ) ; insn = emit_insn ( x ) ; if ( recog_memoized ( insn ) < 0 ) { remove_insn ( insn ) ; return false ; } return true ; } </s>

Construct ( set target ( vec_select op0 ( parallel perm ) ) ) and return true if that 's a valid instruction in the active ISA .


<s> static bool mips_expand_vselect_vconcat ( rtx target , rtx op0 , rtx op1 , const unsigned char * perm , unsigned nelt ) { machine_mode v2mode ; rtx x ; v2mode = GET_MODE_2XWIDER_MODE ( GET_MODE ( op0 ) ) ; x = gen_rtx_VEC_CONCAT ( v2mode , op0 , op1 ) ; return mips_expand_vselect ( target , x , perm , nelt ) ; } </s>

Similar , but generate a vec_concat from op0 and op1 as well .


"\n%s -G value = %d, Arch = %s, ISA = %d\n"


<s> void mips_final_prescan_insn ( rtx_insn * insn , rtx * opvec , int noperands ) { if ( mips_need_noat_wrapper_p ( insn , opvec , noperands ) ) mips_push_asm_switch ( & mips_noat ) ; } </s>


<s> static bool mips_find_gp_ref ( bool * cache , bool ( * pred ) ( rtx_insn * ) ) { rtx_insn * insn ; if ( ! * cache ) { push_topmost_sequence ( ) ; for ( insn = get_insns ( ) ; insn ; insn = NEXT_INSN ( insn ) ) if ( USEFUL_INSN_P ( insn ) && pred ( insn ) ) { * cache = true ; break ; } pop_topmost_sequence ( ) ; } return * cache ; } </s>

Return true if predicate PRED is true for at least one instruction . Cache the result in * CACHE , and assume that the result is true if * CACHE is already true .


<s> static rtx mips_frame_set ( rtx mem , rtx reg ) { rtx set ; set = gen_rtx_SET ( VOIDmode , mem , reg ) ; RTX_FRAME_RELATED_P ( set ) = 1 ; return set ; } </s>

Return a frame-related rtx that stores register REGNO at ( SP + OFFSET ) . The expression should only be used to store single registers .


<s> static void mips_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; struct mips_arg_info info ; mips_get_arg_info ( & info , cum , mode , type , named ) ; if ( ! info . fpr_p ) cum -> gp_reg_found = true ; if ( cum -> arg_number < 2 && info . fpr_p ) cum -> fp_code += ( mode == SFmode ? 1 : 2 ) << ( cum -> arg_number * 2 ) ; if ( mips_abi != ABI_EABI || ! info . fpr_p ) cum -> num_gprs = info . reg_offset + info . reg_words ; else if ( info . reg_words > 0 ) cum -> num_fprs += MAX_FPRS_PER_FMT ; if ( info . stack_words > 0 ) cum -> stack_words = info . stack_offset + info . stack_words ; cum -> arg_number ++ ; } </s>


<s> static rtx mips_function_value_1 ( const_tree valtype , const_tree fn_decl_or_type , machine_mode mode ) { if ( valtype ) { tree fields [ 2 ] ; int unsigned_p ; const_tree func ; if ( fn_decl_or_type && DECL_P ( fn_decl_or_type ) ) func = fn_decl_or_type ; else func = NULL ; mode = TYPE_MODE ( valtype ) ; unsigned_p = TYPE_UNSIGNED ( valtype ) ; mode = promote_function_mode ( valtype , mode , & unsigned_p , func , 1 ) ; switch ( mips_fpr_return_fields ( valtype , fields ) ) { case 1 : return mips_return_fpr_single ( mode , TYPE_MODE ( TREE_TYPE ( fields [ 0 ] ) ) ) ; case 2 : return mips_return_fpr_pair ( mode , TYPE_MODE ( TREE_TYPE ( fields [ 0 ] ) ) , int_byte_position ( fields [ 0 ] ) , TYPE_MODE ( TREE_TYPE ( fields [ 1 ] ) ) , int_byte_position ( fields [ 1 ] ) ) ; } if ( mips_return_in_msb ( valtype ) ) { HOST_WIDE_INT size = int_size_in_bytes ( valtype ) ; if ( size % UNITS_PER_WORD != 0 ) { size += UNITS_PER_WORD - size % UNITS_PER_WORD ; mode = mode_for_size ( size * BITS_PER_UNIT , MODE_INT , 0 ) ; } } if ( mips_abi != ABI_EABI && ! FLOAT_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , GP_RETURN ) ; } if ( ! TARGET_MIPS16 ) { if ( mode == TFmode ) return mips_return_fpr_pair ( mode , DImode , 0 , DImode , GET_MODE_SIZE ( mode ) / 2 ) ; if ( mips_return_mode_in_fpr_p ( mode ) ) { if ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) return mips_return_fpr_pair ( mode , GET_MODE_INNER ( mode ) , 0 , GET_MODE_INNER ( mode ) , GET_MODE_SIZE ( mode ) / 2 ) ; else return gen_rtx_REG ( mode , FP_RETURN ) ; } } return gen_rtx_REG ( mode , GP_RETURN ) ; } </s>

Implement TARGET_FUNCTION_VALUE and TARGET_LIBCALL_VALUE . For normal calls , VALTYPE is the return type and MODE is VOIDmode . For libcalls , VALTYPE is null and MODE is the mode of the return value .


<s> static machine_mode mips_get_reg_raw_mode ( int regno ) { if ( TARGET_FLOATXX && FP_REG_P ( regno ) ) return DFmode ; return default_get_reg_raw_mode ( regno ) ; } </s>


<s> static unsigned int mips_global_pointer ( void ) { unsigned int regno ; if ( ! TARGET_USE_GOT ) return GLOBAL_POINTER_REGNUM ; if ( mips_cfun_has_inflexible_gp_ref_p ( ) ) return GLOBAL_POINTER_REGNUM ; if ( TARGET_ABSOLUTE_JUMPS && ! mips_cfun_has_flexible_gp_ref_p ( ) ) return INVALID_REGNUM ; if ( TARGET_CALL_SAVED_GP && crtl -> is_leaf ) for ( regno = GP_REG_FIRST ; regno <= GP_REG_LAST ; regno ++ ) if ( ! df_regs_ever_live_p ( regno ) && call_really_used_regs [ regno ] && ! fixed_regs [ regno ] && regno != PIC_FUNCTION_ADDR_REGNUM ) return regno ; return GLOBAL_POINTER_REGNUM ; } </s>

Return the register that should be used as the global pointer within this function . Return 0 if the function does n't need a global pointer .


<s> machine_mode mips_hard_regno_caller_save_mode ( unsigned int regno , unsigned int nregs , machine_mode mode ) { if ( mode == VOIDmode ) return choose_hard_reg_mode ( regno , nregs , false ) ; else return mode ; } </s>


<s> static bool mips_hard_regno_mode_ok_p ( unsigned int regno , machine_mode mode ) { unsigned int size ; enum mode_class mclass ; if ( mode == CCV2mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 2 == 0 ) ; if ( mode == CCV4mode ) return ( ISA_HAS_8CC && ST_REG_P ( regno ) && ( regno - ST_REG_FIRST ) % 4 == 0 ) ; if ( mode == CCmode ) return ISA_HAS_8CC ? ST_REG_P ( regno ) : regno == FPSW_REGNUM ; size = GET_MODE_SIZE ( mode ) ; mclass = GET_MODE_CLASS ( mode ) ; if ( GP_REG_P ( regno ) && mode != CCFmode ) return ( ( regno - GP_REG_FIRST ) & 1 ) == 0 || size <= UNITS_PER_WORD ; if ( FP_REG_P ( regno ) && ( ( ( regno - FP_REG_FIRST ) % MAX_FPRS_PER_FMT ) == 0 || ( MIN_FPRS_PER_FMT == 1 && size <= UNITS_PER_FPREG ) ) ) { if ( TARGET_O32_FP64A_ABI && size <= 4 && ( regno & 1 ) != 0 ) return false ; if ( mode == CCFmode ) return ! ( TARGET_FLOATXX && ( regno & 1 ) != 0 ) ; if ( TARGET_LOONGSON_VECTORS && ( mode == V2SImode || mode == V4HImode || mode == V8QImode || mode == DImode ) ) return true ; if ( mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT || mclass == MODE_VECTOR_FLOAT ) return size <= UNITS_PER_FPVALUE ; if ( mclass == MODE_INT ) return size >= MIN_UNITS_PER_WORD && size <= UNITS_PER_FPREG ; } if ( ACC_REG_P ( regno ) && ! VECTOR_MODE_P ( mode ) && ( INTEGRAL_MODE_P ( mode ) || ALL_FIXED_POINT_MODE_P ( mode ) ) ) { if ( MD_REG_P ( regno ) ) { if ( size <= UNITS_PER_WORD * 2 ) return regno == ( size <= UNITS_PER_WORD ? LO_REGNUM : MD_REG_FIRST ) ; } else { if ( size <= UNITS_PER_WORD ) return true ; if ( size <= UNITS_PER_WORD * 2 && ( ( regno - DSP_ACC_REG_FIRST ) & 1 ) == 0 ) return true ; } } if ( ALL_COP_REG_P ( regno ) ) return mclass == MODE_INT && size <= UNITS_PER_WORD ; if ( regno == GOT_VERSION_REGNUM ) return mode == SImode ; return false ; } </s>

Return true if register REGNO can store a value of mode MODE . The result of this function is cached in mips_hard_regno_mode_ok .


<s> unsigned int mips_hard_regno_nregs ( int regno , machine_mode mode ) { if ( ST_REG_P ( regno ) ) return ( GET_MODE_SIZE ( mode ) + 3 ) / 4 ; if ( FP_REG_P ( regno ) ) return ( GET_MODE_SIZE ( mode ) + UNITS_PER_FPREG - 1 ) / UNITS_PER_FPREG ; return ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; } </s>


<s> int mips_idiv_insns ( void ) { int count ; count = 1 ; if ( TARGET_CHECK_ZERO_DIV ) { if ( GENERATE_DIVIDE_TRAPS ) count ++ ; else count += 2 ; } if ( TARGET_FIX_R4000 || TARGET_FIX_R4400 ) count ++ ; return count ; } </s>

Return the number of instructions needed for an integer division .


<s> static void mips_init_builtins ( void ) { const struct mips_builtin_description * d ; unsigned int i ; for ( i = 0 ; i < ARRAY_SIZE ( mips_builtins ) ; i ++ ) { d = & mips_builtins [ i ] ; if ( d -> avail ( ) ) mips_builtin_decls [ i ] = add_builtin_function ( d -> name , mips_build_function_type ( d -> function_type ) , i , BUILT_IN_MD , NULL , NULL ) ; } } </s>

Init builtin functions . This is called from TARGET_INIT_BUILTIN .


<s> static bool mips_interrupt_extra_call_saved_reg_p ( unsigned int regno ) { if ( ( ISA_HAS_HILO || TARGET_DSP ) && MD_REG_P ( regno ) ) return true ; if ( TARGET_DSP && DSP_ACC_REG_P ( regno ) ) return true ; if ( GP_REG_P ( regno ) && ! cfun -> machine -> use_shadow_register_set_p ) { if ( regno == GP_REG_FIRST ) return false ; if ( KERNEL_REG_P ( regno ) ) return false ; if ( regno == STACK_POINTER_REGNUM ) return false ; return call_really_used_regs [ regno ] ; } return false ; } </s>

Return true if REGNO is a register that is ordinarily call-clobbered but must nevertheless be preserved by an interrupt handler .


<s> static int mips_issue_rate ( void ) { switch ( mips_tune ) { case PROCESSOR_74KC : case PROCESSOR_74KF2_1 : case PROCESSOR_74KF1_1 : case PROCESSOR_74KF3_2 : case PROCESSOR_R10000 : return 4 ; case PROCESSOR_20KC : case PROCESSOR_R4130 : case PROCESSOR_R5400 : case PROCESSOR_R5500 : case PROCESSOR_R5900 : case PROCESSOR_R7000 : case PROCESSOR_R9000 : case PROCESSOR_OCTEON : case PROCESSOR_OCTEON2 : case PROCESSOR_OCTEON3 : return 2 ; case PROCESSOR_SB1 : case PROCESSOR_SB1A : return 3 ; case PROCESSOR_LOONGSON_2E : case PROCESSOR_LOONGSON_2F : case PROCESSOR_LOONGSON_3A : case PROCESSOR_P5600 : return 4 ; case PROCESSOR_XLP : return ( reload_completed ? 4 : 3 ) ; default : return 1 ; } } </s>

Return the number of instructions that can be issued per cycle .


<s> static void mips_legitimize_const_move ( machine_mode mode , rtx dest , rtx src ) { rtx base , offset ; if ( splittable_const_int_operand ( src , mode ) ) { mips_move_integer ( dest , dest , INTVAL ( src ) ) ; return ; } if ( mips_split_symbol ( dest , src , MAX_MACHINE_MODE , & src ) ) { emit_insn ( gen_rtx_SET ( VOIDmode , dest , src ) ) ; return ; } if ( mips_tls_symbol_p ( src ) ) { mips_emit_move ( dest , mips_legitimize_tls_address ( src ) ) ; return ; } split_const ( src , & base , & offset ) ; if ( offset != const0_rtx && ( targetm . cannot_force_const_mem ( mode , src ) || ( ! TARGET_MIPS16 && can_create_pseudo_p ( ) ) ) ) { base = mips_force_temporary ( dest , base ) ; mips_emit_move ( dest , mips_add_offset ( NULL , base , INTVAL ( offset ) ) ) ; return ; } src = force_const_mem ( mode , src ) ; mips_split_symbol ( dest , XEXP ( src , 0 ) , mode , & XEXP ( src , 0 ) ) ; mips_emit_move ( dest , src ) ; } </s>

Subroutine of mips_legitimize_move . Move constant SRC into register DEST given that SRC satisfies immediate_operand but does n't satisfy move_operand .


<s> bool mips_legitimize_move ( machine_mode mode , rtx dest , rtx src ) { if ( ! register_operand ( dest , mode ) && ! reg_or_0_operand ( src , mode ) ) { mips_emit_move ( dest , force_reg ( mode , src ) ) ; return true ; } if ( CONSTANT_P ( src ) && ! move_operand ( src , mode ) ) { mips_legitimize_const_move ( mode , dest , src ) ; set_unique_reg_note ( get_last_insn ( ) , REG_EQUAL , copy_rtx ( src ) ) ; return true ; } return false ; } </s>

If ( set DEST SRC ) is not a valid instruction , emit an equivalent sequence that is valid .