<s> bool nds32_rtx_costs_impl ( rtx x , int code , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ) { if ( speed ) goto performance_cost ; else goto size_cost ; performance_cost : switch ( code ) { case SET : return false ; case USE : * total = 0 ; break ; case MULT : * total = COSTS_N_INSNS ( 1 ) ; break ; case DIV : case UDIV : case MOD : case UMOD : * total = COSTS_N_INSNS ( 7 ) ; break ; default : * total = COSTS_N_INSNS ( 1 ) ; break ; } return true ; size_cost : switch ( code ) { case SET : return false ; case USE : * total = 0 ; break ; case CONST_INT : if ( outer_code == SET ) { if ( satisfies_constraint_Is05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else if ( satisfies_constraint_Is20 ( x ) ) * total = COSTS_N_INSNS ( 1 ) ; else * total = COSTS_N_INSNS ( 2 ) ; } else if ( outer_code == PLUS || outer_code == MINUS ) { if ( satisfies_constraint_Iu05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else if ( outer_code == ASHIFT ) { if ( satisfies_constraint_Iu03 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else if ( outer_code == ASHIFTRT || outer_code == LSHIFTRT ) { if ( satisfies_constraint_Iu05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else { * total = COSTS_N_INSNS ( 1 ) ; } break ; case CONST_DOUBLE : * total = COSTS_N_INSNS ( 2 ) ; break ; default : * total = COSTS_N_INSNS ( 1 ) ; break ; } return true ; } </s>

This target hook describes the relative costs of RTL expressions . Return 'true ' when all subexpressions of x have been processed . Return 'false ' to sum the costs of sub-rtx , plus cost of this operation . Refer to gcc/rtlanal.cc for more information .


<s> bool nds32_rtx_costs_impl ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int outer_code , int opno ATTRIBUTE_UNUSED , int * total , bool speed ) { int code = GET_CODE ( x ) ; if ( speed ) goto performance_cost ; else goto size_cost ; performance_cost : switch ( code ) { case SET : return false ; case USE : * total = 0 ; break ; case MULT : * total = COSTS_N_INSNS ( 1 ) ; break ; case DIV : case UDIV : case MOD : case UMOD : * total = COSTS_N_INSNS ( 7 ) ; break ; default : * total = COSTS_N_INSNS ( 1 ) ; break ; } return true ; size_cost : switch ( code ) { case SET : return false ; case USE : * total = 0 ; break ; case CONST_INT : if ( outer_code == SET ) { if ( satisfies_constraint_Is05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else if ( satisfies_constraint_Is20 ( x ) ) * total = COSTS_N_INSNS ( 1 ) ; else * total = COSTS_N_INSNS ( 2 ) ; } else if ( outer_code == PLUS || outer_code == MINUS ) { if ( satisfies_constraint_Iu05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else if ( outer_code == ASHIFT ) { if ( satisfies_constraint_Iu03 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else if ( outer_code == ASHIFTRT || outer_code == LSHIFTRT ) { if ( satisfies_constraint_Iu05 ( x ) ) * total = COSTS_N_INSNS ( 1 ) - 2 ; else * total = COSTS_N_INSNS ( 1 ) ; } else { * total = COSTS_N_INSNS ( 1 ) ; } break ; case CONST_DOUBLE : * total = COSTS_N_INSNS ( 2 ) ; break ; default : * total = COSTS_N_INSNS ( 1 ) ; break ; } return true ; } </s>


<s> bool nds32_rtx_costs_impl ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int outer_code , int opno , int * total , bool speed ) { int code = GET_CODE ( x ) ; if ( speed ) return rtx_cost_model . speed_prefer ( x , code , outer_code , opno , total ) ; else return rtx_cost_model . size_prefer ( x , code , outer_code , opno , total ) ; } </s>


<s> int nds32_fp_as_gp_check_available ( void ) { return 0 ; } </s>

Function to determine whether it is worth to do fp_as_gp optimization . Return 0 : It is NOT worth to do fp_as_gp optimization . Return 1 : It is APPROXIMATELY worth to do fp_as_gp optimization . Note that if it is worth to do fp_as_gp optimization , we MUST set FP_REGNUM ever live in this function .


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


<s> static bool nds32_fp_as_gp_check_available ( void ) { basic_block bb ; basic_block exit_bb ; edge_iterator ei ; edge e ; bool first_exit_blocks_p ; if ( TARGET_FORBID_FP_AS_GP || nds32_naked_function_p ( current_function_decl ) || ! optimize_size || frame_pointer_needed || NDS32_REQUIRED_CALLEE_SAVED_P ( FP_REGNUM ) || ( cfun -> stdarg == 1 ) || ( find_fallthru_edge ( EXIT_BLOCK_PTR_FOR_FN ( cfun ) -> preds ) == NULL ) ) return false ; first_exit_blocks_p = true ; exit_bb = NULL ; FOR_EACH_EDGE ( e , ei , EXIT_BLOCK_PTR_FOR_FN ( cfun ) -> preds ) { if ( ! first_exit_blocks_p ) return false ; exit_bb = e -> src ; first_exit_blocks_p = false ; } if ( ! exit_bb ) return false ; FOR_EACH_BB_FN ( bb , cfun ) { if ( ! dominated_by_p ( CDI_POST_DOMINATORS , bb , exit_bb ) ) return false ; } if ( TARGET_FORCE_FP_AS_GP ) { return true ; } else { bool good_gain = false ; int symbol_count ; int threshold ; if ( flag_pic || nds32_have_prologue_p ( ) ) { threshold = 3 ; } else { threshold = 5 + ( TARGET_V3PUSH ? 0 : 2 ) ; } symbol_count = nds32_get_symbol_count ( ) ; if ( symbol_count >= threshold ) good_gain = true ; return good_gain ; } } </s>


<s> static bool nds32_have_prologue_p ( void ) { int i ; for ( i = 0 ; i < 28 ; i ++ ) if ( NDS32_REQUIRED_CALLEE_SAVED_P ( i ) ) return true ; return ( flag_pic || NDS32_REQUIRED_CALLEE_SAVED_P ( FP_REGNUM ) || NDS32_REQUIRED_CALLEE_SAVED_P ( LP_REGNUM ) ) ; } </s>

A helper function to check if this function should contain prologue .


<s>
static
rtx
nds32_expand_builtin_null_ftype_reg
(
enum
insn_code
icode
,
tree
exp
,
rtx
target
)
{
struct
expand_operand
ops
[
1
]
;
tree
arg0
;
rtx
value0
;
arg0
=
CALL_EXPR_ARG
(
exp
,
0
)
;
value0
=
expand_normal
(
arg0
)
;
create_input_operand
(
&
ops
[
0
]
,
value0
,
TYPE_MODE
(
TREE_TYPE
(
arg0
)
)
)
;
if
(
!
maybe_expand_insn
(
icode
,
1
,
ops
)
)
error
(
"invalid argument to built-in function"
)
;
return
target
;
}
</s>

Function to expand builtin function for ' [ ( unspec_volatile [ ( reg ) ] ) ] ' .


<s>
static
rtx
nds32_expand_builtin_null_ftype_reg_imm
(
enum
insn_code
icode
,
tree
exp
,
rtx
target
)
{
struct
expand_operand
ops
[
2
]
;
tree
arg0
,
arg1
;
rtx
value0
,
value1
;
arg0
=
CALL_EXPR_ARG
(
exp
,
0
)
;
arg1
=
CALL_EXPR_ARG
(
exp
,
1
)
;
value0
=
expand_normal
(
arg0
)
;
value1
=
expand_normal
(
arg1
)
;
create_input_operand
(
&
ops
[
0
]
,
value0
,
TYPE_MODE
(
TREE_TYPE
(
arg0
)
)
)
;
create_input_operand
(
&
ops
[
1
]
,
value1
,
TYPE_MODE
(
TREE_TYPE
(
arg1
)
)
)
;
if
(
!
maybe_expand_insn
(
icode
,
2
,
ops
)
)
error
(
"invalid argument to built-in function"
)
;
return
target
;
}
</s>

Function to expand builtin function for ' [ ( unspec_volatile [ ( reg ) ( imm ) ] ) ] ' pattern .


<s>
static
rtx
nds32_expand_builtin_reg_ftype_imm
(
enum
insn_code
icode
,
tree
exp
,
rtx
target
)
{
struct
expand_operand
ops
[
2
]
;
tree
arg0
;
rtx
value0
;
arg0
=
CALL_EXPR_ARG
(
exp
,
0
)
;
value0
=
expand_normal
(
arg0
)
;
create_output_operand
(
&
ops
[
0
]
,
target
,
TYPE_MODE
(
TREE_TYPE
(
exp
)
)
)
;
create_input_operand
(
&
ops
[
1
]
,
value0
,
TYPE_MODE
(
TREE_TYPE
(
arg0
)
)
)
;
if
(
!
maybe_expand_insn
(
icode
,
2
,
ops
)
)
error
(
"invalid argument to built-in function"
)
;
return
target
;
}
</s>

Function to expand builtin function for ' [ ( set ( reg ) ( unspec_volatile [ ( imm ) ] ) ) ] ' .


<s> tree nds32_builtin_decl_impl ( unsigned code , bool initialize_p ATTRIBUTE_UNUSED ) { if ( code >= NDS32_BUILTIN_COUNT ) return error_mark_node ; return nds32_builtin_decls [ code ] ; } </s>


"invalid argument to built-in function %s"

Return true if OPVAL can be used for operand OPNUM of instruction ICODE . The instruction should require a constant operand of some sort . The function prints an error if OPVAL is not valid .


<s> static rtx nds32_expand_binopimm_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p , const char * name ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; int op0_num = return_p ? 1 : 0 ; int op1_num = return_p ? 2 : 1 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; if ( ! nds32_check_constant_argument ( icode , op1_num , op1 , name ) ) return NULL_RTX ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; op1 = nds32_legitimize_argument ( icode , op1_num , op1 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( op0 , op1 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>

Expand builtins that take two operands and the second is immediate .


<s> static rtx nds32_expand_binop_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; int op0_num = return_p ? 1 : 0 ; int op1_num = return_p ? 2 : 1 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; op1 = nds32_legitimize_argument ( icode , op1_num , op1 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( op0 , op1 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>

Expand builtins that take two operands .


<s> static rtx nds32_expand_builtin_load ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx addr_helper = gen_reg_rtx ( insn_data [ icode ] . operand [ 1 ] . mode ) ; target = nds32_legitimize_target ( icode , target ) ; op0 = nds32_legitimize_argument ( icode , 1 , op0 ) ; pat = GEN_FCN ( icode ) ( target , op0 , addr_helper ) ; if ( ! pat ) return NULL_RTX ; emit_move_insn ( addr_helper , GEN_INT ( 0 ) ) ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_builtin_store ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; rtx addr_helper = gen_reg_rtx ( insn_data [ icode ] . operand [ 1 ] . mode ) ; op0 = nds32_legitimize_argument ( icode , 0 , op0 ) ; op1 = nds32_legitimize_argument ( icode , 2 , op1 ) ; pat = GEN_FCN ( icode ) ( op0 , addr_helper , op1 ) ; if ( ! pat ) return NULL_RTX ; emit_move_insn ( addr_helper , GEN_INT ( 0 ) ) ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_cctl_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p , const char * name ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; int op0_num = return_p ? 1 : 0 ; int op1_num = return_p ? 2 : 1 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; if ( ! nds32_check_constant_argument ( icode , op0_num , op0 , name ) ) return NULL_RTX ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; op1 = nds32_legitimize_argument ( icode , op1_num , op1 ) ; if ( icode == CODE_FOR_cctl_idx_write ) { rtx op2 = nds32_read_argument ( exp , 2 ) ; op2 = nds32_legitimize_argument ( icode , 2 , op2 ) ; pat = GEN_FCN ( icode ) ( op0 , op1 , op2 ) ; } else if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 ) ; else pat = GEN_FCN ( icode ) ( op0 , op1 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_noarg_builtin ( enum insn_code icode , rtx target ) { rtx pat ; target = nds32_legitimize_target ( icode , target ) ; pat = GEN_FCN ( icode ) ( target ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_priority_builtin ( enum insn_code icode , tree exp , rtx target , const char * name ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; if ( ! nds32_check_constant_argument ( icode , 0 , op0 , name ) ) return NULL_RTX ; if ( ! nds32_check_constant_argument ( icode , 1 , op1 , name ) ) return NULL_RTX ; op0 = nds32_legitimize_argument ( icode , 0 , op0 ) ; op1 = nds32_legitimize_argument ( icode , 1 , op1 ) ; pat = GEN_FCN ( icode ) ( op0 , op1 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_scw_builtin ( enum insn_code icode , tree exp , rtx target ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; rtx addr_helper = gen_reg_rtx ( insn_data [ icode ] . operand [ 1 ] . mode ) ; target = nds32_legitimize_target ( icode , target ) ; op0 = nds32_legitimize_argument ( icode , 1 , op0 ) ; op1 = nds32_legitimize_argument ( icode , 2 , op1 ) ; pat = GEN_FCN ( icode ) ( target , op0 , addr_helper , target ) ; if ( ! pat ) return NULL_RTX ; emit_move_insn ( addr_helper , GEN_INT ( 0 ) ) ; emit_move_insn ( target , op1 ) ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_expand_triopimm_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p , const char * name ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; rtx op2 = nds32_read_argument ( exp , 2 ) ; int op0_num = return_p ? 1 : 0 ; int op1_num = return_p ? 2 : 1 ; int op2_num = return_p ? 3 : 2 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; if ( ! nds32_check_constant_argument ( icode , op2_num , op2 , name ) ) return NULL_RTX ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; op1 = nds32_legitimize_argument ( icode , op1_num , op1 ) ; op2 = nds32_legitimize_argument ( icode , op2_num , op2 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 , op2 ) ; else pat = GEN_FCN ( icode ) ( op0 , op1 , op2 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>

Expand builtins that take three operands and the third is immediate .


<s> static rtx nds32_expand_triop_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; rtx op1 = nds32_read_argument ( exp , 1 ) ; rtx op2 = nds32_read_argument ( exp , 2 ) ; int op0_num = return_p ? 1 : 0 ; int op1_num = return_p ? 2 : 1 ; int op2_num = return_p ? 3 : 2 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; op1 = nds32_legitimize_argument ( icode , op1_num , op1 ) ; op2 = nds32_legitimize_argument ( icode , op2_num , op2 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 , op1 , op2 ) ; else pat = GEN_FCN ( icode ) ( op0 , op1 , op2 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>

Expand builtins that take three operands .


<s> static rtx nds32_expand_unopimm_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p , const char * name ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; int op0_num = return_p ? 1 : 0 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; if ( ! nds32_check_constant_argument ( icode , op0_num , op0 , name ) ) return NULL_RTX ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 ) ; else pat = GEN_FCN ( icode ) ( op0 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>

Expand builtins that take one operands and the first is immediate .


<s> static rtx nds32_expand_unop_builtin ( enum insn_code icode , tree exp , rtx target , bool return_p ) { rtx pat ; rtx op0 = nds32_read_argument ( exp , 0 ) ; int op0_num = return_p ? 1 : 0 ; if ( return_p ) target = nds32_legitimize_target ( icode , target ) ; op0 = nds32_legitimize_argument ( icode , op0_num , op0 ) ; if ( return_p ) pat = GEN_FCN ( icode ) ( target , op0 ) ; else pat = GEN_FCN ( icode ) ( op0 ) ; if ( ! pat ) return NULL_RTX ; emit_insn ( pat ) ; return target ; } </s>


<s> static rtx nds32_legitimize_argument ( enum insn_code icode , int opnum , rtx arg ) { enum machine_mode mode = insn_data [ icode ] . operand [ opnum ] . mode ; if ( ( * insn_data [ icode ] . operand [ opnum ] . predicate ) ( arg , mode ) ) return arg ; else if ( VECTOR_MODE_P ( mode ) && CONST_INT_P ( arg ) ) { int nunits = GET_MODE_NUNITS ( mode ) ; int i , shift = 0 ; rtvec v = rtvec_alloc ( nunits ) ; int val = INTVAL ( arg ) ; enum machine_mode val_mode = ( mode == V4QImode ) ? QImode : HImode ; int shift_acc = ( val_mode == QImode ) ? 8 : 16 ; int mask = ( val_mode == QImode ) ? 0xff : 0xffff ; int tmp_val = val ; if ( TARGET_BIG_ENDIAN ) for ( i = 0 ; i < nunits ; i ++ ) { tmp_val = ( val >> shift ) & mask ; RTVEC_ELT ( v , nunits - i - 1 ) = gen_int_mode ( tmp_val , val_mode ) ; shift += shift_acc ; } else for ( i = 0 ; i < nunits ; i ++ ) { tmp_val = ( val >> shift ) & mask ; RTVEC_ELT ( v , i ) = gen_int_mode ( tmp_val , val_mode ) ; shift += shift_acc ; } return copy_to_mode_reg ( mode , gen_rtx_CONST_VECTOR ( mode , v ) ) ; } else { rtx tmp_rtx = gen_reg_rtx ( mode ) ; convert_move ( tmp_rtx , arg , false ) ; return tmp_rtx ; } } </s>

Given that ARG is being passed as operand OPNUM to instruction ICODE , check whether ARG satisfies the operand 's constraints . If it does n't , copy ARG to a temporary register and return that . Otherwise return ARG itself .


<s> static rtx nds32_legitimize_target ( enum insn_code icode , rtx target ) { enum machine_mode mode = insn_data [ icode ] . operand [ 0 ] . mode ; if ( ! target || GET_MODE ( target ) != mode || ! ( * insn_data [ icode ] . operand [ 0 ] . predicate ) ( target , mode ) ) return gen_reg_rtx ( mode ) ; else return target ; } </s>

Return a legitimate rtx for instruction ICODE 's return value . Use TARGET if it 's not null , has the right mode , and satisfies operand 0 's predicate .


<s> static rtx nds32_read_argument ( tree exp , unsigned int index ) { return expand_normal ( CALL_EXPR_ARG ( exp , index ) ) ; } </s>

Read the requested argument from the EXP given by INDEX . Return the value as an rtx .


A helper function to handle isr stuff at the end of asm file .


<s> void nds32_asm_file_start_for_isr ( void ) { int i ; for ( i = 0 ; i < NDS32_N_ISR_VECTORS ; i ++ ) { nds32_isr_vectors [ i ] . category = NDS32_ISR_NONE ; strcpy ( nds32_isr_vectors [ i ] . func_name , "" ) ; nds32_isr_vectors [ i ] . save_reg = NDS32_PARTIAL_SAVE ; nds32_isr_vectors [ i ] . nested_type = NDS32_NOT_NESTED ; nds32_isr_vectors [ i ] . total_n_vectors = 0 ; strcpy ( nds32_isr_vectors [ i ] . nmi_name , "" ) ; strcpy ( nds32_isr_vectors [ i ] . warm_name , "" ) ; } } </s>

A helper function to handle isr stuff at the beginning of asm file .


"multiple save reg attributes to function %qD"

"multiple nested types attributes to function %qD"

"multiple interrupt attributes to function %qD"

Function for nds32_merge_decl_attributes ( ) and nds32_insert_attributes ( ) to check if there are any conflict isr-specific attributes being set . We need to check : 1 . Only 'save_all ' or 'partial_save ' in the attributes . 2 . Only 'nested ' , 'not_nested ' , or 'nested_ready ' in the attributes . 3 . Only 'interrupt ' , 'exception ' , or 'reset ' in the attributes .


<s> void nds32_construct_isr_vectors_information ( tree func_attrs , const char * func_name ) { tree save_all , partial_save ; tree nested , not_nested , nested_ready ; tree intr , excp , reset ; save_all = lookup_attribute ( "save_all" , func_attrs ) ; partial_save = lookup_attribute ( "partial_save" , func_attrs ) ; nested = lookup_attribute ( "nested" , func_attrs ) ; not_nested = lookup_attribute ( "not_nested" , func_attrs ) ; nested_ready = lookup_attribute ( "nested_ready" , func_attrs ) ; intr = lookup_attribute ( "interrupt" , func_attrs ) ; excp = lookup_attribute ( "exception" , func_attrs ) ; reset = lookup_attribute ( "reset" , func_attrs ) ; if ( ! intr && ! excp && ! reset ) return ; if ( intr || excp ) { tree id_list ; id_list = ( intr ) ? ( TREE_VALUE ( intr ) ) : ( TREE_VALUE ( excp ) ) ; while ( id_list ) { tree id ; int vector_id ; unsigned int vector_number_offset ; vector_number_offset = ( intr ) ? ( 9 ) : ( 0 ) ; id = TREE_VALUE ( id_list ) ; vector_id = TREE_INT_CST_LOW ( id ) + vector_number_offset ; nds32_isr_vectors [ vector_id ] . category = ( intr ) ? ( NDS32_ISR_INTERRUPT ) : ( NDS32_ISR_EXCEPTION ) ; strcpy ( nds32_isr_vectors [ vector_id ] . func_name , func_name ) ; if ( save_all ) nds32_isr_vectors [ vector_id ] . save_reg = NDS32_SAVE_ALL ; else if ( partial_save ) nds32_isr_vectors [ vector_id ] . save_reg = NDS32_PARTIAL_SAVE ; if ( nested ) nds32_isr_vectors [ vector_id ] . nested_type = NDS32_NESTED ; else if ( not_nested ) nds32_isr_vectors [ vector_id ] . nested_type = NDS32_NOT_NESTED ; else if ( nested_ready ) nds32_isr_vectors [ vector_id ] . nested_type = NDS32_NESTED_READY ; id_list = TREE_CHAIN ( id_list ) ; } } else { tree id_list ; tree id ; tree nmi , warm ; nds32_isr_vectors [ 0 ] . category = NDS32_ISR_RESET ; id_list = TREE_VALUE ( reset ) ; id = TREE_VALUE ( id_list ) ; nds32_isr_vectors [ 0 ] . total_n_vectors = TREE_INT_CST_LOW ( id ) + 8 + 1 ; strcpy ( nds32_isr_vectors [ 0 ] . func_name , func_name ) ; nmi = lookup_attribute ( "nmi" , func_attrs ) ; warm = lookup_attribute ( "warm" , func_attrs ) ; if ( nmi != NULL_TREE ) { tree nmi_func_list ; tree nmi_func ; nmi_func_list = TREE_VALUE ( nmi ) ; nmi_func = TREE_VALUE ( nmi_func_list ) ; strcpy ( nds32_isr_vectors [ 0 ] . nmi_name , IDENTIFIER_POINTER ( nmi_func ) ) ; } if ( warm != NULL_TREE ) { tree warm_func_list ; tree warm_func ; warm_func_list = TREE_VALUE ( warm ) ; warm_func = TREE_VALUE ( warm_func_list ) ; strcpy ( nds32_isr_vectors [ 0 ] . warm_name , IDENTIFIER_POINTER ( warm_func ) ) ; } } } </s>

Function to construct isr vectors information array . We DO NOT HAVE TO check if the attributes are valid because those works are supposed to be done on nds32_merge_decl_attributes ( ) and nds32_insert_attributes ( ) .


<s> static void nds32_emit_isr_jmptbl_section ( int vector_id ) { char section_name [ 100 ] ; char symbol_name [ 100 ] ; snprintf ( section_name , sizeof ( section_name ) , ".nds32_jmptbl.%02d" , vector_id ) ; snprintf ( symbol_name , sizeof ( symbol_name ) , "_nds32_jmptbl_%02d" , vector_id ) ; nds32_emit_section_head_template ( section_name , symbol_name , 2 , true ) ; fprintf ( asm_out_file , "\t.word\t%s\n" , nds32_isr_vectors [ vector_id ] . func_name ) ; nds32_emit_section_tail_template ( symbol_name ) ; } </s>

Function to emit isr jump table section .


"\t ! references to jmptbl section entries\n"

"\t ! references to vector section entries\n"

Function to emit isr reset handler content . Including all jmptbl/vector references , jmptbl section , vector section , nmi handler section , and warm handler section .


"\tj\t%s ! jump to first level handler\n"

"\tmovi\t$r0, %d ! preparing software vid\n"


<s> void nds32_asm_file_start_for_isr ( void ) { int i ; for ( i = 0 ; i < NDS32_N_ISR_VECTORS ; i ++ ) { nds32_isr_vectors [ i ] . category = NDS32_ISR_NONE ; strcpy ( nds32_isr_vectors [ i ] . func_name , "" ) ; nds32_isr_vectors [ i ] . save_reg = NDS32_PARTIAL_SAVE ; nds32_isr_vectors [ i ] . nested_type = NDS32_NOT_NESTED ; nds32_isr_vectors [ i ] . security_level = 0 ; nds32_isr_vectors [ i ] . total_n_vectors = 0 ; strcpy ( nds32_isr_vectors [ i ] . nmi_name , "" ) ; strcpy ( nds32_isr_vectors [ i ] . warm_name , "" ) ; } } </s>


"multiple save register attributes to function %qD"

"cannot use interrupt attributes to function %qD "

"cannot use exception attributes to function %qD "

"cannot use reset attributes to function %qD "


"\t! The vector %02d is a critical isr !\n"


"\tj\t%s ! jump to user handler directly\n"


<s>
static
void
nds32_emit_section_head_template
(
char
section_name
[
]
,
char
symbol_name
[
]
,
int
align_value
,
bool
object_p
)
{
const
char
*
flags_str
;
const
char
*
type_str
;
flags_str
=
(
object_p
)
"\"a\""
:
"\"ax\""
;
type_str
=
(
object_p
)
"@object"
:
"@function"
;
fprintf
(
asm_out_file
,
"\t.section\t%s, %s\n"
,
section_name
,
flags_str
)
;
fprintf
(
asm_out_file
,
"\t.align\t%d\n"
,
align_value
)
;
fprintf
(
asm_out_file
,
"\t.global\t%s\n"
,
symbol_name
)
;
fprintf
(
asm_out_file
,
"\t.type\t%s, %s\n"
,
symbol_name
,
type_str
)
;
fprintf
(
asm_out_file
,
"%s:\n"
,
symbol_name
)
;
}
</s>

A helper function to emit section head template .


<s>
static
void
nds32_emit_section_tail_template
(
char
symbol_name
[
]
)
{
fprintf
(
asm_out_file
,
"\t.size\t%s, .-%s\n"
,
symbol_name
,
symbol_name
)
;
}
</s>

A helper function to emit section tail template .


"invalid id value for interrupt attribute"

FIXME : FOR BACKWARD COMPATIBILITY , we need to support following patterns : __attribute__ ( ( interrupt ( `` XXX ; YYY ; id=ZZZ '' ) ) ) __attribute__ ( ( exception ( `` XXX ; YYY ; id=ZZZ '' ) ) ) __attribute__ ( ( reset ( `` vectors=XXX ; nmi_func=YYY ; warm_func=ZZZ '' ) ) ) We provide several functions to parse the strings .


<s> bool nds32_isr_function_critical_p ( tree func ) { tree t_intr ; tree t_excp ; tree t_critical ; tree attrs ; if ( TREE_CODE ( func ) != FUNCTION_DECL ) abort ( ) ; attrs = DECL_ATTRIBUTES ( func ) ; t_intr = lookup_attribute ( "interrupt" , attrs ) ; t_excp = lookup_attribute ( "exception" , attrs ) ; t_critical = lookup_attribute ( "critical" , attrs ) ; if ( ( t_intr == NULL_TREE ) && ( t_excp == NULL_TREE ) ) return false ; if ( t_critical != NULL_TREE ) return true ; if ( t_intr != NULL_TREE || t_excp != NULL_TREE ) { char target_str [ 100 ] ; char * critical_str ; tree t_check ; tree string_arg ; t_check = t_intr ? t_intr : t_excp ; if ( TREE_CODE ( TREE_VALUE ( TREE_VALUE ( t_check ) ) ) == STRING_CST ) { string_arg = TREE_VALUE ( TREE_VALUE ( t_check ) ) ; strcpy ( target_str , TREE_STRING_POINTER ( string_arg ) ) ; critical_str = strstr ( target_str , "critical" ) ; if ( critical_str ) return true ; } } return false ; } </s>

Return true if FUNC is a isr function with critical attribute .

nds32 "interrupt" "exception" "critical" 100 "critical"


<s> bool nds32_isr_function_p ( tree func ) { tree t_intr ; tree t_excp ; tree t_reset ; tree attrs ; if ( TREE_CODE ( func ) != FUNCTION_DECL ) abort ( ) ; attrs = DECL_ATTRIBUTES ( func ) ; t_intr = lookup_attribute ( "interrupt" , attrs ) ; t_excp = lookup_attribute ( "exception" , attrs ) ; t_reset = lookup_attribute ( "reset" , attrs ) ; return ( ( t_intr != NULL_TREE ) || ( t_excp != NULL_TREE ) || ( t_reset != NULL_TREE ) ) ; } </s>


<s> enum nds32_16bit_address_type nds32_mem_format ( rtx op ) { machine_mode mode_test ; int val ; int regno ; if ( ! TARGET_16_BIT ) return ADDRESS_NOT_16BIT_FORMAT ; mode_test = GET_MODE ( op ) ; op = XEXP ( op , 0 ) ; if ( GET_CODE ( op ) == REG && ( mode_test == SImode ) ) return ADDRESS_REG ; if ( GET_CODE ( op ) == REG && ( REGNO ( op ) < R8_REGNUM ) ) return ADDRESS_LO_REG_IMM3U ; if ( ( GET_CODE ( op ) == POST_INC ) && ( mode_test == SImode ) ) { regno = REGNO ( XEXP ( op , 0 ) ) ; if ( regno < 8 ) return ADDRESS_POST_INC_LO_REG_IMM3U ; } if ( ( GET_CODE ( op ) == POST_MODIFY ) && ( mode_test == SImode ) && ( REG_P ( XEXP ( XEXP ( op , 1 ) , 0 ) ) ) && ( CONST_INT_P ( XEXP ( XEXP ( op , 1 ) , 1 ) ) ) ) { regno = REGNO ( XEXP ( XEXP ( op , 1 ) , 0 ) ) ; val = INTVAL ( XEXP ( XEXP ( op , 1 ) , 1 ) ) ; if ( regno < 8 && val < 32 ) return ADDRESS_POST_INC_LO_REG_IMM3U ; } if ( ( GET_CODE ( op ) == PLUS ) && ( GET_CODE ( XEXP ( op , 0 ) ) == REG ) && ( GET_CODE ( XEXP ( op , 1 ) ) == CONST_INT ) ) { val = INTVAL ( XEXP ( op , 1 ) ) ; regno = REGNO ( XEXP ( op , 0 ) ) ; if ( regno > 7 && regno != SP_REGNUM && regno != FP_REGNUM ) return ADDRESS_NOT_16BIT_FORMAT ; switch ( mode_test ) { case QImode : if ( val >= 0 && val < 8 && regno < 8 ) return ADDRESS_LO_REG_IMM3U ; break ; case HImode : if ( val >= 0 && val < 16 && ( val % 2 == 0 ) && regno < 8 ) return ADDRESS_LO_REG_IMM3U ; break ; case SImode : case SFmode : case DFmode : if ( ( regno == FP_REGNUM ) && ( val >= 0 && val < 512 && ( val % 4 == 0 ) ) ) return ADDRESS_FP_IMM7U ; else if ( ( regno == SP_REGNUM ) && ( val >= 0 && val < 512 && ( val % 4 == 0 ) ) ) return ADDRESS_SP_IMM7U ; else if ( val >= 0 && val < 32 && ( val % 4 == 0 ) && regno < 8 ) return ADDRESS_LO_REG_IMM3U ; break ; default : break ; } } return ADDRESS_NOT_16BIT_FORMAT ; } </s>

A helper function to return memory format .


<s>
const
char
*
nds32_output_16bit_load
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
unsigned
char
size
;
rtx
code
=
XEXP
(
operands
[
1
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
nds32_mem_format
(
operands
[
1
]
)
)
{
case
ADDRESS_REG
:
operands
[
1
]
=
code
;
output_asm_insn
(
"lwi450\t%0, [%1]"
,
operands
)
;
break
;
case
ADDRESS_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci333\t%%0, %%1"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_INC_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci333.bi\t%%0, %%1"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_FP_IMM7U
:
output_asm_insn
(
"lwi37\t%0, %1"
,
operands
)
;
break
;
case
ADDRESS_SP_IMM7U
:
operands
[
1
]
=
XEXP
(
code
,
1
)
;
output_asm_insn
(
"lwi37.sp\t%0, [ + (%1)]"
,
operands
)
;
break
;
default
:
break
;
}
return
""
;
}
</s>


<s>
const
char
*
nds32_output_16bit_store
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
char
size
;
rtx
code
=
XEXP
(
operands
[
0
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
nds32_mem_format
(
operands
[
0
]
)
)
{
case
ADDRESS_REG
:
operands
[
0
]
=
code
;
output_asm_insn
(
"swi450\t%1, [%0]"
,
operands
)
;
break
;
case
ADDRESS_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci333\t%%1, %%0"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_INC_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci333.bi\t%%1, %%0"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_FP_IMM7U
:
output_asm_insn
(
"swi37\t%1, %0"
,
operands
)
;
break
;
case
ADDRESS_SP_IMM7U
:
operands
[
0
]
=
XEXP
(
code
,
1
)
;
output_asm_insn
(
"swi37.sp\t%1, [ + (%0)]"
,
operands
)
;
break
;
default
:
break
;
}
return
""
;
}
</s>


<s>
const
char
*
nds32_output_casesi
(
rtx
*
operands
)
{
output_asm_insn
(
"la\t$ta, %l1"
,
operands
)
;
output_asm_insn
(
"lw\t%2, [$ta + %0 << 2]"
,
operands
)
;
if
(
TARGET_16_BIT
)
return
"jr5\t%2"
;
else
return
"jr\t%2"
;
}
</s>

Function to generate normal jump table .


<s>
const
char
*
nds32_output_casesi_pc_relative
(
rtx
*
operands
)
{
machine_mode
mode
;
rtx
diff_vec
;
diff_vec
=
PATTERN
(
NEXT_INSN
(
as_a
<
rtx_insn
*
>
(
operands
[
1
]
)
)
)
;
gcc_assert
(
GET_CODE
(
diff_vec
)
==
ADDR_DIFF_VEC
)
;
output_asm_insn
(
"la\t$ta, %l1"
,
operands
)
;
mode
=
GET_MODE
(
diff_vec
)
;
switch
(
mode
)
{
case
QImode
:
output_asm_insn
(
"lb\t%2, [$ta + %0 << 0]"
,
operands
)
;
break
;
case
HImode
:
output_asm_insn
(
"lh\t%2, [$ta + %0 << 1]"
,
operands
)
;
break
;
case
SImode
:
output_asm_insn
(
"lw\t%2, [$ta + %0 << 2]"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
output_asm_insn
(
"add\t$ta, %2, $ta"
,
operands
)
;
if
(
TARGET_16_BIT
)
return
"jr5\t$ta"
;
else
return
"jr\t$ta"
;
}
</s>

Function to generate PC relative jump table . Refer to nds32.md for more details . The following is the sample for the case that diff value can be presented in '.short ' size . addi $ r1 , $ r1 , - ( case_lower_bound ) slti $ ta , $ r1 , ( case_number ) beqz $ ta , .L_skip_label la $ ta , .L35 ! get jump table address lh $ r1 , [ $ ta + $ r1 < < 1 ] ! load symbol diff from jump table entry addi $ ta , $ r1 , $ ta jr5 $ ta ! jump table entry L35 : .short .L25-.L35 .short .L26-.L35 .short .L27-.L35 .short .L28-.L35 .short .L29-.L35 .short .L30-.L35 .short .L31-.L35 .short .L32-.L35 .short .L33-.L35 .short .L34-.L35


<s>
const
char
*
nds32_output_stack_pop
(
rtx
par_rtx
ATTRIBUTE_UNUSED
)
{
char
pattern
[
100
]
;
rtx
operands
[
3
]
;
int
rb_callee_saved
=
cfun
->
machine
->
callee_saved_first_gpr_regno
;
int
re_callee_saved
=
cfun
->
machine
->
callee_saved_last_gpr_regno
;
if
(
TARGET_V3PUSH
&&
!
nds32_isr_function_p
(
current_function_decl
)
&&
(
cfun
->
machine
->
va_args_size
==
0
)
)
{
int
sp_adjust
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
sp_adjust
=
cfun
->
machine
->
local_size
+
cfun
->
machine
->
out_args_size
+
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
;
if
(
satisfies_constraint_Iu08
(
GEN_INT
(
sp_adjust
)
)
&&
NDS32_DOUBLE_WORD_ALIGN_P
(
sp_adjust
)
&&
!
cfun
->
calls_alloca
)
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
else
operands
[
1
]
=
GEN_INT
(
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop25\t%%0, %%1"
)
;
}
else
{
int
pop_en4_only_p
=
0
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_callee_saved
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
if
(
!
cfun
->
machine
->
fp_size
&&
!
cfun
->
machine
->
gp_size
&&
!
cfun
->
machine
->
lp_size
&&
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
{
return
""
;
}
else
{
if
(
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
pop_en4_only_p
=
1
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop.s\t%s{%s%s%s }"
,
pop_en4_only_p
""
:
"%0, %1, "
,
cfun
->
machine
->
fp_size
" $fp"
:
""
,
cfun
->
machine
->
gp_size
" $gp"
:
""
,
cfun
->
machine
->
lp_size
" $lp"
:
""
)
;
}
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>

Function to output stack pop operation . We need to deal with normal stack pop multiple or stack v3pop .


<s>
const
char
*
nds32_output_stack_push
(
rtx
par_rtx
)
{
char
pattern
[
100
]
;
rtx
operands
[
3
]
;
int
rb_va_args
=
cfun
->
machine
->
va_args_first_regno
;
int
re_va_args
=
cfun
->
machine
->
va_args_last_regno
;
int
last_argument_regno
=
NDS32_FIRST_GPR_REGNUM
+
NDS32_MAX_GPR_REGS_FOR_ARGS
1
;
int
rb_callee_saved
=
cfun
->
machine
->
callee_saved_first_gpr_regno
;
int
re_callee_saved
=
cfun
->
machine
->
callee_saved_last_gpr_regno
;
if
(
reg_mentioned_p
(
gen_rtx_REG
(
SImode
,
last_argument_regno
)
,
par_rtx
)
)
{
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_va_args
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_va_args
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"push.s\t%s"
,
"%0, %1, { }"
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
if
(
TARGET_V3PUSH
&&
!
nds32_isr_function_p
(
current_function_decl
)
&&
(
cfun
->
machine
->
va_args_size
==
0
)
)
{
int
sp_adjust
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
sp_adjust
=
cfun
->
machine
->
local_size
+
cfun
->
machine
->
out_args_size
+
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
;
if
(
satisfies_constraint_Iu08
(
GEN_INT
(
sp_adjust
)
)
&&
NDS32_DOUBLE_WORD_ALIGN_P
(
sp_adjust
)
)
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
else
operands
[
1
]
=
GEN_INT
(
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"push25\t%%0, %%1"
)
;
}
else
{
int
push_en4_only_p
=
0
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_callee_saved
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
if
(
!
cfun
->
machine
->
fp_size
&&
!
cfun
->
machine
->
gp_size
&&
!
cfun
->
machine
->
lp_size
&&
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
{
return
""
;
}
else
{
if
(
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
push_en4_only_p
=
1
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"push.s\t%s{%s%s%s }"
,
push_en4_only_p
""
:
"%0, %1, "
,
cfun
->
machine
->
fp_size
" $fp"
:
""
,
cfun
->
machine
->
gp_size
" $gp"
:
""
,
cfun
->
machine
->
lp_size
" $lp"
:
""
)
;
}
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>

Function to output stack push operation . We need to deal with normal stack push multiple or stack v3push .


<s> bool nds32_long_call_p ( rtx symbol ) { return TARGET_CMODEL_LARGE ; } </s>


<s>
const
char
*
nds32_output_casesi_pc_relative
(
rtx
*
operands
)
{
machine_mode
mode
;
rtx
diff_vec
;
diff_vec
=
PATTERN
(
NEXT_INSN
(
as_a
<
rtx_insn
*
>
(
operands
[
1
]
)
)
)
;
gcc_assert
(
GET_CODE
(
diff_vec
)
==
ADDR_DIFF_VEC
)
;
output_asm_insn
(
"la\t$ta, %l1"
,
operands
)
;
mode
=
GET_MODE
(
diff_vec
)
;
switch
(
mode
)
{
case
E_QImode
:
output_asm_insn
(
"lb\t%2, [$ta + %0 << 0]"
,
operands
)
;
break
;
case
E_HImode
:
output_asm_insn
(
"lh\t%2, [$ta + %0 << 1]"
,
operands
)
;
break
;
case
E_SImode
:
output_asm_insn
(
"lw\t%2, [$ta + %0 << 2]"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
output_asm_insn
(
"add\t$ta, %2, $ta"
,
operands
)
;
if
(
TARGET_16_BIT
)
return
"jr5\t$ta"
;
else
return
"jr\t$ta"
;
}
</s>


<s>
const
char
*
nds32_output_stack_pop
(
rtx
par_rtx
ATTRIBUTE_UNUSED
)
{
char
pattern
[
100
]
;
rtx
operands
[
3
]
;
int
rb_eh_data
=
cfun
->
machine
->
eh_return_data_first_regno
;
int
re_eh_data
=
cfun
->
machine
->
eh_return_data_last_regno
;
int
first_eh_data_regno
=
EH_RETURN_DATA_REGNO
(
0
)
;
int
rb_callee_saved
=
cfun
->
machine
->
callee_saved_first_gpr_regno
;
int
re_callee_saved
=
cfun
->
machine
->
callee_saved_last_gpr_regno
;
if
(
reg_mentioned_p
(
gen_rtx_REG
(
SImode
,
first_eh_data_regno
)
,
par_rtx
)
)
{
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_eh_data
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_eh_data
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop.s\t%s"
,
"%0, %1, { }"
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
if
(
TARGET_V3PUSH
&&
!
nds32_isr_function_p
(
current_function_decl
)
&&
(
cfun
->
machine
->
va_args_size
==
0
)
)
{
int
sp_adjust
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
sp_adjust
=
cfun
->
machine
->
local_size
+
cfun
->
machine
->
out_args_size
+
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
+
cfun
->
machine
->
callee_saved_fpr_regs_size
;
if
(
satisfies_constraint_Iu08
(
GEN_INT
(
sp_adjust
)
)
&&
NDS32_DOUBLE_WORD_ALIGN_P
(
sp_adjust
)
&&
!
cfun
->
calls_alloca
)
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
else
{
if
(
cfun
->
machine
->
callee_saved_first_fpr_regno
!=
SP_REGNUM
)
{
sp_adjust
=
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
+
cfun
->
machine
->
callee_saved_fpr_regs_size
;
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
}
else
{
operands
[
1
]
=
GEN_INT
(
0
)
;
}
}
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop25\t%%0, %%1"
)
;
}
else
{
int
pop_en4_only_p
=
0
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_callee_saved
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
if
(
!
cfun
->
machine
->
fp_size
&&
!
cfun
->
machine
->
gp_size
&&
!
cfun
->
machine
->
lp_size
&&
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
{
return
""
;
}
else
{
if
(
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
pop_en4_only_p
=
1
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop.s\t%s{%s%s%s }"
,
pop_en4_only_p
""
:
"%0, %1, "
,
cfun
->
machine
->
fp_size
" $fp"
:
""
,
cfun
->
machine
->
gp_size
" $gp"
:
""
,
cfun
->
machine
->
lp_size
" $lp"
:
""
)
;
}
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>


<s> void nds32_spilt_doubleword ( rtx * operands , bool load_p ) { int reg = load_p ? 0 : 1 ; int mem = load_p ? 1 : 0 ; rtx reg_rtx = load_p ? operands [ 0 ] : operands [ 1 ] ; rtx mem_rtx = load_p ? operands [ 1 ] : operands [ 0 ] ; rtx low_part [ 2 ] , high_part [ 2 ] ; rtx sub_mem = XEXP ( mem_rtx , 0 ) ; low_part [ reg ] = simplify_gen_subreg ( SImode , reg_rtx , GET_MODE ( reg_rtx ) , 0 ) ; high_part [ reg ] = simplify_gen_subreg ( SImode , reg_rtx , GET_MODE ( reg_rtx ) , 4 ) ; if ( GET_CODE ( sub_mem ) == POST_DEC ) { sub_mem = XEXP ( sub_mem , 0 ) ; low_part [ mem ] = gen_frame_mem ( SImode , gen_rtx_POST_MODIFY ( Pmode , sub_mem , gen_rtx_PLUS ( Pmode , sub_mem , GEN_INT ( 4 ) ) ) ) ; high_part [ mem ] = gen_frame_mem ( SImode , gen_rtx_POST_MODIFY ( Pmode , sub_mem , gen_rtx_PLUS ( Pmode , sub_mem , GEN_INT ( - 12 ) ) ) ) ; } else if ( GET_CODE ( sub_mem ) == POST_MODIFY ) { rtx post_mem = XEXP ( sub_mem , 0 ) ; rtx plus_op = XEXP ( sub_mem , 1 ) ; rtx post_val = XEXP ( plus_op , 1 ) ; low_part [ mem ] = gen_frame_mem ( SImode , gen_rtx_POST_MODIFY ( Pmode , post_mem , gen_rtx_PLUS ( Pmode , post_mem , post_val ) ) ) ; high_part [ mem ] = gen_frame_mem ( SImode , plus_constant ( Pmode , post_mem , 4 ) ) ; } else { low_part [ mem ] = adjust_address ( mem_rtx , SImode , 0 ) ; high_part [ mem ] = adjust_address ( mem_rtx , SImode , 4 ) ; } if ( ( load_p && reg_overlap_mentioned_p ( low_part [ 0 ] , high_part [ 1 ] ) ) || GET_CODE ( sub_mem ) == POST_MODIFY ) { operands [ 2 ] = high_part [ 0 ] ; operands [ 3 ] = high_part [ 1 ] ; operands [ 4 ] = low_part [ 0 ] ; operands [ 5 ] = low_part [ 1 ] ; } else { operands [ 2 ] = low_part [ 0 ] ; operands [ 3 ] = low_part [ 1 ] ; operands [ 4 ] = high_part [ 0 ] ; operands [ 5 ] = high_part [ 1 ] ; } } </s>

Spilt a doubleword instrucion to two single word instructions .


<s> static char nds32_byte_to_size ( int byte ) { switch ( byte ) { case 4 : return 'w' ; case 2 : return 'h' ; case 1 : return 'b' ; default : gcc_unreachable ( ) ; } } </s>

A helper function to return character based on byte size .


<s> bool nds32_indirect_call_referenced_p ( rtx x ) { if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_ICT ) x = XVECEXP ( x , 0 , 0 ) ; if ( GET_CODE ( x ) == SYMBOL_REF ) { tree decl = SYMBOL_REF_DECL ( x ) ; return decl && ( lookup_attribute ( "indirect_call" , DECL_ATTRIBUTES ( decl ) ) != NULL ) ; } return false ; } </s>

Return true X is a indirect call symbol .


<s> rtx nds32_legitimize_ict_address ( rtx x ) { rtx symbol = x ; rtx addr = x ; rtx reg = gen_reg_rtx ( Pmode ) ; gcc_assert ( GET_CODE ( x ) == SYMBOL_REF && nds32_indirect_call_referenced_p ( x ) ) ; addr = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , symbol ) , UNSPEC_ICT ) ; addr = gen_rtx_CONST ( SImode , addr ) ; emit_insn ( gen_sethi ( reg , addr ) ) ; x = gen_const_mem ( SImode , gen_rtx_LO_SUM ( Pmode , reg , addr ) ) ; return x ; } </s>

Expand ICT symbol . Example for @ ICT and ICT model=large : la $ r0 , symbol @ ICT - > sethi $ rt , hi20 ( symbol @ ICT ) lwi $ r0 , [ $ rt + lo12 ( symbol @ ICT ) ]


<s> rtx nds32_legitimize_pic_address ( rtx x ) { rtx addr = x ; rtx reg = gen_reg_rtx ( Pmode ) ; rtx pat ; int relax_group_id = nds32_alloc_relax_group_id ( ) ; if ( GET_CODE ( x ) == LABEL_REF || ( GET_CODE ( x ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( x ) || SYMBOL_REF_LOCAL_P ( x ) ) ) ) { addr = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_GOTOFF ) ; addr = gen_rtx_CONST ( SImode , addr ) ; emit_insn ( gen_sym_got ( reg , addr , GEN_INT ( relax_group_id ) ) ) ; x = gen_rtx_PLUS ( Pmode , reg , pic_offset_table_rtx ) ; } else if ( GET_CODE ( x ) == SYMBOL_REF ) { addr = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_GOT ) ; addr = gen_rtx_CONST ( SImode , addr ) ; emit_insn ( gen_sym_got ( reg , addr , GEN_INT ( relax_group_id ) ) ) ; x = gen_const_mem ( SImode , gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , reg ) ) ; } else if ( GET_CODE ( x ) == CONST ) { addr = XEXP ( x , 0 ) ; gcc_assert ( GET_CODE ( addr ) == PLUS ) ; rtx op0 = XEXP ( addr , 0 ) ; rtx op1 = XEXP ( addr , 1 ) ; if ( ( GET_CODE ( op0 ) == LABEL_REF || ( GET_CODE ( op0 ) == SYMBOL_REF && ( CONSTANT_POOL_ADDRESS_P ( op0 ) || SYMBOL_REF_LOCAL_P ( op0 ) ) ) ) && GET_CODE ( op1 ) == CONST_INT ) { pat = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , op0 ) , UNSPEC_GOTOFF ) ; pat = gen_rtx_PLUS ( Pmode , pat , op1 ) ; pat = gen_rtx_CONST ( Pmode , pat ) ; emit_insn ( gen_sym_got ( reg , pat , GEN_INT ( relax_group_id ) ) ) ; x = gen_rtx_PLUS ( Pmode , reg , pic_offset_table_rtx ) ; } else if ( GET_CODE ( op0 ) == SYMBOL_REF && GET_CODE ( op1 ) == CONST_INT ) { addr = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , op0 ) , UNSPEC_GOT ) ; addr = gen_rtx_CONST ( SImode , addr ) ; emit_insn ( gen_sym_got ( reg , addr , GEN_INT ( relax_group_id ) ) ) ; addr = gen_const_mem ( SImode , gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , reg ) ) ; emit_move_insn ( reg , addr ) ; if ( satisfies_constraint_Is15 ( op1 ) ) x = gen_rtx_PLUS ( Pmode , reg , op1 ) ; else { rtx tmp_reg = gen_reg_rtx ( SImode ) ; emit_insn ( gen_movsi ( tmp_reg , op1 ) ) ; x = gen_rtx_PLUS ( Pmode , reg , tmp_reg ) ; } } else { debug_rtx ( x ) ; gcc_unreachable ( ) ; } } return x ; } </s>

Expand PIC code for @ GOTOFF and @ GOT . Example for @ GOTOFF : la $ r0 , symbol @ GOTOFF - > sethi $ ta , hi20 ( symbol @ GOTOFF ) ori $ ta , $ ta , lo12 ( symbol @ GOTOFF ) add $ r0 , $ ta , $ gp Example for @ GOT : la $ r0 , symbol @ GOT - > sethi $ ta , hi20 ( symbol @ GOT ) ori $ ta , $ ta , lo12 ( symbol @ GOT ) lw $ r0 , [ $ ta + $ gp ]


<s> rtx nds32_legitimize_tls_address ( rtx x ) { rtx tmp_reg ; rtx tp_reg = gen_rtx_REG ( Pmode , TP_REGNUM ) ; rtx pat , insns , reg0 ; int relax_group_id = nds32_alloc_relax_group_id ( ) ; if ( GET_CODE ( x ) == SYMBOL_REF ) switch ( SYMBOL_REF_TLS_MODEL ( x ) ) { case TLS_MODEL_GLOBAL_DYNAMIC : case TLS_MODEL_LOCAL_DYNAMIC : if ( SYMBOL_REF_TLS_MODEL ( x ) == TLS_MODEL_GLOBAL_DYNAMIC ) pat = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_TLSGD ) ; else pat = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_TLSLD ) ; pat = gen_rtx_CONST ( SImode , pat ) ; reg0 = gen_rtx_REG ( Pmode , 0 ) ; insns = emit_call_insn ( gen_tls_desc ( pat , GEN_INT ( relax_group_id ) ) ) ; use_reg ( & CALL_INSN_FUNCTION_USAGE ( insns ) , pic_offset_table_rtx ) ; RTL_CONST_CALL_P ( insns ) = 1 ; tmp_reg = gen_reg_rtx ( SImode ) ; emit_move_insn ( tmp_reg , reg0 ) ; x = tmp_reg ; break ; case TLS_MODEL_INITIAL_EXEC : pat = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_TLSIE ) ; tmp_reg = gen_reg_rtx ( SImode ) ; pat = gen_rtx_CONST ( SImode , pat ) ; emit_insn ( gen_tls_ie ( tmp_reg , pat , GEN_INT ( relax_group_id ) ) ) ; if ( flag_pic ) emit_use ( pic_offset_table_rtx ) ; x = gen_rtx_PLUS ( Pmode , tmp_reg , tp_reg ) ; break ; case TLS_MODEL_LOCAL_EXEC : tmp_reg = gen_reg_rtx ( SImode ) ; pat = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , x ) , UNSPEC_TLSLE ) ; pat = gen_rtx_CONST ( SImode , pat ) ; emit_insn ( gen_tls_le ( tmp_reg , pat , GEN_INT ( relax_group_id ) ) ) ; x = gen_rtx_PLUS ( Pmode , tmp_reg , tp_reg ) ; break ; default : gcc_unreachable ( ) ; } else if ( GET_CODE ( x ) == CONST ) { rtx base , addend ; split_const ( x , & base , & addend ) ; if ( SYMBOL_REF_TLS_MODEL ( base ) == TLS_MODEL_LOCAL_EXEC ) { tmp_reg = gen_reg_rtx ( SImode ) ; pat = gen_rtx_UNSPEC ( SImode , gen_rtvec ( 1 , base ) , UNSPEC_TLSLE ) ; pat = gen_rtx_PLUS ( SImode , pat , addend ) ; pat = gen_rtx_CONST ( SImode , pat ) ; emit_insn ( gen_tls_le ( tmp_reg , pat , GEN_INT ( relax_group_id ) ) ) ; x = gen_rtx_PLUS ( Pmode , tmp_reg , tp_reg ) ; } } return x ; } </s>

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


<s> bool nds32_long_call_p ( rtx symbol ) { if ( nds32_indirect_call_referenced_p ( symbol ) ) return TARGET_ICT_MODEL_LARGE ; else return TARGET_CMODEL_LARGE ; } </s>


<s>
const
char
*
nds32_output_16bit_load
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
unsigned
char
size
;
rtx
code
=
XEXP
(
operands
[
1
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
nds32_mem_format
(
operands
[
1
]
)
)
{
case
ADDRESS_REG
:
operands
[
1
]
=
code
;
output_asm_insn
(
"lwi450\t%0, [%1]"
,
operands
)
;
break
;
case
ADDRESS_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci333\t%%0, %%1"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_INC_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"lwi333.bi\t%%0, %%1, 4"
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_MODIFY_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"lwi333.bi\t%%0, %%1"
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_R8_IMM7U
:
output_asm_insn
(
"lwi45.fe\t%0, %e1"
,
operands
)
;
break
;
case
ADDRESS_FP_IMM7U
:
output_asm_insn
(
"lwi37\t%0, %1"
,
operands
)
;
break
;
case
ADDRESS_SP_IMM7U
:
operands
[
1
]
=
XEXP
(
code
,
1
)
;
output_asm_insn
(
"lwi37.sp\t%0, [ + (%1)]"
,
operands
)
;
break
;
default
:
break
;
}
return
""
;
}
</s>


<s>
const
char
*
nds32_output_16bit_store
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
char
size
;
rtx
code
=
XEXP
(
operands
[
0
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
nds32_mem_format
(
operands
[
0
]
)
)
{
case
ADDRESS_REG
:
operands
[
0
]
=
code
;
output_asm_insn
(
"swi450\t%1, [%0]"
,
operands
)
;
break
;
case
ADDRESS_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci333\t%%1, %%0"
,
size
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_INC_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"swi333.bi\t%%1, %%0, 4"
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_POST_MODIFY_LO_REG_IMM3U
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"swi333.bi\t%%1, %%0"
)
;
output_asm_insn
(
pattern
,
operands
)
;
break
;
case
ADDRESS_FP_IMM7U
:
output_asm_insn
(
"swi37\t%1, %0"
,
operands
)
;
break
;
case
ADDRESS_SP_IMM7U
:
operands
[
0
]
=
XEXP
(
code
,
1
)
;
output_asm_insn
(
"swi37.sp\t%1, [ + (%0)]"
,
operands
)
;
break
;
default
:
break
;
}
return
""
;
}
</s>


<s>
const
char
*
nds32_output_32bit_load
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
unsigned
char
size
;
rtx
code
;
code
=
XEXP
(
operands
[
1
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
GET_CODE
(
code
)
)
{
case
REG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci\t%%0, %%1"
,
size
)
;
break
;
case
SYMBOL_REF
:
case
CONST
:
operands
[
1
]
=
XEXP
(
operands
[
1
]
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci.gp\t%%0, [ + %%1]"
,
size
)
;
break
;
case
POST_INC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci.bi\t%%0, %%1, %d"
,
size
,
byte
)
;
break
;
case
POST_DEC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci.bi\t%%0, %%1, -%d"
,
size
,
byte
)
;
break
;
case
POST_MODIFY
:
switch
(
GET_CODE
(
XEXP
(
XEXP
(
code
,
1
)
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%c.bi\t%%0, %%1"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci.bi\t%%0, %%1"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
PLUS
:
switch
(
GET_CODE
(
XEXP
(
code
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%c\t%%0, %%1"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci\t%%0, %%1"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
LO_SUM
:
operands
[
2
]
=
XEXP
(
code
,
1
)
;
operands
[
1
]
=
XEXP
(
code
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%ci\t%%0, [%%1 + lo12(%%2)]"
,
size
)
;
break
;
default
:
abort
(
)
;
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>


<s>
const
char
*
nds32_output_32bit_load_s
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
unsigned
char
size
;
rtx
code
;
code
=
XEXP
(
operands
[
1
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
GET_CODE
(
code
)
)
{
case
REG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi\t%%0, %%1"
,
size
)
;
break
;
case
SYMBOL_REF
:
case
CONST
:
operands
[
1
]
=
XEXP
(
operands
[
1
]
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi.gp\t%%0, [ + %%1]"
,
size
)
;
break
;
case
POST_INC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi.bi\t%%0, %%1, %d"
,
size
,
byte
)
;
break
;
case
POST_DEC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi.bi\t%%0, %%1, -%d"
,
size
,
byte
)
;
break
;
case
POST_MODIFY
:
switch
(
GET_CODE
(
XEXP
(
XEXP
(
code
,
1
)
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%cs.bi\t%%0, %%1"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi.bi\t%%0, %%1"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
PLUS
:
switch
(
GET_CODE
(
XEXP
(
code
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%cs\t%%0, %%1"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi\t%%0, %%1"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
LO_SUM
:
operands
[
2
]
=
XEXP
(
code
,
1
)
;
operands
[
1
]
=
XEXP
(
code
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"l%csi\t%%0, [%%1 + lo12(%%2)]"
,
size
)
;
break
;
default
:
abort
(
)
;
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>

Output 32-bit load with signed extension .


<s>
const
char
*
nds32_output_32bit_store
(
rtx
*
operands
,
int
byte
)
{
char
pattern
[
100
]
;
unsigned
char
size
;
rtx
code
=
XEXP
(
operands
[
0
]
,
0
)
;
size
=
nds32_byte_to_size
(
byte
)
;
switch
(
GET_CODE
(
code
)
)
{
case
REG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci\t%%1, %%0"
,
size
)
;
break
;
case
SYMBOL_REF
:
case
CONST
:
operands
[
0
]
=
XEXP
(
operands
[
0
]
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci.gp\t%%1, [ + %%0]"
,
size
)
;
break
;
case
POST_INC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci.bi\t%%1, %%0, %d"
,
size
,
byte
)
;
break
;
case
POST_DEC
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci.bi\t%%1, %%0, -%d"
,
size
,
byte
)
;
break
;
case
POST_MODIFY
:
switch
(
GET_CODE
(
XEXP
(
XEXP
(
code
,
1
)
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%c.bi\t%%1, %%0"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci.bi\t%%1, %%0"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
PLUS
:
switch
(
GET_CODE
(
XEXP
(
code
,
1
)
)
)
{
case
REG
:
case
SUBREG
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%c\t%%1, %%0"
,
size
)
;
break
;
case
CONST_INT
:
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci\t%%1, %%0"
,
size
)
;
break
;
default
:
abort
(
)
;
}
break
;
case
LO_SUM
:
operands
[
2
]
=
XEXP
(
code
,
1
)
;
operands
[
0
]
=
XEXP
(
code
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"s%ci\t%%1, [%%0 + lo12(%%2)]"
,
size
)
;
break
;
default
:
abort
(
)
;
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>


<s>
const
char
*
nds32_output_casesi
(
rtx
*
operands
)
{
if
(
flag_pic
)
{
output_asm_insn
(
"sethi\t$ta, hi20(%l1@GOTOFF)"
,
operands
)
;
output_asm_insn
(
"ori\t$ta, $ta, lo12(%l1@GOTOFF)"
,
operands
)
;
output_asm_insn
(
"add\t$ta, $ta, $gp"
,
operands
)
;
}
else
output_asm_insn
(
"la\t$ta, %l1"
,
operands
)
;
output_asm_insn
(
"lw\t%2, [$ta + %0 << 2]"
,
operands
)
;
if
(
TARGET_16_BIT
)
return
"jr5\t%2"
;
else
return
"jr\t%2"
;
}
</s>


<s>
const
char
*
nds32_output_casesi_pc_relative
(
rtx
*
operands
)
{
machine_mode
mode
;
rtx
diff_vec
;
diff_vec
=
PATTERN
(
NEXT_INSN
(
as_a
<
rtx_insn
*
>
(
operands
[
1
]
)
)
)
;
gcc_assert
(
GET_CODE
(
diff_vec
)
==
ADDR_DIFF_VEC
)
;
if
(
flag_pic
)
{
output_asm_insn
(
"sethi\t$ta, hi20(%l1@GOTOFF)"
,
operands
)
;
output_asm_insn
(
"ori\t$ta, $ta, lo12(%l1@GOTOFF)"
,
operands
)
;
output_asm_insn
(
"add\t$ta, $ta, $gp"
,
operands
)
;
}
else
output_asm_insn
(
"la\t$ta, %l1"
,
operands
)
;
mode
=
GET_MODE
(
diff_vec
)
;
switch
(
mode
)
{
case
E_QImode
:
output_asm_insn
(
"lb\t%2, [$ta + %0 << 0]"
,
operands
)
;
break
;
case
E_HImode
:
output_asm_insn
(
"lh\t%2, [$ta + %0 << 1]"
,
operands
)
;
break
;
case
E_SImode
:
output_asm_insn
(
"lw\t%2, [$ta + %0 << 2]"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
output_asm_insn
(
"add\t$ta, %2, $ta"
,
operands
)
;
if
(
TARGET_16_BIT
)
return
"jr5\t$ta"
;
else
return
"jr\t$ta"
;
}
</s>


<s>
const
char
*
nds32_output_double
(
rtx
*
operands
,
bool
load_p
)
{
char
pattern
[
100
]
;
int
reg
=
load_p
0
:
1
;
int
mem
=
load_p
1
:
0
;
rtx
otherops
[
3
]
;
rtx
addr
=
XEXP
(
operands
[
mem
]
,
0
)
;
otherops
[
0
]
=
gen_rtx_REG
(
SImode
,
REGNO
(
operands
[
reg
]
)
)
;
otherops
[
1
]
=
gen_rtx_REG
(
SImode
,
REGNO
(
operands
[
reg
]
)
+
1
)
;
if
(
GET_CODE
(
addr
)
==
POST_INC
)
{
otherops
[
2
]
=
XEXP
(
addr
,
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"%cmw.bim\t%%0, [%%2], %%1, 0"
,
load_p
'l'
:
's'
)
;
}
else
{
otherops
[
2
]
=
addr
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"%cmw.bi\t%%0, [%%2], %%1, 0"
,
load_p
'l'
:
's'
)
;
}
output_asm_insn
(
pattern
,
otherops
)
;
return
""
;
}
</s>

Using multiple load/store instruction to output doubleword instruction .


<s>
const
char
*
nds32_output_float_load
(
rtx
*
operands
)
{
char
buff
[
100
]
;
const
char
*
pattern
;
rtx
addr
,
addr_op0
,
addr_op1
;
int
dp
=
GET_MODE_SIZE
(
GET_MODE
(
operands
[
0
]
)
)
==
8
;
addr
=
XEXP
(
operands
[
1
]
,
0
)
;
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
pattern
=
"fl%ci\t%%0, %%1"
;
break
;
case
PLUS
:
addr_op0
=
XEXP
(
addr
,
0
)
;
addr_op1
=
XEXP
(
addr
,
1
)
;
if
(
REG_P
(
addr_op0
)
&&
REG_P
(
addr_op1
)
)
pattern
=
"fl%c\t%%0, %%1"
;
else
if
(
REG_P
(
addr_op0
)
&&
CONST_INT_P
(
addr_op1
)
)
pattern
=
"fl%ci\t%%0, %%1"
;
else
if
(
GET_CODE
(
addr_op0
)
==
MULT
&&
REG_P
(
addr_op1
)
&&
REG_P
(
XEXP
(
addr_op0
,
0
)
)
&&
CONST_INT_P
(
XEXP
(
addr_op0
,
1
)
)
)
pattern
=
"fl%c\t%%0, %%1"
;
else
gcc_unreachable
(
)
;
break
;
case
POST_MODIFY
:
addr_op0
=
XEXP
(
addr
,
0
)
;
addr_op1
=
XEXP
(
addr
,
1
)
;
if
(
REG_P
(
addr_op0
)
&&
GET_CODE
(
addr_op1
)
==
PLUS
&&
REG_P
(
XEXP
(
addr_op1
,
1
)
)
)
pattern
=
"fl%c.bi\t%%0, %%1"
;
else
if
(
REG_P
(
addr_op0
)
&&
GET_CODE
(
addr_op1
)
==
PLUS
&&
CONST_INT_P
(
XEXP
(
addr_op1
,
1
)
)
)
pattern
=
"fl%ci.bi\t%%0, %%1"
;
else
gcc_unreachable
(
)
;
break
;
case
POST_INC
:
if
(
REG_P
(
XEXP
(
addr
,
0
)
)
)
{
if
(
dp
)
pattern
=
"fl%ci.bi\t%%0, %%1, 8"
;
else
pattern
=
"fl%ci.bi\t%%0, %%1, 4"
;
}
else
gcc_unreachable
(
)
;
break
;
case
POST_DEC
:
if
(
REG_P
(
XEXP
(
addr
,
0
)
)
)
{
if
(
dp
)
pattern
=
"fl%ci.bi\t%%0, %%1, -8"
;
else
pattern
=
"fl%ci.bi\t%%0, %%1, -4"
;
}
else
gcc_unreachable
(
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
sprintf
(
buff
,
pattern
,
dp
'd'
:
's'
)
;
output_asm_insn
(
buff
,
operands
)
;
return
""
;
}
</s>


<s>
const
char
*
nds32_output_float_store
(
rtx
*
operands
)
{
char
buff
[
100
]
;
const
char
*
pattern
;
rtx
addr
,
addr_op0
,
addr_op1
;
int
dp
=
GET_MODE_SIZE
(
GET_MODE
(
operands
[
0
]
)
)
==
8
;
addr
=
XEXP
(
operands
[
0
]
,
0
)
;
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
pattern
=
"fs%ci\t%%1, %%0"
;
break
;
case
PLUS
:
addr_op0
=
XEXP
(
addr
,
0
)
;
addr_op1
=
XEXP
(
addr
,
1
)
;
if
(
REG_P
(
addr_op0
)
&&
REG_P
(
addr_op1
)
)
pattern
=
"fs%c\t%%1, %%0"
;
else
if
(
REG_P
(
addr_op0
)
&&
CONST_INT_P
(
addr_op1
)
)
pattern
=
"fs%ci\t%%1, %%0"
;
else
if
(
GET_CODE
(
addr_op0
)
==
MULT
&&
REG_P
(
addr_op1
)
&&
REG_P
(
XEXP
(
addr_op0
,
0
)
)
&&
CONST_INT_P
(
XEXP
(
addr_op0
,
1
)
)
)
pattern
=
"fs%c\t%%1, %%0"
;
else
gcc_unreachable
(
)
;
break
;
case
POST_MODIFY
:
addr_op0
=
XEXP
(
addr
,
0
)
;
addr_op1
=
XEXP
(
addr
,
1
)
;
if
(
REG_P
(
addr_op0
)
&&
GET_CODE
(
addr_op1
)
==
PLUS
&&
REG_P
(
XEXP
(
addr_op1
,
1
)
)
)
pattern
=
"fs%c.bi\t%%1, %%0"
;
else
if
(
REG_P
(
addr_op0
)
&&
GET_CODE
(
addr_op1
)
==
PLUS
&&
CONST_INT_P
(
XEXP
(
addr_op1
,
1
)
)
)
pattern
=
"fs%ci.bi\t%%1, %%0"
;
else
gcc_unreachable
(
)
;
break
;
case
POST_INC
:
if
(
REG_P
(
XEXP
(
addr
,
0
)
)
)
{
if
(
dp
)
pattern
=
"fs%ci.bi\t%%1, %%0, 8"
;
else
pattern
=
"fs%ci.bi\t%%1, %%0, 4"
;
}
else
gcc_unreachable
(
)
;
break
;
case
POST_DEC
:
if
(
REG_P
(
XEXP
(
addr
,
0
)
)
)
{
if
(
dp
)
pattern
=
"fs%ci.bi\t%%1, %%0, -8"
;
else
pattern
=
"fs%ci.bi\t%%1, %%0, -4"
;
}
else
gcc_unreachable
(
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
sprintf
(
buff
,
pattern
,
dp
'd'
:
's'
)
;
output_asm_insn
(
buff
,
operands
)
;
return
""
;
}
</s>


<s>
const
char
*
nds32_output_return
(
void
)
{
char
pattern
[
100
]
;
rtx
operands
[
2
]
;
int
re_callee_saved
=
cfun
->
machine
->
callee_saved_last_gpr_regno
;
int
sp_adjust
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
sp_adjust
=
cfun
->
machine
->
local_size
+
cfun
->
machine
->
out_args_size
+
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
+
cfun
->
machine
->
callee_saved_fpr_regs_size
;
if
(
satisfies_constraint_Iu08
(
GEN_INT
(
sp_adjust
)
)
&&
NDS32_DOUBLE_WORD_ALIGN_P
(
sp_adjust
)
&&
!
cfun
->
calls_alloca
)
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
else
operands
[
1
]
=
GEN_INT
(
0
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop25\t%%0, %%1"
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>


<s>
const
char
*
nds32_output_stack_pop
(
rtx
par_rtx
ATTRIBUTE_UNUSED
)
{
char
pattern
[
100
]
;
rtx
operands
[
3
]
;
int
rb_eh_data
=
cfun
->
machine
->
eh_return_data_first_regno
;
int
re_eh_data
=
cfun
->
machine
->
eh_return_data_last_regno
;
int
first_eh_data_regno
=
EH_RETURN_DATA_REGNO
(
0
)
;
int
rb_callee_saved
=
cfun
->
machine
->
callee_saved_first_gpr_regno
;
int
re_callee_saved
=
cfun
->
machine
->
callee_saved_last_gpr_regno
;
if
(
reg_mentioned_p
(
gen_rtx_REG
(
SImode
,
first_eh_data_regno
)
,
par_rtx
)
)
{
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_eh_data
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_eh_data
)
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop.s\t%s"
,
"%0, %1, { }"
)
;
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
if
(
NDS32_V3PUSH_AVAILABLE_P
)
{
int
sp_adjust
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
sp_adjust
=
cfun
->
machine
->
local_size
+
cfun
->
machine
->
out_args_size
+
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
+
cfun
->
machine
->
callee_saved_fpr_regs_size
;
if
(
satisfies_constraint_Iu08
(
GEN_INT
(
sp_adjust
)
)
&&
NDS32_DOUBLE_WORD_ALIGN_P
(
sp_adjust
)
&&
!
cfun
->
calls_alloca
)
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
else
{
if
(
cfun
->
machine
->
callee_saved_first_fpr_regno
!=
SP_REGNUM
)
{
sp_adjust
=
cfun
->
machine
->
callee_saved_area_gpr_padding_bytes
+
cfun
->
machine
->
callee_saved_fpr_regs_size
;
operands
[
1
]
=
GEN_INT
(
sp_adjust
)
;
}
else
{
operands
[
1
]
=
GEN_INT
(
0
)
;
}
}
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop25\t%%0, %%1"
)
;
}
else
{
int
pop_en4_only_p
=
0
;
operands
[
0
]
=
gen_rtx_REG
(
SImode
,
rb_callee_saved
)
;
operands
[
1
]
=
gen_rtx_REG
(
SImode
,
re_callee_saved
)
;
if
(
!
cfun
->
machine
->
fp_size
&&
!
cfun
->
machine
->
gp_size
&&
!
cfun
->
machine
->
lp_size
&&
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
{
return
""
;
}
else
{
if
(
REGNO
(
operands
[
0
]
)
==
SP_REGNUM
&&
REGNO
(
operands
[
1
]
)
==
SP_REGNUM
)
pop_en4_only_p
=
1
;
snprintf
(
pattern
,
sizeof
(
pattern
)
,
"pop.s\t%s{%s%s%s }"
,
pop_en4_only_p
""
:
"%0, %1, "
,
cfun
->
machine
->
fp_size
" $fp"
:
""
,
cfun
->
machine
->
gp_size
" $gp"
:
""
,
cfun
->
machine
->
lp_size
" $lp"
:
""
)
;
}
}
output_asm_insn
(
pattern
,
operands
)
;
return
""
;
}
</s>


".relax_hint %%1\n\tsethi $r0, hi20(%%0)\n\t"

".relax_hint %%1\n\tadd $r0, $r0, $gp\n\t"

Auxiliary function for output TLS patterns .


<s> void nds32_spilt_doubleword ( rtx * operands , bool load_p ) { int reg = load_p ? 0 : 1 ; int mem = load_p ? 1 : 0 ; rtx reg_rtx = load_p ? operands [ 0 ] : operands [ 1 ] ; rtx mem_rtx = load_p ? operands [ 1 ] : operands [ 0 ] ; rtx low_part [ 2 ] , high_part [ 2 ] ; rtx sub_mem = XEXP ( mem_rtx , 0 ) ; low_part [ reg ] = simplify_gen_subreg ( SImode , reg_rtx , GET_MODE ( reg_rtx ) , 0 ) ; high_part [ reg ] = simplify_gen_subreg ( SImode , reg_rtx , GET_MODE ( reg_rtx ) , 4 ) ; if ( GET_CODE ( sub_mem ) == POST_DEC ) { sub_mem = XEXP ( sub_mem , 0 ) ; low_part [ mem ] = gen_rtx_MEM ( SImode , gen_rtx_POST_MODIFY ( Pmode , sub_mem , gen_rtx_PLUS ( Pmode , sub_mem , GEN_INT ( 4 ) ) ) ) ; high_part [ mem ] = gen_rtx_MEM ( SImode , gen_rtx_POST_MODIFY ( Pmode , sub_mem , gen_rtx_PLUS ( Pmode , sub_mem , GEN_INT ( - 12 ) ) ) ) ; } else if ( GET_CODE ( sub_mem ) == POST_INC ) { sub_mem = XEXP ( sub_mem , 0 ) ; low_part [ mem ] = gen_rtx_MEM ( SImode , gen_rtx_POST_INC ( Pmode , sub_mem ) ) ; high_part [ mem ] = gen_rtx_MEM ( SImode , gen_rtx_POST_INC ( Pmode , sub_mem ) ) ; } else if ( GET_CODE ( sub_mem ) == POST_MODIFY ) { rtx post_mem = XEXP ( sub_mem , 0 ) ; rtx plus_op = XEXP ( sub_mem , 1 ) ; rtx post_val = XEXP ( plus_op , 1 ) ; low_part [ mem ] = gen_rtx_MEM ( SImode , gen_rtx_POST_MODIFY ( Pmode , post_mem , gen_rtx_PLUS ( Pmode , post_mem , post_val ) ) ) ; high_part [ mem ] = gen_rtx_MEM ( SImode , plus_constant ( Pmode , post_mem , 4 ) ) ; } else { low_part [ mem ] = adjust_address ( mem_rtx , SImode , 0 ) ; high_part [ mem ] = adjust_address ( mem_rtx , SImode , 4 ) ; } if ( ( load_p && reg_overlap_mentioned_p ( low_part [ 0 ] , high_part [ 1 ] ) ) || GET_CODE ( sub_mem ) == POST_MODIFY ) { operands [ 2 ] = high_part [ 0 ] ; operands [ 3 ] = high_part [ 1 ] ; operands [ 4 ] = low_part [ 0 ] ; operands [ 5 ] = low_part [ 1 ] ; } else { operands [ 2 ] = low_part [ 0 ] ; operands [ 3 ] = low_part [ 1 ] ; operands [ 4 ] = high_part [ 0 ] ; operands [ 5 ] = high_part [ 1 ] ; } } </s>


<s> static bool nds32_symbol_binds_local_p ( const_rtx x ) { return ( SYMBOL_REF_DECL ( x ) ? targetm . binds_local_p ( SYMBOL_REF_DECL ( x ) ) : SYMBOL_REF_LOCAL_P ( x ) ) ; } </s>

Return true if SYMBOL_REF X binds locally .


<s> bool nds32_tls_referenced_p ( rtx x ) { if ( ! targetm . have_tls ) return false ; if ( GET_CODE ( x ) == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS ) x = XEXP ( XEXP ( x , 0 ) , 0 ) ; if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) ) return true ; return false ; } </s>

Return true if X contains a thread-local symbol .


<s> bool nds32_valid_smw_lwm_base_p ( rtx op ) { rtx base_addr ; if ( ! MEM_P ( op ) ) return false ; base_addr = XEXP ( op , 0 ) ; if ( REG_P ( base_addr ) ) return true ; else { if ( GET_CODE ( base_addr ) == POST_INC && REG_P ( XEXP ( base_addr , 0 ) ) ) return true ; } return false ; } </s>


<s> bool symbolic_reference_mentioned_p ( rtx op ) { const char * fmt ; int i ; if ( GET_CODE ( op ) == SYMBOL_REF || GET_CODE ( op ) == LABEL_REF ) return true ; fmt = GET_RTX_FORMAT ( GET_CODE ( op ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( op ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( op , i ) - 1 ; j >= 0 ; j -- ) if ( symbolic_reference_mentioned_p ( XVECEXP ( op , i , j ) ) ) return true ; } else if ( fmt [ i ] == 'e' && symbolic_reference_mentioned_p ( XEXP ( op , i ) ) ) return true ; } return false ; } </s>

Return true if OP contains a symbol reference


<s> rtx nds32_expand_load_multiple ( int base_regno , int count , rtx base_addr , rtx basemem ) { int par_index ; int offset ; rtx result ; rtx new_addr , mem , reg ; result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count ) ) ; for ( par_index = 0 ; par_index < count ; par_index ++ ) { offset = par_index * 4 ; new_addr = plus_constant ( Pmode , base_addr , offset ) ; mem = adjust_automodify_address_nv ( basemem , SImode , new_addr , offset ) ; reg = gen_rtx_REG ( SImode , base_regno + par_index ) ; XVECEXP ( result , 0 , par_index ) = gen_rtx_SET ( VOIDmode , reg , mem ) ; } return result ; } </s>

Functions to expand load_multiple and store_multiple . They are auxiliary extern functions to help create rtx template . Check nds32-multiple.md file for the patterns .


<s> int nds32_expand_movmemqi ( rtx dstmem , rtx srcmem , rtx total_bytes , rtx alignment ) { HOST_WIDE_INT in_words , out_words ; rtx dst_base_reg , src_base_reg ; int maximum_bytes ; if ( TARGET_REDUCED_REGS ) maximum_bytes = 16 ; else maximum_bytes = 32 ; if ( GET_CODE ( total_bytes ) != CONST_INT || GET_CODE ( alignment ) != CONST_INT || INTVAL ( total_bytes ) > maximum_bytes || INTVAL ( total_bytes ) & 3 || INTVAL ( alignment ) & 3 ) return 0 ; dst_base_reg = copy_to_mode_reg ( SImode , XEXP ( dstmem , 0 ) ) ; src_base_reg = copy_to_mode_reg ( SImode , XEXP ( srcmem , 0 ) ) ; out_words = in_words = INTVAL ( total_bytes ) / UNITS_PER_WORD ; emit_insn ( nds32_expand_load_multiple ( 0 , in_words , src_base_reg , srcmem ) ) ; emit_insn ( nds32_expand_store_multiple ( 0 , out_words , dst_base_reg , dstmem ) ) ; return 1 ; } </s>

Function to move block memory content by using load_multiple and store_multiple . This is auxiliary extern function to help create rtx template . Check nds32-multiple.md file for the patterns .


<s> rtx nds32_expand_load_multiple ( int base_regno , int count , rtx base_addr , rtx basemem ) { int par_index ; int offset ; rtx result ; rtx new_addr , mem , reg ; result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count ) ) ; for ( par_index = 0 ; par_index < count ; par_index ++ ) { offset = par_index * 4 ; new_addr = plus_constant ( Pmode , base_addr , offset ) ; mem = adjust_automodify_address_nv ( basemem , SImode , new_addr , offset ) ; reg = gen_rtx_REG ( SImode , base_regno + par_index ) ; XVECEXP ( result , 0 , par_index ) = gen_rtx_SET ( reg , mem ) ; } return result ; } </s>


<s> bool nds32_expand_movmemsi ( rtx dstmem , rtx srcmem , rtx total_bytes , rtx alignment ) { if ( nds32_expand_movmemsi_unroll ( dstmem , srcmem , total_bytes , alignment ) ) return true ; if ( ! optimize_size && optimize > 2 ) return nds32_expand_movmemsi_loop ( dstmem , srcmem , total_bytes , alignment ) ; return false ; } </s>


<s> static bool nds32_expand_movmemsi_loop_unknown_size ( rtx dstmem , rtx srcmem , rtx size , rtx alignment ) { rtx dst_base_reg , src_base_reg ; rtx dst_itr , src_itr ; rtx dstmem_m , srcmem_m , dst_itr_m , src_itr_m ; rtx dst_end ; rtx size_least_3_bit ; rtx double_word_end ; rtx double_word_mode_loop , byte_mode_entry , byte_mode_loop , end_label ; rtx tmp ; rtx mask_least_3_bit ; int start_regno ; bool align_to_4_bytes = ( INTVAL ( alignment ) & 3 ) == 0 ; if ( TARGET_ISA_V3M && ! align_to_4_bytes ) return 0 ; if ( TARGET_REDUCED_REGS ) start_regno = 2 ; else start_regno = 16 ; dst_itr = gen_reg_rtx ( Pmode ) ; src_itr = gen_reg_rtx ( Pmode ) ; dst_end = gen_reg_rtx ( Pmode ) ; tmp = gen_reg_rtx ( QImode ) ; mask_least_3_bit = GEN_INT ( ~ 7 ) ; double_word_mode_loop = gen_label_rtx ( ) ; byte_mode_entry = gen_label_rtx ( ) ; byte_mode_loop = gen_label_rtx ( ) ; end_label = gen_label_rtx ( ) ; dst_base_reg = copy_to_mode_reg ( Pmode , XEXP ( dstmem , 0 ) ) ; src_base_reg = copy_to_mode_reg ( Pmode , XEXP ( srcmem , 0 ) ) ; size_least_3_bit = expand_binop ( SImode , and_optab , size , mask_least_3_bit , NULL_RTX , 0 , OPTAB_WIDEN ) ; dst_end = expand_binop ( Pmode , add_optab , dst_base_reg , size , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_move_insn ( dst_itr , dst_base_reg ) ; emit_move_insn ( src_itr , src_base_reg ) ; emit_cmp_and_jump_insns ( size_least_3_bit , const0_rtx , EQ , NULL , SImode , 1 , byte_mode_entry ) ; double_word_end = expand_binop ( Pmode , add_optab , dst_base_reg , size_least_3_bit , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_label ( double_word_mode_loop ) ; src_itr_m = src_itr ; dst_itr_m = dst_itr ; srcmem_m = srcmem ; dstmem_m = dstmem ; nds32_emit_mem_move_block ( start_regno , 2 , & dst_itr_m , & dstmem_m , & src_itr_m , & srcmem_m , true ) ; emit_move_insn ( dst_itr , dst_itr_m ) ; emit_move_insn ( src_itr , src_itr_m ) ; emit_cmp_and_jump_insns ( double_word_end , dst_itr , NE , NULL , Pmode , 1 , double_word_mode_loop ) ; emit_label ( byte_mode_entry ) ; emit_cmp_and_jump_insns ( dst_itr , dst_end , EQ , NULL , Pmode , 1 , end_label ) ; emit_label ( byte_mode_loop ) ; nds32_emit_post_inc_load_store ( tmp , src_itr , QImode , true ) ; nds32_emit_post_inc_load_store ( tmp , dst_itr , QImode , false ) ; emit_cmp_and_jump_insns ( dst_itr , dst_end , NE , NULL , SImode , 1 , byte_mode_loop ) ; emit_label ( end_label ) ; return true ; } </s>

Auxiliary function for expand movmem pattern .


<s> static rtx nds32_gen_dup_4_byte_to_word_value ( rtx value ) { rtx value4word = gen_reg_rtx ( SImode ) ; gcc_assert ( GET_MODE ( value ) == QImode || CONST_INT_P ( value ) ) ; if ( CONST_INT_P ( value ) ) { unsigned HOST_WIDE_INT val = UINTVAL ( value ) & GET_MODE_MASK ( QImode ) ; rtx new_val = gen_int_mode ( val | ( val << 8 ) | ( val << 16 ) | ( val << 24 ) , SImode ) ; emit_move_insn ( value4word , new_val ) ; } else { rtx tmp1 , tmp2 , tmp3 , tmp4 , final_value ; tmp1 = expand_binop ( SImode , and_optab , value , gen_int_mode ( 0xff , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp2 = expand_binop ( SImode , ashl_optab , tmp1 , gen_int_mode ( 8 , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp3 = expand_binop ( SImode , ior_optab , tmp1 , tmp2 , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp4 = expand_binop ( SImode , ashl_optab , tmp3 , gen_int_mode ( 16 , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; final_value = expand_binop ( SImode , ior_optab , tmp3 , tmp4 , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_move_insn ( value4word , final_value ) ; } return value4word ; } </s>

Auxiliary function for expand setmem pattern .


<s> static void nds32_emit_load_store ( rtx reg , rtx mem , enum machine_mode mode , int offset , bool load_p ) { rtx new_mem ; new_mem = adjust_address ( mem , mode , offset ) ; if ( load_p ) emit_move_insn ( reg , new_mem ) ; else emit_move_insn ( new_mem , reg ) ; } </s>


<s> bool nds32_expand_cpymemsi ( rtx dstmem , rtx srcmem , rtx total_bytes , rtx alignment ) { if ( nds32_expand_cpymemsi_unroll ( dstmem , srcmem , total_bytes , alignment ) ) return true ; if ( ! optimize_size && optimize > 2 ) return nds32_expand_cpymemsi_loop ( dstmem , srcmem , total_bytes , alignment ) ; return false ; } </s>


<s> static bool nds32_expand_cpymemsi_loop_unknown_size ( rtx dstmem , rtx srcmem , rtx size , rtx alignment ) { rtx dst_base_reg , src_base_reg ; rtx dst_itr , src_itr ; rtx dstmem_m , srcmem_m , dst_itr_m , src_itr_m ; rtx dst_end ; rtx size_least_3_bit ; rtx double_word_end ; rtx double_word_mode_loop , byte_mode_entry , byte_mode_loop , end_label ; rtx tmp ; rtx mask_least_3_bit ; int start_regno ; bool align_to_4_bytes = ( INTVAL ( alignment ) & 3 ) == 0 ; if ( TARGET_ISA_V3M && ! align_to_4_bytes ) return 0 ; if ( TARGET_REDUCED_REGS ) start_regno = 2 ; else start_regno = 16 ; dst_itr = gen_reg_rtx ( Pmode ) ; src_itr = gen_reg_rtx ( Pmode ) ; dst_end = gen_reg_rtx ( Pmode ) ; tmp = gen_reg_rtx ( QImode ) ; mask_least_3_bit = GEN_INT ( ~ 7 ) ; double_word_mode_loop = gen_label_rtx ( ) ; byte_mode_entry = gen_label_rtx ( ) ; byte_mode_loop = gen_label_rtx ( ) ; end_label = gen_label_rtx ( ) ; dst_base_reg = copy_to_mode_reg ( Pmode , XEXP ( dstmem , 0 ) ) ; src_base_reg = copy_to_mode_reg ( Pmode , XEXP ( srcmem , 0 ) ) ; size_least_3_bit = expand_binop ( SImode , and_optab , size , mask_least_3_bit , NULL_RTX , 0 , OPTAB_WIDEN ) ; dst_end = expand_binop ( Pmode , add_optab , dst_base_reg , size , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_move_insn ( dst_itr , dst_base_reg ) ; emit_move_insn ( src_itr , src_base_reg ) ; emit_cmp_and_jump_insns ( size_least_3_bit , const0_rtx , EQ , NULL , SImode , 1 , byte_mode_entry ) ; double_word_end = expand_binop ( Pmode , add_optab , dst_base_reg , size_least_3_bit , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_label ( double_word_mode_loop ) ; src_itr_m = src_itr ; dst_itr_m = dst_itr ; srcmem_m = srcmem ; dstmem_m = dstmem ; nds32_emit_mem_move_block ( start_regno , 2 , & dst_itr_m , & dstmem_m , & src_itr_m , & srcmem_m , true ) ; emit_move_insn ( dst_itr , dst_itr_m ) ; emit_move_insn ( src_itr , src_itr_m ) ; emit_cmp_and_jump_insns ( double_word_end , dst_itr , NE , NULL , Pmode , 1 , double_word_mode_loop ) ; emit_label ( byte_mode_entry ) ; emit_cmp_and_jump_insns ( dst_itr , dst_end , EQ , NULL , Pmode , 1 , end_label ) ; emit_label ( byte_mode_loop ) ; nds32_emit_post_inc_load_store ( tmp , src_itr , QImode , true ) ; nds32_emit_post_inc_load_store ( tmp , dst_itr , QImode , false ) ; emit_cmp_and_jump_insns ( dst_itr , dst_end , NE , NULL , SImode , 1 , byte_mode_loop ) ; emit_label ( end_label ) ; return true ; } </s>

Auxiliary function for expand cpymem pattern .


<s> rtx nds32_expand_load_multiple ( int base_regno , int count , rtx base_addr , rtx basemem , bool update_base_reg_p , rtx * update_base_reg ) { int par_index ; int offset ; int start_idx ; rtx result ; rtx new_addr , mem , reg ; if ( count == 1 ) { reg = gen_rtx_REG ( SImode , base_regno ) ; if ( update_base_reg_p ) { * update_base_reg = gen_reg_rtx ( SImode ) ; return gen_unaligned_load_update_base_w ( * update_base_reg , reg , base_addr ) ; } else return gen_unaligned_load_w ( reg , gen_rtx_MEM ( SImode , base_addr ) ) ; } if ( update_base_reg_p ) { result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count + 1 ) ) ; start_idx = 1 ; } else { result = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( count ) ) ; start_idx = 0 ; } if ( update_base_reg_p ) { offset = count * 4 ; new_addr = plus_constant ( Pmode , base_addr , offset ) ; * update_base_reg = gen_reg_rtx ( SImode ) ; XVECEXP ( result , 0 , 0 ) = gen_rtx_SET ( * update_base_reg , new_addr ) ; } for ( par_index = 0 ; par_index < count ; par_index ++ ) { offset = par_index * 4 ; new_addr = plus_constant ( Pmode , base_addr , offset ) ; mem = adjust_automodify_address_nv ( basemem , SImode , new_addr , offset ) ; reg = gen_rtx_REG ( SImode , base_regno + par_index ) ; XVECEXP ( result , 0 , ( par_index + start_idx ) ) = gen_rtx_SET ( reg , mem ) ; } return result ; } </s>


<s> bool nds32_expand_strlen ( rtx result , rtx str , rtx target_char , rtx align ATTRIBUTE_UNUSED ) { rtx base_reg , backup_base_reg ; rtx ffb_result ; rtx target_char_ptr , length ; rtx loop_label , tmp ; if ( optimize_size || optimize < 3 ) return false ; gcc_assert ( MEM_P ( str ) ) ; gcc_assert ( CONST_INT_P ( target_char ) || REG_P ( target_char ) ) ; base_reg = copy_to_mode_reg ( SImode , XEXP ( str , 0 ) ) ; loop_label = gen_label_rtx ( ) ; ffb_result = gen_reg_rtx ( Pmode ) ; tmp = gen_reg_rtx ( SImode ) ; backup_base_reg = gen_reg_rtx ( SImode ) ; emit_move_insn ( backup_base_reg , base_reg ) ; emit_label ( loop_label ) ; emit_insn ( gen_unaligned_load_update_base_w ( base_reg , tmp , base_reg ) ) ; emit_insn ( gen_unspec_ffb ( ffb_result , tmp , target_char ) ) ; emit_cmp_and_jump_insns ( ffb_result , const0_rtx , EQ , NULL , SImode , 1 , loop_label ) ; target_char_ptr = expand_binop ( Pmode , add_optab , base_reg , ffb_result , NULL_RTX , 0 , OPTAB_WIDEN ) ; length = expand_binop ( Pmode , sub_optab , target_char_ptr , backup_base_reg , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_move_insn ( result , length ) ; return true ; } </s>

Auxiliary function for expand strlen pattern .


<s> static rtx nds32_gen_dup_4_byte_to_word_value ( rtx value ) { rtx value4word = gen_reg_rtx ( SImode ) ; nds32_gen_dup_4_byte_to_word_value_aux ( value , value4word ) ; return value4word ; } </s>


<s> static rtx nds32_gen_dup_4_byte_to_word_value_aux ( rtx value , rtx value4word ) { gcc_assert ( GET_MODE ( value ) == QImode || CONST_INT_P ( value ) ) ; if ( CONST_INT_P ( value ) ) { unsigned HOST_WIDE_INT val = UINTVAL ( value ) & GET_MODE_MASK ( QImode ) ; rtx new_val = gen_int_mode ( val | ( val << 8 ) | ( val << 16 ) | ( val << 24 ) , SImode ) ; emit_move_insn ( value4word , new_val ) ; } else { if ( NDS32_EXT_DSP_P ( ) ) { rtx tmp = gen_reg_rtx ( SImode ) ; convert_move ( tmp , value , true ) ; emit_insn ( gen_insvsi_internal ( tmp , gen_int_mode ( 0x8 , SImode ) , tmp ) ) ; emit_insn ( gen_pkbbsi_1 ( value4word , tmp , tmp ) ) ; } else { rtx tmp1 , tmp2 , tmp3 , tmp4 ; tmp1 = expand_binop ( SImode , and_optab , value , gen_int_mode ( 0xff , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp2 = expand_binop ( SImode , ashl_optab , tmp1 , gen_int_mode ( 8 , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp3 = expand_binop ( SImode , ior_optab , tmp1 , tmp2 , NULL_RTX , 0 , OPTAB_WIDEN ) ; tmp4 = expand_binop ( SImode , ashl_optab , tmp3 , gen_int_mode ( 16 , SImode ) , NULL_RTX , 0 , OPTAB_WIDEN ) ; emit_insn ( gen_iorsi3 ( value4word , tmp3 , tmp4 ) ) ; } } return value4word ; } </s>


<s> bool n7_consumed_by_ii_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : if ( movd44_even_dep_p ( consumer , def_reg ) ) return true ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MUL : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( INSN_CODE ( consumer ) == CODE_FOR_divmodsi4 || INSN_CODE ( consumer ) == CODE_FOR_udivmodsi4 ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_LOAD : if ( post_update_insn_p ( consumer ) ) use_rtx = extract_base_reg ( consumer ) ; else use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_STORE : if ( post_update_insn_p ( consumer ) ) use_rtx = extract_base_reg ( consumer ) ; else use_rtx = extract_mem_rtx ( consumer ) ; if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; if ( ! post_update_insn_p ( consumer ) && ! immed_offset_p ( extract_mem_rtx ( consumer ) ) ) return false ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_LOAD_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; use_rtx = extract_nth_access_rtx ( consumer , 0 ) ; break ; case TYPE_BRANCH : use_rtx = PATTERN ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>

Check the dependency between the producer defining DEF_REG and CONSUMER requiring input operand at II .


<s> bool n8_consumed_by_ex_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : if ( movd44_even_dep_p ( consumer , def_reg ) ) return true ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MUL : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( INSN_CODE ( consumer ) == CODE_FOR_divmodsi4 || INSN_CODE ( consumer ) == CODE_FOR_udivmodsi4 ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_BRANCH : use_rtx = extract_branch_condition_rtx ( consumer ) ; break ; case TYPE_STORE : if ( ! post_update_insn_p ( consumer ) && ! immed_offset_p ( extract_mem_rtx ( consumer ) ) ) return false ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_STORE_MULTIPLE : use_rtx = extract_nth_access_rtx ( consumer , 0 ) ; break ; default : gcc_unreachable ( ) ; } return reg_overlap_p ( def_reg , use_rtx ) ; } </s>

Check the dependency between the producer defining DEF_REG and CONSUMER requiring input operand at EX .


<s> bool n9_2r1w_consumed_by_ex_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : if ( movd44_even_dep_p ( consumer , def_reg ) ) return true ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_PBSAD : case TYPE_MUL : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_ALU_SHIFT : use_rtx = extract_shift_reg ( consumer ) ; break ; case TYPE_PBSADA : return pbsada_insn_ra_rb_dep_reg_p ( consumer , def_reg ) ; case TYPE_MAC : use_rtx = PATTERN ( consumer ) ; break ; case TYPE_DIV : if ( INSN_CODE ( consumer ) == CODE_FOR_divmodsi4 || INSN_CODE ( consumer ) == CODE_FOR_udivmodsi4 ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MMU : if ( GET_CODE ( PATTERN ( consumer ) ) == SET ) use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; else return true ; break ; case TYPE_LOAD : if ( post_update_insn_p ( consumer ) ) use_rtx = extract_base_reg ( consumer ) ; else use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_STORE : if ( post_update_insn_p ( consumer ) ) use_rtx = extract_base_reg ( consumer ) ; else use_rtx = extract_mem_rtx ( consumer ) ; if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; if ( ! post_update_insn_p ( consumer ) && ! immed_offset_p ( extract_mem_rtx ( consumer ) ) ) return false ; use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_LOAD_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; use_rtx = extract_nth_access_rtx ( consumer , 0 ) ; break ; case TYPE_BRANCH : use_rtx = PATTERN ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>


<s> bool n9_3r2w_consumed_by_ex_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : case TYPE_PBSAD : case TYPE_MUL : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_ALU_SHIFT : use_rtx = extract_shift_reg ( consumer ) ; break ; case TYPE_PBSADA : return pbsada_insn_ra_rb_dep_reg_p ( consumer , def_reg ) ; case TYPE_MAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( INSN_CODE ( consumer ) == CODE_FOR_divmodsi4 || INSN_CODE ( consumer ) == CODE_FOR_udivmodsi4 ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MMU : if ( GET_CODE ( PATTERN ( consumer ) ) == SET ) use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; else return true ; break ; case TYPE_LOAD : case TYPE_STORE : use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_LOAD_MULTIPLE : case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; case TYPE_BRANCH : use_rtx = PATTERN ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>


<s> bool nds32_n9_3r2w_mm_to_ex_p ( rtx_insn * producer , rtx_insn * consumer ) { rtx def_reg ; switch ( get_attr_type ( producer ) ) { case TYPE_LOAD : case TYPE_MUL : case TYPE_MAC : def_reg = SET_DEST ( PATTERN ( producer ) ) ; break ; case TYPE_DIV : if ( INSN_CODE ( producer ) == CODE_FOR_divmodsi4 || INSN_CODE ( producer ) == CODE_FOR_udivmodsi4 ) { rtx def_reg1 = SET_DEST ( parallel_element ( producer , 0 ) ) ; rtx def_reg2 = SET_DEST ( parallel_element ( producer , 1 ) ) ; return ( n9_3r2w_consumed_by_ex_dep_p ( consumer , def_reg1 ) || n9_3r2w_consumed_by_ex_dep_p ( consumer , def_reg2 ) ) ; } def_reg = SET_DEST ( PATTERN ( producer ) ) ; break ; default : gcc_unreachable ( ) ; } return n9_3r2w_consumed_by_ex_dep_p ( consumer , def_reg ) ; } </s>


<s> bool bpick_ra_rb_dep_p ( rtx insn , rtx def_reg ) { rtx ior_rtx = SET_SRC ( PATTERN ( insn ) ) ; rtx and1_rtx = XEXP ( ior_rtx , 0 ) ; rtx and2_rtx = XEXP ( ior_rtx , 1 ) ; rtx reg1_0 = XEXP ( and1_rtx , 0 ) ; rtx reg1_1 = XEXP ( and1_rtx , 1 ) ; rtx reg2_0 = XEXP ( and2_rtx , 0 ) ; rtx reg2_1 = XEXP ( and2_rtx , 1 ) ; if ( GET_CODE ( reg1_0 ) == NOT ) { if ( rtx_equal_p ( reg1_0 , reg2_0 ) ) return reg_overlap_p ( def_reg , reg1_1 ) || reg_overlap_p ( def_reg , reg2_1 ) ; if ( rtx_equal_p ( reg1_0 , reg2_1 ) ) return reg_overlap_p ( def_reg , reg1_1 ) || reg_overlap_p ( def_reg , reg2_0 ) ; } if ( GET_CODE ( reg1_1 ) == NOT ) { if ( rtx_equal_p ( reg1_1 , reg2_0 ) ) return reg_overlap_p ( def_reg , reg1_0 ) || reg_overlap_p ( def_reg , reg2_1 ) ; if ( rtx_equal_p ( reg1_1 , reg2_1 ) ) return reg_overlap_p ( def_reg , reg1_0 ) || reg_overlap_p ( def_reg , reg2_0 ) ; } if ( GET_CODE ( reg2_0 ) == NOT ) { if ( rtx_equal_p ( reg2_0 , reg1_0 ) ) return reg_overlap_p ( def_reg , reg2_1 ) || reg_overlap_p ( def_reg , reg1_1 ) ; if ( rtx_equal_p ( reg2_0 , reg1_1 ) ) return reg_overlap_p ( def_reg , reg2_1 ) || reg_overlap_p ( def_reg , reg1_0 ) ; } if ( GET_CODE ( reg2_1 ) == NOT ) { if ( rtx_equal_p ( reg2_1 , reg1_0 ) ) return reg_overlap_p ( def_reg , reg2_0 ) || reg_overlap_p ( def_reg , reg1_1 ) ; if ( rtx_equal_p ( reg2_1 , reg1_1 ) ) return reg_overlap_p ( def_reg , reg2_0 ) || reg_overlap_p ( def_reg , reg1_0 ) ; } gcc_unreachable ( ) ; } </s>

Check if INSN is a bpick insn consuming DEF_REG .


<s> memory_access_direction determine_access_direction ( rtx_insn * insn ) { int post_update_rtx_index ; rtx plus_rtx ; rtx mem_rtx ; rtx offset_rtx ; switch ( get_attr_type ( insn ) ) { case TYPE_LOAD_MULTIPLE : gcc_assert ( parallel_elements ( insn ) >= 2 ) ; post_update_rtx_index = find_post_update_rtx ( insn ) ; if ( post_update_rtx_index != - 1 ) plus_rtx = SET_SRC ( parallel_element ( insn , post_update_rtx_index ) ) ; else { mem_rtx = SET_SRC ( parallel_element ( insn , 1 ) ) ; if ( GET_CODE ( mem_rtx ) == UNSPEC ) mem_rtx = XVECEXP ( mem_rtx , 0 , 0 ) ; gcc_assert ( MEM_P ( mem_rtx ) ) ; plus_rtx = XEXP ( mem_rtx , 0 ) ; } break ; case TYPE_STORE_MULTIPLE : gcc_assert ( parallel_elements ( insn ) >= 2 ) ; post_update_rtx_index = find_post_update_rtx ( insn ) ; if ( post_update_rtx_index != - 1 ) plus_rtx = SET_SRC ( parallel_element ( insn , post_update_rtx_index ) ) ; else { mem_rtx = SET_DEST ( parallel_element ( insn , 1 ) ) ; if ( GET_CODE ( mem_rtx ) == UNSPEC ) mem_rtx = XVECEXP ( mem_rtx , 0 , 0 ) ; gcc_assert ( MEM_P ( mem_rtx ) ) ; plus_rtx = XEXP ( mem_rtx , 0 ) ; } break ; case TYPE_LOAD : case TYPE_STORE : mem_rtx = extract_mem_rtx ( insn ) ; switch ( GET_CODE ( XEXP ( mem_rtx , 0 ) ) ) { case POST_INC : return MEM_ACCESS_DIR_POS ; case POST_DEC : return MEM_ACCESS_DIR_NEG ; case PLUS : plus_rtx = XEXP ( mem_rtx , 0 ) ; break ; case POST_MODIFY : plus_rtx = XEXP ( XEXP ( mem_rtx , 0 ) , 1 ) ; break ; default : gcc_unreachable ( ) ; } break ; default : gcc_unreachable ( ) ; } gcc_assert ( GET_CODE ( plus_rtx ) == PLUS ) ; offset_rtx = XEXP ( plus_rtx , 1 ) ; if ( GET_CODE ( offset_rtx ) == CONST_INT ) { if ( INTVAL ( offset_rtx ) < 0 ) return MEM_ACCESS_DIR_NEG ; else return MEM_ACCESS_DIR_POS ; } return MEM_ACCESS_DIR_UNKNOWN ; } </s>

Determine the memory access direction of a load/store insn .


<s> bool e8_consumed_by_addr_in_p ( rtx_insn * consumer , rtx def_reg ) { return n8_consumed_by_addr_in_p ( consumer , def_reg ) ; } </s>

Check the dependency between the producer defining DEF_REG and CONSUMER requiring input operand at AG ( II ) .


<s> bool e8_consumed_by_ex_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : case TYPE_STORE : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MUL : case TYPE_MAC : case TYPE_DIV : case TYPE_BRANCH : case TYPE_STORE_MULTIPLE : return n8_consumed_by_ex_p ( consumer , def_reg ) ; default : gcc_unreachable ( ) ; } return reg_overlap_p ( def_reg , use_rtx ) ; } </s>


<s> rtx extract_nth_access_reg ( rtx_insn * insn , int index ) { switch ( GET_CODE ( PATTERN ( insn ) ) ) { case PARALLEL : return extract_nth_lmsw_access_reg ( insn , index ) ; case SET : return extract_nth_ls2_access_reg ( insn , index ) ; default : gcc_unreachable ( ) ; } } </s>

Returns the register operated by the nth load/store operation in the real micro-operation accessing order .


<s> rtx extract_nth_access_rtx ( rtx_insn * insn , int n ) { int n_elems = parallel_elements ( insn ) ; int post_update_rtx_index = find_post_update_rtx ( insn ) ; memory_access_direction direction = determine_access_direction ( insn ) ; gcc_assert ( direction != MEM_ACCESS_DIR_UNKNOWN ) ; if ( direction == MEM_ACCESS_DIR_NEG ) n = - 1 * n - 1 ; if ( post_update_rtx_index != - 1 ) { if ( n >= 0 && post_update_rtx_index <= n ) ++ n ; else if ( n < 0 && post_update_rtx_index >= n + n_elems ) -- n ; } return parallel_element ( insn , n ) ; } </s>

Return the nth load/store operation in the real micro-operation accessing order .


<s> rtx extract_nth_lmsw_access_reg ( rtx_insn * insn , int n ) { rtx nth_rtx = extract_nth_access_rtx ( insn , n ) ; if ( nth_rtx == NULL_RTX ) return NULL_RTX ; switch ( get_attr_type ( insn ) ) { case TYPE_LOAD_MULTIPLE : return SET_DEST ( nth_rtx ) ; case TYPE_STORE_MULTIPLE : return SET_SRC ( nth_rtx ) ; default : gcc_unreachable ( ) ; } } </s>

Returns the register operated by the nth load/store operation in the real micro-operation accessing order . This function assumes INSN must be a multiple-word load/store insn .


<s> rtx extract_nth_ls2_access_reg ( rtx_insn * insn , int n ) { rtx reg ; machine_mode mode ; if ( post_update_insn_p ( insn ) ) { memory_access_direction direction = determine_access_direction ( insn ) ; gcc_assert ( direction != MEM_ACCESS_DIR_UNKNOWN ) ; if ( direction == MEM_ACCESS_DIR_NEG ) n = - 1 * n - 1 ; } if ( n < - 2 || n > 1 ) return NULL_RTX ; if ( n < 0 ) n = 2 + n ; switch ( get_attr_type ( insn ) ) { case TYPE_LOAD : reg = SET_DEST ( PATTERN ( insn ) ) ; break ; case TYPE_STORE : reg = SET_SRC ( PATTERN ( insn ) ) ; break ; default : gcc_unreachable ( ) ; } gcc_assert ( REG_P ( reg ) || GET_CODE ( reg ) == SUBREG ) ; switch ( GET_MODE ( reg ) ) { case E_DImode : mode = SImode ; break ; case E_DFmode : mode = SFmode ; break ; default : gcc_unreachable ( ) ; } if ( n == 0 ) return gen_lowpart ( mode , reg ) ; else return gen_highpart ( mode , reg ) ; } </s>

Returns the register operated by the nth load/store operation in the real micro-operation accessing order . This function assumes INSN must be a double-word load/store insn .


<s> bool gw_consumed_by_ex_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : case TYPE_PBSAD : case TYPE_MUL : case TYPE_DALU : case TYPE_DALU64 : case TYPE_DMUL : case TYPE_DPACK : case TYPE_DINSB : case TYPE_DCMP : case TYPE_DCLIP : case TYPE_DALUROUND : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_ALU_SHIFT : use_rtx = extract_shift_reg ( consumer ) ; break ; case TYPE_PBSADA : return pbsada_insn_ra_rb_dep_reg_p ( consumer , def_reg ) ; case TYPE_MAC : case TYPE_DMAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( divmod_p ( consumer ) ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_DWEXT : return wext_odd_dep_p ( consumer , def_reg ) ; case TYPE_DBPICK : return bpick_ra_rb_dep_p ( consumer , def_reg ) ; case TYPE_MMU : if ( GET_CODE ( PATTERN ( consumer ) ) == SET ) use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; else return true ; break ; case TYPE_LOAD : case TYPE_STORE : use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_LOAD_MULTIPLE : case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; case TYPE_BRANCH : use_rtx = PATTERN ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>


<s> bool movd44_even_dep_p ( rtx_insn * insn , rtx def_reg ) { if ( ! movd44_insn_p ( insn ) ) return false ; rtx use_rtx = SET_SRC ( PATTERN ( insn ) ) ; if ( REG_P ( def_reg ) ) { return rtx_equal_p ( def_reg , use_rtx ) ; } else if ( GET_CODE ( def_reg ) == SUBREG && GET_MODE ( def_reg ) == SImode && rtx_equal_p ( SUBREG_REG ( def_reg ) , use_rtx ) ) { if ( TARGET_BIG_ENDIAN && SUBREG_BYTE ( def_reg ) == 4 ) return true ; if ( ! TARGET_BIG_ENDIAN && SUBREG_BYTE ( def_reg ) == 0 ) return true ; return false ; } return false ; } </s>

Check if INSN is a movd44 insn consuming DEF_REG .


<s> bool n10_consumed_by_ex_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : case TYPE_PBSAD : case TYPE_MUL : case TYPE_DALU : case TYPE_DALU64 : case TYPE_DMUL : case TYPE_DPACK : case TYPE_DINSB : case TYPE_DCMP : case TYPE_DCLIP : case TYPE_DALUROUND : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_ALU_SHIFT : use_rtx = extract_shift_reg ( consumer ) ; break ; case TYPE_PBSADA : return pbsada_insn_ra_rb_dep_reg_p ( consumer , def_reg ) ; case TYPE_MAC : case TYPE_DMAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( divmod_p ( consumer ) ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_DWEXT : return wext_odd_dep_p ( consumer , def_reg ) ; case TYPE_DBPICK : return bpick_ra_rb_dep_p ( consumer , def_reg ) ; case TYPE_MMU : if ( GET_CODE ( PATTERN ( consumer ) ) == SET ) use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; else return true ; break ; case TYPE_LOAD : case TYPE_STORE : use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_LOAD_MULTIPLE : case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; case TYPE_BRANCH : use_rtx = PATTERN ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>


<s> bool n13_alu_e1_insn_dep_reg_p ( rtx_insn * alu_e1_insn , rtx def_reg ) { rtx unspec_rtx , operand_ra , operand_rb ; rtx src_rtx , dst_rtx ; switch ( INSN_CODE ( alu_e1_insn ) ) { case CODE_FOR_unspec_bsp : case CODE_FOR_unspec_bse : unspec_rtx = SET_SRC ( parallel_element ( alu_e1_insn , 0 ) ) ; gcc_assert ( GET_CODE ( unspec_rtx ) == UNSPEC ) ; operand_ra = XVECEXP ( unspec_rtx , 0 , 0 ) ; operand_rb = XVECEXP ( unspec_rtx , 0 , 1 ) ; if ( rtx_equal_p ( def_reg , operand_ra ) || rtx_equal_p ( def_reg , operand_rb ) ) return true ; return false ; case CODE_FOR_move_di : case CODE_FOR_move_df : src_rtx = SET_SRC ( PATTERN ( alu_e1_insn ) ) ; dst_rtx = SET_DEST ( PATTERN ( alu_e1_insn ) ) ; if ( REG_P ( dst_rtx ) && REG_P ( src_rtx ) && rtx_equal_p ( src_rtx , def_reg ) ) return true ; return false ; default : return false ; } } </s>

Check dependencies from any stages to ALU_E1 ( E1 ) . This is a helper function of n13_consumed_by_e1_dep_p ( ) .


<s> bool n13_consumed_by_e1_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : return n13_alu_e1_insn_dep_reg_p ( consumer , def_reg ) ; case TYPE_PBSADA : return pbsada_insn_ra_rb_dep_reg_p ( consumer , def_reg ) ; case TYPE_PBSAD : case TYPE_MUL : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MAC : use_rtx = extract_mac_non_acc_rtx ( consumer ) ; break ; case TYPE_DIV : if ( divmod_p ( consumer ) ) use_rtx = SET_SRC ( parallel_element ( consumer , 0 ) ) ; else use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_MMU : if ( GET_CODE ( PATTERN ( consumer ) ) == SET ) use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; else return true ; break ; case TYPE_BRANCH : use_rtx = extract_branch_target_rtx ( consumer ) ; break ; case TYPE_LOAD : case TYPE_STORE : use_rtx = extract_mem_rtx ( consumer ) ; break ; case TYPE_LOAD_MULTIPLE : case TYPE_STORE_MULTIPLE : use_rtx = extract_base_reg ( consumer ) ; break ; default : return false ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>

Check the dependency between the producer defining DEF_REG and CONSUMER requiring input operand at E1 . Because the address generation unti is at E1 , the address input should be ready at E1 . Note that the branch target is also a kind of addresses , so we have to check it .


<s> bool n13_consumed_by_e2_dep_p ( rtx_insn * consumer , rtx def_reg ) { rtx use_rtx ; switch ( get_attr_type ( consumer ) ) { case TYPE_ALU : case TYPE_STORE : use_rtx = SET_SRC ( PATTERN ( consumer ) ) ; break ; case TYPE_ALU_SHIFT : use_rtx = extract_shift_reg ( consumer ) ; break ; case TYPE_PBSADA : return pbsada_insn_rt_dep_reg_p ( consumer , def_reg ) ; case TYPE_STORE_MULTIPLE : use_rtx = extract_nth_access_rtx ( consumer , 0 ) ; break ; case TYPE_BRANCH : use_rtx = extract_branch_condition_rtx ( consumer ) ; break ; default : gcc_unreachable ( ) ; } if ( reg_overlap_p ( def_reg , use_rtx ) ) return true ; return false ; } </s>

Check the dependency between the producer defining DEF_REG and CONSUMER requiring input operand at E2 .