<s> void microblaze_cpp_define ( cpp_reader * pfile ) { builtin_assert ( "cpu=microblaze" ) ; builtin_assert ( "machine=microblaze" ) ; builtin_define ( "__MICROBLAZE__" ) ; builtin_define ( "__microblaze__" ) ; if ( TARGET_LITTLE_ENDIAN ) { builtin_define ( "_LITTLE_ENDIAN" ) ; builtin_define ( "__LITTLE_ENDIAN__" ) ; builtin_define ( "__MICROBLAZEEL__" ) ; } else { builtin_define ( "_BIG_ENDIAN" ) ; builtin_define ( "__BIG_ENDIAN__" ) ; builtin_define ( "__MICROBLAZEEB__" ) ; } if ( ! TARGET_SOFT_MUL ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_MUL" ) ; builtin_define ( "__HAVE_HW_MUL__" ) ; } if ( TARGET_MULTIPLY_HIGH ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_MUL_HIGH" ) ; builtin_define ( "__HAVE_HW_MUL_HIGH__" ) ; } if ( ! TARGET_SOFT_DIV ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_DIV" ) ; builtin_define ( "__HAVE_HW_DIV__" ) ; } if ( TARGET_BARREL_SHIFT ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_BSHIFT" ) ; builtin_define ( "__HAVE_HW_BSHIFT__" ) ; } if ( TARGET_PATTERN_COMPARE ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_PCMP" ) ; builtin_define ( "__HAVE_HW_PCMP__" ) ; } if ( TARGET_HARD_FLOAT ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_FPU" ) ; builtin_define ( "__HAVE_HW_FPU__" ) ; } if ( TARGET_FLOAT_CONVERT ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_FPU_CONVERT" ) ; builtin_define ( "__HAVE_HW_FPU_CONVERT__" ) ; } if ( TARGET_FLOAT_SQRT ) { if ( ! flag_iso ) builtin_define ( "HAVE_HW_FPU_SQRT" ) ; builtin_define ( "__HAVE_HW_FPU_SQRT__" ) ; } } </s>

Define preprocessor symbols for MicroBlaze . Symbols which do not start with __ are deprecated .


<s> static rtx get_branch_target ( rtx branch ) { if ( CALL_P ( branch ) ) { rtx call ; call = XVECEXP ( PATTERN ( branch ) , 0 , 0 ) ; if ( GET_CODE ( call ) == SET ) call = SET_SRC ( call ) ; if ( GET_CODE ( call ) != CALL ) gcc_unreachable ( ) ; return XEXP ( XEXP ( call , 0 ) , 0 ) ; } return NULL_RTX ; } </s>

Returns 0 if we do n't want a hint for this branch . Otherwise return the rtx for the branch target .


<s> static int microblaze_address_insns ( rtx x , machine_mode mode ) { struct microblaze_address_info addr ; if ( microblaze_classify_address ( & addr , x , mode , false ) ) { switch ( addr . type ) { case ADDRESS_REG : if ( SMALL_INT ( addr . offset ) ) return 1 ; else return 2 ; case ADDRESS_CONST_INT : if ( SMALL_INT ( x ) ) return 1 ; else return 2 ; case ADDRESS_REG_INDEX : return 1 ; case ADDRESS_SYMBOLIC : case ADDRESS_SYMBOLIC_TXT_REL : case ADDRESS_GOTOFF : return 2 ; case ADDRESS_TLS : switch ( addr . tls_type ) { case TLS_GD : return 2 ; case TLS_LDM : return 2 ; case TLS_DTPREL : return 1 ; default : gcc_unreachable ( ) ; } default : break ; } } return 0 ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at X . Return 0 if X is n't valid for MODE .


<s>
void
print_operand_address
(
FILE
*
file
,
rtx
addr
)
{
struct
microblaze_address_info
info
;
enum
microblaze_address_type
type
;
if
(
!
microblaze_classify_address
(
&
info
,
addr
,
GET_MODE
(
addr
)
,
2
)
)
fatal_insn
(
"insn contains an invalid address !"
,
addr
)
;
type
=
info
.
type
;
switch
(
info
.
type
)
{
case
ADDRESS_REG
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_REG_INDEX
:
if
(
REGNO
(
info
.
regA
)
==
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
else
if
(
REGNO
(
info
.
regB
)
!=
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
break
;
case
ADDRESS_CONST_INT
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_SYMBOLIC
:
case
ADDRESS_SYMBOLIC_TXT_REL
:
case
ADDRESS_GOTOFF
:
case
ADDRESS_PLT
:
case
ADDRESS_TLS
:
if
(
info
.
regA
)
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
symbol
)
;
if
(
type
==
ADDRESS_GOTOFF
)
{
fputs
(
"@GOT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_PLT
)
{
fputs
(
"@PLT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_SYMBOLIC_TXT_REL
)
{
if
(
info
.
offset
!=
&&
CONST_INT_P
(
info
.
offset
)
&&
INTVAL
(
info
.
offset
)
>
0
)
{
fprintf
(
file
,
"+"
)
;
output_addr_const
(
file
,
info
.
offset
)
;
}
fputs
(
"@TXTREL"
,
file
)
;
}
else
if
(
type
==
ADDRESS_TLS
)
{
switch
(
info
.
tls_type
)
{
case
TLS_GD
:
fputs
(
"@TLSGD"
,
file
)
;
break
;
case
TLS_LDM
:
fputs
(
"@TLSLDM"
,
file
)
;
break
;
case
TLS_DTPREL
:
fputs
(
"@TLSDTPREL"
,
file
)
;
break
;
default
:
gcc_unreachable
(
)
;
break
;
}
}
break
;
case
ADDRESS_INVALID
:
fatal_insn
(
"invalid address"
,
addr
)
;
break
;
}
}
</s>

Print the operand address represented by the rtx addr


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


<s> int double_memory_operand ( rtx op , machine_mode mode ) { rtx addr ; if ( GET_CODE ( op ) != MEM || ! memory_operand ( op , mode ) ) { if ( reload_in_progress && GET_CODE ( op ) == REG && REGNO ( op ) >= FIRST_PSEUDO_REGISTER && reg_renumber [ REGNO ( op ) ] < 0 && reg_equiv_mem ( REGNO ( op ) ) != 0 && double_memory_operand ( reg_equiv_mem ( REGNO ( op ) ) , mode ) ) return 1 ; return 0 ; } addr = XEXP ( op , 0 ) ; if ( CONSTANT_ADDRESS_P ( addr ) ) return 1 ; return memory_address_p ( ( GET_MODE_CLASS ( mode ) == MODE_INT ? SImode : SFmode ) , plus_constant ( Pmode , addr , 4 ) ) ; } </s>

Return nonzero for a memory address that can be used to load or store a doubleword .


<s> static int function_arg_partial_bytes ( cumulative_args_t cum_v , machine_mode mode , tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; if ( ( mode == BLKmode || GET_MODE_CLASS ( mode ) != MODE_COMPLEX_INT || GET_MODE_CLASS ( mode ) != MODE_COMPLEX_FLOAT ) && cum -> arg_words < MAX_ARGS_IN_REGISTERS ) { int words ; if ( mode == BLKmode ) words = ( ( int_size_in_bytes ( type ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; else words = ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ; if ( words + cum -> arg_words <= MAX_ARGS_IN_REGISTERS ) return 0 ; return ( MAX_ARGS_IN_REGISTERS - cum -> arg_words ) * UNITS_PER_WORD ; } else if ( mode == DImode && cum -> arg_words == MAX_ARGS_IN_REGISTERS - 1 ) return UNITS_PER_WORD ; return 0 ; } </s>

Return number of bytes of argument to put in registers .


<s> static int microblaze_address_insns ( rtx x , machine_mode mode ) { struct microblaze_address_info addr ; if ( microblaze_classify_address ( & addr , x , mode , false ) ) { switch ( addr . type ) { case ADDRESS_REG : if ( SMALL_INT ( addr . offset ) ) return 1 ; else return 2 ; case ADDRESS_CONST_INT : if ( SMALL_INT ( x ) ) return 1 ; else return 2 ; case ADDRESS_REG_INDEX : return 1 ; case ADDRESS_SYMBOLIC : case ADDRESS_GOTOFF : return 2 ; case ADDRESS_TLS : switch ( addr . tls_type ) { case TLS_GD : return 2 ; case TLS_LDM : return 2 ; case TLS_DTPREL : return 1 ; default : abort ( ) ; } default : break ; } } return 0 ; } </s>


<s>
void
microblaze_asm_output_ident
(
const
char
*
string
)
{
const
char
*
section_asm_op
;
int
size
;
char
*
buf
;
if
(
symtab
->
state
!=
PARSING
)
return
;
size
=
strlen
(
string
)
+
1
;
if
(
size
<=
microblaze_section_threshold
)
section_asm_op
=
SDATA2_SECTION_ASM_OP
;
else
section_asm_op
=
READONLY_DATA_SECTION_ASM_OP
;
buf
=
ACONCAT
(
(
section_asm_op
,
"\n\t.ascii \""
,
string
,
"\\0\"\n"
,
)
)
;
symtab
->
finalize_toplevel_asm
(
build_string
(
strlen
(
buf
)
,
buf
)
)
;
}
</s>

Queue an .ident string in the queue of top-level asm statements . If the string size is below the threshold , put it into .sdata2 . If the front-end is done , we must be being called from toplev.cc . In that case , do nothing .


<s> static void microblaze_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; machine_mode mode ; rtx * regs ; bits = BITS_PER_WORD ; mode = mode_for_size ( bits , MODE_INT , 0 ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( rtx , length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; emit_move_insn ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) emit_move_insn ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , 0 ) ; } } </s>

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


<s> static bool microblaze_const_double_ok ( rtx op , machine_mode mode ) { REAL_VALUE_TYPE d ; if ( GET_CODE ( op ) != CONST_DOUBLE ) return 0 ; if ( GET_MODE ( op ) == VOIDmode ) return 1 ; if ( mode != SFmode && mode != DFmode ) return 0 ; if ( op == CONST0_RTX ( mode ) ) return 1 ; REAL_VALUE_FROM_CONST_DOUBLE ( d , op ) ; if ( REAL_VALUE_ISNAN ( d ) ) return FALSE ; if ( REAL_VALUE_NEGATIVE ( d ) ) d = real_value_negate ( & d ) ; if ( mode == DFmode ) { if ( REAL_VALUES_LESS ( d , dfhigh ) && REAL_VALUES_LESS ( dflow , d ) ) return 1 ; } else { if ( REAL_VALUES_LESS ( d , sfhigh ) && REAL_VALUES_LESS ( sflow , d ) ) return 1 ; } return 0 ; } </s>

Return truth value if a CONST_DOUBLE is ok to be a legitimate constant .


<s> bool microblaze_expand_block_move ( rtx dest , rtx src , rtx length , rtx align_rtx ) { if ( GET_CODE ( length ) == CONST_INT ) { HOST_WIDE_INT bytes = INTVAL ( length ) ; int align = INTVAL ( align_rtx ) ; if ( align > UNITS_PER_WORD ) { align = UNITS_PER_WORD ; } else if ( align < UNITS_PER_WORD ) { if ( INTVAL ( length ) <= MAX_MOVE_BYTES ) { move_by_pieces ( dest , src , bytes , align , 0 ) ; return true ; } else return false ; } if ( INTVAL ( length ) <= 2 * MAX_MOVE_BYTES ) { microblaze_block_move_straight ( dest , src , INTVAL ( length ) ) ; return true ; } else if ( optimize ) { microblaze_block_move_loop ( dest , src , INTVAL ( length ) ) ; return true ; } } return false ; } </s>


<s> void microblaze_expand_epilogue ( void ) { HOST_WIDE_INT fsiz = current_frame_info . total_size ; rtx fsiz_rtx = GEN_INT ( fsiz ) ; rtx reg_rtx ; rtx mem_rtx ; if ( microblaze_can_use_return_insn ( ) ) { emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM ) ) ) ; return ; } if ( fsiz > 0 ) { if ( ! crtl -> is_leaf || interrupt_handler ) { mem_rtx = gen_rtx_MEM ( SImode , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , const0_rtx ) ) ; if ( interrupt_handler ) MEM_VOLATILE_P ( mem_rtx ) = 1 ; reg_rtx = gen_rtx_REG ( SImode , MB_ABI_SUB_RETURN_ADDR_REGNUM ) ; emit_move_insn ( reg_rtx , mem_rtx ) ; } if ( frame_pointer_needed ) emit_insn ( gen_movsi ( stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; save_restore_insns ( 0 ) ; emit_insn ( gen_blockage ( ) ) ; emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , fsiz_rtx ) ) ; } emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM ) ) ) ; } </s>

Expand the epilogue into a bunch of separate insns .


<s> int microblaze_expand_shift ( rtx operands [ ] ) { gcc_assert ( ( GET_CODE ( operands [ 2 ] ) == CONST_INT ) || ( GET_CODE ( operands [ 2 ] ) == REG ) || ( GET_CODE ( operands [ 2 ] ) == SUBREG ) ) ; if ( ( GET_CODE ( operands [ 2 ] ) == CONST_INT ) && ( INTVAL ( operands [ 2 ] ) == 1 ) ) return 0 ; if ( TARGET_BARREL_SHIFT ) return 0 ; gcc_assert ( ( GET_CODE ( operands [ 0 ] ) == REG ) || ( GET_CODE ( operands [ 0 ] ) == SUBREG ) || ( GET_CODE ( operands [ 1 ] ) == REG ) || ( GET_CODE ( operands [ 1 ] ) == SUBREG ) ) ; if ( ( GET_CODE ( operands [ 2 ] ) == CONST_INT ) && ( INTVAL ( operands [ 2 ] ) == 0 ) ) { if ( REGNO ( operands [ 0 ] ) != REGNO ( operands [ 1 ] ) ) emit_insn ( gen_movsi ( operands [ 0 ] , operands [ 1 ] ) ) ; return 1 ; } return 0 ; } </s>


<s> static rtx microblaze_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; rtx ret ; int regbase = - 1 ; int * arg_words = & cum -> arg_words ; cum -> last_arg_fp = 0 ; switch ( mode ) { case SFmode : case DFmode : case VOIDmode : case QImode : case HImode : case SImode : case DImode : case TImode : regbase = GP_ARG_FIRST ; break ; default : gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) ; case BLKmode : regbase = GP_ARG_FIRST ; break ; } if ( * arg_words >= MAX_ARGS_IN_REGISTERS ) ret = 0 ; else { gcc_assert ( regbase != - 1 ) ; ret = gen_rtx_REG ( mode , regbase + * arg_words ) ; } if ( mode == VOIDmode ) { if ( cum -> num_adjusts > 0 ) ret = gen_rtx_PARALLEL ( ( machine_mode ) cum -> fp_code , gen_rtvec_v ( cum -> num_adjusts , cum -> adjust ) ) ; } return ret ; } </s>

Return an RTL expression containing the register for the given mode , or 0 if the argument is to be passed on the stack .


<s> static void microblaze_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; cum -> arg_number ++ ; switch ( mode ) { case VOIDmode : break ; default : gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) ; cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case BLKmode : cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( int_size_in_bytes ( type ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case SFmode : cum -> arg_words ++ ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 1 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case DFmode : cum -> arg_words += 2 ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 2 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case DImode : cum -> gp_reg_found = 1 ; cum -> arg_words += 2 ; break ; case QImode : case HImode : case SImode : case TImode : cum -> gp_reg_found = 1 ; cum -> arg_words ++ ; break ; } } </s>

Advance the argument to the next argument position .


"\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n"

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


<s> static int microblaze_must_save_register ( int regno ) { if ( pic_offset_table_rtx && ( regno == MB_ABI_PIC_ADDR_REGNUM ) && df_regs_ever_live_p ( regno ) ) return 1 ; if ( df_regs_ever_live_p ( regno ) && ! call_used_regs [ regno ] ) return 1 ; if ( frame_pointer_needed && ( regno == HARD_FRAME_POINTER_REGNUM ) ) return 1 ; if ( ! crtl -> is_leaf ) { if ( regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) return 1 ; if ( ( microblaze_is_interrupt_variant ( ) || save_volatiles ) && ( regno >= 3 && regno <= 12 ) ) return 1 ; } if ( microblaze_is_interrupt_variant ( ) ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_MSR_SAVE_REG || ( interrupt_handler && ( regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) ) ) return 1 ; } if ( save_volatiles ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) return 1 ; } return 0 ; } </s>

Determine of register must be saved/restored in call .


<s> rtx microblaze_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return NULL_RTX ; return gen_rtx_PLUS ( Pmode , get_hard_reg_initial_val ( Pmode , MB_ABI_SUB_RETURN_ADDR_REGNUM ) , GEN_INT ( 8 ) ) ; } </s>

Return an RTX indicating where the return address to the calling function can be found .


<s> static int microblaze_version_to_int ( const char * version ) { const char * p , * v ; const char * tmpl = "vXX.YY.Z" ; int iver = 0 ; p = version ; v = tmpl ; while ( * p ) { if ( * v == 'X' ) { if ( * p == '.' ) { * v ++ ; } else { if ( ! ( * p >= '0' && * p <= '9' ) ) return - 1 ; iver += ( int ) ( * p - '0' ) ; iver *= 10 ; } } else if ( * v == 'Y' ) { if ( ! ( * p >= '0' && * p <= '9' ) ) return - 1 ; iver += ( int ) ( * p - '0' ) ; iver *= 10 ; } else if ( * v == 'Z' ) { if ( ! ( * p >= 'a' && * p <= 'z' ) ) return - 1 ; iver *= 10 ; iver += ( int ) ( * p - 'a' ) ; } else { if ( * p != * v ) return - 1 ; } v ++ ; p ++ ; } if ( * p ) return - 1 ; return iver ; } </s>

Convert a version number of the form `` vX.YY.Z '' to an integer encoding for easier range comparison .


<s>
void
print_operand_address
(
FILE
*
file
,
rtx
addr
)
{
struct
microblaze_address_info
info
;
enum
microblaze_address_type
type
;
if
(
!
microblaze_classify_address
(
&
info
,
addr
,
GET_MODE
(
addr
)
,
1
)
)
fatal_insn
(
"insn contains an invalid address !"
,
addr
)
;
type
=
info
.
type
;
switch
(
info
.
type
)
{
case
ADDRESS_REG
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_REG_INDEX
:
if
(
REGNO
(
info
.
regA
)
==
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
else
if
(
REGNO
(
info
.
regB
)
!=
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
break
;
case
ADDRESS_CONST_INT
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_SYMBOLIC
:
case
ADDRESS_GOTOFF
:
case
ADDRESS_PLT
:
case
ADDRESS_TLS
:
if
(
info
.
regA
)
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
symbol
)
;
if
(
type
==
ADDRESS_GOTOFF
)
{
fputs
(
"@GOT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_PLT
)
{
fputs
(
"@PLT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_TLS
)
{
switch
(
info
.
tls_type
)
{
case
TLS_GD
:
fputs
(
"@TLSGD"
,
file
)
;
break
;
case
TLS_LDM
:
fputs
(
"@TLSLDM"
,
file
)
;
break
;
case
TLS_DTPREL
:
fputs
(
"@TLSDTPREL"
,
file
)
;
break
;
default
:
abort
(
)
;
break
;
}
}
break
;
case
ADDRESS_INVALID
:
fatal_insn
(
"invalid address"
,
addr
)
;
break
;
}
}
</s>


<s> static rtx get_branch_target ( rtx branch ) { if ( CALL_P ( branch ) ) { rtx call ; call = XVECEXP ( PATTERN ( branch ) , 0 , 0 ) ; if ( GET_CODE ( call ) == SET ) call = SET_SRC ( call ) ; if ( GET_CODE ( call ) != CALL ) abort ( ) ; return XEXP ( XEXP ( call , 0 ) , 0 ) ; } } </s>


<s> static void insert_wic ( void ) { rtx_insn * insn ; int i , j ; basic_block bb , prev = 0 ; rtx branch_target = 0 ; shorten_branches ( get_insns ( ) ) ; for ( i = 0 ; i < n_basic_blocks_for_fn ( cfun ) - 1 ; i ++ ) { edge e ; edge_iterator ei ; bool simple_loop = false ; bb = BASIC_BLOCK_FOR_FN ( cfun , i ) ; if ( bb == NULL ) continue ; if ( ( prev != 0 ) && ( prev != bb ) ) continue ; else prev = 0 ; FOR_EACH_EDGE ( e , ei , bb -> preds ) if ( e -> src == bb ) { simple_loop = true ; prev = e -> dest ; break ; } for ( insn = BB_END ( bb ) ; insn ; insn = PREV_INSN ( insn ) ) { if ( INSN_P ( insn ) && ! simple_loop && CALL_P ( insn ) ) { if ( ( branch_target = get_branch_target ( insn ) ) ) insert_wic_for_ilb_runout ( next_active_insn ( next_active_insn ( insn ) ) ) ; } if ( insn == BB_HEAD ( bb ) ) break ; } } } </s>

Insert instruction prefetch instruction at the fall through path of the function call .


<s> static void insert_wic_for_ilb_runout ( rtx_insn * first ) { rtx_insn * insn ; rtx_insn * before_4 = 0 ; rtx_insn * before_16 = 0 ; int addr_offset = 0 ; int length ; int wic_addr0 = 128 * 4 ; int wic_addr1 = 128 * 4 ; int first_addr = INSN_ADDRESSES ( INSN_UID ( first ) ) ; for ( insn = first ; insn ; insn = NEXT_INSN ( insn ) ) if ( INSN_P ( insn ) ) { addr_offset = INSN_ADDRESSES ( INSN_UID ( insn ) ) - first_addr ; length = get_attr_length ( insn ) ; if ( before_4 == 0 && addr_offset + length >= 4 * 4 ) before_4 = insn ; if ( JUMP_P ( insn ) ) return ; if ( before_16 == 0 && addr_offset + length >= 14 * 4 ) before_16 = insn ; if ( CALL_P ( insn ) || tablejump_p ( insn , 0 , 0 ) ) return ; if ( addr_offset + length >= 32 * 4 ) { gcc_assert ( before_4 && before_16 ) ; if ( wic_addr0 > 4 * 4 ) { insn = emit_insn_before ( gen_iprefetch ( gen_int_mode ( addr_offset , SImode ) ) , before_4 ) ; recog_memoized ( insn ) ; INSN_LOCATION ( insn ) = INSN_LOCATION ( before_4 ) ; INSN_ADDRESSES_NEW ( insn , INSN_ADDRESSES ( INSN_UID ( before_4 ) ) ) ; return ; } } } } </s>

Heuristics to identify where to insert at the fall through path of the caller function . If there is a call after the caller branch delay slot then we dont generate the instruction prefetch instruction . Scan up to 32 instructions after the call and checks for the JUMP and call instruction . If there is a call or JUMP instruction in the range of 32 instruction `` wic '' instruction wont be generated . Otherwise insert the `` wic '' instruction in the fall through of the call instruction four instruction after the call . before_4 is used for the position to insert `` wic '' instructions . before_16 is used to check for call and JUMP instruction for first 15 insns .


<s> static int microblaze_must_save_register ( int regno ) { if ( pic_offset_table_rtx && ( regno == MB_ABI_PIC_ADDR_REGNUM ) && df_regs_ever_live_p ( regno ) ) return 1 ; if ( df_regs_ever_live_p ( regno ) && ! call_used_regs [ regno ] ) return 1 ; if ( frame_pointer_needed && ( regno == HARD_FRAME_POINTER_REGNUM ) ) return 1 ; if ( crtl -> calls_eh_return && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) return 1 ; if ( ! crtl -> is_leaf ) { if ( regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) return 1 ; if ( ( microblaze_is_interrupt_variant ( ) || save_volatiles ) && ( regno >= 3 && regno <= 12 ) ) return 1 ; } if ( microblaze_is_interrupt_variant ( ) ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_MSR_SAVE_REG || ( interrupt_handler && ( regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) ) ) return 1 ; } if ( save_volatiles ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) return 1 ; } if ( crtl -> calls_eh_return && ( regno == EH_RETURN_DATA_REGNO ( 0 ) || regno == EH_RETURN_DATA_REGNO ( 1 ) ) ) return 1 ; return 0 ; } </s>


<s> static void microblaze_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; machine_mode mode ; rtx * regs ; bits = BITS_PER_WORD ; mode = int_mode_for_size ( bits , 0 ) . require ( ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( rtx , length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; emit_move_insn ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) emit_move_insn ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , 0 ) ; } } </s>


<s> static rtx microblaze_function_arg ( cumulative_args_t cum_v , machine_mode mode , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; rtx ret ; int regbase = - 1 ; int * arg_words = & cum -> arg_words ; cum -> last_arg_fp = 0 ; switch ( mode ) { case E_SFmode : case E_DFmode : case E_VOIDmode : case E_QImode : case E_HImode : case E_SImode : case E_DImode : case E_TImode : regbase = GP_ARG_FIRST ; break ; default : gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) ; case E_BLKmode : regbase = GP_ARG_FIRST ; break ; } if ( * arg_words >= MAX_ARGS_IN_REGISTERS ) ret = 0 ; else { gcc_assert ( regbase != - 1 ) ; ret = gen_rtx_REG ( mode , regbase + * arg_words ) ; } if ( mode == VOIDmode ) { if ( cum -> num_adjusts > 0 ) ret = gen_rtx_PARALLEL ( ( machine_mode ) cum -> fp_code , gen_rtvec_v ( cum -> num_adjusts , cum -> adjust ) ) ; } return ret ; } </s>


<s> static void microblaze_function_arg_advance ( cumulative_args_t cum_v , machine_mode mode , const_tree type , bool named ATTRIBUTE_UNUSED ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; cum -> arg_number ++ ; switch ( mode ) { case E_VOIDmode : break ; default : gcc_assert ( GET_MODE_CLASS ( mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) ; cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( GET_MODE_SIZE ( mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case E_BLKmode : cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( int_size_in_bytes ( type ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case E_SFmode : cum -> arg_words ++ ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 1 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case E_DFmode : cum -> arg_words += 2 ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 2 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case E_DImode : cum -> gp_reg_found = 1 ; cum -> arg_words += 2 ; break ; case E_QImode : case E_HImode : case E_SImode : case E_TImode : cum -> gp_reg_found = 1 ; cum -> arg_words ++ ; break ; } } </s>


<s> int double_memory_operand ( rtx op , machine_mode mode ) { rtx addr ; if ( GET_CODE ( op ) != MEM || ! memory_operand ( op , mode ) ) { if ( reload_in_progress && GET_CODE ( op ) == REG && REGNO ( op ) >= FIRST_PSEUDO_REGISTER && reg_renumber [ REGNO ( op ) ] < 0 && reg_equiv_mem ( REGNO ( op ) ) != 0 && double_memory_operand ( reg_equiv_mem ( REGNO ( op ) ) , mode ) ) return 1 ; return 0 ; } addr = XEXP ( op , 0 ) ; if ( CONSTANT_ADDRESS_P ( addr ) ) return 1 ; return memory_address_p ( ( GET_MODE_CLASS ( mode ) == MODE_INT ? E_SImode : E_SFmode ) , plus_constant ( Pmode , addr , 4 ) ) ; } </s>


<s> static int function_arg_partial_bytes ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; if ( ( arg . mode == BLKmode || GET_MODE_CLASS ( arg . mode ) != MODE_COMPLEX_INT || GET_MODE_CLASS ( arg . mode ) != MODE_COMPLEX_FLOAT ) && cum -> arg_words < MAX_ARGS_IN_REGISTERS ) { int words = ( ( arg . promoted_size_in_bytes ( ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; if ( words + cum -> arg_words <= MAX_ARGS_IN_REGISTERS ) return 0 ; return ( MAX_ARGS_IN_REGISTERS - cum -> arg_words ) * UNITS_PER_WORD ; } else if ( arg . mode == DImode && cum -> arg_words == MAX_ARGS_IN_REGISTERS - 1 ) return UNITS_PER_WORD ; return 0 ; } </s>


<s> static int get_base_reg ( rtx x ) { tree decl ; int base_reg ; if ( ! flag_pic || microblaze_tls_symbol_p ( x ) ) base_reg = MB_ABI_BASE_REGNUM ; else if ( flag_pic ) base_reg = MB_ABI_PIC_ADDR_REGNUM ; if ( TARGET_XLGPOPT && GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_SMALL_P ( x ) && ( decl = SYMBOL_REF_DECL ( x ) ) != NULL ) { if ( TREE_READONLY ( decl ) ) base_reg = MB_ABI_GPRO_REGNUM ; else base_reg = MB_ABI_GPRW_REGNUM ; } return base_reg ; } </s>

Get the base register for accessing a value from the memory or Symbol ref . Used for MicroBlaze Small Data Area Pointer Optimization .


<s> static rtx get_branch_target ( rtx branch ) { if ( CALL_P ( branch ) ) { rtx call ; call = XVECEXP ( PATTERN ( branch ) , 0 , 0 ) ; if ( GET_CODE ( call ) == SET ) call = SET_SRC ( call ) ; if ( GET_CODE ( call ) != CALL ) abort ( ) ; return XEXP ( XEXP ( call , 0 ) , 0 ) ; } return NULL_RTX ; } </s>

Returns 0 if we do n't want a hint for this branch . Otherwise return the rtx for the branch target .


<s> void init_cumulative_args ( CUMULATIVE_ARGS * cum , tree fntype , rtx libname ATTRIBUTE_UNUSED ) { static CUMULATIVE_ARGS zero_cum ; tree param , next_param ; * cum = zero_cum ; for ( param = fntype ? TYPE_ARG_TYPES ( fntype ) : 0 ; param != 0 ; param = next_param ) { next_param = TREE_CHAIN ( param ) ; if ( next_param == 0 && TREE_VALUE ( param ) != void_type_node ) cum -> gp_reg_found = 1 ; } } </s>

Handle the INIT_CUMULATIVE_ARGS macro . Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE . For a library call , FNTYPE is 0 .


<s> static void insert_wic ( void ) { rtx_insn * insn ; int i ; basic_block bb , prev = 0 ; rtx branch_target = 0 ; shorten_branches ( get_insns ( ) ) ; for ( i = 0 ; i < n_basic_blocks_for_fn ( cfun ) - 1 ; i ++ ) { edge e ; edge_iterator ei ; bool simple_loop = false ; bb = BASIC_BLOCK_FOR_FN ( cfun , i ) ; if ( bb == NULL ) continue ; if ( ( prev != 0 ) && ( prev != bb ) ) continue ; else prev = 0 ; FOR_EACH_EDGE ( e , ei , bb -> preds ) if ( e -> src == bb ) { simple_loop = true ; prev = e -> dest ; break ; } for ( insn = BB_END ( bb ) ; insn ; insn = PREV_INSN ( insn ) ) { if ( INSN_P ( insn ) && ! simple_loop && CALL_P ( insn ) ) { if ( ( branch_target = get_branch_target ( insn ) ) ) insert_wic_for_ilb_runout ( next_active_insn ( next_active_insn ( insn ) ) ) ; } if ( insn == BB_HEAD ( bb ) ) break ; } } } </s>


<s> static void insert_wic_for_ilb_runout ( rtx_insn * first ) { rtx_insn * insn ; rtx_insn * before_4 = 0 ; rtx_insn * before_16 = 0 ; int addr_offset = 0 ; int length ; int wic_addr0 = 128 * 4 ; int first_addr = INSN_ADDRESSES ( INSN_UID ( first ) ) ; for ( insn = first ; insn ; insn = NEXT_INSN ( insn ) ) if ( INSN_P ( insn ) ) { addr_offset = INSN_ADDRESSES ( INSN_UID ( insn ) ) - first_addr ; length = get_attr_length ( insn ) ; if ( before_4 == 0 && addr_offset + length >= 4 * 4 ) before_4 = insn ; if ( JUMP_P ( insn ) ) return ; if ( before_16 == 0 && addr_offset + length >= 14 * 4 ) before_16 = insn ; if ( CALL_P ( insn ) || tablejump_p ( insn , 0 , 0 ) ) return ; if ( addr_offset + length >= 32 * 4 ) { gcc_assert ( before_4 && before_16 ) ; if ( wic_addr0 > 4 * 4 ) { insn = emit_insn_before ( gen_iprefetch ( gen_int_mode ( addr_offset , SImode ) ) , before_4 ) ; recog_memoized ( insn ) ; INSN_LOCATION ( insn ) = INSN_LOCATION ( before_4 ) ; INSN_ADDRESSES_NEW ( insn , INSN_ADDRESSES ( INSN_UID ( before_4 ) ) ) ; return ; } } } } </s>


<s> int label_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( GET_CODE ( x ) == LABEL_REF ) return 1 ; if ( GET_CODE ( x ) == UNSPEC ) return 0 ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( label_mentioned_p ( XVECEXP ( x , i , j ) ) ) return 1 ; } else if ( fmt [ i ] == 'e' && label_mentioned_p ( XEXP ( x , i ) ) ) return 1 ; } return 0 ; } </s>

Return TRUE if X references a LABEL_REF .


<s> static int microblaze_address_cost ( rtx addr , machine_mode mode ATTRIBUTE_UNUSED , addr_space_t as ATTRIBUTE_UNUSED , bool speed ATTRIBUTE_UNUSED ) { return COSTS_N_INSNS ( microblaze_address_insns ( addr , GET_MODE ( addr ) ) ) ; } </s>

Provide the costs of an addressing mode that contains ADDR . If ADDR is not a valid address , its cost is irrelevant .


<s> static int microblaze_address_insns ( rtx x , machine_mode mode ) { struct microblaze_address_info addr ; if ( microblaze_classify_address ( & addr , x , mode , false ) ) { switch ( addr . type ) { case ADDRESS_REG : if ( SMALL_INT ( addr . offset ) ) return 1 ; else return 2 ; case ADDRESS_CONST_INT : if ( SMALL_INT ( x ) ) return 1 ; else return 2 ; case ADDRESS_REG_INDEX : return 1 ; case ADDRESS_SYMBOLIC : case ADDRESS_SYMBOLIC_TXT_REL : case ADDRESS_GOTOFF : return 2 ; case ADDRESS_TLS : switch ( addr . tls_type ) { case TLS_GD : return 2 ; case TLS_LDM : return 2 ; case TLS_DTPREL : return 1 ; default : abort ( ) ; } default : break ; } } return 0 ; } </s>

Return the number of instructions needed to load or store a value of mode MODE at X . Return 0 if X is n't valid for MODE .


<s> static void microblaze_adjust_block_mem ( rtx mem , HOST_WIDE_INT length , rtx * loop_reg , rtx * loop_mem ) { * loop_reg = copy_addr_to_reg ( XEXP ( mem , 0 ) ) ; * loop_mem = change_address ( mem , BLKmode , * loop_reg ) ; set_mem_align ( * loop_mem , MIN ( ( HOST_WIDE_INT ) MEM_ALIGN ( mem ) , length * BITS_PER_UNIT ) ) ; } </s>

Helper function for doing a loop-based block operation on memory reference MEM . Each iteration of the loop will operate on LENGTH bytes of MEM . Create a new base register for use within the loop and point it to the start of MEM . Create a new memory reference that uses this register . Store them in * LOOP_REG and * LOOP_MEM respectively .


<s> static int microblaze_adjust_cost ( rtx_insn * , int dep_type , rtx_insn * , int cost , unsigned int ) { if ( dep_type == REG_DEP_OUTPUT || dep_type == 0 ) return cost ; return 0 ; } </s>


<s>
void
microblaze_asm_output_ident
(
const
char
*
string
)
{
const
char
*
section_asm_op
;
int
size
;
char
*
buf
;
if
(
symtab
->
state
!=
PARSING
)
return
;
size
=
strlen
(
string
)
+
1
;
if
(
size
<=
microblaze_section_threshold
)
section_asm_op
=
SDATA2_SECTION_ASM_OP
;
else
section_asm_op
=
READONLY_DATA_SECTION_ASM_OP
;
buf
=
ACONCAT
(
(
"\t.pushsection"
,
section_asm_op
,
"\n\t.ascii \""
,
string
,
"\\0\"\n"
,
"\t.popsection\n"
,
)
)
;
symtab
->
finalize_toplevel_asm
(
build_string
(
strlen
(
buf
)
,
buf
)
)
;
}
</s>

Queue an .ident string in the queue of top-level asm statements . If the string size is below the threshold , put it into .sdata2 . If the front-end is done , we must be being called from toplev.cc . In that case , do nothing .


<s>
static
void
microblaze_asm_trampoline_template
(
FILE
*
f
)
{
fprintf
(
f
,
"\tmfs r18, rpc\n"
)
;
fprintf
(
f
,
"\tlwi r3, r18, 16\n"
)
;
fprintf
(
f
,
"\tlwi r18, r18, 20\n"
)
;
fprintf
(
f
,
"\tbra r18\n"
)
;
}
</s>

Generate assembler code for constant parts of a trampoline .

microblaze
"\tmfs r18, rpc\n"
"\tlwi r3, r18, 16\n"
"\tlwi r18, r18, 20\n"
"\tbra r18\n"


<s> static void microblaze_block_move_loop ( rtx dest , rtx src , HOST_WIDE_INT length ) { rtx_code_label * label ; rtx src_reg , dest_reg , final_src ; HOST_WIDE_INT leftover ; leftover = length % MAX_MOVE_BYTES ; length -= leftover ; microblaze_adjust_block_mem ( src , MAX_MOVE_BYTES , & src_reg , & src ) ; microblaze_adjust_block_mem ( dest , MAX_MOVE_BYTES , & dest_reg , & dest ) ; final_src = expand_simple_binop ( Pmode , PLUS , src_reg , GEN_INT ( length ) , 0 , 0 , OPTAB_WIDEN ) ; label = gen_label_rtx ( ) ; emit_label ( label ) ; microblaze_block_move_straight ( dest , src , MAX_MOVE_BYTES ) ; emit_move_insn ( src_reg , plus_constant ( Pmode , src_reg , MAX_MOVE_BYTES ) ) ; emit_move_insn ( dest_reg , plus_constant ( Pmode , dest_reg , MAX_MOVE_BYTES ) ) ; emit_insn ( gen_cbranchsi4 ( gen_rtx_NE ( SImode , src_reg , final_src ) , src_reg , final_src , label ) ) ; if ( leftover ) microblaze_block_move_straight ( dest , src , leftover ) ; } </s>

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


<s> static void microblaze_block_move_straight ( rtx dest , rtx src , HOST_WIDE_INT length ) { HOST_WIDE_INT offset , delta ; unsigned HOST_WIDE_INT bits ; int i ; machine_mode mode ; rtx * regs ; bits = BITS_PER_WORD ; mode = int_mode_for_size ( bits , 0 ) . require ( ) ; delta = bits / BITS_PER_UNIT ; regs = XALLOCAVEC ( rtx , length / delta ) ; for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) { regs [ i ] = gen_reg_rtx ( mode ) ; emit_move_insn ( regs [ i ] , adjust_address ( src , mode , offset ) ) ; } for ( offset = 0 , i = 0 ; offset + delta <= length ; offset += delta , i ++ ) emit_move_insn ( adjust_address ( dest , mode , offset ) , regs [ i ] ) ; if ( offset < length ) { src = adjust_address ( src , BLKmode , offset ) ; dest = adjust_address ( dest , BLKmode , offset ) ; move_by_pieces ( dest , src , length - offset , MIN ( MEM_ALIGN ( src ) , MEM_ALIGN ( dest ) ) , RETURN_BEGIN ) ; } } </s>

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


<s> static bool microblaze_can_eliminate ( const int from , const int to ) { return ( ( from == RETURN_ADDRESS_POINTER_REGNUM && ! leaf_function_p ( ) ) || ( to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p ( ) ) || ( from != RETURN_ADDRESS_POINTER_REGNUM && ( to == HARD_FRAME_POINTER_REGNUM || ( to == STACK_POINTER_REGNUM && ! frame_pointer_needed ) ) ) ) ; } </s>

Make sure that we 're not trying to eliminate to the wrong hard frame pointer .


<s> int microblaze_can_use_return_insn ( void ) { if ( ! reload_completed ) return 0 ; if ( df_regs_ever_live_p ( MB_ABI_SUB_RETURN_ADDR_REGNUM ) || profile_flag ) return 0 ; if ( current_frame_info . initialized ) return current_frame_info . total_size == 0 ; return compute_frame_size ( get_frame_size ( ) ) == 0 ; } </s>

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


<s> static HOST_WIDE_INT microblaze_constant_alignment ( const_tree exp , HOST_WIDE_INT align ) { if ( TREE_CODE ( exp ) == STRING_CST || TREE_CODE ( exp ) == CONSTRUCTOR ) return MAX ( align , BITS_PER_WORD ) ; return align ; } </s>


<s> static bool microblaze_const_double_ok ( rtx op , machine_mode mode ) { REAL_VALUE_TYPE d ; if ( GET_CODE ( op ) != CONST_DOUBLE ) return 0 ; if ( GET_MODE ( op ) == VOIDmode ) return 1 ; if ( mode != SFmode && mode != DFmode ) return 0 ; if ( op == CONST0_RTX ( mode ) ) return 1 ; d = * CONST_DOUBLE_REAL_VALUE ( op ) ; if ( REAL_VALUE_ISNAN ( d ) ) return FALSE ; if ( REAL_VALUE_NEGATIVE ( d ) ) d = real_value_negate ( & d ) ; if ( mode == DFmode ) { if ( real_less ( & d , & dfhigh ) && real_less ( & dflow , & d ) ) return 1 ; } else { if ( real_less ( & d , & sfhigh ) && real_less ( & sflow , & d ) ) return 1 ; } return 0 ; } </s>

Return truth value if a CONST_DOUBLE is ok to be a legitimate constant .


<s> void microblaze_declare_object ( FILE * stream , const char * name , const char * section , const char * fmt , int size ) { fputs ( section , stream ) ; assemble_name ( stream , name ) ; fprintf ( stream , fmt , size ) ; } </s>

Emit either a label , .comm , or .lcomm directive , and mark that the symbol is used , so that we do n't emit an .extern for it in microblaze_asm_file_end .


<s> static void microblaze_elf_asm_constructor ( rtx symbol , int priority ) { microblaze_elf_asm_cdtor ( symbol , priority , true ) ; } </s>

Add a function to the list of static constructors .


<s> static void microblaze_elf_asm_destructor ( rtx symbol , int priority ) { microblaze_elf_asm_cdtor ( symbol , priority , false ) ; } </s>

Add a function to the list of static destructors .


<s> static bool microblaze_elf_in_small_data_p ( const_tree decl ) { HOST_WIDE_INT size ; if ( ! TARGET_XLGPOPT ) return false ; if ( TREE_CODE ( decl ) == STRING_CST ) return false ; if ( TREE_CODE ( decl ) == FUNCTION_DECL ) return false ; if ( TREE_CODE ( decl ) == VAR_DECL && DECL_SECTION_NAME ( decl ) ) { const char * section = DECL_SECTION_NAME ( decl ) ; if ( strcmp ( section , ".sdata" ) == 0 || strcmp ( section , ".sdata2" ) == 0 || strcmp ( section , ".sbss" ) == 0 || strcmp ( section , ".sbss2" ) == 0 ) return true ; } size = int_size_in_bytes ( TREE_TYPE ( decl ) ) ; return ( size > 0 && size <= microblaze_section_threshold ) ; } </s>

Returns true if decl should be placed into a `` small data '' section .


<s> static void microblaze_encode_section_info ( tree decl , rtx rtl , int first ) { default_encode_section_info ( decl , rtl , first ) ; } </s>

Encode info about sections into the RTL based on a symbol 's declaration . The default definition of this hook , default_encode_section_info in ` varasm.cc ' , sets a number of commonly-useful bits in SYMBOL_REF_FLAGS .


<s> bool microblaze_expand_block_move ( rtx dest , rtx src , rtx length , rtx align_rtx ) { if ( GET_CODE ( length ) == CONST_INT ) { unsigned HOST_WIDE_INT bytes = UINTVAL ( length ) ; unsigned int align = UINTVAL ( align_rtx ) ; if ( align > UNITS_PER_WORD ) { align = UNITS_PER_WORD ; } else if ( align < UNITS_PER_WORD ) { if ( UINTVAL ( length ) <= MAX_MOVE_BYTES ) { move_by_pieces ( dest , src , bytes , align , RETURN_BEGIN ) ; return true ; } else return false ; } if ( UINTVAL ( length ) <= 2 * MAX_MOVE_BYTES ) { microblaze_block_move_straight ( dest , src , UINTVAL ( length ) ) ; return true ; } else if ( optimize ) { microblaze_block_move_loop ( dest , src , UINTVAL ( length ) ) ; return true ; } } return false ; } </s>


<s> void microblaze_expand_conditional_branch ( machine_mode mode , rtx operands [ ] ) { enum rtx_code code = GET_CODE ( operands [ 0 ] ) ; rtx cmp_op0 = operands [ 1 ] ; rtx cmp_op1 = operands [ 2 ] ; rtx label1 = operands [ 3 ] ; rtx comp_reg = gen_reg_rtx ( SImode ) ; rtx condition ; gcc_assert ( ( GET_CODE ( cmp_op0 ) == REG ) || ( GET_CODE ( cmp_op0 ) == SUBREG ) ) ; if ( cmp_op1 == const0_rtx ) { comp_reg = cmp_op0 ; condition = gen_rtx_fmt_ee ( signed_condition ( code ) , SImode , comp_reg , const0_rtx ) ; emit_jump_insn ( gen_condjump ( condition , label1 ) ) ; } else if ( code == EQ || code == NE ) { emit_insn ( gen_xorsi3 ( comp_reg , cmp_op0 , cmp_op1 ) ) ; condition = gen_rtx_fmt_ee ( signed_condition ( code ) , SImode , comp_reg , const0_rtx ) ; emit_jump_insn ( gen_condjump ( condition , label1 ) ) ; } else { cmp_op1 = force_reg ( mode , cmp_op1 ) ; condition = gen_rtx_fmt_ee ( code , mode , cmp_op0 , cmp_op1 ) ; emit_jump_insn ( gen_branch_compare ( condition , cmp_op0 , cmp_op1 , label1 ) ) ; } } </s>

Generate conditional branch -- first , generate test condition , second , generate correct branch instruction .


<s> void microblaze_expand_epilogue ( void ) { HOST_WIDE_INT fsiz = current_frame_info . total_size ; rtx fsiz_rtx = GEN_INT ( fsiz ) ; rtx reg_rtx ; rtx mem_rtx ; if ( microblaze_can_use_return_insn ( ) ) { emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM ) ) ) ; return ; } if ( fsiz > 0 ) { if ( ! crtl -> is_leaf || interrupt_handler ) { mem_rtx = gen_rtx_MEM ( SImode , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , const0_rtx ) ) ; if ( interrupt_handler ) MEM_VOLATILE_P ( mem_rtx ) = 1 ; reg_rtx = gen_rtx_REG ( SImode , MB_ABI_SUB_RETURN_ADDR_REGNUM ) ; emit_move_insn ( reg_rtx , mem_rtx ) ; } if ( frame_pointer_needed ) emit_insn ( gen_movsi ( stack_pointer_rtx , hard_frame_pointer_rtx ) ) ; save_restore_insns ( 0 ) ; emit_insn ( gen_blockage ( ) ) ; emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , fsiz_rtx ) ) ; } if ( crtl -> calls_eh_return ) emit_insn ( gen_addsi3 ( stack_pointer_rtx , stack_pointer_rtx , gen_raw_REG ( SImode , MB_EH_STACKADJ_REGNUM ) ) ) ; emit_jump_insn ( gen_return_internal ( gen_rtx_REG ( Pmode , GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM ) ) ) ; } </s>

Expand the epilogue into a bunch of separate insns .


<s> int microblaze_expand_shift ( rtx operands [ ] ) { gcc_assert ( ( GET_CODE ( operands [ 2 ] ) == CONST_INT ) || ( GET_CODE ( operands [ 2 ] ) == REG ) || ( GET_CODE ( operands [ 2 ] ) == SUBREG ) ) ; if ( ( GET_CODE ( operands [ 2 ] ) == CONST_INT ) && ( INTVAL ( operands [ 2 ] ) == 1 ) ) return 0 ; if ( TARGET_BARREL_SHIFT ) return 0 ; gcc_assert ( ( GET_CODE ( operands [ 0 ] ) == REG ) || ( GET_CODE ( operands [ 0 ] ) == SUBREG ) || ( GET_CODE ( operands [ 1 ] ) == REG ) || ( GET_CODE ( operands [ 1 ] ) == SUBREG ) ) ; if ( operands [ 2 ] == const0_rtx && ! rtx_equal_p ( operands [ 0 ] , operands [ 1 ] ) ) { emit_insn ( gen_movsi ( operands [ 0 ] , operands [ 1 ] ) ) ; return 1 ; } return 0 ; } </s>


<s> static bool microblaze_frame_pointer_required ( void ) { if ( cfun -> calls_alloca ) return true ; return false ; } </s>


<s> static rtx microblaze_function_arg ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; rtx ret ; int regbase = - 1 ; int * arg_words = & cum -> arg_words ; cum -> last_arg_fp = 0 ; switch ( arg . mode ) { case E_SFmode : case E_DFmode : case E_VOIDmode : case E_QImode : case E_HImode : case E_SImode : case E_DImode : case E_TImode : regbase = GP_ARG_FIRST ; break ; default : gcc_assert ( GET_MODE_CLASS ( arg . mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( arg . mode ) == MODE_COMPLEX_FLOAT ) ; case E_BLKmode : regbase = GP_ARG_FIRST ; break ; } if ( * arg_words >= MAX_ARGS_IN_REGISTERS ) ret = 0 ; else { gcc_assert ( regbase != - 1 ) ; ret = gen_rtx_REG ( arg . mode , regbase + * arg_words ) ; } if ( arg . end_marker_p ( ) ) { if ( cum -> num_adjusts > 0 ) ret = gen_rtx_PARALLEL ( ( machine_mode ) cum -> fp_code , gen_rtvec_v ( cum -> num_adjusts , cum -> adjust ) ) ; } return ret ; } </s>

Return an RTL expression containing the register for the given mode , or 0 if the argument is to be passed on the stack .


<s> static void microblaze_function_arg_advance ( cumulative_args_t cum_v , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( cum_v ) ; cum -> arg_number ++ ; switch ( arg . mode ) { case E_VOIDmode : break ; default : gcc_assert ( GET_MODE_CLASS ( arg . mode ) == MODE_COMPLEX_INT || GET_MODE_CLASS ( arg . mode ) == MODE_COMPLEX_FLOAT ) ; cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( GET_MODE_SIZE ( arg . mode ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case E_BLKmode : cum -> gp_reg_found = 1 ; cum -> arg_words += ( ( int_size_in_bytes ( arg . type ) + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD ) ; break ; case E_SFmode : cum -> arg_words ++ ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 1 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case E_DFmode : cum -> arg_words += 2 ; if ( ! cum -> gp_reg_found && cum -> arg_number <= 2 ) cum -> fp_code += 2 << ( ( cum -> arg_number - 1 ) * 2 ) ; break ; case E_DImode : cum -> gp_reg_found = 1 ; cum -> arg_words += 2 ; break ; case E_QImode : case E_HImode : case E_SImode : case E_TImode : cum -> gp_reg_found = 1 ; cum -> arg_words ++ ; break ; } } </s>

Advance the argument to the next argument position .


<s>
static
void
microblaze_function_end_prologue
(
FILE
*
file
)
{
if
(
TARGET_STACK_CHECK
)
{
fprintf
(
file
,
"\t# Stack Check Stub -- Start.\n\t"
)
;
fprintf
(
file
,
"ori\tr18,r0,_stack_end\n\t"
)
;
fprintf
(
file
,
"cmpu\tr18,r1,r18\n\t"
)
;
fprintf
(
file
,
"bgei\tr18,_stack_overflow_exit\n\t"
)
;
fprintf
(
file
,
"# Stack Check Stub -- End.\n"
)
;
}
}
</s>

Output extra assembler code at the end of a prologue .


"\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n"

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


<s> static rtx microblaze_function_value ( const_tree valtype , const_tree func ATTRIBUTE_UNUSED , bool outgoing ATTRIBUTE_UNUSED ) { return LIBCALL_VALUE ( TYPE_MODE ( valtype ) ) ; } </s>


<s> static bool microblaze_gen_pic_addr_dif_vec ( void ) { return ( flag_pic && ! TARGET_PIC_DATA_TEXT_REL ) ; } </s>

We need to disable address diff vectors incase of pic data text relative mode .


<s> static bool microblaze_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { return microblaze_hard_regno_mode_ok_p [ mode ] [ regno ] ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . In 32 bit mode , require that DImode and DFmode be in even registers . For DImode , this makes some of the insns easier to write , since you do n't have to worry about a DImode value in registers 3 & 4 , producing a result in 4 & 5 . To make the code simpler , the hook now just references an array built in override_options .


<s> HOST_WIDE_INT microblaze_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT offset ; switch ( from ) { case FRAME_POINTER_REGNUM : offset = 0 ; break ; case ARG_POINTER_REGNUM : if ( to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM ) offset = compute_frame_size ( get_frame_size ( ) ) ; else gcc_unreachable ( ) ; break ; case RETURN_ADDRESS_POINTER_REGNUM : if ( crtl -> is_leaf ) offset = 0 ; else offset = current_frame_info . gp_offset + ( ( UNITS_PER_WORD - ( POINTER_SIZE / BITS_PER_UNIT ) ) ) ; break ; default : gcc_unreachable ( ) ; } return offset ; } </s>

Implement INITIAL_ELIMINATION_OFFSET . FROM is either the frame pointer or argument pointer or the return address pointer . TO is either the stack pointer or hard frame pointer .


<s> static int microblaze_interrupt_function_p ( tree func ) { tree a ; if ( TREE_CODE ( func ) != FUNCTION_DECL ) return 0 ; a = lookup_attribute ( "interrupt_handler" , DECL_ATTRIBUTES ( func ) ) ; return a != NULL_TREE ; } </s>

Return true if FUNC is an interrupt function as specified by the `` interrupt_handler '' attribute .


<s> int microblaze_is_interrupt_variant ( void ) { return ( interrupt_handler || fast_interrupt ) ; } </s>

Return whether function is tagged with 'interrupt_handler ' or 'fast_interrupt ' attribute . Return true if function should use return from interrupt rather than normal function return .


<s> bool microblaze_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { struct microblaze_address_info addr ; return microblaze_classify_address ( & addr , x , mode , strict ) ; } </s>

This function is used to implement GO_IF_LEGITIMATE_ADDRESS . It returns a nonzero value if X is a legitimate address for a memory operand of the indicated MODE . STRICT is nonzero if this function is called during reload .


<s> static bool microblaze_legitimate_constant_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { if ( microblaze_cannot_force_const_mem ( mode , x ) ) return false ; if ( GET_CODE ( x ) == CONST_DOUBLE ) { return microblaze_const_double_ok ( x , GET_MODE ( x ) ) ; } if ( GET_CODE ( x ) == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS ) { rtx p0 , p1 ; p0 = XEXP ( XEXP ( x , 0 ) , 0 ) ; p1 = XEXP ( XEXP ( x , 0 ) , 1 ) ; if ( GET_CODE ( p1 ) == CONST_INT ) { if ( ( GET_CODE ( p0 ) == UNSPEC ) ) return false ; if ( ( GET_CODE ( p0 ) == SYMBOL_REF || GET_CODE ( p0 ) == LABEL_REF ) && ( microblaze_tls_symbol_p ( p0 ) || ! SMALL_INT ( p1 ) ) ) return false ; } } return true ; } </s>

Implement TARGET_LEGITIMATE_CONSTANT_P . At present , GAS does n't understand li . [ sd ] , so do n't allow it to be generated at present .


<s> static void microblaze_machine_dependent_reorg ( void ) { if ( TARGET_PREFETCH ) { compute_bb_for_insn ( ) ; loop_optimizer_init ( AVOID_CFG_MODIFICATIONS ) ; shorten_branches ( get_insns ( ) ) ; insert_wic ( ) ; loop_optimizer_finalize ( ) ; free_bb_for_insn ( ) ; return ; } } </s>

The reorg function defined through the macro TARGET_MACHINE_DEPENDENT_REORG .


<s> static int microblaze_must_save_register ( int regno ) { if ( pic_offset_table_rtx && ( regno == MB_ABI_PIC_ADDR_REGNUM ) && df_regs_ever_live_p ( regno ) ) return 1 ; if ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) return 1 ; if ( frame_pointer_needed && ( regno == HARD_FRAME_POINTER_REGNUM ) ) return 1 ; if ( crtl -> calls_eh_return && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) return 1 ; if ( ! crtl -> is_leaf ) { if ( regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) return 1 ; if ( ( microblaze_is_interrupt_variant ( ) || save_volatiles ) && ( regno >= 3 && regno <= 12 ) ) return 1 ; } if ( microblaze_is_interrupt_variant ( ) ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_MSR_SAVE_REG || ( ( interrupt_handler || fast_interrupt ) && ( regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) ) ) return 1 ; } if ( save_volatiles ) { if ( df_regs_ever_live_p ( regno ) || regno == MB_ABI_ASM_TEMP_REGNUM || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM ) return 1 ; } if ( crtl -> calls_eh_return && ( regno == EH_RETURN_DATA_REGNO ( 0 ) || regno == EH_RETURN_DATA_REGNO ( 1 ) ) ) return 1 ; return 0 ; } </s>

Determine of register must be saved/restored in call .


<s> int microblaze_regno_ok_for_base_p ( int regno , int strict ) { if ( regno >= FIRST_PSEUDO_REGISTER ) { if ( ! strict ) return true ; regno = reg_renumber [ regno ] ; } if ( regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM ) return true ; return GP_REG_P ( regno ) ; } </s>


<s> rtx microblaze_return_addr ( int count , rtx frame ATTRIBUTE_UNUSED ) { if ( count != 0 ) return NULL_RTX ; return get_hard_reg_initial_val ( Pmode , MB_ABI_SUB_RETURN_ADDR_REGNUM ) ; } </s>

Return an RTX indicating where the return address to the calling function can be found .


<s> static int microblaze_save_volatiles ( tree func ) { tree a ; if ( TREE_CODE ( func ) != FUNCTION_DECL ) return 0 ; a = lookup_attribute ( "save_volatiles" , DECL_ATTRIBUTES ( func ) ) ; return a != NULL_TREE ; } </s>

Return true if FUNC is an interrupt function which uses normal return , indicated by the `` save_volatiles '' attribute .


<s> static reg_class_t microblaze_secondary_reload ( bool in_p ATTRIBUTE_UNUSED , rtx x ATTRIBUTE_UNUSED , reg_class_t rclass , machine_mode mode ATTRIBUTE_UNUSED , secondary_reload_info * sri ATTRIBUTE_UNUSED ) { if ( rclass == ST_REGS ) return GR_REGS ; return NO_REGS ; } </s>


<s> static HOST_WIDE_INT microblaze_starting_frame_offset ( void ) { return ( crtl -> outgoing_args_size + FIRST_PARM_OFFSET ( FNDECL ) ) ; } </s>


<s> bool microblaze_tls_referenced_p ( rtx x ) { if ( ! TARGET_HAVE_TLS ) return false ; subrtx_iterator :: array_type array ; FOR_EACH_SUBRTX ( iter , array , x , ALL ) { const_rtx x = * iter ; if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) != 0 ) return true ; if ( GET_CODE ( x ) == UNSPEC && XINT ( x , 1 ) == UNSPEC_TLS ) iter . skip_subrtxes ( ) ; } return false ; } </s>

Return TRUE if X contains any TLS symbol references .


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

Return TRUE if X is a thread-local symbol .


<s> static void microblaze_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx mem ; emit_block_move ( m_tramp , assemble_trampoline_template ( ) , GEN_INT ( 6 * UNITS_PER_WORD ) , BLOCK_OP_NORMAL ) ; mem = adjust_address ( m_tramp , SImode , 16 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , SImode , 20 ) ; emit_move_insn ( mem , fnaddr ) ; } </s>


<s> static bool microblaze_valid_base_register_p ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int strict ) { if ( ! strict && GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; return ( GET_CODE ( x ) == REG && microblaze_regno_ok_for_base_p ( REGNO ( x ) , strict ) ) ; } </s>

Return true if X is a valid base register for the given mode . Allow only hard registers if STRICT .


<s> static bool microblaze_valid_index_register_p ( rtx x , machine_mode mode ATTRIBUTE_UNUSED , int strict ) { if ( ! strict && GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; return ( GET_CODE ( x ) == REG && microblaze_regno_ok_for_base_p ( REGNO ( x ) , strict ) ) ; } </s>

Return true if X is a valid index register for the given mode . Allow only hard registers if STRICT .


<s> static int microblaze_version_to_int ( const char * version ) { const char * p , * v ; const char * tmpl = "vXX.YY.Z" ; int iver = 0 ; p = version ; v = tmpl ; while ( * p ) { if ( * v == 'X' ) { if ( * p == '.' ) { v ++ ; } else { if ( ! ( * p >= '0' && * p <= '9' ) ) return - 1 ; iver += ( int ) ( * p - '0' ) ; iver *= 10 ; } } else if ( * v == 'Y' ) { if ( ! ( * p >= '0' && * p <= '9' ) ) return - 1 ; iver += ( int ) ( * p - '0' ) ; iver *= 10 ; } else if ( * v == 'Z' ) { if ( ! ( * p >= 'a' && * p <= 'z' ) ) return - 1 ; iver *= 10 ; iver += ( int ) ( * p - 'a' ) ; } else { if ( * p != * v ) return - 1 ; } v ++ ; p ++ ; } if ( * p ) return - 1 ; return iver ; } </s>

Convert a version number of the form `` vX.YY.Z '' to an integer encoding for easier range comparison .


<s> int pic_address_needs_scratch ( rtx x ) { if ( GET_CODE ( x ) == CONST && GET_CODE ( XEXP ( x , 0 ) ) == PLUS ) { rtx p0 , p1 ; p0 = XEXP ( XEXP ( x , 0 ) , 0 ) ; p1 = XEXP ( XEXP ( x , 0 ) , 1 ) ; if ( ( GET_CODE ( p0 ) == SYMBOL_REF || GET_CODE ( p0 ) == LABEL_REF ) && ( GET_CODE ( p1 ) == CONST_INT ) && ( flag_pic == 2 || microblaze_tls_symbol_p ( p0 ) || ! SMALL_INT ( p1 ) ) ) return 1 ; } return 0 ; } </s>

Return true if X is an address which needs a temporary register when reloaded while generating PIC code .


<s>
void
print_operand_address
(
FILE
*
file
,
rtx
addr
)
{
struct
microblaze_address_info
info
;
enum
microblaze_address_type
type
;
if
(
!
microblaze_classify_address
(
&
info
,
addr
,
GET_MODE
(
addr
)
,
2
)
)
fatal_insn
(
"insn contains an invalid address !"
,
addr
)
;
type
=
info
.
type
;
switch
(
info
.
type
)
{
case
ADDRESS_REG
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_REG_INDEX
:
if
(
REGNO
(
info
.
regA
)
==
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
else
if
(
REGNO
(
info
.
regB
)
!=
0
)
fprintf
(
file
,
"%s,%s"
,
reg_names
[
REGNO
(
info
.
regB
)
]
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
break
;
case
ADDRESS_CONST_INT
:
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
offset
)
;
break
;
case
ADDRESS_SYMBOLIC
:
case
ADDRESS_SYMBOLIC_TXT_REL
:
case
ADDRESS_GOTOFF
:
case
ADDRESS_PLT
:
case
ADDRESS_TLS
:
if
(
info
.
regA
)
fprintf
(
file
,
"%s,"
,
reg_names
[
REGNO
(
info
.
regA
)
]
)
;
output_addr_const
(
file
,
info
.
symbol
)
;
if
(
type
==
ADDRESS_GOTOFF
)
{
fputs
(
"@GOT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_PLT
)
{
fputs
(
"@PLT"
,
file
)
;
}
else
if
(
type
==
ADDRESS_SYMBOLIC_TXT_REL
)
{
if
(
info
.
offset
!=
&&
CONST_INT_P
(
info
.
offset
)
&&
INTVAL
(
info
.
offset
)
>
0
)
{
fprintf
(
file
,
"+"
)
;
output_addr_const
(
file
,
info
.
offset
)
;
}
fputs
(
"@TXTREL"
,
file
)
;
}
else
if
(
type
==
ADDRESS_TLS
)
{
switch
(
info
.
tls_type
)
{
case
TLS_GD
:
fputs
(
"@TLSGD"
,
file
)
;
break
;
case
TLS_LDM
:
fputs
(
"@TLSLDM"
,
file
)
;
break
;
case
TLS_DTPREL
:
fputs
(
"@TLSDTPREL"
,
file
)
;
break
;
default
:
abort
(
)
;
break
;
}
}
break
;
case
ADDRESS_INVALID
:
fatal_insn
(
"invalid address"
,
addr
)
;
break
;
}
}
</s>

Print the operand address represented by the rtx addr


<s> static void save_restore_insns ( int prologue ) { rtx base_reg_rtx , reg_rtx , mem_rtx , isr_reg_rtx = 0 , isr_mem_rtx = 0 ; rtx isr_msr_rtx = 0 , insn ; long mask = current_frame_info . mask ; HOST_WIDE_INT gp_offset ; int regno ; if ( frame_pointer_needed && ! BITSET_P ( mask , HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST ) ) gcc_unreachable ( ) ; if ( mask == 0 ) return ; gp_offset = current_frame_info . gp_offset ; gcc_assert ( gp_offset > 0 ) ; base_reg_rtx = stack_pointer_rtx ; if ( microblaze_is_interrupt_variant ( ) ) { isr_mem_rtx = gen_rtx_MEM ( SImode , gen_rtx_PLUS ( Pmode , base_reg_rtx , GEN_INT ( current_frame_info . gp_offset - UNITS_PER_WORD ) ) ) ; MEM_VOLATILE_P ( isr_mem_rtx ) = 1 ; isr_reg_rtx = gen_rtx_REG ( SImode , MB_ABI_MSR_SAVE_REG ) ; isr_msr_rtx = gen_rtx_REG ( SImode , ST_REG ) ; } if ( microblaze_is_interrupt_variant ( ) && ! prologue ) { emit_move_insn ( isr_reg_rtx , isr_mem_rtx ) ; emit_move_insn ( isr_msr_rtx , isr_reg_rtx ) ; emit_insn ( gen_rtx_USE ( SImode , isr_reg_rtx ) ) ; emit_insn ( gen_rtx_USE ( SImode , isr_msr_rtx ) ) ; } for ( regno = GP_REG_FIRST ; regno <= GP_REG_LAST ; regno ++ ) { if ( BITSET_P ( mask , regno - GP_REG_FIRST ) ) { if ( regno == MB_ABI_SUB_RETURN_ADDR_REGNUM ) continue ; reg_rtx = gen_rtx_REG ( SImode , regno ) ; insn = gen_rtx_PLUS ( Pmode , base_reg_rtx , GEN_INT ( gp_offset ) ) ; mem_rtx = gen_rtx_MEM ( SImode , insn ) ; if ( microblaze_is_interrupt_variant ( ) || save_volatiles ) MEM_VOLATILE_P ( mem_rtx ) = 1 ; if ( prologue ) { insn = emit_move_insn ( mem_rtx , reg_rtx ) ; RTX_FRAME_RELATED_P ( insn ) = 1 ; } else { insn = emit_move_insn ( reg_rtx , mem_rtx ) ; } gp_offset += GET_MODE_SIZE ( SImode ) ; } } if ( microblaze_is_interrupt_variant ( ) && prologue ) { emit_move_insn ( isr_reg_rtx , isr_msr_rtx ) ; emit_move_insn ( isr_mem_rtx , isr_reg_rtx ) ; emit_insn ( gen_rtx_USE ( SImode , isr_reg_rtx ) ) ; emit_insn ( gen_rtx_USE ( SImode , isr_msr_rtx ) ) ; } } </s>

Save or restore instructions based on whether this is the prologue or epilogue . prologue is 1 for the prologue .


<s> int simple_memory_operand ( rtx op , machine_mode mode ATTRIBUTE_UNUSED ) { rtx addr , plus0 , plus1 ; if ( GET_CODE ( op ) != MEM ) return 0 ; if ( GET_MODE_SIZE ( GET_MODE ( op ) ) > UNITS_PER_WORD ) return 0 ; addr = XEXP ( op , 0 ) ; switch ( GET_CODE ( addr ) ) { case REG : return 1 ; case PLUS : plus0 = XEXP ( addr , 0 ) ; plus1 = XEXP ( addr , 1 ) ; if ( GET_CODE ( plus0 ) != REG ) return 0 ; if ( GET_CODE ( plus0 ) == REG && GET_CODE ( plus1 ) == CONST_INT && SMALL_INT ( plus1 ) ) { return 1 ; } else if ( GET_CODE ( plus1 ) == REG && GET_CODE ( plus0 ) == CONST_INT ) { return 1 ; } else if ( GET_CODE ( plus0 ) == REG && GET_CODE ( plus1 ) == REG ) { return 1 ; } else return 0 ; case SYMBOL_REF : return 0 ; default : break ; } return 0 ; } </s>

Return truth value if a memory operand fits in a single instruction ( ie , register + small offset ) .


<s> int symbol_mentioned_p ( rtx x ) { const char * fmt ; int i ; if ( GET_CODE ( x ) == SYMBOL_REF ) return 1 ; if ( GET_CODE ( x ) == UNSPEC ) return 0 ; fmt = GET_RTX_FORMAT ( GET_CODE ( x ) ) ; for ( i = GET_RTX_LENGTH ( GET_CODE ( x ) ) - 1 ; i >= 0 ; i -- ) { if ( fmt [ i ] == 'E' ) { int j ; for ( j = XVECLEN ( x , i ) - 1 ; j >= 0 ; j -- ) if ( symbol_mentioned_p ( XVECEXP ( x , i , j ) ) ) return 1 ; } else if ( fmt [ i ] == 'e' && symbol_mentioned_p ( XEXP ( x , i ) ) ) return 1 ; } return 0 ; } </s>

Return TRUE if X references a SYMBOL_REF .