<s> int flags_in_68881 ( ) { return cc_status . flags & CC_IN_68881 ; } </s>

Return nonzero if flags are currently in the 68881 flag register .


<s> void init_68881_table ( ) { int i ; REAL_VALUE_TYPE r ; enum machine_mode mode ; mode = SFmode ; for ( i = 0 ; i < 7 ; i ++ ) { if ( i == 6 ) mode = DFmode ; r = REAL_VALUE_ATOF ( strings_68881 [ i ] , mode ) ; values_68881 [ i ] = r ; } inited_68881_table = 1 ; } </s>

Set up values_68881 array by converting the decimal values strings_68881 to binary .


"-malign-loops=%d is not between 1 and %d"

"-malign-jumps=%d is not between 1 and %d"

"-malign-functions=%d is not between 1 and %d"

Set global variables as needed for the options enabled .


<s> int use_return_insn ( ) { int regno ; if ( ! reload_completed || frame_pointer_needed || get_frame_size ( ) != 0 ) return 0 ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) if ( regs_ever_live [ regno ] && ! call_used_regs [ regno ] ) return 0 ; if ( flag_pic && current_function_uses_pic_offset_table ) return 0 ; return 1 ; } </s>

Return true if this function 's epilogue can be output as RTL .


<s> static int const_int_cost ( rtx constant ) { switch ( const_method ( constant ) ) { case MOVQ : return 0 ; case MVZ : case MVS : case NOTB : case NOTW : case NEGW : case SWAP : return 1 ; case MOVL : return 2 ; default : gcc_unreachable ( ) ; } } </s>

Return the cost of moving constant I into a data register .


<s> int flags_in_68881 ( void ) { return cc_status . flags & CC_IN_68881 ; } </s>


<s> int floating_exact_log2 ( rtx x ) { REAL_VALUE_TYPE r , r1 ; int exp ; REAL_VALUE_FROM_CONST_DOUBLE ( r , x ) ; if ( REAL_VALUES_LESS ( r , dconst1 ) ) return 0 ; exp = real_exponent ( & r ) ; real_2expN ( & r1 , exp ) ; if ( REAL_VALUES_EQUAL ( r1 , r ) ) return exp ; return 0 ; } </s>

If X is a floating-point constant , return the logarithm of X base 2 , or 0 if X is not a power of 2 .


<s> void init_68881_table ( void ) { int i ; REAL_VALUE_TYPE r ; enum machine_mode mode ; mode = SFmode ; for ( i = 0 ; i < 7 ; i ++ ) { if ( i == 6 ) mode = DFmode ; r = REAL_VALUE_ATOF ( strings_68881 [ i ] , mode ) ; values_68881 [ i ] = r ; } inited_68881_table = 1 ; } </s>


<s> rtx legitimize_pic_address ( rtx orig , enum machine_mode mode ATTRIBUTE_UNUSED , rtx reg ) { rtx pic_ref = orig ; if ( GET_CODE ( orig ) == SYMBOL_REF || GET_CODE ( orig ) == LABEL_REF ) { gcc_assert ( reg ) ; pic_ref = gen_rtx_MEM ( Pmode , gen_rtx_PLUS ( Pmode , pic_offset_table_rtx , orig ) ) ; current_function_uses_pic_offset_table = 1 ; MEM_READONLY_P ( pic_ref ) = 1 ; emit_move_insn ( reg , pic_ref ) ; return reg ; } else if ( GET_CODE ( orig ) == CONST ) { rtx base ; if ( GET_CODE ( XEXP ( orig , 0 ) ) == PLUS && XEXP ( XEXP ( orig , 0 ) , 0 ) == pic_offset_table_rtx ) return orig ; gcc_assert ( reg ) ; gcc_assert ( GET_CODE ( XEXP ( orig , 0 ) ) == PLUS ) ; base = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 0 ) , Pmode , reg ) ; orig = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 1 ) , Pmode , base == reg ? 0 : reg ) ; if ( GET_CODE ( orig ) == CONST_INT ) return plus_constant ( base , INTVAL ( orig ) ) ; pic_ref = gen_rtx_PLUS ( Pmode , base , orig ) ; } return pic_ref ; } </s>

Legitimize PIC addresses . If the address is already position-independent , we return ORIG . Newly generated position-independent addresses go into a reg . This is REG if nonzero , otherwise we allocate register ( s ) as necessary .


<s> static void m68k_coff_asm_named_section ( const char * name , unsigned int flags , tree decl ATTRIBUTE_UNUSED ) { char flagchar ; if ( flags & SECTION_WRITE ) flagchar = 'd' ; else flagchar = 'x' ; fprintf ( asm_out_file , "\t.section\t%s,\"%c\"\n" , name , flagchar ) ; } </s>

Output assembly to switch to section NAME with attribute FLAGS .


"%qs attribute only applies to functions"

Handle an attribute requiring a FUNCTION_DECL ; arguments as in struct attribute_spec.handler .


"-mshared-library-id=%s is not between 0 and %d"


<s> int m68k_hard_regno_rename_ok ( unsigned int old_reg ATTRIBUTE_UNUSED , unsigned int new_reg ) { if ( m68k_interrupt_function_p ( current_function_decl ) && ! regs_ever_live [ new_reg ] ) return 0 ; return 1 ; } </s>

Return nonzero if register old_reg can be renamed to register new_reg .


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

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


Output a BSR instruction suitable for PIC code .


<s> bool m68k_regno_mode_ok ( int regno , enum machine_mode mode ) { if ( regno < 8 ) { if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 8 ) return true ; } else if ( regno < 16 ) { if ( GET_MODE_SIZE ( mode ) == 1 ) return false ; if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 16 ) return true ; } else if ( regno < 24 ) { if ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) && GET_MODE_UNIT_SIZE ( mode ) <= 12 ) return true ; } return false ; } </s>

Value is true if hard register REGNO can hold a value of machine-mode MODE . On the 68000 , we let the cpu registers can hold any mode , but restrict the 68881 registers to floating-point modes .


<s> static bool m68k_save_reg ( unsigned int regno , bool interrupt_handler ) { if ( flag_pic && regno == PIC_OFFSET_TABLE_REGNUM ) { if ( current_function_uses_pic_offset_table ) return true ; if ( ! current_function_is_leaf && TARGET_ID_SHARED_LIBRARY ) return true ; } if ( current_function_calls_eh_return ) { unsigned int i ; for ( i = 0 ; ; i ++ ) { unsigned int test = EH_RETURN_DATA_REGNO ( i ) ; if ( test == INVALID_REGNUM ) break ; if ( test == regno ) return true ; } } if ( fixed_regs [ regno ] ) return false ; if ( regno == FRAME_POINTER_REGNUM && frame_pointer_needed ) return false ; if ( interrupt_handler ) { if ( regs_ever_live [ regno ] ) return true ; if ( ! current_function_is_leaf && call_used_regs [ regno ] ) return true ; } if ( ! regs_ever_live [ regno ] ) return false ; return ! call_used_regs [ regno ] ; } </s>

Refer to the array ` regs_ever_live ' to determine which registers to save ; ` regs_ever_live [ I ] ' is nonzero if register number I is ever used in the function . This function is responsible for knowing which registers should not be saved even if used . Return true if we need to save REGNO .


<s>
const
char
*
output_addsi3
(
rtx
*
operands
)
{
if
(
!
operands_match_p
(
operands
[
0
]
,
operands
[
1
]
)
)
{
if
(
!
ADDRESS_REG_P
(
operands
[
1
]
)
)
{
rtx
tmp
=
operands
[
1
]
;
operands
[
1
]
=
operands
[
2
]
;
operands
[
2
]
=
tmp
;
}
if
(
GET_CODE
(
operands
[
2
]
)
==
CONST_INT
&&
(
INTVAL
(
operands
[
2
]
)
<
32768
||
INTVAL
(
operands
[
2
]
)
>
32767
)
)
return
"move%.l %2,%0\n\tadd%.l %1,%0"
;
if
(
GET_CODE
(
operands
[
2
]
)
==
REG
)
return
MOTOROLA
"lea (%1,%2.l),%0"
:
"lea %1@(0,%2:l),%0"
;
return
MOTOROLA
"lea (%c2,%1),%0"
:
"lea %1@(%c2),%0"
;
}
if
(
GET_CODE
(
operands
[
2
]
)
==
CONST_INT
)
{
if
(
INTVAL
(
operands
[
2
]
)
>
0
&&
INTVAL
(
operands
[
2
]
)
<=
8
)
return
"addq%.l %2,%0"
;
if
(
INTVAL
(
operands
[
2
]
)
<
0
&&
INTVAL
(
operands
[
2
]
)
>=
8
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
)
;
return
"subq%.l %2,%0"
;
}
if
(
TARGET_CPU32
&&
REG_P
(
operands
[
0
]
)
)
{
if
(
INTVAL
(
operands
[
2
]
)
>
8
&&
INTVAL
(
operands
[
2
]
)
<=
16
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
8
)
;
return
"addq%.l #8,%0\n\taddq%.l %2,%0"
;
}
if
(
INTVAL
(
operands
[
2
]
)
<
8
&&
INTVAL
(
operands
[
2
]
)
>=
16
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
8
)
;
return
"subq%.l #8,%0\n\tsubq%.l %2,%0"
;
}
}
if
(
ADDRESS_REG_P
(
operands
[
0
]
)
&&
INTVAL
(
operands
[
2
]
)
>=
0x8000
&&
INTVAL
(
operands
[
2
]
)
<
0x8000
)
{
if
(
TARGET_68040
)
return
"add%.w %2,%0"
;
else
return
MOTOROLA
"lea (%c2,%0),%0"
:
"lea %0@(%c2),%0"
;
}
}
return
"add%.l %2,%0"
;
}
</s>

Output assembler code to perform a 32 bit 3 operand add .


Output a dbCC ; jCC sequence . Note we do not handle the floating point version of this sequence ( Fdbcc ) . We also do not handle alternative conditions when CC_NO_OVERFLOW is set . It is assumed that valid_dbcc_comparison_p and flags_in_68881 will kick those out before we get here .


<s>
const
char
*
output_move_const_into_data_reg
(
rtx
*
operands
)
{
int
i
;
i
=
INTVAL
(
operands
[
1
]
)
;
switch
(
const_method
(
operands
[
1
]
)
)
{
case
MVZ
:
return
"mvsw %1,%0"
;
case
MVS
:
return
"mvzw %1,%0"
;
case
MOVQ
:
return
"moveq %1,%0"
;
case
NOTB
:
CC_STATUS_INIT
;
operands
[
1
]
=
GEN_INT
(
i
^
0xff
)
;
return
"moveq %1,%0\n\tnot%.b %0"
;
case
NOTW
:
CC_STATUS_INIT
;
operands
[
1
]
=
GEN_INT
(
i
^
0xffff
)
;
return
"moveq %1,%0\n\tnot%.w %0"
;
case
NEGW
:
CC_STATUS_INIT
;
return
"moveq #-128,%0\n\tneg%.w %0"
;
case
SWAP
:
{
unsigned
u
=
i
;
operands
[
1
]
=
GEN_INT
(
(
u
<<
16
)
|
(
u
>>
16
)
)
;
return
"moveq %1,%0\n\tswap %0"
;
}
case
MOVL
:
return
"move%.l %1,%0"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an instruction to move CONST_INT OPERANDS [ 1 ] into data register OPERANDS [ 0 ] .


<s>
const
char
*
output_move_simode_const
(
rtx
*
operands
)
{
if
(
operands
[
1
]
==
const0_rtx
&&
(
DATA_REG_P
(
operands
[
0
]
)
||
GET_CODE
(
operands
[
0
]
)
==
MEM
)
&&
(
(
TARGET_68020
||
TARGET_COLDFIRE
)
||
!
(
GET_CODE
(
operands
[
0
]
)
==
MEM
&&
MEM_VOLATILE_P
(
operands
[
0
]
)
)
)
)
return
"clr%.l %0"
;
else
if
(
(
GET_MODE
(
operands
[
0
]
)
==
SImode
)
&&
valid_mov3q_const
(
operands
[
1
]
)
)
return
"mov3q%.l %1,%0"
;
else
if
(
operands
[
1
]
==
const0_rtx
&&
ADDRESS_REG_P
(
operands
[
0
]
)
)
return
"sub%.l %0,%0"
;
else
if
(
DATA_REG_P
(
operands
[
0
]
)
)
return
output_move_const_into_data_reg
(
operands
)
;
else
if
(
ADDRESS_REG_P
(
operands
[
0
]
)
&&
INTVAL
(
operands
[
1
]
)
<
0x8000
&&
INTVAL
(
operands
[
1
]
)
>=
0x8000
)
{
if
(
valid_mov3q_const
(
operands
[
1
]
)
)
return
"mov3q%.l %1,%0"
;
return
"move%.w %1,%0"
;
}
else
if
(
GET_CODE
(
operands
[
0
]
)
==
MEM
&&
GET_CODE
(
XEXP
(
operands
[
0
]
,
0
)
)
==
PRE_DEC
&&
REGNO
(
XEXP
(
XEXP
(
operands
[
0
]
,
0
)
,
0
)
)
==
STACK_POINTER_REGNUM
&&
INTVAL
(
operands
[
1
]
)
<
0x8000
&&
INTVAL
(
operands
[
1
]
)
>=
0x8000
)
{
if
(
valid_mov3q_const
(
operands
[
1
]
)
)
return
"mov3q%.l %1,%-"
;
return
"pea %a1"
;
}
return
"move%.l %1,%0"
;
}
</s>

Return an instruction to move CONST_INT OPERANDS [ 1 ] into OPERANDS [ 0 ] . I is the value of OPERANDS [ 1 ] .


"cannot specify both -msep-data and -mid-shared-library"

"-fPIC is not currently supported on the 68000 or 68010"


<s> void print_operand ( FILE * file , rtx op , int letter ) { if ( letter == '.' ) { if ( MOTOROLA ) fprintf ( file , "." ) ; } else if ( letter == '#' ) asm_fprintf ( file , "%I" ) ; else if ( letter == '-' ) asm_fprintf ( file , MOTOROLA ? "-(%Rsp)" : "%Rsp@-" ) ; else if ( letter == '+' ) asm_fprintf ( file , MOTOROLA ? "(%Rsp)+" : "%Rsp@+" ) ; else if ( letter == '@' ) asm_fprintf ( file , MOTOROLA ? "(%Rsp)" : "%Rsp@" ) ; else if ( letter == '!' ) asm_fprintf ( file , "%Rfpcr" ) ; else if ( letter == '$' ) { if ( TARGET_68040_ONLY ) fprintf ( file , "s" ) ; } else if ( letter == '&' ) { if ( TARGET_68040_ONLY ) fprintf ( file , "d" ) ; } else if ( letter == '/' ) asm_fprintf ( file , "%R" ) ; else if ( letter == 'o' ) { gcc_assert ( GET_CODE ( op ) == MEM && GET_CODE ( XEXP ( op , 0 ) ) == SYMBOL_REF && TARGET_PCREL ) ; output_addr_const ( file , XEXP ( op , 0 ) ) ; } else if ( GET_CODE ( op ) == REG ) { if ( letter == 'R' ) fputs ( M68K_REGNAME ( REGNO ( op ) + 1 ) , file ) ; else fputs ( M68K_REGNAME ( REGNO ( op ) ) , file ) ; } else if ( GET_CODE ( op ) == MEM ) { output_address ( XEXP ( op , 0 ) ) ; if ( letter == 'd' && ! TARGET_68020 && CONSTANT_ADDRESS_P ( XEXP ( op , 0 ) ) && ! ( GET_CODE ( XEXP ( op , 0 ) ) == CONST_INT && INTVAL ( XEXP ( op , 0 ) ) < 0x8000 && INTVAL ( XEXP ( op , 0 ) ) >= - 0x8000 ) ) fprintf ( file , MOTOROLA ? ".l" : ":l" ) ; } else if ( GET_CODE ( op ) == CONST_DOUBLE && GET_MODE ( op ) == SFmode ) { REAL_VALUE_TYPE r ; REAL_VALUE_FROM_CONST_DOUBLE ( r , op ) ; ASM_OUTPUT_FLOAT_OPERAND ( letter , file , r ) ; } else if ( GET_CODE ( op ) == CONST_DOUBLE && GET_MODE ( op ) == XFmode ) { REAL_VALUE_TYPE r ; REAL_VALUE_FROM_CONST_DOUBLE ( r , op ) ; ASM_OUTPUT_LONG_DOUBLE_OPERAND ( file , r ) ; } else if ( GET_CODE ( op ) == CONST_DOUBLE && GET_MODE ( op ) == DFmode ) { REAL_VALUE_TYPE r ; REAL_VALUE_FROM_CONST_DOUBLE ( r , op ) ; ASM_OUTPUT_DOUBLE_OPERAND ( file , r ) ; } else { asm_fprintf ( file , "%I" ) ; if ( TARGET_PCREL && ( GET_CODE ( op ) == SYMBOL_REF || GET_CODE ( op ) == CONST ) ) print_operand_address ( file , op ) ; else output_addr_const ( file , op ) ; } } </s>

Use S for SI regsUse B & T for parts of DI regs X - stack pointer name Registers Q - byte sized register name U - high byte of word register V - low byte of word register H - word register name I - next word register name S & B - long register name T - next long register name D - quad register name P - register name in size of pointer Integers O - log two of value P - inverted log two H - bottom 16 bits I - top 16 bits N - negative B - high 32 bits of 32bit number . default : value Memory I - adjusted upwards by two T - adjusted upwards by four default : value Address H - low 16 bits I - high 16 bits A - as long constant S - as A but with # default : error Misc C - conditional name D - reverse conditional name F - clear v flag if necessary


<s> bool strict_low_part_peephole_ok ( enum machine_mode mode , rtx first_insn , rtx target ) { rtx p ; p = prev_nonnote_insn ( first_insn ) ; while ( p ) { if ( GET_CODE ( p ) != INSN ) return false ; if ( reg_set_p ( target , p ) ) { rtx set = single_set ( p ) ; rtx dest ; if ( ! set ) return false ; dest = SET_DEST ( set ) ; if ( rtx_equal_p ( dest , target ) && SET_SRC ( set ) == const0_rtx ) return true ; else if ( GET_CODE ( dest ) == STRICT_LOW_PART && GET_CODE ( XEXP ( dest , 0 ) ) == REG && REGNO ( XEXP ( dest , 0 ) ) == REGNO ( target ) && ( GET_MODE_SIZE ( GET_MODE ( XEXP ( dest , 0 ) ) ) <= GET_MODE_SIZE ( mode ) ) ) ; else return false ; } p = prev_nonnote_insn ( p ) ; } return false ; } </s>

Check for cases where a clr insns can be omitted from code using strict_low_part sets . For example , the second clrl here is not needed : clrl d0 ; movw a0 @ + , d0 ; use d0 ; clrl d0 ; movw a0 @ + ; use d0 ; ... MODE is the mode of this STRICT_LOW_PART set . FIRST_INSN is the clear insn we are checking for redundancy . TARGET is the register set by the clear insn .


<s> bool use_return_insn ( void ) { if ( ! reload_completed || frame_pointer_needed || get_frame_size ( ) != 0 ) return false ; m68k_compute_frame_layout ( ) ; return current_frame . reg_no ? false : true ; } </s>

Return true if this function 's epilogue can be output as RTL .


<s> int valid_dbcc_comparison_p_2 ( rtx x , enum machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( x ) ) { case EQ : case NE : case GTU : case LTU : case GEU : case LEU : return 1 ; case GT : case LT : case GE : case LE : return ! ( cc_prev_status . flags & CC_NO_OVERFLOW ) ; default : return 0 ; } } </s>

Return true if X is a valid comparison operator for the dbcc instruction . Note it rejects floating point comparison operators . ( In the future we could use Fdbcc ) . It also rejects some comparisons when CC_NO_OVERFLOW is set .


<s> int valid_mov3q_const ( rtx constant ) { int i ; if ( TARGET_CFV4 && GET_CODE ( constant ) == CONST_INT ) { i = INTVAL ( constant ) ; if ( ( i == - 1 ) || ( i >= 1 && i <= 7 ) ) return 1 ; } return 0 ; } </s>

Return 1 if 'constant ' can be represented by mov3q on a ColdFire V4 core .


<s> static void emit_reg_adjust ( rtx reg1 , int n ) { rtx reg2 ; gcc_assert ( GET_MODE ( reg1 ) == SImode && - 12 <= n && n != 0 && n <= 12 ) ; reg1 = copy_rtx ( reg1 ) ; reg2 = copy_rtx ( reg1 ) ; if ( n < 0 ) emit_insn ( gen_subsi3 ( reg1 , reg2 , GEN_INT ( - n ) ) ) ; else if ( n > 0 ) emit_insn ( gen_addsi3 ( reg1 , reg2 , GEN_INT ( n ) ) ) ; else gcc_unreachable ( ) ; } </s>


<s> int floating_exact_log2 ( rtx x ) { REAL_VALUE_TYPE r , r1 ; int exp ; REAL_VALUE_FROM_CONST_DOUBLE ( r , x ) ; if ( REAL_VALUES_LESS ( r , dconst1 ) ) return 0 ; exp = real_exponent ( & r ) ; real_2expN ( & r1 , exp , DFmode ) ; if ( REAL_VALUES_EQUAL ( r1 , r ) ) return exp ; return 0 ; } </s>

If X is a floating-point constant , return the logarithm of X base 2 , or 0 if X is not a power of 2 .


<s> static rtx m68k_call_m68k_read_tp ( void ) { rtx a0 ; rtx eqv ; rtx_insn * insns ; rtx dest ; start_sequence ( ) ; m68k_libcall_value_in_a0_p = true ; a0 = emit_library_call_value ( m68k_get_m68k_read_tp ( ) , NULL_RTX , LCT_PURE , Pmode , 0 ) ; m68k_libcall_value_in_a0_p = false ; insns = get_insns ( ) ; end_sequence ( ) ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const1_rtx ) , UNSPEC_RELOC32 ) ; gcc_assert ( can_create_pseudo_p ( ) ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , a0 , eqv ) ; return dest ; } </s>

Emit instruction sequence that calls __m68k_read_tp . A pseudo register with result of __m68k_read_tp call is returned .


<s> static rtx m68k_call_tls_get_addr ( rtx x , rtx eqv , enum m68k_reloc reloc ) { rtx a0 ; rtx_insn * insns ; rtx dest ; start_sequence ( ) ; x = m68k_wrap_symbol ( x , reloc , m68k_get_gp ( ) , NULL_RTX ) ; m68k_libcall_value_in_a0_p = true ; a0 = emit_library_call_value ( m68k_get_tls_get_addr ( ) , NULL_RTX , LCT_PURE , Pmode , 1 , x , Pmode ) ; m68k_libcall_value_in_a0_p = false ; insns = get_insns ( ) ; end_sequence ( ) ; gcc_assert ( can_create_pseudo_p ( ) ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , a0 , eqv ) ; return dest ; } </s>

Emit instruction sequence that calls __tls_get_addr . X is the TLS symbol we are referencing and RELOC is the symbol type to use ( either TLSGD or TLSLDM ) . EQV is the REG_EQUAL note for the sequence emitted . A pseudo register with result of __tls_get_addr call is returned .


<s> static void m68k_conditional_register_usage ( void ) { int i ; HARD_REG_SET x ; if ( ! TARGET_HARD_FLOAT ) { COPY_HARD_REG_SET ( x , reg_class_contents [ ( int ) FP_REGS ] ) ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( TEST_HARD_REG_BIT ( x , i ) ) fixed_regs [ i ] = call_used_regs [ i ] = 1 ; } if ( flag_pic ) fixed_regs [ PIC_REG ] = call_used_regs [ PIC_REG ] = 1 ; } </s>

Make sure everything 's fine if we * do n't * have a given processor . This assumes that putting a register in fixed_regs will keep the compiler 's mitts completely off it . We do n't bother to zero it out of register classes .


<s> static rtx_insn * m68k_emit_movem ( rtx base , HOST_WIDE_INT offset , unsigned int count , unsigned int regno , unsigned int mask , bool store_p , bool adjust_stack_p ) { int i ; rtx body , addr , src , operands [ 2 ] ; machine_mode mode ; body = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( adjust_stack_p + count ) ) ; mode = reg_raw_mode [ regno ] ; i = 0 ; if ( adjust_stack_p ) { src = plus_constant ( Pmode , base , ( count * GET_MODE_SIZE ( mode ) * ( HOST_WIDE_INT ) ( store_p ? - 1 : 1 ) ) ) ; XVECEXP ( body , 0 , i ++ ) = gen_rtx_SET ( VOIDmode , base , src ) ; } for ( ; mask != 0 ; mask >>= 1 , regno ++ ) if ( mask & 1 ) { addr = plus_constant ( Pmode , base , offset ) ; operands [ ! store_p ] = gen_frame_mem ( mode , addr ) ; operands [ store_p ] = gen_rtx_REG ( mode , regno ) ; XVECEXP ( body , 0 , i ++ ) = gen_rtx_SET ( VOIDmode , operands [ 0 ] , operands [ 1 ] ) ; offset += GET_MODE_SIZE ( mode ) ; } gcc_assert ( i == XVECLEN ( body , 0 ) ) ; return emit_insn ( body ) ; } </s>

Emit RTL for a MOVEM or FMOVEM instruction . BASE + OFFSET represents the lowest memory address . COUNT is the number of registers to be moved , with register REGNO + I being moved if bit I of MASK is set . STORE_P specifies the direction of the move and ADJUST_STACK_P says whether or not this is pre-decrement ( if STORE_P ) or post-increment ( if ! STORE_P ) operation .


<s> static rtx m68k_function_arg ( cumulative_args_t cum ATTRIBUTE_UNUSED , machine_mode mode ATTRIBUTE_UNUSED , const_tree type ATTRIBUTE_UNUSED , bool named ATTRIBUTE_UNUSED ) { return NULL_RTX ; } </s>

On the m68k all args are always pushed .


<s> rtx m68k_function_value ( const_tree valtype , const_tree func ATTRIBUTE_UNUSED ) { machine_mode mode ; mode = TYPE_MODE ( valtype ) ; switch ( mode ) { case SFmode : case DFmode : case XFmode : if ( TARGET_68881 ) return gen_rtx_REG ( mode , FP0_REG ) ; break ; default : break ; } if ( func && POINTER_TYPE_P ( TREE_TYPE ( TREE_TYPE ( func ) ) ) ) return gen_rtx_PARALLEL ( mode , gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , A0_REG ) , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , D0_REG ) , const0_rtx ) ) ) ; else if ( POINTER_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , A0_REG ) ; else return gen_rtx_REG ( mode , D0_REG ) ; } </s>

Location in which function value is returned . NOTE : Due to differences in ABIs , do n't call this function directly , use FUNCTION_VALUE instead .


<s> static const char * m68k_get_reloc_decoration ( enum m68k_reloc reloc ) { gcc_assert ( MOTOROLA || reloc == RELOC_GOT ) ; switch ( reloc ) { case RELOC_GOT : if ( MOTOROLA ) { if ( flag_pic == 1 && TARGET_68020 ) return "@GOT.w" ; else return "@GOT" ; } else { if ( TARGET_68020 ) { switch ( flag_pic ) { case 1 : return ":w" ; case 2 : return ":l" ; default : return "" ; } } } case RELOC_TLSGD : return "@TLSGD" ; case RELOC_TLSLDM : return "@TLSLDM" ; case RELOC_TLSLDO : return "@TLSLDO" ; case RELOC_TLSIE : return "@TLSIE" ; case RELOC_TLSLE : return "@TLSLE" ; default : gcc_unreachable ( ) ; } } </s>

Return string for TLS relocation RELOC .


<s> rtx m68k_libcall_value ( machine_mode mode ) { switch ( mode ) { case SFmode : case DFmode : case XFmode : if ( TARGET_68881 ) return gen_rtx_REG ( mode , FP0_REG ) ; break ; default : break ; } return gen_rtx_REG ( mode , m68k_libcall_value_in_a0_p ? A0_REG : D0_REG ) ; } </s>

Return floating point values in a 68881 register . This makes 68881 code a little bit faster . It also makes -msoft-float code incompatible with hard-float code , so people have to be careful not to mix the two . For ColdFire it was decided the ABI incompatibility is undesirable . If there is need for a hard-float ABI it is probably worth doing it properly and also passing function arguments in FP registers .


<s> bool m68k_regno_mode_ok ( int regno , machine_mode mode ) { if ( DATA_REGNO_P ( regno ) ) { if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 8 ) return true ; } else if ( ADDRESS_REGNO_P ( regno ) ) { if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 16 ) return true ; } else if ( FP_REGNO_P ( regno ) ) { if ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) && GET_MODE_UNIT_SIZE ( mode ) <= TARGET_FP_REG_SIZE ) return true ; } return false ; } </s>

Value is true if hard register REGNO can hold a value of machine-mode MODE . On the 68000 , we let the cpu registers can hold any mode , but restrict the 68881 registers to floating-point modes .


<s> static int m68k_return_pops_args ( tree fundecl , tree funtype , int size ) { return ( ( TARGET_RTD && ( ! fundecl || TREE_CODE ( fundecl ) != IDENTIFIER_NODE ) && ( ! stdarg_p ( funtype ) ) ) ? size : 0 ) ; } </s>

On the 68000 , the RTS insn can not pop anything . On the 68010 , the RTD insn may be used to pop them if the number of args is fixed , but if the number is variable then the caller must pop them all . RTD ca n't be used for library calls now because the library is compiled with the Unix compiler . Use of RTD is a selectable option , since it is incompatible with standard Unix calling sequences . If the option is not selected , the caller must always pop the args .


<s> static bool m68k_save_reg ( unsigned int regno , bool interrupt_handler ) { if ( flag_pic && regno == PIC_REG ) { if ( crtl -> saves_all_registers ) return true ; if ( crtl -> uses_pic_offset_table ) return true ; if ( crtl -> uses_const_pool ) return true ; } if ( crtl -> calls_eh_return ) { unsigned int i ; for ( i = 0 ; ; i ++ ) { unsigned int test = EH_RETURN_DATA_REGNO ( i ) ; if ( test == INVALID_REGNUM ) break ; if ( test == regno ) return true ; } } if ( fixed_regs [ regno ] ) return false ; if ( regno == FRAME_POINTER_REGNUM && frame_pointer_needed ) return false ; if ( interrupt_handler ) { if ( df_regs_ever_live_p ( regno ) ) return true ; if ( ! crtl -> is_leaf && call_used_regs [ regno ] ) return true ; } if ( ! df_regs_ever_live_p ( regno ) ) return false ; return ! call_used_regs [ regno ] ; } </s>

Refer to the array ` regs_ever_live ' to determine which registers to save ; ` regs_ever_live [ I ] ' is nonzero if register number I is ever used in the function . This function is responsible for knowing which registers should not be saved even if used . Return true if we need to save REGNO .


<s> static int m68k_sched_adjust_cost ( rtx_insn * insn , rtx link ATTRIBUTE_UNUSED , rtx_insn * def_insn , int cost ) { int delay ; if ( recog_memoized ( def_insn ) < 0 || recog_memoized ( insn ) < 0 ) return cost ; if ( sched_cfv4_bypass_data . scale == 1 ) { gcc_assert ( sched_cfv4_bypass_data . pro == def_insn && sched_cfv4_bypass_data . con == insn ) ; if ( cost < 3 ) cost = 3 ; sched_cfv4_bypass_data . pro = NULL ; sched_cfv4_bypass_data . con = NULL ; sched_cfv4_bypass_data . scale = 0 ; } else gcc_assert ( sched_cfv4_bypass_data . pro == NULL && sched_cfv4_bypass_data . con == NULL && sched_cfv4_bypass_data . scale == 0 ) ; delay = min_insn_conflict_delay ( sched_adjust_cost_state , def_insn , insn ) ; if ( delay > cost ) cost = delay ; return cost ; } </s>

Implement adjust_cost scheduler hook . Return adjusted COST of dependency LINK between DEF_INSN and INSN .


<s>
void
output_dbcc_and_branch
(
rtx
*
operands
)
{
switch
(
GET_CODE
(
operands
[
3
]
)
)
{
case
EQ
:
output_asm_insn
(
"dbeq %0,%l1\n\tjeq %l2"
,
operands
)
;
break
;
case
NE
:
output_asm_insn
(
"dbne %0,%l1\n\tjne %l2"
,
operands
)
;
break
;
case
GT
:
output_asm_insn
(
"dbgt %0,%l1\n\tjgt %l2"
,
operands
)
;
break
;
case
GTU
:
output_asm_insn
(
"dbhi %0,%l1\n\tjhi %l2"
,
operands
)
;
break
;
case
LT
:
output_asm_insn
(
"dblt %0,%l1\n\tjlt %l2"
,
operands
)
;
break
;
case
LTU
:
output_asm_insn
(
"dbcs %0,%l1\n\tjcs %l2"
,
operands
)
;
break
;
case
GE
:
output_asm_insn
(
"dbge %0,%l1\n\tjge %l2"
,
operands
)
;
break
;
case
GEU
:
output_asm_insn
(
"dbcc %0,%l1\n\tjcc %l2"
,
operands
)
;
break
;
case
LE
:
output_asm_insn
(
"dble %0,%l1\n\tjle %l2"
,
operands
)
;
break
;
case
LEU
:
output_asm_insn
(
"dbls %0,%l1\n\tjls %l2"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
switch
(
GET_MODE
(
operands
[
0
]
)
)
{
case
SImode
:
output_asm_insn
(
"clr%.w %0\n\tsubq%.l #1,%0\n\tjpl %l1"
,
operands
)
;
break
;
case
HImode
:
break
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Output a dbCC ; jCC sequence . Note we do not handle the floating point version of this sequence ( Fdbcc ) . We also do not handle alternative conditions when CC_NO_OVERFLOW is set . It is assumed that valid_dbcc_comparison_p and flags_in_68881 will kick those out before we get here .


<s>
static
void
output_reg_adjust
(
rtx
reg
,
int
n
)
{
const
char
*
s
;
gcc_assert
(
GET_MODE
(
reg
)
==
SImode
&&
12
<=
n
&&
n
!=
0
&&
n
<=
12
)
;
switch
(
n
)
{
case
12
:
s
=
"add%.l #12,%0"
;
break
;
case
8
:
s
=
"addq%.l #8,%0"
;
break
;
case
4
:
s
=
"addq%.l #4,%0"
;
break
;
case
12
:
s
=
"sub%.l #12,%0"
;
break
;
case
8
:
s
=
"subq%.l #8,%0"
;
break
;
case
4
:
s
=
"subq%.l #4,%0"
;
break
;
default
:
gcc_unreachable
(
)
;
s
=
;
}
output_asm_insn
(
s
,
&
reg
)
;
}
</s>

Output assembler code to adjust REG by N .


<s> static enum attr_op_type sched_attr_op_type ( rtx_insn * insn , bool opx_p , bool address_p ) { rtx op ; op = sched_get_operand ( insn , opx_p ) ; if ( op == NULL ) { gcc_assert ( ! reload_completed ) ; return OP_TYPE_RN ; } if ( address_p ) return sched_address_type ( QImode , op ) ; if ( memory_operand ( op , VOIDmode ) ) return sched_address_type ( GET_MODE ( op ) , XEXP ( op , 0 ) ) ; if ( register_operand ( op , VOIDmode ) ) { if ( ( ! reload_completed && FLOAT_MODE_P ( GET_MODE ( op ) ) ) || ( reload_completed && FP_REG_P ( op ) ) ) return OP_TYPE_FPN ; return OP_TYPE_RN ; } if ( GET_CODE ( op ) == CONST_INT ) { int ival ; ival = INTVAL ( op ) ; switch ( get_attr_type ( insn ) ) { case TYPE_ALUQ_L : if ( IN_RANGE ( ival , 1 , 8 ) || IN_RANGE ( ival , - 8 , - 1 ) ) return OP_TYPE_IMM_Q ; gcc_assert ( ! reload_completed ) ; break ; case TYPE_MOVEQ_L : if ( USE_MOVQ ( ival ) ) return OP_TYPE_IMM_Q ; gcc_assert ( ! reload_completed ) ; break ; case TYPE_MOV3Q_L : if ( valid_mov3q_const ( ival ) ) return OP_TYPE_IMM_Q ; gcc_assert ( ! reload_completed ) ; break ; default : break ; } if ( IN_RANGE ( ival , - 0x8000 , 0x7fff ) ) return OP_TYPE_IMM_W ; return OP_TYPE_IMM_L ; } if ( GET_CODE ( op ) == CONST_DOUBLE ) { switch ( GET_MODE ( op ) ) { case SFmode : return OP_TYPE_IMM_W ; case VOIDmode : case DFmode : return OP_TYPE_IMM_L ; default : gcc_unreachable ( ) ; } } if ( GET_CODE ( op ) == CONST || symbolic_operand ( op , VOIDmode ) || LABEL_P ( op ) ) { switch ( GET_MODE ( op ) ) { case QImode : return OP_TYPE_IMM_Q ; case HImode : return OP_TYPE_IMM_W ; case SImode : return OP_TYPE_IMM_L ; default : if ( symbolic_operand ( m68k_unwrap_symbol ( op , false ) , VOIDmode ) ) return OP_TYPE_IMM_W ; return OP_TYPE_IMM_L ; } } gcc_assert ( ! reload_completed ) ; if ( FLOAT_MODE_P ( GET_MODE ( op ) ) ) return OP_TYPE_FPN ; return OP_TYPE_RN ; } </s>

Return type of INSN 's operand X ( if OPX_P ) or operand Y ( if ! OPX_P ) . If ADDRESS_P is true , return type of memory location operand refers to .


<s> int valid_dbcc_comparison_p_2 ( rtx x , machine_mode mode ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( x ) ) { case EQ : case NE : case GTU : case LTU : case GEU : case LEU : return 1 ; case GT : case LT : case GE : case LE : return ! ( cc_prev_status . flags & CC_NO_OVERFLOW ) ; default : return 0 ; } } </s>

Return true if X is a valid comparison operator for the dbcc instruction . Note it rejects floating point comparison operators . ( In the future we could use Fdbcc ) . It also rejects some comparisons when CC_NO_OVERFLOW is set .


<s>
void
output_dbcc_and_branch
(
rtx
*
operands
)
{
switch
(
GET_CODE
(
operands
[
3
]
)
)
{
case
EQ
:
output_asm_insn
(
"dbeq %0,%l1\n\tjeq %l2"
,
operands
)
;
break
;
case
NE
:
output_asm_insn
(
"dbne %0,%l1\n\tjne %l2"
,
operands
)
;
break
;
case
GT
:
output_asm_insn
(
"dbgt %0,%l1\n\tjgt %l2"
,
operands
)
;
break
;
case
GTU
:
output_asm_insn
(
"dbhi %0,%l1\n\tjhi %l2"
,
operands
)
;
break
;
case
LT
:
output_asm_insn
(
"dblt %0,%l1\n\tjlt %l2"
,
operands
)
;
break
;
case
LTU
:
output_asm_insn
(
"dbcs %0,%l1\n\tjcs %l2"
,
operands
)
;
break
;
case
GE
:
output_asm_insn
(
"dbge %0,%l1\n\tjge %l2"
,
operands
)
;
break
;
case
GEU
:
output_asm_insn
(
"dbcc %0,%l1\n\tjcc %l2"
,
operands
)
;
break
;
case
LE
:
output_asm_insn
(
"dble %0,%l1\n\tjle %l2"
,
operands
)
;
break
;
case
LEU
:
output_asm_insn
(
"dbls %0,%l1\n\tjls %l2"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
switch
(
GET_MODE
(
operands
[
0
]
)
)
{
case
E_SImode
:
output_asm_insn
(
"clr%.w %0\n\tsubq%.l #1,%0\n\tjpl %l1"
,
operands
)
;
break
;
case
E_HImode
:
break
;
default
:
gcc_unreachable
(
)
;
}
}
</s>


<s> static int const_int_cost ( HOST_WIDE_INT i ) { switch ( m68k_const_method ( i ) ) { case MOVQ : return 0 ; case MVZ : case MVS : case NOTB : case NOTW : case NEGW : case SWAP : return 1 ; case MOVL : return 2 ; default : gcc_unreachable ( ) ; } } </s>

Return the cost of moving constant I into a data register .


<s> static rtx copy_operand ( rtx op , machine_mode mode ) { if ( GET_MODE ( op ) != VOIDmode ) { if ( REG_P ( op ) ) op = gen_rtx_REG ( mode , REGNO ( op ) ) ; else { op = copy_rtx ( op ) ; PUT_MODE ( op , mode ) ; } } return op ; } </s>


<s> static void emit_movsi ( rtx operands [ 2 ] ) { operands [ 0 ] = copy_operand ( operands [ 0 ] , SImode ) ; operands [ 1 ] = copy_operand ( operands [ 1 ] , SImode ) ; emit_insn ( gen_movsi ( operands [ 0 ] , operands [ 1 ] ) ) ; } </s>

Emit rtl code for moving operands [ 1 ] into operands [ 0 ] as a fullword .


<s> static void emit_reg_adjust ( rtx reg1 , int n ) { rtx reg2 ; gcc_assert ( GET_MODE ( reg1 ) == SImode && n >= - 12 && n != 0 && n <= 12 ) ; reg1 = copy_rtx ( reg1 ) ; reg2 = copy_rtx ( reg1 ) ; if ( n < 0 ) emit_insn ( gen_subsi3 ( reg1 , reg2 , GEN_INT ( - n ) ) ) ; else if ( n > 0 ) emit_insn ( gen_addsi3 ( reg1 , reg2 , GEN_INT ( n ) ) ) ; else gcc_unreachable ( ) ; } </s>


<s> static rtx find_addr_reg ( rtx addr ) { while ( GET_CODE ( addr ) == PLUS ) { if ( GET_CODE ( XEXP ( addr , 0 ) ) == REG ) addr = XEXP ( addr , 0 ) ; else if ( GET_CODE ( XEXP ( addr , 1 ) ) == REG ) addr = XEXP ( addr , 1 ) ; else if ( CONSTANT_P ( XEXP ( addr , 0 ) ) ) addr = XEXP ( addr , 1 ) ; else if ( CONSTANT_P ( XEXP ( addr , 1 ) ) ) addr = XEXP ( addr , 0 ) ; else gcc_unreachable ( ) ; } gcc_assert ( GET_CODE ( addr ) == REG ) ; return addr ; } </s>

Return a REG that occurs in ADDR with coefficient 1 . ADDR can be effectively incremented by incrementing REG . r0 is special and we must not select it as an address register by this routine since our caller will try to increment the returned register via an `` la '' instruction .


<s> int floating_exact_log2 ( rtx x ) { const REAL_VALUE_TYPE * r ; REAL_VALUE_TYPE r1 ; int exp ; r = CONST_DOUBLE_REAL_VALUE ( x ) ; if ( real_less ( r , & dconst1 ) ) return 0 ; exp = real_exponent ( r ) ; real_2expN ( & r1 , exp , DFmode ) ; if ( real_equal ( & r1 , r ) ) return exp ; return 0 ; } </s>

If X is a floating-point constant , return the logarithm of X base 2 , or 0 if X is not a power of 2 .


<s> static rtx force_mode ( machine_mode mode , rtx orig ) { if ( mode == GET_MODE ( orig ) ) return orig ; if ( REGNO ( orig ) >= FIRST_PSEUDO_REGISTER ) abort ( ) ; return gen_rtx_REG ( mode , REGNO ( orig ) ) ; } </s>

Ensure mode of ORIG , a REG rtx , is MODE . Returns either ORIG or a new rtx with the correct mode .


<s> static int fp_reg_operand ( rtx op , machine_mode mode ATTRIBUTE_UNUSED ) { return reg_renumber && FP_REG_P ( op ) ; } </s>

Return truth value of whether OP can be used as a float register operand . Reject ( SUBREG : SF ( REG : SI ) ) ) )


<s> static void handle_flags_for_move ( rtx * operands ) { flags_compare_op0 = flags_compare_op1 = NULL_RTX ; if ( ! ADDRESS_REG_P ( operands [ 0 ] ) ) { flags_valid = FLAGS_VALID_MOVE ; flags_operand1 = side_effects_p ( operands [ 0 ] ) ? NULL_RTX : operands [ 0 ] ; if ( side_effects_p ( operands [ 1 ] ) || modified_in_p ( operands [ 1 ] , current_output_insn ) ) flags_operand2 = NULL_RTX ; else flags_operand2 = operands [ 1 ] ; return ; } if ( flags_operand1 != NULL_RTX && modified_in_p ( flags_operand1 , current_output_insn ) ) flags_operand1 = NULL_RTX ; if ( flags_operand2 != NULL_RTX && modified_in_p ( flags_operand2 , current_output_insn ) ) flags_operand2 = NULL_RTX ; } </s>

Update flags for a move operation with OPERANDS . Called for move operations where attr_flags_valid returns `` set '' .


<s> void init_68881_table ( void ) { int i ; REAL_VALUE_TYPE r ; machine_mode mode ; mode = SFmode ; for ( i = 0 ; i < 7 ; i ++ ) { if ( i == 6 ) mode = DFmode ; r = REAL_VALUE_ATOF ( strings_68881 [ i ] , mode ) ; values_68881 [ i ] = r ; } inited_68881_table = 1 ; } </s>

Set up values_68881 array by converting the decimal values strings_68881 to binary .


<s> rtx legitimize_pic_address ( rtx orig , machine_mode mode ATTRIBUTE_UNUSED , rtx reg ) { rtx pic_ref = orig ; if ( GET_CODE ( orig ) == SYMBOL_REF || GET_CODE ( orig ) == LABEL_REF ) { gcc_assert ( reg ) ; pic_ref = m68k_wrap_symbol_into_got_ref ( orig , RELOC_GOT , reg ) ; pic_ref = m68k_move_to_reg ( pic_ref , orig , reg ) ; } else if ( GET_CODE ( orig ) == CONST ) { rtx base ; if ( m68k_unwrap_symbol ( orig , true ) != orig ) return orig ; gcc_assert ( reg ) ; gcc_assert ( GET_CODE ( XEXP ( orig , 0 ) ) == PLUS ) ; base = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 0 ) , Pmode , reg ) ; orig = legitimize_pic_address ( XEXP ( XEXP ( orig , 0 ) , 1 ) , Pmode , base == reg ? 0 : reg ) ; if ( GET_CODE ( orig ) == CONST_INT ) pic_ref = plus_constant ( Pmode , base , INTVAL ( orig ) ) ; else pic_ref = gen_rtx_PLUS ( Pmode , base , orig ) ; } return pic_ref ; } </s>

Legitimize PIC addresses . If the address is already position-independent , we return ORIG . Newly generated position-independent addresses go into a reg . This is REG if nonzero , otherwise we allocate register ( s ) as necessary .


<s> static void m68k_adjust_decorated_operand ( rtx op ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , op , ALL ) { rtx x = * iter ; if ( m68k_unwrap_symbol ( x , true ) != x ) { rtx plus ; gcc_assert ( GET_CODE ( x ) == CONST ) ; plus = XEXP ( x , 0 ) ; if ( GET_CODE ( plus ) == PLUS || GET_CODE ( plus ) == MINUS ) { rtx unspec ; rtx addend ; unspec = XEXP ( plus , 0 ) ; gcc_assert ( GET_CODE ( unspec ) == UNSPEC ) ; addend = XEXP ( plus , 1 ) ; gcc_assert ( CONST_INT_P ( addend ) ) ; XEXP ( plus , 0 ) = XVECEXP ( unspec , 0 , 0 ) ; XVECEXP ( unspec , 0 , 0 ) = plus ; XEXP ( x , 0 ) = unspec ; } iter . skip_subrtxes ( ) ; } } } </s>

Adjust decorated address operand before outputing assembler for it .


<s> static void m68k_asm_final_postscan_insn ( FILE * , rtx_insn * insn , rtx [ ] , int ) { enum attr_flags_valid v = get_attr_flags_valid ( insn ) ; if ( v == FLAGS_VALID_SET ) return ; flags_compare_op0 = flags_compare_op1 = NULL_RTX ; if ( v == FLAGS_VALID_NO ) { flags_operand1 = flags_operand2 = NULL_RTX ; return ; } else if ( v == FLAGS_VALID_UNCHANGED ) { if ( flags_operand1 != NULL_RTX && modified_in_p ( flags_operand1 , insn ) ) flags_operand1 = NULL_RTX ; if ( flags_operand2 != NULL_RTX && modified_in_p ( flags_operand2 , insn ) ) flags_operand2 = NULL_RTX ; return ; } flags_valid = v ; rtx set = single_set ( insn ) ; rtx dest = SET_DEST ( set ) ; rtx src = SET_SRC ( set ) ; if ( side_effects_p ( dest ) ) dest = NULL_RTX ; switch ( v ) { case FLAGS_VALID_YES : case FLAGS_VALID_NOOV : flags_operand1 = dest ; flags_operand2 = NULL_RTX ; break ; case FLAGS_VALID_MOVE : if ( dest != NULL_RTX && ! FP_REG_P ( dest ) && ( FP_REG_P ( src ) || GET_CODE ( src ) == FIX || FLOAT_MODE_P ( GET_MODE ( dest ) ) ) ) flags_operand1 = flags_operand2 = NULL_RTX ; else { flags_operand1 = dest ; if ( GET_MODE ( src ) != VOIDmode && ! side_effects_p ( src ) && ! modified_in_p ( src , insn ) ) flags_operand2 = src ; else flags_operand2 = NULL_RTX ; } break ; default : gcc_unreachable ( ) ; } return ; } </s>

Process INSN to remember flag operands if possible .


<s> static rtx m68k_call_m68k_read_tp ( void ) { rtx a0 ; rtx eqv ; rtx_insn * insns ; rtx dest ; start_sequence ( ) ; m68k_libcall_value_in_a0_p = true ; a0 = emit_library_call_value ( m68k_get_m68k_read_tp ( ) , NULL_RTX , LCT_PURE , Pmode ) ; m68k_libcall_value_in_a0_p = false ; insns = get_insns ( ) ; end_sequence ( ) ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const1_rtx ) , UNSPEC_RELOC32 ) ; gcc_assert ( can_create_pseudo_p ( ) ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , a0 , eqv ) ; return dest ; } </s>

Emit instruction sequence that calls __m68k_read_tp . A pseudo register with result of __m68k_read_tp call is returned .


<s> static rtx m68k_call_tls_get_addr ( rtx x , rtx eqv , enum m68k_reloc reloc ) { rtx a0 ; rtx_insn * insns ; rtx dest ; start_sequence ( ) ; x = m68k_wrap_symbol ( x , reloc , m68k_get_gp ( ) , NULL_RTX ) ; m68k_libcall_value_in_a0_p = true ; a0 = emit_library_call_value ( m68k_get_tls_get_addr ( ) , NULL_RTX , LCT_PURE , Pmode , x , Pmode ) ; m68k_libcall_value_in_a0_p = false ; insns = get_insns ( ) ; end_sequence ( ) ; gcc_assert ( can_create_pseudo_p ( ) ) ; dest = gen_reg_rtx ( Pmode ) ; emit_libcall_block ( insns , dest , a0 , eqv ) ; return dest ; } </s>

Emit instruction sequence that calls __tls_get_addr . X is the TLS symbol we are referencing and RELOC is the symbol type to use ( either TLSGD or TLSLDM ) . EQV is the REG_EQUAL note for the sequence emitted . A pseudo register with result of __tls_get_addr call is returned .


<s> static bool m68k_cannot_force_const_mem ( machine_mode mode ATTRIBUTE_UNUSED , rtx x ) { return m68k_illegitimate_symbolic_constant_p ( x ) ; } </s>


<s> bool m68k_can_eliminate ( const int from ATTRIBUTE_UNUSED , const int to ) { return ( to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true ) ; } </s>

Worker function for TARGET_CAN_ELIMINATE .


<s> static void m68k_conditional_register_usage ( void ) { int i ; HARD_REG_SET x ; if ( ! TARGET_HARD_FLOAT ) { x = reg_class_contents [ FP_REGS ] ; for ( i = 0 ; i < FIRST_PSEUDO_REGISTER ; i ++ ) if ( TEST_HARD_REG_BIT ( x , i ) ) fixed_regs [ i ] = call_used_regs [ i ] = 1 ; } if ( flag_pic ) fixed_regs [ PIC_REG ] = call_used_regs [ PIC_REG ] = 1 ; } </s>

Make sure everything 's fine if we * do n't * have a given processor . This assumes that putting a register in fixed_regs will keep the compiler 's mitts completely off it . We do n't bother to zero it out of register classes .


<s> M68K_CONST_METHOD m68k_const_method ( HOST_WIDE_INT i ) { unsigned u ; if ( USE_MOVQ ( i ) ) return MOVQ ; if ( ! TARGET_COLDFIRE ) { if ( USE_MOVQ ( i ^ 0xff ) ) return NOTB ; if ( USE_MOVQ ( i ^ 0xffff ) ) return NOTW ; if ( i == - 65408 ) return NEGW ; } u = i ; if ( USE_MOVQ ( ( u >> 16 ) | ( u << 16 ) ) ) return SWAP ; if ( TARGET_ISAB ) { if ( i >= 0 && i <= 65535 ) return MVZ ; if ( i >= - 32768 && i <= 32767 ) return MVS ; } return MOVL ; } </s>

Return the type of move that should be used for integer I .


<s> const char * m68k_cpp_cpu_family ( const char * prefix ) { if ( ! m68k_cpu_entry ) return NULL ; return concat ( "__m" , prefix , "_family_" , m68k_cpu_entry -> family , NULL ) ; } </s>

Generate a macro of the form __mPREFIX_family_NAME , where PREFIX is the given argument and NAME is the name of the representative device for the -mcpu argument 's family . Return NULL if -mcpu was not passed .


<s> const char * m68k_cpp_cpu_ident ( const char * prefix ) { if ( ! m68k_cpu_entry ) return NULL ; return concat ( "__m" , prefix , "_cpu_" , m68k_cpu_entry -> name , NULL ) ; } </s>

Generate a macro of the form __mPREFIX_cpu_NAME , where PREFIX is the given argument and NAME is the argument passed to -mcpu . Return NULL if -mcpu was not passed .


<s> static bool m68k_decompose_index ( rtx x , bool strict_p , struct m68k_address * address ) { int scale ; scale = 1 ; if ( ( TARGET_68020 || TARGET_COLDFIRE ) && GET_CODE ( x ) == MULT && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT && ( INTVAL ( XEXP ( x , 1 ) ) == 2 || INTVAL ( XEXP ( x , 1 ) ) == 4 || ( INTVAL ( XEXP ( x , 1 ) ) == 8 && ( TARGET_COLDFIRE_FPU || ! TARGET_COLDFIRE ) ) ) ) { scale = INTVAL ( XEXP ( x , 1 ) ) ; x = XEXP ( x , 0 ) ; } if ( ! TARGET_COLDFIRE && GET_CODE ( x ) == SIGN_EXTEND && GET_MODE ( XEXP ( x , 0 ) ) == HImode ) x = XEXP ( x , 0 ) ; if ( m68k_legitimate_index_reg_p ( x , strict_p ) ) { address -> scale = scale ; address -> index = x ; return true ; } return false ; } </s>

Return true if X is a legitimate index expression for a ( d8 , An , Xn ) or ( bd , An , Xn ) addressing mode . Fill in the INDEX and SCALE fields of ADDRESS if so . STRICT_P says whether we need strict checking .


<s> static rtx m68k_delegitimize_address ( rtx orig_x ) { rtx x ; struct m68k_address addr ; rtx unspec ; orig_x = delegitimize_mem_from_attrs ( orig_x ) ; x = orig_x ; if ( MEM_P ( x ) ) x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) != PLUS || GET_MODE ( x ) != Pmode ) return orig_x ; if ( ! m68k_decompose_address ( GET_MODE ( x ) , x , false , & addr ) || addr . offset == NULL_RTX || GET_CODE ( addr . offset ) != CONST ) return orig_x ; unspec = XEXP ( addr . offset , 0 ) ; if ( GET_CODE ( unspec ) == PLUS && CONST_INT_P ( XEXP ( unspec , 1 ) ) ) unspec = XEXP ( unspec , 0 ) ; if ( GET_CODE ( unspec ) != UNSPEC || ( XINT ( unspec , 1 ) != UNSPEC_RELOC16 && XINT ( unspec , 1 ) != UNSPEC_RELOC32 ) ) return orig_x ; x = XVECEXP ( unspec , 0 , 0 ) ; gcc_assert ( GET_CODE ( x ) == SYMBOL_REF || GET_CODE ( x ) == LABEL_REF ) ; if ( unspec != XEXP ( addr . offset , 0 ) ) x = gen_rtx_PLUS ( Pmode , x , XEXP ( XEXP ( addr . offset , 0 ) , 1 ) ) ; if ( addr . index ) { rtx idx = addr . index ; if ( addr . scale != 1 ) idx = gen_rtx_MULT ( Pmode , idx , GEN_INT ( addr . scale ) ) ; x = gen_rtx_PLUS ( Pmode , idx , x ) ; } if ( addr . base ) x = gen_rtx_PLUS ( Pmode , addr . base , x ) ; if ( MEM_P ( orig_x ) ) x = replace_equiv_address_nv ( orig_x , x ) ; return x ; } </s>

In the name of slightly smaller debug output , and to cater to general assembler lossage , recognize various UNSPEC sequences and turn them back into a direct symbol reference .


<s> static rtx_insn * m68k_emit_movem ( rtx base , HOST_WIDE_INT offset , unsigned int count , unsigned int regno , unsigned int mask , bool store_p , bool adjust_stack_p ) { int i ; rtx body , addr , src , operands [ 2 ] ; machine_mode mode ; body = gen_rtx_PARALLEL ( VOIDmode , rtvec_alloc ( adjust_stack_p + count ) ) ; mode = reg_raw_mode [ regno ] ; i = 0 ; if ( adjust_stack_p ) { src = plus_constant ( Pmode , base , ( count * GET_MODE_SIZE ( mode ) * ( HOST_WIDE_INT ) ( store_p ? - 1 : 1 ) ) ) ; XVECEXP ( body , 0 , i ++ ) = gen_rtx_SET ( base , src ) ; } for ( ; mask != 0 ; mask >>= 1 , regno ++ ) if ( mask & 1 ) { addr = plus_constant ( Pmode , base , offset ) ; operands [ ! store_p ] = gen_frame_mem ( mode , addr ) ; operands [ store_p ] = gen_rtx_REG ( mode , regno ) ; XVECEXP ( body , 0 , i ++ ) = gen_rtx_SET ( operands [ 0 ] , operands [ 1 ] ) ; offset += GET_MODE_SIZE ( mode ) ; } gcc_assert ( i == XVECLEN ( body , 0 ) ) ; return emit_insn ( body ) ; } </s>

Emit RTL for a MOVEM or FMOVEM instruction . BASE + OFFSET represents the lowest memory address . COUNT is the number of registers to be moved , with register REGNO + I being moved if bit I of MASK is set . STORE_P specifies the direction of the move and ADJUST_STACK_P says whether or not this is pre-decrement ( if STORE_P ) or post-increment ( if ! STORE_P ) operation .


<s> void m68k_emit_move_double ( rtx operands [ 2 ] ) { handle_move_double ( operands , emit_reg_adjust , emit_movsi , emit_movsi ) ; } </s>

Output rtl code to perform a doubleword move insn with operands OPERANDS .


<s> bool m68k_epilogue_uses ( int regno ATTRIBUTE_UNUSED ) { return ( reload_completed && ( m68k_get_function_kind ( current_function_decl ) == m68k_fk_interrupt_handler ) ) ; } </s>

Implements EPILOGUE_USES . All registers are live on exit from an interrupt routine .


"%<-fexcess-precision=16%> is not supported on this target"

Implement TARGET_C_EXCESS_PRECISION . Set the value of FLT_EVAL_METHOD in float.h . When using 68040 fp instructions , we get proper intermediate rounding , otherwise we get extended precision results .


<s> rtx_code m68k_find_flags_value ( rtx op0 , rtx op1 , rtx_code code ) { if ( flags_compare_op0 != NULL_RTX ) { if ( rtx_equal_p ( op0 , flags_compare_op0 ) && rtx_equal_p ( op1 , flags_compare_op1 ) ) return code ; if ( rtx_equal_p ( op0 , flags_compare_op1 ) && rtx_equal_p ( op1 , flags_compare_op0 ) ) return swap_condition ( code ) ; return UNKNOWN ; } machine_mode mode = GET_MODE ( op0 ) ; if ( op1 != CONST0_RTX ( mode ) ) return UNKNOWN ; gcc_assert ( code != LTU && code != GEU ) ; if ( flags_valid == FLAGS_VALID_NOOV && ( code == GT || code == LE ) ) return UNKNOWN ; if ( rtx_equal_p ( flags_operand1 , op0 ) || rtx_equal_p ( flags_operand2 , op0 ) ) return ( FLOAT_MODE_P ( mode ) ? code : code == GE ? PLUS : code == LT ? MINUS : code ) ; if ( code != GE && code != LT ) return UNKNOWN ; if ( mode == SImode && flags_operand1 != NULL_RTX && GET_MODE ( flags_operand1 ) == DImode && REG_P ( flags_operand1 ) && REG_P ( op0 ) && hard_regno_nregs ( REGNO ( flags_operand1 ) , DImode ) == 2 && REGNO ( flags_operand1 ) == REGNO ( op0 ) ) return code == GE ? PLUS : MINUS ; if ( mode == SImode && flags_operand2 != NULL_RTX && GET_MODE ( flags_operand2 ) == DImode && REG_P ( flags_operand2 ) && REG_P ( op0 ) && hard_regno_nregs ( REGNO ( flags_operand2 ) , DImode ) == 2 && REGNO ( flags_operand2 ) == REGNO ( op0 ) ) return code == GE ? PLUS : MINUS ; return UNKNOWN ; } </s>

Return a code other than UNKNOWN if we can elide a CODE comparison of OP0 with OP1 .


<s> static rtx m68k_function_arg ( cumulative_args_t , const function_arg_info & ) { return NULL_RTX ; } </s>

On the m68k all args are always pushed .


<s> rtx m68k_function_value ( const_tree valtype , const_tree func ATTRIBUTE_UNUSED ) { machine_mode mode ; mode = TYPE_MODE ( valtype ) ; switch ( mode ) { case E_SFmode : case E_DFmode : case E_XFmode : if ( TARGET_68881 ) return gen_rtx_REG ( mode , FP0_REG ) ; break ; default : break ; } if ( func && POINTER_TYPE_P ( TREE_TYPE ( TREE_TYPE ( func ) ) ) ) return gen_rtx_PARALLEL ( mode , gen_rtvec ( 2 , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , A0_REG ) , const0_rtx ) , gen_rtx_EXPR_LIST ( VOIDmode , gen_rtx_REG ( mode , D0_REG ) , const0_rtx ) ) ) ; else if ( POINTER_TYPE_P ( valtype ) ) return gen_rtx_REG ( mode , A0_REG ) ; else return gen_rtx_REG ( mode , D0_REG ) ; } </s>

Location in which function value is returned . NOTE : Due to differences in ABIs , do n't call this function directly , use FUNCTION_VALUE instead .


<s> enum m68k_function_kind m68k_get_function_kind ( tree func ) { tree a ; gcc_assert ( TREE_CODE ( func ) == FUNCTION_DECL ) ; a = lookup_attribute ( "interrupt" , DECL_ATTRIBUTES ( func ) ) ; if ( a != NULL_TREE ) return m68k_fk_interrupt_handler ; a = lookup_attribute ( "interrupt_handler" , DECL_ATTRIBUTES ( func ) ) ; if ( a != NULL_TREE ) return m68k_fk_interrupt_handler ; a = lookup_attribute ( "interrupt_thread" , DECL_ATTRIBUTES ( func ) ) ; if ( a != NULL_TREE ) return m68k_fk_interrupt_thread ; return m68k_fk_normal_function ; } </s>

Return m68k_fk_interrupt_handler if FUNC has an `` interrupt '' or `` interrupt_handler '' attribute and interrupt_thread if FUNC has an `` interrupt_thread '' attribute . Otherwise , return m68k_fk_normal_function .


<s> static rtx m68k_get_gp ( void ) { if ( pic_offset_table_rtx == NULL_RTX ) pic_offset_table_rtx = gen_rtx_REG ( Pmode , PIC_REG ) ; crtl -> uses_pic_offset_table = 1 ; return pic_offset_table_rtx ; } </s>


<s> static rtx m68k_get_m68k_read_tp ( void ) { if ( m68k_read_tp == NULL_RTX ) m68k_read_tp = init_one_libfunc ( "__m68k_read_tp" ) ; return m68k_read_tp ; } </s>


<s> static const char * m68k_get_reloc_decoration ( enum m68k_reloc reloc ) { gcc_assert ( MOTOROLA || reloc == RELOC_GOT ) ; switch ( reloc ) { case RELOC_GOT : if ( MOTOROLA ) { if ( flag_pic == 1 && TARGET_68020 ) return "@GOT.w" ; else return "@GOT" ; } else { if ( TARGET_68020 ) { switch ( flag_pic ) { case 1 : return ":w" ; case 2 : return ":l" ; default : return "" ; } } } gcc_unreachable ( ) ; case RELOC_TLSGD : return "@TLSGD" ; case RELOC_TLSLDM : return "@TLSLDM" ; case RELOC_TLSLDO : return "@TLSLDO" ; case RELOC_TLSIE : return "@TLSIE" ; case RELOC_TLSLE : return "@TLSLE" ; default : gcc_unreachable ( ) ; } } </s>

Return string for TLS relocation RELOC .


<s> static rtx m68k_get_tls_get_addr ( void ) { if ( m68k_tls_get_addr == NULL_RTX ) m68k_tls_get_addr = init_one_libfunc ( "__tls_get_addr" ) ; return m68k_tls_get_addr ; } </s>


"%qE attribute only applies to functions"

"multiple interrupt attributes not allowed"

"%<interrupt_thread%> is available only on fido"

Handle an attribute requiring a FUNCTION_DECL ; arguments as in struct attribute_spec.handler .


<s> static bool m68k_hard_regno_mode_ok ( unsigned int regno , machine_mode mode ) { if ( DATA_REGNO_P ( regno ) ) { if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 8 ) return true ; } else if ( ADDRESS_REGNO_P ( regno ) ) { if ( regno + GET_MODE_SIZE ( mode ) / 4 <= 16 ) return true ; } else if ( FP_REGNO_P ( regno ) ) { if ( ( GET_MODE_CLASS ( mode ) == MODE_FLOAT || GET_MODE_CLASS ( mode ) == MODE_COMPLEX_FLOAT ) && GET_MODE_UNIT_SIZE ( mode ) <= TARGET_FP_REG_SIZE ) return true ; } return false ; } </s>

Implement TARGET_HARD_REGNO_MODE_OK . On the 68000 , we let the cpu registers can hold any mode , but restrict the 68881 registers to floating-point modes .


<s> static unsigned int m68k_hard_regno_nregs ( unsigned int regno , machine_mode mode ) { if ( regno >= 16 ) return GET_MODE_NUNITS ( mode ) ; return CEIL ( GET_MODE_SIZE ( mode ) , UNITS_PER_WORD ) ; } </s>

Implement TARGET_HARD_REGNO_NREGS . On the m68k , ordinary registers hold 32 bits worth ; for the 68881 registers , a single register is always enough for anything that can be stored in them at all .


<s> int m68k_hard_regno_rename_ok ( unsigned int old_reg ATTRIBUTE_UNUSED , unsigned int new_reg ) { if ( ( m68k_get_function_kind ( current_function_decl ) == m68k_fk_interrupt_handler ) && ! df_regs_ever_live_p ( new_reg ) ) return 0 ; return 1 ; } </s>

Return nonzero if register old_reg can be renamed to register new_reg .


<s> bool m68k_illegitimate_symbolic_constant_p ( rtx x ) { rtx base , offset ; if ( M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P ) { split_const ( x , & base , & offset ) ; if ( GET_CODE ( base ) == SYMBOL_REF && ! offset_within_block_p ( base , INTVAL ( offset ) ) ) return true ; } return m68k_tls_reference_p ( x , false ) ; } </s>

Return true if X is an illegitimate symbolic constant .


Called through CC_STATUS_INIT , which is invoked by final whenever a label is encountered .


<s> static bool m68k_jump_table_ref_p ( rtx x ) { if ( GET_CODE ( x ) != LABEL_REF ) return false ; rtx_insn * insn = as_a < rtx_insn * > ( XEXP ( x , 0 ) ) ; if ( ! NEXT_INSN ( insn ) && ! PREV_INSN ( insn ) ) return true ; insn = next_nonnote_insn ( insn ) ; return insn && JUMP_TABLE_DATA_P ( insn ) ; } </s>

Return true if X is a LABEL_REF for a jump table . Assume that unplaced labels will become jump tables .


<s> bool m68k_legitimate_address_p ( machine_mode mode , rtx x , bool strict_p ) { struct m68k_address address ; return m68k_decompose_address ( mode , x , strict_p , & address ) ; } </s>

Return true if X is a legitimate address for values of mode MODE . STRICT_P says whether strict checking is needed .


<s> bool m68k_legitimate_base_reg_p ( rtx x , bool strict_p ) { if ( ! strict_p && GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; return ( REG_P ( x ) && ( strict_p ? REGNO_OK_FOR_BASE_P ( REGNO ( x ) ) : REGNO_OK_FOR_BASE_NONSTRICT_P ( REGNO ( x ) ) ) ) ; } </s>

Return true if X is a legitimate base register . STRICT_P says whether we need strict checking .


<s> static bool m68k_legitimate_constant_address_p ( rtx x , unsigned int reach , bool strict_p ) { rtx base , offset ; if ( ! CONSTANT_ADDRESS_P ( x ) ) return false ; if ( flag_pic && ! ( strict_p && TARGET_PCREL ) && symbolic_operand ( x , VOIDmode ) ) return false ; if ( M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P && reach > 1 ) { split_const ( x , & base , & offset ) ; if ( GET_CODE ( base ) == SYMBOL_REF && ! offset_within_block_p ( base , INTVAL ( offset ) + reach - 1 ) ) return false ; } return ! m68k_tls_reference_p ( x , false ) ; } </s>

Return true if X is a legitimate constant address that can reach bytes in the range [ X , X + REACH ) . STRICT_P says whether we need strict checking .


<s> bool m68k_legitimate_constant_p ( machine_mode mode , rtx x ) { return mode != XFmode && ! m68k_illegitimate_symbolic_constant_p ( x ) ; } </s>


<s> bool m68k_legitimate_index_reg_p ( rtx x , bool strict_p ) { if ( ! strict_p && GET_CODE ( x ) == SUBREG ) x = SUBREG_REG ( x ) ; return ( REG_P ( x ) && ( strict_p ? REGNO_OK_FOR_INDEX_P ( REGNO ( x ) ) : REGNO_OK_FOR_INDEX_NONSTRICT_P ( REGNO ( x ) ) ) ) ; } </s>

Return true if X is a legitimate index register . STRICT_P says whether we need strict checking .


<s> static bool m68k_legitimate_mem_p ( rtx x , struct m68k_address * address ) { return ( MEM_P ( x ) && m68k_decompose_address ( GET_MODE ( x ) , XEXP ( x , 0 ) , reload_in_progress || reload_completed , address ) ) ; } </s>

Return true if X is a memory , describing its address in ADDRESS if so . Apply strict checking if called during or after reload .


<s> static rtx m68k_legitimize_address ( rtx x , rtx oldx , machine_mode mode ) { if ( m68k_tls_symbol_p ( x ) ) return m68k_legitimize_tls_address ( x ) ; if ( GET_CODE ( x ) == PLUS ) { int ch = ( x ) != ( oldx ) ; int copied = 0 ; if ( GET_CODE ( XEXP ( x , 0 ) ) == MULT ) { COPY_ONCE ( x ) ; XEXP ( x , 0 ) = force_operand ( XEXP ( x , 0 ) , 0 ) ; } if ( GET_CODE ( XEXP ( x , 1 ) ) == MULT ) { COPY_ONCE ( x ) ; XEXP ( x , 1 ) = force_operand ( XEXP ( x , 1 ) , 0 ) ; } if ( ch ) { if ( GET_CODE ( XEXP ( x , 1 ) ) == REG && GET_CODE ( XEXP ( x , 0 ) ) == REG ) { if ( TARGET_COLDFIRE_FPU && GET_MODE_CLASS ( mode ) == MODE_FLOAT ) { COPY_ONCE ( x ) ; x = force_operand ( x , 0 ) ; } return x ; } if ( memory_address_p ( mode , x ) ) return x ; } if ( GET_CODE ( XEXP ( x , 0 ) ) == REG || ( GET_CODE ( XEXP ( x , 0 ) ) == SIGN_EXTEND && GET_CODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == REG && GET_MODE ( XEXP ( XEXP ( x , 0 ) , 0 ) ) == HImode ) ) { rtx temp = gen_reg_rtx ( Pmode ) ; rtx val = force_operand ( XEXP ( x , 1 ) , 0 ) ; emit_move_insn ( temp , val ) ; COPY_ONCE ( x ) ; XEXP ( x , 1 ) = temp ; if ( TARGET_COLDFIRE_FPU && GET_MODE_CLASS ( mode ) == MODE_FLOAT && GET_CODE ( XEXP ( x , 0 ) ) == REG ) x = force_operand ( x , 0 ) ; } else if ( GET_CODE ( XEXP ( x , 1 ) ) == REG || ( GET_CODE ( XEXP ( x , 1 ) ) == SIGN_EXTEND && GET_CODE ( XEXP ( XEXP ( x , 1 ) , 0 ) ) == REG && GET_MODE ( XEXP ( XEXP ( x , 1 ) , 0 ) ) == HImode ) ) { rtx temp = gen_reg_rtx ( Pmode ) ; rtx val = force_operand ( XEXP ( x , 0 ) , 0 ) ; emit_move_insn ( temp , val ) ; COPY_ONCE ( x ) ; XEXP ( x , 0 ) = temp ; if ( TARGET_COLDFIRE_FPU && GET_MODE_CLASS ( mode ) == MODE_FLOAT && GET_CODE ( XEXP ( x , 1 ) ) == REG ) x = force_operand ( x , 0 ) ; } } return x ; } </s>

Convert X to a legitimate address and return it if successful . Otherwise return X . For the 68000 , we handle X+REG by loading X into a register R and using R+REG . R will go in an address reg and indexing will be used . However , if REG is a broken-out memory address or multiplication , nothing needs to be done because REG can certainly go in an address reg .


<s> rtx m68k_legitimize_call_address ( rtx x ) { gcc_assert ( MEM_P ( x ) ) ; if ( call_operand ( XEXP ( x , 0 ) , VOIDmode ) ) return x ; return replace_equiv_address ( x , force_reg ( Pmode , XEXP ( x , 0 ) ) ) ; } </s>

Convert X to a legitimate function call memory reference and return the result .


<s> rtx m68k_legitimize_sibcall_address ( rtx x ) { gcc_assert ( MEM_P ( x ) ) ; if ( sibcall_operand ( XEXP ( x , 0 ) , VOIDmode ) ) return x ; emit_move_insn ( gen_rtx_REG ( Pmode , STATIC_CHAIN_REGNUM ) , XEXP ( x , 0 ) ) ; return replace_equiv_address ( x , gen_rtx_REG ( Pmode , STATIC_CHAIN_REGNUM ) ) ; } </s>


<s> rtx m68k_legitimize_tls_address ( rtx orig ) { switch ( SYMBOL_REF_TLS_MODEL ( orig ) ) { case TLS_MODEL_GLOBAL_DYNAMIC : orig = m68k_call_tls_get_addr ( orig , orig , RELOC_TLSGD ) ; break ; case TLS_MODEL_LOCAL_DYNAMIC : { rtx eqv ; rtx a0 ; rtx x ; eqv = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 1 , const0_rtx ) , UNSPEC_RELOC32 ) ; a0 = m68k_call_tls_get_addr ( orig , eqv , RELOC_TLSLDM ) ; x = m68k_wrap_symbol ( orig , RELOC_TLSLDO , a0 , NULL_RTX ) ; if ( can_create_pseudo_p ( ) ) x = m68k_move_to_reg ( x , orig , NULL_RTX ) ; orig = x ; break ; } case TLS_MODEL_INITIAL_EXEC : { rtx a0 ; rtx x ; a0 = m68k_call_m68k_read_tp ( ) ; x = m68k_wrap_symbol_into_got_ref ( orig , RELOC_TLSIE , NULL_RTX ) ; x = gen_rtx_PLUS ( Pmode , x , a0 ) ; if ( can_create_pseudo_p ( ) ) x = m68k_move_to_reg ( x , orig , NULL_RTX ) ; orig = x ; break ; } case TLS_MODEL_LOCAL_EXEC : { rtx a0 ; rtx x ; a0 = m68k_call_m68k_read_tp ( ) ; x = m68k_wrap_symbol ( orig , RELOC_TLSLE , a0 , NULL_RTX ) ; if ( can_create_pseudo_p ( ) ) x = m68k_move_to_reg ( x , orig , NULL_RTX ) ; orig = x ; break ; } default : gcc_unreachable ( ) ; } return orig ; } </s>

Return a legitimized address for accessing TLS SYMBOL_REF X . For explanations on instructions sequences see TLS/NPTL ABI for m68k and ColdFire .


<s> rtx m68k_libcall_value ( machine_mode mode ) { switch ( mode ) { case E_SFmode : case E_DFmode : case E_XFmode : if ( TARGET_68881 ) return gen_rtx_REG ( mode , FP0_REG ) ; break ; default : break ; } return gen_rtx_REG ( mode , m68k_libcall_value_in_a0_p ? A0_REG : D0_REG ) ; } </s>

Return floating point values in a 68881 register . This makes 68881 code a little bit faster . It also makes -msoft-float code incompatible with hard-float code , so people have to be careful not to mix the two . For ColdFire it was decided the ABI incompatibility is undesirable . If there is need for a hard-float ABI it is probably worth doing it properly and also passing function arguments in FP registers .


<s> bool m68k_matches_q_p ( rtx x ) { struct m68k_address address ; return ( m68k_legitimate_mem_p ( x , & address ) && address . code == UNKNOWN && address . base && ! address . offset && ! address . index ) ; } </s>

Return true if X matches the ' Q ' constraint . It must be a memory with a base address and no constant offset or index .


<s> bool m68k_matches_u_p ( rtx x ) { struct m68k_address address ; return ( m68k_legitimate_mem_p ( x , & address ) && address . code == UNKNOWN && address . base && address . offset && ! address . index ) ; } </s>

Return true if X matches the ' U ' constraint . It must be a base address with a constant offset and no index .


<s> static bool m68k_modes_tieable_p ( machine_mode mode1 , machine_mode mode2 ) { return ( ! TARGET_HARD_FLOAT || ( ( GET_MODE_CLASS ( mode1 ) == MODE_FLOAT || GET_MODE_CLASS ( mode1 ) == MODE_COMPLEX_FLOAT ) == ( GET_MODE_CLASS ( mode2 ) == MODE_FLOAT || GET_MODE_CLASS ( mode2 ) == MODE_COMPLEX_FLOAT ) ) ) ; } </s>


<s> bool m68k_movem_pattern_p ( rtx pattern , rtx automod_base , HOST_WIDE_INT automod_offset , bool store_p ) { rtx base , mem_base , set , mem , reg , last_reg ; HOST_WIDE_INT offset , mem_offset ; int i , first , len ; enum reg_class rclass ; len = XVECLEN ( pattern , 0 ) ; first = ( automod_base != NULL ) ; if ( automod_base ) { if ( store_p != ( automod_offset < 0 ) ) return false ; base = automod_base ; offset = ( automod_offset < 0 ? automod_offset : 0 ) ; } else { base = NULL ; offset = 0 ; } last_reg = NULL ; rclass = NO_REGS ; for ( i = first ; i < len ; i ++ ) { set = XVECEXP ( pattern , 0 , i ) ; if ( GET_CODE ( set ) != SET ) return false ; mem = XEXP ( set , ! store_p ) ; if ( ! MEM_P ( mem ) || ! memory_operand ( mem , VOIDmode ) ) return false ; if ( base == NULL ) { m68k_split_offset ( XEXP ( mem , 0 ) , & base , & offset ) ; if ( TARGET_COLDFIRE && ! m68k_legitimate_base_reg_p ( base , reload_completed ) ) return false ; } else { m68k_split_offset ( XEXP ( mem , 0 ) , & mem_base , & mem_offset ) ; if ( ! rtx_equal_p ( base , mem_base ) || offset != mem_offset ) return false ; } reg = XEXP ( set , store_p ) ; if ( ! REG_P ( reg ) || ! HARD_REGISTER_P ( reg ) || GET_MODE ( reg ) != reg_raw_mode [ REGNO ( reg ) ] ) return false ; if ( last_reg ) { if ( ! TEST_HARD_REG_BIT ( reg_class_contents [ rclass ] , REGNO ( reg ) ) || REGNO ( last_reg ) >= REGNO ( reg ) ) return false ; } else { if ( INT_REGNO_P ( REGNO ( reg ) ) ) rclass = GENERAL_REGS ; else if ( FP_REGNO_P ( REGNO ( reg ) ) ) rclass = FP_REGS ; else return false ; } last_reg = reg ; offset += GET_MODE_SIZE ( GET_MODE ( reg ) ) ; } if ( automod_base && offset != ( automod_offset < 0 ? 0 : automod_offset ) ) return false ; if ( len < first + ( rclass == FP_REGS ? MIN_FMOVEM_REGS : MIN_MOVEM_REGS ) ) return false ; return true ; } </s>

Return true if PATTERN is a PARALLEL suitable for a movem or fmovem instruction . STORE_P says whether the move is a load or store . If the instruction uses post-increment or pre-decrement addressing , AUTOMOD_BASE is the base register and AUTOMOD_OFFSET is the total adjustment . This adjustment will be made by the first element of PARALLEL , with the loads or stores starting at element 1 . If the instruction does not use post-increment or pre-decrement addressing , AUTOMOD_BASE is null , AUTOMOD_OFFSET is 0 , and the loads or stores start at element 0 .


<s> static rtx m68k_move_to_reg ( rtx x , rtx orig , rtx reg ) { rtx_insn * insn ; if ( reg == NULL_RTX ) { gcc_assert ( can_create_pseudo_p ( ) ) ; reg = gen_reg_rtx ( Pmode ) ; } insn = emit_move_insn ( reg , x ) ; set_unique_reg_note ( insn , REG_EQUAL , orig ) ; return reg ; } </s>

Move X to a register and add REG_EQUAL note pointing to ORIG . If REG is non-null , use it ; generate new pseudo otherwise .


<s> static bool m68k_ok_for_sibcall_p ( tree decl , tree exp ) { enum m68k_function_kind kind ; if ( CALL_EXPR_STATIC_CHAIN ( exp ) ) return false ; if ( ! VOID_TYPE_P ( TREE_TYPE ( DECL_RESULT ( cfun -> decl ) ) ) ) { rtx cfun_value ; rtx call_value ; cfun_value = FUNCTION_VALUE ( TREE_TYPE ( DECL_RESULT ( cfun -> decl ) ) , cfun -> decl ) ; call_value = FUNCTION_VALUE ( TREE_TYPE ( exp ) , decl ) ; if ( ! ( rtx_equal_p ( cfun_value , call_value ) || ( REG_P ( cfun_value ) && m68k_reg_present_p ( call_value , REGNO ( cfun_value ) ) ) ) ) return false ; } kind = m68k_get_function_kind ( current_function_decl ) ; if ( kind == m68k_fk_normal_function ) return true ; if ( decl && m68k_get_function_kind ( decl ) == kind ) return true ; return false ; } </s>


<s> static bool m68k_output_addr_const_extra ( FILE * file , rtx x ) { if ( GET_CODE ( x ) == UNSPEC ) { switch ( XINT ( x , 1 ) ) { case UNSPEC_RELOC16 : case UNSPEC_RELOC32 : output_addr_const ( file , XVECEXP ( x , 0 , 0 ) ) ; fputs ( m68k_get_reloc_decoration ( ( enum m68k_reloc ) INTVAL ( XVECEXP ( x , 0 , 1 ) ) ) , file ) ; return true ; default : break ; } } return false ; } </s>


<s>
rtx_code
m68k_output_bftst
(
rtx
zxop0
,
rtx
zxop1
,
rtx
zxop2
,
rtx_code
code
)
{
if
(
zxop1
==
const1_rtx
&&
GET_CODE
(
zxop2
)
==
CONST_INT
)
{
int
width
=
GET_CODE
(
zxop0
)
==
REG
31
:
7
;
return
m68k_output_btst
(
GEN_INT
(
width
INTVAL
(
zxop2
)
)
,
zxop0
,
code
,
1000
)
;
}
rtx
ops
[
3
]
=
{
zxop0
,
zxop1
,
zxop2
}
;
output_asm_insn
(
"bftst %0{%b2:%b1}"
,
ops
)
;
return
code
;
}
</s>

Output a bftst instruction for a zero_extract with ZXOP0 , ZXOP1 and ZXOP2 operands . CODE is the code of the comparison , and we return the code to be actually used in the jump .


<s>
const
char
*
m68k_output_branch_float
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"fjeq %l3"
;
case
NE
:
return
"fjne %l3"
;
case
GT
:
return
"fjgt %l3"
;
case
LT
:
return
"fjlt %l3"
;
case
GE
:
return
"fjge %l3"
;
case
LE
:
return
"fjle %l3"
;
case
ORDERED
:
return
"fjor %l3"
;
case
UNORDERED
:
return
"fjun %l3"
;
case
UNEQ
:
return
"fjueq %l3"
;
case
UNGE
:
return
"fjuge %l3"
;
case
UNGT
:
return
"fjugt %l3"
;
case
UNLE
:
return
"fjule %l3"
;
case
UNLT
:
return
"fjult %l3"
;
case
LTGT
:
return
"fjogl %l3"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a floating point branch instruction with CODE .

m68k
"fjeq %l3"
"fjne %l3"
"fjgt %l3"
"fjlt %l3"
"fjge %l3"
"fjle %l3"
"fjor %l3"
"fjun %l3"
"fjueq %l3"
"fjuge %l3"
"fjugt %l3"
"fjule %l3"
"fjult %l3"
"fjogl %l3"


<s>
const
char
*
m68k_output_branch_float_rev
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"fjne %l3"
;
case
NE
:
return
"fjeq %l3"
;
case
GT
:
return
"fjngt %l3"
;
case
LT
:
return
"fjnlt %l3"
;
case
GE
:
return
"fjnge %l3"
;
case
LE
:
return
"fjnle %l3"
;
case
ORDERED
:
return
"fjun %l3"
;
case
UNORDERED
:
return
"fjor %l3"
;
case
UNEQ
:
return
"fjogl %l3"
;
case
UNGE
:
return
"fjolt %l3"
;
case
UNGT
:
return
"fjole %l3"
;
case
UNLE
:
return
"fjogt %l3"
;
case
UNLT
:
return
"fjoge %l3"
;
case
LTGT
:
return
"fjueq %l3"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a reversed floating point branch instruction with CODE .

m68k
"fjne %l3"
"fjeq %l3"
"fjngt %l3"
"fjnlt %l3"
"fjnge %l3"
"fjnle %l3"
"fjun %l3"
"fjor %l3"
"fjogl %l3"
"fjolt %l3"
"fjole %l3"
"fjogt %l3"
"fjoge %l3"
"fjueq %l3"


<s>
const
char
*
m68k_output_branch_integer
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"jeq %l3"
;
case
NE
:
return
"jne %l3"
;
case
GT
:
return
"jgt %l3"
;
case
GTU
:
return
"jhi %l3"
;
case
LT
:
return
"jlt %l3"
;
case
LTU
:
return
"jcs %l3"
;
case
GE
:
return
"jge %l3"
;
case
GEU
:
return
"jcc %l3"
;
case
LE
:
return
"jle %l3"
;
case
LEU
:
return
"jls %l3"
;
case
PLUS
:
return
"jpl %l3"
;
case
MINUS
:
return
"jmi %l3"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a branch with CODE .

m68k
"jeq %l3"
"jne %l3"
"jgt %l3"
"jhi %l3"
"jlt %l3"
"jcs %l3"
"jge %l3"
"jcc %l3"
"jle %l3"
"jls %l3"
"jpl %l3"
"jmi %l3"


<s>
const
char
*
m68k_output_branch_integer_rev
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"jne %l3"
;
case
NE
:
return
"jeq %l3"
;
case
GT
:
return
"jle %l3"
;
case
GTU
:
return
"jls %l3"
;
case
LT
:
return
"jge %l3"
;
case
LTU
:
return
"jcc %l3"
;
case
GE
:
return
"jlt %l3"
;
case
GEU
:
return
"jcs %l3"
;
case
LE
:
return
"jgt %l3"
;
case
LEU
:
return
"jhi %l3"
;
case
PLUS
:
return
"jmi %l3"
;
case
MINUS
:
return
"jpl %l3"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a reversed branch with CODE .

m68k
"jne %l3"
"jeq %l3"
"jle %l3"
"jls %l3"
"jge %l3"
"jcc %l3"
"jlt %l3"
"jcs %l3"
"jgt %l3"
"jhi %l3"
"jmi %l3"
"jpl %l3"


Emit a comparison between OP0 and OP1 . Return true iff the comparison was reversed . SC1 is an SImode scratch reg , and SC2 a DImode scratch reg , as needed . CODE is the code of the comparison , we return it unchanged or swapped , as necessary .


<s>
rtx_code
m68k_output_compare_fp
(
rtx
op0
,
rtx
op1
,
rtx_code
code
)
{
rtx_code
tmp
=
m68k_find_flags_value
(
op0
,
op1
,
code
)
;
if
(
tmp
!=
UNKNOWN
)
return
tmp
;
rtx
ops
[
2
]
;
ops
[
0
]
=
op0
;
ops
[
1
]
=
op1
;
remember_compare_flags
(
op0
,
op1
)
;
machine_mode
mode
=
GET_MODE
(
op0
)
;
std
::
string
prec
=
mode
==
SFmode
"s"
:
mode
==
DFmode
"d"
:
"x"
;
if
(
op1
==
CONST0_RTX
(
GET_MODE
(
op0
)
)
)
{
if
(
FP_REG_P
(
op0
)
)
{
if
(
TARGET_COLDFIRE_FPU
)
output_asm_insn
(
"ftst%.d %0"
,
ops
)
;
else
output_asm_insn
(
"ftst%.x %0"
,
ops
)
;
}
else
output_asm_insn
(
(
"ftst%."
+
prec
+
" %0"
)
.
c_str
(
)
,
ops
)
;
return
code
;
}
switch
(
which_alternative
)
{
case
0
:
if
(
TARGET_COLDFIRE_FPU
)
output_asm_insn
(
"fcmp%.d %1,%0"
,
ops
)
;
else
output_asm_insn
(
"fcmp%.x %1,%0"
,
ops
)
;
break
;
case
1
:
output_asm_insn
(
(
"fcmp%."
+
prec
+
" %f1,%0"
)
.
c_str
(
)
,
ops
)
;
break
;
case
2
:
output_asm_insn
(
(
"fcmp%."
+
prec
+
" %0,%f1"
)
.
c_str
(
)
,
ops
)
;
std
::
swap
(
flags_compare_op0
,
flags_compare_op1
)
;
return
swap_condition
(
code
)
;
case
3
:
gcc_unreachable
(
)
;
}
return
code
;
}
</s>

Emit a comparison between OP0 and OP1 . CODE is the code of the comparison . It is returned , potentially modified if necessary .


<s>
rtx_code
m68k_output_compare_hi
(
rtx
op0
,
rtx
op1
,
rtx_code
code
)
{
rtx_code
tmp
=
m68k_find_flags_value
(
op0
,
op1
,
code
)
;
if
(
tmp
!=
UNKNOWN
)
return
tmp
;
remember_compare_flags
(
op0
,
op1
)
;
rtx
ops
[
2
]
;
ops
[
0
]
=
op0
;
ops
[
1
]
=
op1
;
if
(
op1
==
const0_rtx
)
output_asm_insn
(
"tst%.w %d0"
,
ops
)
;
else
if
(
GET_CODE
(
op0
)
==
MEM
&&
GET_CODE
(
op1
)
==
MEM
)
output_asm_insn
(
"cmpm%.w %1,%0"
,
ops
)
;
else
if
(
(
REG_P
(
op1
)
&&
!
ADDRESS_REG_P
(
op1
)
)
||
(
!
REG_P
(
op0
)
&&
GET_CODE
(
op0
)
!=
MEM
)
)
{
output_asm_insn
(
"cmp%.w %d0,%d1"
,
ops
)
;
std
::
swap
(
flags_compare_op0
,
flags_compare_op1
)
;
return
swap_condition
(
code
)
;
}
else
output_asm_insn
(
"cmp%.w %d1,%d0"
,
ops
)
;
return
code
;
}
</s>


<s>
rtx_code
m68k_output_compare_qi
(
rtx
op0
,
rtx
op1
,
rtx_code
code
)
{
rtx_code
tmp
=
m68k_find_flags_value
(
op0
,
op1
,
code
)
;
if
(
tmp
!=
UNKNOWN
)
return
tmp
;
remember_compare_flags
(
op0
,
op1
)
;
rtx
ops
[
2
]
;
ops
[
0
]
=
op0
;
ops
[
1
]
=
op1
;
if
(
op1
==
const0_rtx
)
output_asm_insn
(
"tst%.b %d0"
,
ops
)
;
else
if
(
GET_CODE
(
op0
)
==
MEM
&&
GET_CODE
(
op1
)
==
MEM
)
output_asm_insn
(
"cmpm%.b %1,%0"
,
ops
)
;
else
if
(
REG_P
(
op1
)
||
(
!
REG_P
(
op0
)
&&
GET_CODE
(
op0
)
!=
MEM
)
)
{
output_asm_insn
(
"cmp%.b %d0,%d1"
,
ops
)
;
std
::
swap
(
flags_compare_op0
,
flags_compare_op1
)
;
return
swap_condition
(
code
)
;
}
else
output_asm_insn
(
"cmp%.b %d1,%d0"
,
ops
)
;
return
code
;
}
</s>


<s>
rtx_code
m68k_output_compare_si
(
rtx
op0
,
rtx
op1
,
rtx_code
code
)
{
rtx_code
tmp
=
m68k_find_flags_value
(
op0
,
op1
,
code
)
;
if
(
tmp
!=
UNKNOWN
)
return
tmp
;
remember_compare_flags
(
op0
,
op1
)
;
rtx
ops
[
2
]
;
ops
[
0
]
=
op0
;
ops
[
1
]
=
op1
;
if
(
op1
==
const0_rtx
&&
(
TARGET_68020
||
TARGET_COLDFIRE
||
!
ADDRESS_REG_P
(
op0
)
)
)
output_asm_insn
(
"tst%.l %0"
,
ops
)
;
else
if
(
GET_CODE
(
op0
)
==
MEM
&&
GET_CODE
(
op1
)
==
MEM
)
output_asm_insn
(
"cmpm%.l %1,%0"
,
ops
)
;
else
if
(
REG_P
(
op1
)
||
(
!
REG_P
(
op0
)
&&
GET_CODE
(
op0
)
!=
MEM
)
)
{
output_asm_insn
(
"cmp%.l %d0,%d1"
,
ops
)
;
std
::
swap
(
flags_compare_op0
,
flags_compare_op1
)
;
return
swap_condition
(
code
)
;
}
else
if
(
!
TARGET_COLDFIRE
&&
ADDRESS_REG_P
(
op0
)
&&
GET_CODE
(
op1
)
==
CONST_INT
&&
INTVAL
(
op1
)
<
0x8000
&&
INTVAL
(
op1
)
>=
0x8000
)
output_asm_insn
(
"cmp%.w %1,%0"
,
ops
)
;
else
output_asm_insn
(
"cmp%.l %d1,%d0"
,
ops
)
;
return
code
;
}
</s>


<s> static void m68k_output_dwarf_dtprel ( FILE * file , int size , rtx x ) { gcc_assert ( size == 4 ) ; fputs ( "\t.long\t" , file ) ; output_addr_const ( file , x ) ; fputs ( "@TLSLDO+0x8000" , file ) ; } </s>


<s>
const
char
*
m68k_output_movem
(
rtx
*
operands
,
rtx
pattern
,
HOST_WIDE_INT
automod_offset
,
bool
store_p
)
{
unsigned
int
mask
;
int
i
,
first
;
gcc_assert
(
GET_CODE
(
pattern
)
==
PARALLEL
)
;
mask
=
0
;
first
=
(
automod_offset
!=
0
)
;
for
(
i
=
first
;
i
<
XVECLEN
(
pattern
,
0
)
;
i
++
)
{
unsigned
int
regno
;
gcc_assert
(
MEM_P
(
XEXP
(
XVECEXP
(
pattern
,
0
,
i
)
,
!
store_p
)
)
)
;
gcc_assert
(
REG_P
(
XEXP
(
XVECEXP
(
pattern
,
0
,
i
)
,
store_p
)
)
)
;
regno
=
REGNO
(
XEXP
(
XVECEXP
(
pattern
,
0
,
i
)
,
store_p
)
)
;
if
(
automod_offset
<
0
)
{
if
(
FP_REGNO_P
(
regno
)
)
mask
|=
1
<<
(
regno
FP0_REG
)
;
else
mask
|=
1
<<
(
15
(
regno
D0_REG
)
)
;
}
else
{
if
(
FP_REGNO_P
(
regno
)
)
mask
|=
1
<<
(
7
(
regno
FP0_REG
)
)
;
else
mask
|=
1
<<
(
regno
D0_REG
)
;
}
}
CC_STATUS_INIT
;
if
(
automod_offset
==
0
)
operands
[
0
]
=
XEXP
(
XEXP
(
XVECEXP
(
pattern
,
0
,
first
)
,
!
store_p
)
,
0
)
;
else
if
(
automod_offset
<
0
)
operands
[
0
]
=
gen_rtx_PRE_DEC
(
Pmode
,
SET_DEST
(
XVECEXP
(
pattern
,
0
,
0
)
)
)
;
else
operands
[
0
]
=
gen_rtx_POST_INC
(
Pmode
,
SET_DEST
(
XVECEXP
(
pattern
,
0
,
0
)
)
)
;
operands
[
1
]
=
GEN_INT
(
mask
)
;
if
(
FP_REGNO_P
(
REGNO
(
XEXP
(
XVECEXP
(
pattern
,
0
,
first
)
,
store_p
)
)
)
)
{
if
(
store_p
)
return
"fmovem %1,%a0"
;
else
return
"fmovem %a0,%1"
;
}
else
{
if
(
store_p
)
return
"movem%.l %1,%a0"
;
else
return
"movem%.l %a0,%1"
;
}
}
</s>

Return the assembly code template for a movem or fmovem instruction whose pattern is given by PATTERN . Store the template 's operands in OPERANDS . If the instruction uses post-increment or pre-decrement addressing , AUTOMOD_OFFSET is the total adjustment , otherwise it is 0 . STORE_P is true if this is a store instruction .


<s>
const
char
*
m68k_output_scc
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"seq %0"
;
case
NE
:
return
"sne %0"
;
case
GT
:
return
"sgt %0"
;
case
GTU
:
return
"shi %0"
;
case
LT
:
return
"slt %0"
;
case
LTU
:
return
"scs %0"
;
case
GE
:
return
"sge %0"
;
case
GEU
:
return
"scc %0"
;
case
LE
:
return
"sle %0"
;
case
LEU
:
return
"sls %0"
;
case
PLUS
:
return
"spl %0"
;
case
MINUS
:
return
"smi %0"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a scc instruction with CODE .


<s>
const
char
*
m68k_output_scc_float
(
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
return
"fseq %0"
;
case
NE
:
return
"fsne %0"
;
case
GT
:
return
"fsgt %0"
;
case
GTU
:
return
"fshi %0"
;
case
LT
:
return
"fslt %0"
;
case
GE
:
return
"fsge %0"
;
case
LE
:
return
"fsle %0"
;
case
ORDERED
:
return
"fsor %0"
;
case
UNORDERED
:
return
"fsun %0"
;
case
UNEQ
:
return
"fsueq %0"
;
case
UNGE
:
return
"fsuge %0"
;
case
UNGT
:
return
"fsugt %0"
;
case
UNLE
:
return
"fsule %0"
;
case
UNLT
:
return
"fsult %0"
;
case
LTGT
:
return
"fsogl %0"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an output template for a floating point scc instruction with CODE .

m68k
"fseq %0"
"fsne %0"
"fsgt %0"
"fshi %0"
"fslt %0"
"fsge %0"
"fsle %0"
"fsor %0"
"fsun %0"
"fsueq %0"
"fsuge %0"
"fsugt %0"
"fsule %0"
"fsult %0"
"fsogl %0"


<s> static void m68k_override_options_after_change ( void ) { if ( m68k_sched_cpu == CPU_UNKNOWN ) { flag_schedule_insns = 0 ; flag_schedule_insns_after_reload = 0 ; flag_modulo_sched = 0 ; flag_live_range_shrinkage = 0 ; } } </s>


<s> enum reg_class m68k_preferred_reload_class ( rtx x , enum reg_class rclass ) { enum reg_class secondary_class ; secondary_class = m68k_secondary_reload_class ( rclass , GET_MODE ( x ) , x ) ; if ( secondary_class != NO_REGS && reg_class_subset_p ( secondary_class , rclass ) ) return secondary_class ; if ( GET_CODE ( x ) == CONST_INT && reg_class_subset_p ( DATA_REGS , rclass ) && IN_RANGE ( INTVAL ( x ) , - 0x80 , 0x7f ) ) return DATA_REGS ; if ( GET_CODE ( x ) == CONST_DOUBLE && GET_MODE_CLASS ( GET_MODE ( x ) ) == MODE_FLOAT ) { if ( TARGET_HARD_FLOAT && reg_class_subset_p ( FP_REGS , rclass ) ) return FP_REGS ; return NO_REGS ; } return rclass ; } </s>


<s> static machine_mode m68k_promote_function_mode ( const_tree type , machine_mode mode , int * punsignedp ATTRIBUTE_UNUSED , const_tree fntype ATTRIBUTE_UNUSED , int for_return ) { if ( type == NULL_TREE && ! for_return && ( mode == QImode || mode == HImode ) ) return SImode ; return mode ; } </s>


<s> poly_int64 m68k_push_rounding ( poly_int64 bytes ) { if ( TARGET_COLDFIRE ) return bytes ; return ( bytes + 1 ) & ~ 1 ; } </s>

Implement PUSH_ROUNDING . On the 680x0 , sp @ - in a byte insn really pushes a word . On the ColdFire , sp @ - in a byte insn pushes just a byte .


<s> static bool m68k_reg_present_p ( const_rtx parallel , unsigned int regno ) { int i ; if ( REG_P ( parallel ) && REGNO ( parallel ) == regno ) return true ; if ( GET_CODE ( parallel ) != PARALLEL ) return false ; for ( i = 0 ; i < XVECLEN ( parallel , 0 ) ; ++ i ) { const_rtx x ; x = XEXP ( XVECEXP ( parallel , 0 , i ) , 0 ) ; if ( REG_P ( x ) && REGNO ( x ) == regno ) return true ; } return false ; } </s>

Return true if PARALLEL contains register REGNO .


<s> static poly_int64 m68k_return_pops_args ( tree fundecl , tree funtype , poly_int64 size ) { return ( ( TARGET_RTD && ( ! fundecl || TREE_CODE ( fundecl ) != IDENTIFIER_NODE ) && ( ! stdarg_p ( funtype ) ) ) ? ( HOST_WIDE_INT ) size : 0 ) ; } </s>

On the 68000 , the RTS insn can not pop anything . On the 68010 , the RTD insn may be used to pop them if the number of args is fixed , but if the number is variable then the caller must pop them all . RTD ca n't be used for library calls now because the library is compiled with the Unix compiler . Use of RTD is a selectable option , since it is incompatible with standard Unix calling sequences . If the option is not selected , the caller must always pop the args .


<s> static bool m68k_save_reg ( unsigned int regno , bool interrupt_handler ) { if ( flag_pic && regno == PIC_REG ) { if ( crtl -> saves_all_registers ) return true ; if ( crtl -> uses_pic_offset_table ) return true ; if ( crtl -> uses_const_pool ) return true ; } if ( crtl -> calls_eh_return ) { unsigned int i ; for ( i = 0 ; ; i ++ ) { unsigned int test = EH_RETURN_DATA_REGNO ( i ) ; if ( test == INVALID_REGNUM ) break ; if ( test == regno ) return true ; } } if ( fixed_regs [ regno ] ) return false ; if ( regno == FRAME_POINTER_REGNUM && frame_pointer_needed ) return false ; if ( interrupt_handler ) { if ( df_regs_ever_live_p ( regno ) ) return true ; if ( ! crtl -> is_leaf && call_used_or_fixed_reg_p ( regno ) ) return true ; } if ( ! df_regs_ever_live_p ( regno ) ) return false ; return ! call_used_or_fixed_reg_p ( regno ) ; } </s>

Refer to the array ` regs_ever_live ' to determine which registers to save ; ` regs_ever_live [ I ] ' is nonzero if register number I is ever used in the function . This function is responsible for knowing which registers should not be saved even if used . Return true if we need to save REGNO .


<s> int m68k_sched_address_bypass_p ( rtx_insn * pro , rtx_insn * con ) { rtx pro_x ; rtx con_mem_read ; pro_x = sched_get_reg_operand ( pro , true ) ; if ( pro_x == NULL ) return 0 ; con_mem_read = sched_get_mem_operand ( con , true , false ) ; gcc_assert ( con_mem_read != NULL ) ; if ( reg_mentioned_p ( pro_x , con_mem_read ) ) return 1 ; return 0 ; } </s>

Return non-zero if PRO modifies register used as part of address in CON .


<s> static int m68k_sched_adjust_cost ( rtx_insn * insn , int , rtx_insn * def_insn , int cost , unsigned int ) { int delay ; if ( recog_memoized ( def_insn ) < 0 || recog_memoized ( insn ) < 0 ) return cost ; if ( sched_cfv4_bypass_data . scale == 1 ) { gcc_assert ( sched_cfv4_bypass_data . pro == def_insn && sched_cfv4_bypass_data . con == insn ) ; if ( cost < 3 ) cost = 3 ; sched_cfv4_bypass_data . pro = NULL ; sched_cfv4_bypass_data . con = NULL ; sched_cfv4_bypass_data . scale = 0 ; } else gcc_assert ( sched_cfv4_bypass_data . pro == NULL && sched_cfv4_bypass_data . con == NULL && sched_cfv4_bypass_data . scale == 0 ) ; delay = min_insn_conflict_delay ( sched_adjust_cost_state , def_insn , insn ) ; if ( delay > cost ) cost = delay ; return cost ; } </s>

Implement adjust_cost scheduler hook . Return adjusted COST of dependency LINK between DEF_INSN and INSN .


<s> enum attr_opx_type m68k_sched_attr_opx_type ( rtx_insn * insn , int address_p ) { switch ( sched_attr_op_type ( insn , true , address_p != 0 ) ) { case OP_TYPE_RN : return OPX_TYPE_RN ; case OP_TYPE_FPN : return OPX_TYPE_FPN ; case OP_TYPE_MEM1 : return OPX_TYPE_MEM1 ; case OP_TYPE_MEM234 : return OPX_TYPE_MEM234 ; case OP_TYPE_MEM5 : return OPX_TYPE_MEM5 ; case OP_TYPE_MEM6 : return OPX_TYPE_MEM6 ; case OP_TYPE_MEM7 : return OPX_TYPE_MEM7 ; case OP_TYPE_IMM_Q : return OPX_TYPE_IMM_Q ; case OP_TYPE_IMM_W : return OPX_TYPE_IMM_W ; case OP_TYPE_IMM_L : return OPX_TYPE_IMM_L ; default : gcc_unreachable ( ) ; } } </s>

Implement opx_type attribute . Return type of INSN 's operand X . If ADDRESS_P is true , return type of memory location operand refers to .


<s> enum attr_opy_type m68k_sched_attr_opy_type ( rtx_insn * insn , int address_p ) { switch ( sched_attr_op_type ( insn , false , address_p != 0 ) ) { case OP_TYPE_RN : return OPY_TYPE_RN ; case OP_TYPE_FPN : return OPY_TYPE_FPN ; case OP_TYPE_MEM1 : return OPY_TYPE_MEM1 ; case OP_TYPE_MEM234 : return OPY_TYPE_MEM234 ; case OP_TYPE_MEM5 : return OPY_TYPE_MEM5 ; case OP_TYPE_MEM6 : return OPY_TYPE_MEM6 ; case OP_TYPE_MEM7 : return OPY_TYPE_MEM7 ; case OP_TYPE_IMM_Q : return OPY_TYPE_IMM_Q ; case OP_TYPE_IMM_W : return OPY_TYPE_IMM_W ; case OP_TYPE_IMM_L : return OPY_TYPE_IMM_L ; default : gcc_unreachable ( ) ; } } </s>

Implement opy_type attribute . Return type of INSN 's operand Y . If ADDRESS_P is true , return type of memory location operand refers to .


<s> enum attr_op_mem m68k_sched_attr_op_mem ( rtx_insn * insn ) { enum attr_op_type opx ; enum attr_op_type opy ; opx = sched_get_opxy_mem_type ( insn , true ) ; opy = sched_get_opxy_mem_type ( insn , false ) ; if ( opy == OP_TYPE_RN && opx == OP_TYPE_RN ) return OP_MEM_00 ; if ( opy == OP_TYPE_RN && opx == OP_TYPE_MEM1 ) { switch ( get_attr_opx_access ( insn ) ) { case OPX_ACCESS_R : return OP_MEM_10 ; case OPX_ACCESS_W : return OP_MEM_01 ; case OPX_ACCESS_RW : return OP_MEM_11 ; default : gcc_unreachable ( ) ; } } if ( opy == OP_TYPE_RN && opx == OP_TYPE_MEM6 ) { switch ( get_attr_opx_access ( insn ) ) { case OPX_ACCESS_R : return OP_MEM_I0 ; case OPX_ACCESS_W : return OP_MEM_0I ; case OPX_ACCESS_RW : return OP_MEM_I1 ; default : gcc_unreachable ( ) ; } } if ( opy == OP_TYPE_MEM1 && opx == OP_TYPE_RN ) return OP_MEM_10 ; if ( opy == OP_TYPE_MEM1 && opx == OP_TYPE_MEM1 ) { switch ( get_attr_opx_access ( insn ) ) { case OPX_ACCESS_W : return OP_MEM_11 ; default : gcc_assert ( ! reload_completed ) ; return OP_MEM_11 ; } } if ( opy == OP_TYPE_MEM1 && opx == OP_TYPE_MEM6 ) { switch ( get_attr_opx_access ( insn ) ) { case OPX_ACCESS_W : return OP_MEM_1I ; default : gcc_assert ( ! reload_completed ) ; return OP_MEM_1I ; } } if ( opy == OP_TYPE_MEM6 && opx == OP_TYPE_RN ) return OP_MEM_I0 ; if ( opy == OP_TYPE_MEM6 && opx == OP_TYPE_MEM1 ) { switch ( get_attr_opx_access ( insn ) ) { case OPX_ACCESS_W : return OP_MEM_I1 ; default : gcc_assert ( ! reload_completed ) ; return OP_MEM_I1 ; } } gcc_assert ( opy == OP_TYPE_MEM6 && opx == OP_TYPE_MEM6 ) ; gcc_assert ( ! reload_completed ) ; return OP_MEM_I1 ; } </s>


<s> enum attr_size m68k_sched_attr_size ( rtx_insn * insn ) { switch ( sched_get_attr_size_int ( insn ) ) { case 1 : return SIZE_1 ; case 2 : return SIZE_2 ; case 3 : return SIZE_3 ; default : gcc_unreachable ( ) ; } } </s>

Return size of INSN as attribute enum value .


<s> static void m68k_sched_dfa_post_advance_cycle ( void ) { int i ; if ( ! sched_ib . enabled_p ) return ; i = max_insn_size - sched_ib . filled ; while ( -- i >= 0 ) { if ( state_transition ( curr_state , sched_ib . insn ) >= 0 ) ++ sched_ib . filled ; } } </s>

Implementation of targetm.sched.dfa_post_advance_cycle ( ) hook . It is invoked just after new cycle begins and is used here to setup number of filled words in the instruction buffer so that instructions which wo n't have all their words prefetched would be stalled for a cycle .


<s> static void m68k_sched_dfa_pre_advance_cycle ( void ) { if ( ! sched_ib . enabled_p ) return ; if ( ! cpu_unit_reservation_p ( curr_state , sched_mem_unit_code ) ) { sched_ib . filled += 2 ; if ( sched_ib . filled > sched_ib . size ) sched_ib . filled = sched_ib . size ; } } </s>

Implementation of targetm.sched.dfa_pre_advance_cycle ( ) hook . It is invoked just before current cycle finishes and is used here to track if instruction buffer got its two words this cycle .


Return how many instructions should scheduler lookahead to choose the best one .


<s> int m68k_sched_indexed_address_bypass_p ( rtx_insn * pro , rtx_insn * con ) { gcc_assert ( sched_cfv4_bypass_data . pro == NULL && sched_cfv4_bypass_data . con == NULL && sched_cfv4_bypass_data . scale == 0 ) ; switch ( sched_get_indexed_address_scale ( pro , con ) ) { case 1 : sched_cfv4_bypass_data . pro = pro ; sched_cfv4_bypass_data . con = con ; sched_cfv4_bypass_data . scale = 1 ; return 0 ; case 2 : case 4 : return 1 ; default : return 0 ; } } </s>

Return non-zero if PRO modifies register used as index with scale 2 or 4 in CON .


<s> static int m68k_sched_issue_rate ( void ) { switch ( m68k_sched_cpu ) { case CPU_CFV1 : case CPU_CFV2 : case CPU_CFV3 : return 1 ; case CPU_CFV4 : return 2 ; default : gcc_unreachable ( ) ; return 0 ; } } </s>

Return maximal number of insns that can be scheduled on a single cycle .


<s> enum reg_class m68k_secondary_reload_class ( enum reg_class rclass , machine_mode mode , rtx x ) { int regno ; regno = true_regnum ( x ) ; if ( GET_MODE_SIZE ( mode ) == 1 && reg_classes_intersect_p ( rclass , ADDR_REGS ) && ! ( INT_REGNO_P ( regno ) || CONSTANT_P ( x ) ) ) return DATA_REGS ; if ( TARGET_PCREL && ! reg_class_subset_p ( rclass , ADDR_REGS ) && symbolic_operand ( x , VOIDmode ) ) return ADDR_REGS ; return NO_REGS ; } </s>


<s> static void m68k_set_frame_related ( rtx_insn * insn ) { rtx body ; int i ; RTX_FRAME_RELATED_P ( insn ) = 1 ; body = PATTERN ( insn ) ; if ( GET_CODE ( body ) == PARALLEL ) for ( i = 0 ; i < XVECLEN ( body , 0 ) ; i ++ ) RTX_FRAME_RELATED_P ( XVECEXP ( body , 0 , i ) ) = 1 ; } </s>


<s> static void m68k_split_offset ( rtx x , rtx * base , HOST_WIDE_INT * offset ) { * offset = 0 ; if ( GET_CODE ( x ) == PLUS && GET_CODE ( XEXP ( x , 1 ) ) == CONST_INT ) { * offset += INTVAL ( XEXP ( x , 1 ) ) ; x = XEXP ( x , 0 ) ; } * base = x ; } </s>

Split X into a base and a constant offset , storing them in * BASE and * OFFSET respectively .


<s> static rtx m68k_struct_value_rtx ( tree fntype ATTRIBUTE_UNUSED , int incoming ATTRIBUTE_UNUSED ) { return gen_rtx_REG ( Pmode , M68K_STRUCT_VALUE_REGNUM ) ; } </s>

Worker function for TARGET_STRUCT_VALUE_RTX .


<s> bool m68k_tls_reference_p ( rtx x , bool legitimate_p ) { if ( ! TARGET_HAVE_TLS ) return false ; if ( ! legitimate_p ) { subrtx_var_iterator :: array_type array ; FOR_EACH_SUBRTX_VAR ( iter , array , x , ALL ) { rtx x = * iter ; if ( GET_CODE ( x ) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL ( x ) != 0 ) return true ; if ( m68k_tls_reference_p ( x , true ) ) iter . skip_subrtxes ( ) ; } return false ; } else { enum m68k_reloc reloc = RELOC_GOT ; return ( m68k_unwrap_symbol_1 ( x , true , & reloc ) != x && TLS_RELOC_P ( reloc ) ) ; } } </s>

If ! LEGITIMATE_P , return true if X is a TLS symbol reference , though illegitimate one . If LEGITIMATE_P , return true if X is a legitimate TLS symbol reference .


<s> static bool m68k_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>


<s> static void m68k_trampoline_init ( rtx m_tramp , tree fndecl , rtx chain_value ) { rtx fnaddr = XEXP ( DECL_RTL ( fndecl ) , 0 ) ; rtx mem ; gcc_assert ( ADDRESS_REGNO_P ( STATIC_CHAIN_REGNUM ) ) ; mem = adjust_address ( m_tramp , HImode , 0 ) ; emit_move_insn ( mem , GEN_INT ( 0x207C + ( ( STATIC_CHAIN_REGNUM - 8 ) << 9 ) ) ) ; mem = adjust_address ( m_tramp , SImode , 2 ) ; emit_move_insn ( mem , chain_value ) ; mem = adjust_address ( m_tramp , HImode , 6 ) ; emit_move_insn ( mem , GEN_INT ( 0x4EF9 ) ) ; mem = adjust_address ( m_tramp , SImode , 8 ) ; emit_move_insn ( mem , fnaddr ) ; FINALIZE_TRAMPOLINE ( XEXP ( m_tramp , 0 ) ) ; } </s>

We generate a two-instructions program at M_TRAMP : movea.l & CHAIN_VALUE , % a0 jmp FNADDR where % a0 can be modified by changing STATIC_CHAIN_REGNUM .


<s> rtx m68k_unwrap_symbol ( rtx orig , bool unwrap_reloc32_p ) { return m68k_unwrap_symbol_1 ( orig , unwrap_reloc32_p , NULL ) ; } </s>

Unwrap symbol from UNSPEC_RELOC16 and , if unwrap_reloc32_p , UNSPEC_RELOC32 wrappers .


<s> static rtx m68k_unwrap_symbol_1 ( rtx orig , bool unwrap_reloc32_p , enum m68k_reloc * reloc_ptr ) { if ( GET_CODE ( orig ) == CONST ) { rtx x ; enum m68k_reloc dummy ; x = XEXP ( orig , 0 ) ; if ( reloc_ptr == NULL ) reloc_ptr = & dummy ; if ( ( GET_CODE ( x ) == PLUS || GET_CODE ( x ) == MINUS ) && CONST_INT_P ( XEXP ( x , 1 ) ) ) x = XEXP ( x , 0 ) ; if ( GET_CODE ( x ) == UNSPEC ) { switch ( XINT ( x , 1 ) ) { case UNSPEC_RELOC16 : orig = XVECEXP ( x , 0 , 0 ) ; * reloc_ptr = ( enum m68k_reloc ) INTVAL ( XVECEXP ( x , 0 , 1 ) ) ; break ; case UNSPEC_RELOC32 : if ( unwrap_reloc32_p ) { orig = XVECEXP ( x , 0 , 0 ) ; * reloc_ptr = ( enum m68k_reloc ) INTVAL ( XVECEXP ( x , 0 , 1 ) ) ; } break ; default : break ; } } } return orig ; } </s>

Helper for m68k_unwrap_symbol . Also , if unwrapping was successful ( that is if ( ORIG ! = < return value > ) ) , sets * RELOC_PTR to relocation type for the symbol .


<s> bool m68k_use_return_insn ( void ) { if ( ! reload_completed || frame_pointer_needed || get_frame_size ( ) != 0 ) return false ; m68k_compute_frame_layout ( ) ; return current_frame . offset == 0 ; } </s>

Return true if a simple ( return ) instruction is sufficient for this instruction ( i.e . if no epilogue is needed ) .


<s> static rtx m68k_wrap_symbol ( rtx x , enum m68k_reloc reloc , rtx base_reg , rtx temp_reg ) { bool use_x_p ; use_x_p = ( base_reg == pic_offset_table_rtx ) ? TARGET_XGOT : TARGET_XTLS ; if ( TARGET_COLDFIRE && use_x_p ) { x = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( reloc ) ) , UNSPEC_RELOC32 ) ; x = gen_rtx_CONST ( Pmode , x ) ; if ( temp_reg == NULL ) { gcc_assert ( can_create_pseudo_p ( ) ) ; temp_reg = gen_reg_rtx ( Pmode ) ; } emit_move_insn ( temp_reg , x ) ; emit_insn ( gen_addsi3 ( temp_reg , temp_reg , base_reg ) ) ; x = temp_reg ; } else { x = gen_rtx_UNSPEC ( Pmode , gen_rtvec ( 2 , x , GEN_INT ( reloc ) ) , UNSPEC_RELOC16 ) ; x = gen_rtx_CONST ( Pmode , x ) ; x = gen_rtx_PLUS ( Pmode , base_reg , x ) ; } return x ; } </s>

Wrap symbol X into unspec representing relocation RELOC . BASE_REG - register that should be added to the result . TEMP_REG - if non-null , temporary register .


<s> static rtx m68k_wrap_symbol_into_got_ref ( rtx x , enum m68k_reloc reloc , rtx temp_reg ) { x = m68k_wrap_symbol ( x , reloc , m68k_get_gp ( ) , temp_reg ) ; x = gen_rtx_MEM ( Pmode , x ) ; MEM_READONLY_P ( x ) = 1 ; return x ; } </s>

Does the same as m68k_wrap_symbol , but returns a memory reference to GOT slot .


<s>
const
char
*
output_addsi3
(
rtx
*
operands
)
{
if
(
!
operands_match_p
(
operands
[
0
]
,
operands
[
1
]
)
)
{
if
(
!
ADDRESS_REG_P
(
operands
[
1
]
)
)
{
rtx
tmp
=
operands
[
1
]
;
operands
[
1
]
=
operands
[
2
]
;
operands
[
2
]
=
tmp
;
}
if
(
GET_CODE
(
operands
[
2
]
)
==
CONST_INT
&&
(
INTVAL
(
operands
[
2
]
)
<
32768
||
INTVAL
(
operands
[
2
]
)
>
32767
)
)
return
"move%.l %2,%0\n\tadd%.l %1,%0"
;
if
(
GET_CODE
(
operands
[
2
]
)
==
REG
)
return
MOTOROLA
"lea (%1,%2.l),%0"
:
"lea %1@(0,%2:l),%0"
;
return
MOTOROLA
"lea (%c2,%1),%0"
:
"lea %1@(%c2),%0"
;
}
if
(
GET_CODE
(
operands
[
2
]
)
==
CONST_INT
)
{
if
(
INTVAL
(
operands
[
2
]
)
>
0
&&
INTVAL
(
operands
[
2
]
)
<=
8
)
return
"addq%.l %2,%0"
;
if
(
INTVAL
(
operands
[
2
]
)
<
0
&&
INTVAL
(
operands
[
2
]
)
>=
8
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
)
;
return
"subq%.l %2,%0"
;
}
if
(
TUNE_CPU32
&&
REG_P
(
operands
[
0
]
)
)
{
if
(
INTVAL
(
operands
[
2
]
)
>
8
&&
INTVAL
(
operands
[
2
]
)
<=
16
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
8
)
;
return
"addq%.l #8,%0\n\taddq%.l %2,%0"
;
}
if
(
INTVAL
(
operands
[
2
]
)
<
8
&&
INTVAL
(
operands
[
2
]
)
>=
16
)
{
operands
[
2
]
=
GEN_INT
(
INTVAL
(
operands
[
2
]
)
8
)
;
return
"subq%.l #8,%0\n\tsubq%.l %2,%0"
;
}
}
if
(
ADDRESS_REG_P
(
operands
[
0
]
)
&&
INTVAL
(
operands
[
2
]
)
>=
0x8000
&&
INTVAL
(
operands
[
2
]
)
<
0x8000
)
{
if
(
TUNE_68040
)
return
"add%.w %2,%0"
;
else
return
MOTOROLA
"lea (%c2,%0),%0"
:
"lea %0@(%c2),%0"
;
}
}
return
"add%.l %2,%0"
;
}
</s>

Output assembler code to perform a 32 bit 3 operand add .


<s>
const
char
*
output_call
(
rtx
x
)
{
if
(
symbolic_operand
(
x
,
VOIDmode
)
)
return
m68k_symbolic_call
;
else
return
"jsr %a0"
;
}
</s>

INSN is either a function call or a millicode call . It may have an unconditional jump in its delay slot . CALL_DEST is the routine we are calling .


<s>
static
void
output_compadr
(
rtx
operands
[
2
]
)
{
output_asm_insn
(
"lea %a1,%0"
,
operands
)
;
}
</s>

Output assembler to load address OPERANDS [ 0 ] to register OPERANDS [ 1 ] .


<s>
void
output_dbcc_and_branch
(
rtx
*
operands
,
rtx_code
code
)
{
switch
(
code
)
{
case
EQ
:
output_asm_insn
(
"dbeq %0,%l1\n\tjeq %l2"
,
operands
)
;
break
;
case
NE
:
output_asm_insn
(
"dbne %0,%l1\n\tjne %l2"
,
operands
)
;
break
;
case
GT
:
output_asm_insn
(
"dbgt %0,%l1\n\tjgt %l2"
,
operands
)
;
break
;
case
GTU
:
output_asm_insn
(
"dbhi %0,%l1\n\tjhi %l2"
,
operands
)
;
break
;
case
LT
:
output_asm_insn
(
"dblt %0,%l1\n\tjlt %l2"
,
operands
)
;
break
;
case
LTU
:
output_asm_insn
(
"dbcs %0,%l1\n\tjcs %l2"
,
operands
)
;
break
;
case
GE
:
output_asm_insn
(
"dbge %0,%l1\n\tjge %l2"
,
operands
)
;
break
;
case
GEU
:
output_asm_insn
(
"dbcc %0,%l1\n\tjcc %l2"
,
operands
)
;
break
;
case
LE
:
output_asm_insn
(
"dble %0,%l1\n\tjle %l2"
,
operands
)
;
break
;
case
LEU
:
output_asm_insn
(
"dbls %0,%l1\n\tjls %l2"
,
operands
)
;
break
;
case
PLUS
:
output_asm_insn
(
"dbpl %0,%l1\n\tjle %l2"
,
operands
)
;
break
;
case
MINUS
:
output_asm_insn
(
"dbmi %0,%l1\n\tjle %l2"
,
operands
)
;
break
;
default
:
gcc_unreachable
(
)
;
}
switch
(
GET_MODE
(
operands
[
0
]
)
)
{
case
E_SImode
:
output_asm_insn
(
"clr%.w %0\n\tsubq%.l #1,%0\n\tjpl %l1"
,
operands
)
;
break
;
case
E_HImode
:
break
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Output a dbCC ; jCC sequence . Note we do not handle the floating point version of this sequence ( Fdbcc ) . We also do not handle alternative conditions when CC_NO_OVERFLOW is set . It is assumed that valid_dbcc_comparison_p and flags_in_68881 will kick those out before we get here .


<s>
static
const
char
*
output_move_const_into_data_reg
(
rtx
*
operands
)
{
HOST_WIDE_INT
i
;
i
=
INTVAL
(
operands
[
1
]
)
;
switch
(
m68k_const_method
(
i
)
)
{
case
MVZ
:
return
"mvzw %1,%0"
;
case
MVS
:
return
"mvsw %1,%0"
;
case
MOVQ
:
return
"moveq %1,%0"
;
case
NOTB
:
CC_STATUS_INIT
;
operands
[
1
]
=
GEN_INT
(
i
^
0xff
)
;
return
"moveq %1,%0\n\tnot%.b %0"
;
case
NOTW
:
CC_STATUS_INIT
;
operands
[
1
]
=
GEN_INT
(
i
^
0xffff
)
;
return
"moveq %1,%0\n\tnot%.w %0"
;
case
NEGW
:
CC_STATUS_INIT
;
return
"moveq #-128,%0\n\tneg%.w %0"
;
case
SWAP
:
{
unsigned
u
=
i
;
operands
[
1
]
=
GEN_INT
(
(
u
<<
16
)
|
(
u
>>
16
)
)
;
return
"moveq %1,%0\n\tswap %0"
;
}
case
MOVL
:
return
"move%.l %1,%0"
;
default
:
gcc_unreachable
(
)
;
}
}
</s>

Return an instruction to move CONST_INT OPERANDS [ 1 ] into data register OPERANDS [ 0 ] .


<s> const char * output_move_double ( rtx * operands ) { handle_move_double ( operands , output_reg_adjust , output_compadr , output_movsi ) ; return "" ; } </s>

Return appropriate code to load up an 8 byte integer or floating point value


<s>
static
const
char
*
output_move_simode_const
(
rtx
*
operands
)
{
rtx
dest
;
HOST_WIDE_INT
src
;
dest
=
operands
[
0
]
;
src
=
INTVAL
(
operands
[
1
]
)
;
if
(
src
==
0
&&
(
DATA_REG_P
(
dest
)
||
MEM_P
(
dest
)
)
&&
(
(
TARGET_68010
||
TARGET_COLDFIRE
)
||
!
(
MEM_P
(
dest
)
&&
MEM_VOLATILE_P
(
dest
)
)
)
)
return
"clr%.l %0"
;
else
if
(
GET_MODE
(
dest
)
==
SImode
&&
valid_mov3q_const
(
src
)
)
return
"mov3q%.l %1,%0"
;
else
if
(
src
==
0
&&
ADDRESS_REG_P
(
dest
)
)
return
"sub%.l %0,%0"
;
else
if
(
DATA_REG_P
(
dest
)
)
return
output_move_const_into_data_reg
(
operands
)
;
else
if
(
ADDRESS_REG_P
(
dest
)
&&
IN_RANGE
(
src
,
0x8000
,
0x7fff
)
)
{
if
(
valid_mov3q_const
(
src
)
)
return
"mov3q%.l %1,%0"
;
return
"move%.w %1,%0"
;
}
else
if
(
MEM_P
(
dest
)
&&
GET_CODE
(
XEXP
(
dest
,
0
)
)
==
PRE_DEC
&&
REGNO
(
XEXP
(
XEXP
(
dest
,
0
)
,
0
)
)
==
STACK_POINTER_REGNUM
&&
IN_RANGE
(
src
,
0x8000
,
0x7fff
)
)
{
if
(
valid_mov3q_const
(
src
)
)
return
"mov3q%.l %1,%-"
;
return
"pea %a1"
;
}
return
"move%.l %1,%0"
;
}
</s>

Return an instruction to move CONST_INT OPERANDS [ 1 ] into OPERANDS [ 0 ] . I is the value of OPERANDS [ 1 ] .


<s> static void output_movsi ( rtx operands [ 2 ] ) { output_asm_insn ( singlemove_string ( operands ) , operands ) ; } </s>

Output the best assembler insn for moving operands [ 1 ] into operands [ 0 ] as a fullword .