#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "function.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "recog.h"
#include "toplev.h"
#include "expr.h"
#include "reload.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
#include "debug.h"
#include "flags.h"
#ifdef SUPPORT_SUN_FPA
const enum reg_class regno_reg_class[]
= { DATA_REGS, ADDR_REGS, FP_REGS,
LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
#endif
int switch_table_difference_label_flag;
static rtx find_addr_reg PARAMS ((rtx));
static const char *singlemove_string PARAMS ((rtx *));
static void m68k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void m68k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void m68k_coff_asm_named_section PARAMS ((const char *, unsigned int));
#ifdef CTOR_LIST_BEGIN
static void m68k_svr3_asm_out_constructor PARAMS ((rtx, int));
#endif
static void m68k_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree));
static int m68k_save_reg PARAMS ((unsigned int));
const char *m68k_align_loops_string;
const char *m68k_align_jumps_string;
const char *m68k_align_funcs_string;
int m68k_align_loops;
int m68k_align_jumps;
int m68k_align_funcs;
int m68k_last_compare_had_fp_operands;
#if INT_OP_GROUP == INT_OP_DOT_WORD
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
#endif
#if INT_OP_GROUP == INT_OP_NO_DOT
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP "\tbyte\t"
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\tshort\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\tlong\t"
#endif
#if INT_OP_GROUP == INT_OP_DC
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP "\tdc.b\t"
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\tdc.w\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\tdc.l\t"
#endif
#undef TARGET_ASM_UNALIGNED_HI_OP
#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_UNALIGNED_SI_OP
#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE m68k_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE m68k_output_function_epilogue
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK m68k_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
struct gcc_target targetm = TARGET_INITIALIZER;
void
override_options ()
{
int def_align;
int i;
def_align = 1;
m68k_align_loops = def_align;
if (m68k_align_loops_string)
{
i = atoi (m68k_align_loops_string);
if (i < 1 || i > MAX_CODE_ALIGN)
error ("-malign-loops=%d is not between 1 and %d", i, MAX_CODE_ALIGN);
else
m68k_align_loops = i;
}
m68k_align_jumps = def_align;
if (m68k_align_jumps_string)
{
i = atoi (m68k_align_jumps_string);
if (i < 1 || i > MAX_CODE_ALIGN)
error ("-malign-jumps=%d is not between 1 and %d", i, MAX_CODE_ALIGN);
else
m68k_align_jumps = i;
}
m68k_align_funcs = def_align;
if (m68k_align_funcs_string)
{
i = atoi (m68k_align_funcs_string);
if (i < 1 || i > MAX_CODE_ALIGN)
error ("-malign-functions=%d is not between 1 and %d",
i, MAX_CODE_ALIGN);
else
m68k_align_funcs = i;
}
if (! TARGET_68020 && flag_pic == 2)
error("-fPIC is not currently supported on the 68000 or 68010\n");
if (TARGET_PCREL && flag_pic == 0)
flag_pic = 1;
if (flag_pic)
flag_no_function_cse = 1;
SUBTARGET_OVERRIDE_OPTIONS;
real_format_for_mode[XFmode - QFmode] = &ieee_extended_motorola_format;
}
static int
m68k_save_reg (regno)
unsigned int regno;
{
if (flag_pic && current_function_uses_pic_offset_table
&& regno == PIC_OFFSET_TABLE_REGNUM)
return 1;
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 1;
}
}
return (regs_ever_live[regno]
&& !call_used_regs[regno]
&& !fixed_regs[regno]
&& !(regno == FRAME_POINTER_REGNUM && frame_pointer_needed));
}
#ifdef CRDS
static void
m68k_output_function_prologue (stream, size)
FILE *stream;
HOST_WIDE_INT size;
{
register int regno;
register int mask = 0;
HOST_WIDE_INT fsize = ((size) + 3) & -4;
if (fsize > 30000)
{
fprintf (stream, "\tmovel sp,a0\n");
fprintf (stream, "\taddl $-%d,a0\n", 2048 + fsize);
fprintf (stream, "\ttstb (a0)\n");
}
else
fprintf (stream, "\ttstb -%d(sp)\n", 2048 + fsize);
if (frame_pointer_needed)
{
if (TARGET_68020 || fsize < 0x8000)
fprintf (stream, "\tlink a6,$%d\n", -fsize);
else
fprintf (stream, "\tlink a6,$0\n\tsubl $%d,sp\n", fsize);
}
else if (fsize)
{
if (fsize + 4 < 0x8000)
fprintf (stream, "\tadd.w $%d,sp\n", - (fsize + 4));
else
fprintf (stream, "\tadd.l $%d,sp\n", - (fsize + 4));
}
for (regno = 16; regno < 24; regno++)
if (m68k_save_reg (regno))
mask |= 1 << (regno - 16);
if ((mask & 0xff) != 0)
fprintf (stream, "\tfmovem $0x%x,-(sp)\n", mask & 0xff);
mask = 0;
for (regno = 0; regno < 16; regno++)
if (m68k_save_reg (regno))
mask |= 1 << (15 - regno);
if (exact_log2 (mask) >= 0)
fprintf (stream, "\tmovel %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]);
else if (mask)
fprintf (stream, "\tmovem $0x%x,-(sp)\n", mask);
}
#else
static void
m68k_output_function_prologue (stream, size)
FILE *stream;
HOST_WIDE_INT size;
{
register int regno;
register int mask = 0;
int num_saved_regs = 0;
HOST_WIDE_INT fsize = (size + 3) & -4;
HOST_WIDE_INT cfa_offset = INCOMING_FRAME_SP_OFFSET;
HOST_WIDE_INT cfa_store_offset = cfa_offset;
if (current_function_limit_stack
&& GET_CODE (stack_limit_rtx) == SYMBOL_REF)
{
#if defined (MOTOROLA)
asm_fprintf (stream, "\tcmp.l %0I%s+%d,%Rsp\n\ttrapcs\n",
XSTR (stack_limit_rtx, 0), fsize + 4);
#else
asm_fprintf (stream, "\tcmpl %0I%s+%d,%Rsp\n\ttrapcs\n",
XSTR (stack_limit_rtx, 0), fsize + 4);
#endif
}
if (frame_pointer_needed)
{
if (fsize == 0 && TARGET_68040)
{
#ifdef MOTOROLA
fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n",
reg_names[FRAME_POINTER_REGNUM],
reg_names[STACK_POINTER_REGNUM],
reg_names[FRAME_POINTER_REGNUM]);
#else
fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n",
reg_names[FRAME_POINTER_REGNUM],
reg_names[STACK_POINTER_REGNUM],
reg_names[FRAME_POINTER_REGNUM]);
#endif
}
else if (fsize < 0x8000)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.w %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
else if (TARGET_68020)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.l %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I%d\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#else
asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
#endif
}
if (dwarf2out_do_frame ())
{
char *l;
l = (char *) dwarf2out_cfi_label ();
cfa_store_offset += 4;
cfa_offset = cfa_store_offset;
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset);
dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, cfa_offset);
cfa_store_offset += fsize;
}
}
else if (fsize)
{
if (fsize + 4 < 0x8000)
{
#ifndef NO_ADDSUB_Q
if (fsize + 4 <= 8)
{
if (!TARGET_5200)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tsubq.w %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\tsubqw %0I%d,%Rsp\n", fsize + 4);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tsubq.l %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\tsubql %0I%d,%Rsp\n", fsize + 4);
#endif
}
}
else if (fsize + 4 <= 16 && TARGET_CPU32)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tsubq.w %0I8,%Rsp\n\tsubq.w %0I%d,%Rsp\n",
fsize + 4 - 8);
#else
asm_fprintf (stream, "\tsubqw %0I8,%Rsp\n\tsubqw %0I%d,%Rsp\n",
fsize + 4 - 8);
#endif
}
else
#endif
if (TARGET_68040)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
#else
asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", - (fsize + 4));
#else
asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", - (fsize + 4));
#endif
}
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
#else
asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));
#endif
}
if (dwarf2out_do_frame ())
{
cfa_store_offset += fsize + 4;
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
}
}
#ifdef SUPPORT_SUN_FPA
for (regno = 24; regno < 56; regno++)
if (m68k_save_reg (regno))
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n",
reg_names[regno]);
#else
asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n",
reg_names[regno]);
#endif
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
cfa_store_offset += 8;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
}
dwarf2out_reg_save (l, regno, -cfa_store_offset);
}
}
#endif
if (TARGET_68881)
{
for (regno = 16; regno < 24; regno++)
if (m68k_save_reg (regno))
{
mask |= 1 << (regno - 16);
num_saved_regs++;
}
if ((mask & 0xff) != 0)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
#else
asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
#endif
if (dwarf2out_do_frame ())
{
char *l = (char *) dwarf2out_cfi_label ();
int n_regs;
cfa_store_offset += num_saved_regs * 12;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
}
for (regno = 16, n_regs = 0; regno < 24; regno++)
if (mask & (1 << (regno - 16)))
dwarf2out_reg_save (l, regno,
-cfa_store_offset + n_regs++ * 12);
}
}
mask = 0;
num_saved_regs = 0;
}
for (regno = 0; regno < 16; regno++)
if (m68k_save_reg (regno))
{
mask |= 1 << (15 - regno);
num_saved_regs++;
}
#if NEED_PROBE
#ifdef MOTOROLA
asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
#else
asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
#endif
#endif
if (current_function_limit_stack)
{
if (REG_P (stack_limit_rtx))
{
#if defined (MOTOROLA)
asm_fprintf (stream, "\tcmp.l %s,%Rsp\n\ttrapcs\n",
reg_names[REGNO (stack_limit_rtx)]);
#else
asm_fprintf (stream, "\tcmpl %s,%Rsp\n\ttrapcs\n",
reg_names[REGNO (stack_limit_rtx)]);
#endif
}
else if (GET_CODE (stack_limit_rtx) != SYMBOL_REF)
warning ("stack limit expression is not supported");
}
if (num_saved_regs <= 2)
{
int i;
for (i = 0; i< 16; i++)
if (mask & (1 << i))
{
asm_fprintf (stream,
#ifdef MOTOROLA
"\t%Omove.l %s,-(%Rsp)\n",
#else
"\tmovel %s,%Rsp@-\n",
#endif
reg_names[15 - i]);
if (dwarf2out_do_frame ())
{
char *l = (char *) dwarf2out_cfi_label ();
cfa_store_offset += 4;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
}
dwarf2out_reg_save (l, 15 - i, -cfa_store_offset);
}
}
}
else if (mask)
{
if (TARGET_5200)
{
int newmask = 0;
int i;
for (i = 0; i < 16; i++)
if (mask & (1 << i))
newmask |= (1 << (15-i));
#ifdef MOTOROLA
asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4);
asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);
#else
asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4);
asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
#else
asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
#endif
}
if (dwarf2out_do_frame ())
{
char *l = (char *) dwarf2out_cfi_label ();
int n_regs;
cfa_store_offset += num_saved_regs * 4;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
}
for (regno = 0, n_regs = 0; regno < 16; regno++)
if (mask & (1 << (15 - regno)))
dwarf2out_reg_save (l, regno,
-cfa_store_offset + n_regs++ * 4);
}
}
if (flag_pic && current_function_uses_pic_offset_table)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM]);
#else
asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM]);
asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n",
reg_names[PIC_OFFSET_TABLE_REGNUM],
reg_names[PIC_OFFSET_TABLE_REGNUM]);
#endif
}
}
#endif
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 (m68k_save_reg (regno))
return 0;
return 1;
}
#ifdef CRDS
static void
m68k_output_function_epilogue (stream, size)
FILE *stream;
HOST_WIDE_INT size;
{
register int regno;
register int mask, fmask;
register int nregs;
HOST_WIDE_INT offset, foffset, fpoffset;
HOST_WIDE_INT fsize = ((size) + 3) & -4;
int big = 0;
nregs = 0; fmask = 0; fpoffset = 0;
for (regno = 16; regno < 24; regno++)
if (m68k_save_reg (regno))
{
nregs++;
fmask |= 1 << (23 - regno);
}
foffset = fpoffset + nregs * 12;
nregs = 0; mask = 0;
for (regno = 0; regno < 16; regno++)
if (m68k_save_reg (regno))
{
nregs++;
mask |= 1 << regno;
}
offset = foffset + nregs * 4;
if (offset + fsize >= 0x8000
&& frame_pointer_needed
&& (mask || fmask || fpoffset))
{
fprintf (stream, "\tmovel $%d,a0\n", -fsize);
fsize = 0, big = 1;
}
if (exact_log2 (mask) >= 0)
{
if (big)
fprintf (stream, "\tmovel -%d(a6,a0.l),%s\n",
offset + fsize, reg_names[exact_log2 (mask)]);
else if (! frame_pointer_needed)
fprintf (stream, "\tmovel (sp)+,%s\n",
reg_names[exact_log2 (mask)]);
else
fprintf (stream, "\tmovel -%d(a6),%s\n",
offset + fsize, reg_names[exact_log2 (mask)]);
}
else if (mask)
{
if (big)
fprintf (stream, "\tmovem -%d(a6,a0.l),$0x%x\n",
offset + fsize, mask);
else if (! frame_pointer_needed)
fprintf (stream, "\tmovem (sp)+,$0x%x\n", mask);
else
fprintf (stream, "\tmovem -%d(a6),$0x%x\n",
offset + fsize, mask);
}
if (fmask)
{
if (big)
fprintf (stream, "\tfmovem -%d(a6,a0.l),$0x%x\n",
foffset + fsize, fmask);
else if (! frame_pointer_needed)
fprintf (stream, "\tfmovem (sp)+,$0x%x\n", fmask);
else
fprintf (stream, "\tfmovem -%d(a6),$0x%x\n",
foffset + fsize, fmask);
}
if (fpoffset != 0)
for (regno = 55; regno >= 24; regno--)
if (m68k_save_reg (regno))
{
if (big)
fprintf(stream, "\tfpmoved -%d(a6,a0.l), %s\n",
fpoffset + fsize, reg_names[regno]);
else if (! frame_pointer_needed)
fprintf(stream, "\tfpmoved (sp)+, %s\n",
reg_names[regno]);
else
fprintf(stream, "\tfpmoved -%d(a6), %s\n",
fpoffset + fsize, reg_names[regno]);
fpoffset -= 8;
}
if (frame_pointer_needed)
fprintf (stream, "\tunlk a6\n");
else if (fsize)
{
if (fsize + 4 < 0x8000)
fprintf (stream, "\tadd.w $%d,sp\n", fsize + 4);
else
fprintf (stream, "\tadd.l $%d,sp\n", fsize + 4);
}
if (current_function_calls_eh_return)
fprintf (stream, "\tadd.l a0,sp\n");
if (current_function_pops_args)
fprintf (stream, "\trtd $%d\n", current_function_pops_args);
else
fprintf (stream, "\trts\n");
}
#else
static void
m68k_output_function_epilogue (stream, size)
FILE *stream;
HOST_WIDE_INT size;
{
register int regno;
register int mask, fmask;
register int nregs;
HOST_WIDE_INT offset, foffset, fpoffset;
HOST_WIDE_INT fsize = (size + 3) & -4;
int big = 0;
rtx insn = get_last_insn ();
int restore_from_sp = 0;
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
{
fprintf (stream, "\tnop\n");
return;
}
#ifdef FUNCTION_EXTRA_EPILOGUE
FUNCTION_EXTRA_EPILOGUE (stream, size);
#endif
nregs = 0; fmask = 0; fpoffset = 0;
#ifdef SUPPORT_SUN_FPA
for (regno = 24 ; regno < 56 ; regno++)
if (m68k_save_reg (regno))
nregs++;
fpoffset = nregs * 8;
#endif
nregs = 0;
if (TARGET_68881)
{
for (regno = 16; regno < 24; regno++)
if (m68k_save_reg (regno))
{
nregs++;
fmask |= 1 << (23 - regno);
}
}
foffset = fpoffset + nregs * 12;
nregs = 0; mask = 0;
for (regno = 0; regno < 16; regno++)
if (m68k_save_reg (regno))
{
nregs++;
mask |= 1 << regno;
}
offset = foffset + nregs * 4;
restore_from_sp = ! frame_pointer_needed
|| (! current_function_calls_alloca && leaf_function_p ());
if (offset + fsize >= 0x8000
&& ! restore_from_sp
&& (mask || fmask || fpoffset))
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize);
#else
asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize);
#endif
fsize = 0, big = 1;
}
if (TARGET_5200 || nregs <= 2)
{
int i;
for (i = 0; i< 16; i++)
if (mask & (1 << i))
{
if (big)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n",
offset + fsize,
reg_names[FRAME_POINTER_REGNUM],
reg_names[i]);
#else
asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, reg_names[i]);
#endif
}
else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n",
reg_names[i]);
#else
asm_fprintf (stream, "\tmovel %Rsp@+,%s\n",
reg_names[i]);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n",
offset + fsize,
reg_names[FRAME_POINTER_REGNUM],
reg_names[i]);
#else
fprintf (stream, "\tmovel %s@(-%d),%s\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, reg_names[i]);
#endif
}
offset = offset - 4;
}
}
else if (mask)
{
if (big)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n",
offset + fsize,
reg_names[FRAME_POINTER_REGNUM],
mask);
#else
asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, mask);
#endif
}
else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
#else
asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n",
offset + fsize,
reg_names[FRAME_POINTER_REGNUM],
mask);
#else
asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, mask);
#endif
}
}
if (fmask)
{
if (big)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n",
foffset + fsize,
reg_names[FRAME_POINTER_REGNUM],
fmask);
#else
asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
foffset + fsize, fmask);
#endif
}
else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);
#else
asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n",
foffset + fsize,
reg_names[FRAME_POINTER_REGNUM],
fmask);
#else
asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
foffset + fsize, fmask);
#endif
}
}
if (fpoffset != 0)
for (regno = 55; regno >= 24; regno--)
if (m68k_save_reg (regno))
{
if (big)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n",
fpoffset + fsize,
reg_names[FRAME_POINTER_REGNUM],
reg_names[regno]);
#else
asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n",
reg_names[FRAME_POINTER_REGNUM],
fpoffset + fsize, reg_names[regno]);
#endif
}
else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n",
reg_names[regno]);
#else
asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n",
reg_names[regno]);
#endif
}
else
{
#ifdef MOTOROLA
fprintf (stream, "\tfpmovd -%d(%s), %s\n",
fpoffset + fsize,
reg_names[FRAME_POINTER_REGNUM],
reg_names[regno]);
#else
fprintf (stream, "\tfpmoved %s@(-%d), %s\n",
reg_names[FRAME_POINTER_REGNUM],
fpoffset + fsize, reg_names[regno]);
#endif
}
fpoffset -= 8;
}
if (frame_pointer_needed)
fprintf (stream, "\tunlk %s\n",
reg_names[FRAME_POINTER_REGNUM]);
else if (fsize)
{
#ifndef NO_ADDSUB_Q
if (fsize + 4 <= 8)
{
if (!TARGET_5200)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\taddq.w %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\taddqw %0I%d,%Rsp\n", fsize + 4);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\taddq.l %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\taddql %0I%d,%Rsp\n", fsize + 4);
#endif
}
}
else if (fsize + 4 <= 16 && TARGET_CPU32)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\taddq.w %0I8,%Rsp\n\taddq.w %0I%d,%Rsp\n",
fsize + 4 - 8);
#else
asm_fprintf (stream, "\taddqw %0I8,%Rsp\n\taddqw %0I%d,%Rsp\n",
fsize + 4 - 8);
#endif
}
else
#endif
if (fsize + 4 < 0x8000)
{
if (TARGET_68040)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
#endif
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4);
#endif
}
}
else
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);
#else
asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4);
#endif
}
}
if (current_function_calls_eh_return)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %Ra0,%Rsp\n");
#else
asm_fprintf (stream, "\taddl %Ra0,%Rsp\n");
#endif
}
if (current_function_pops_args)
asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
else
fprintf (stream, "\trts\n");
}
#endif
int
not_sp_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return op != stack_pointer_rtx && nonimmediate_operand (op, mode);
}
int
valid_dbcc_comparison_p (x, mode)
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;
}
}
int
flags_in_68881 ()
{
return cc_status.flags & CC_IN_68881;
}
void
output_dbcc_and_branch (operands)
rtx *operands;
{
switch (GET_CODE (operands[3]))
{
case EQ:
#ifdef MOTOROLA
output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands);
#else
output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands);
#endif
break;
case NE:
#ifdef MOTOROLA
output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands);
#else
output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands);
#endif
break;
case GT:
#ifdef MOTOROLA
output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands);
#else
output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands);
#endif
break;
case GTU:
#ifdef MOTOROLA
output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands);
#else
output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands);
#endif
break;
case LT:
#ifdef MOTOROLA
output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands);
#else
output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands);
#endif
break;
case LTU:
#ifdef MOTOROLA
output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands);
#else
output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands);
#endif
break;
case GE:
#ifdef MOTOROLA
output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands);
#else
output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands);
#endif
break;
case GEU:
#ifdef MOTOROLA
output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands);
#else
output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands);
#endif
break;
case LE:
#ifdef MOTOROLA
output_asm_insn ("dble %0,%l1\n\tjble %l2", operands);
#else
output_asm_insn ("dble %0,%l1\n\tjle %l2", operands);
#endif
break;
case LEU:
#ifdef MOTOROLA
output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands);
#else
output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands);
#endif
break;
default:
abort ();
}
switch (GET_MODE (operands[0]))
{
case SImode:
#ifdef MOTOROLA
output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands);
#else
output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands);
#endif
break;
case HImode:
break;
default:
abort ();
}
}
const char *
output_scc_di(op, operand1, operand2, dest)
rtx op;
rtx operand1;
rtx operand2;
rtx dest;
{
rtx loperands[7];
enum rtx_code op_code = GET_CODE (op);
CC_STATUS_INIT;
if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG)
{
rtx tmp = operand1;
operand1 = operand2;
operand2 = tmp;
op_code = swap_condition (op_code);
}
loperands[0] = operand1;
if (GET_CODE (operand1) == REG)
loperands[1] = gen_rtx_REG (SImode, REGNO (operand1) + 1);
else
loperands[1] = adjust_address (operand1, SImode, 4);
if (operand2 != const0_rtx)
{
loperands[2] = operand2;
if (GET_CODE (operand2) == REG)
loperands[3] = gen_rtx_REG (SImode, REGNO (operand2) + 1);
else
loperands[3] = adjust_address (operand2, SImode, 4);
}
loperands[4] = gen_label_rtx();
if (operand2 != const0_rtx)
{
#ifdef MOTOROLA
#ifdef SGS_CMP_ORDER
output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands);
#else
output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands);
#endif
#else
#ifdef SGS_CMP_ORDER
output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands);
#else
output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands);
#endif
#endif
}
else
{
if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[0]))
output_asm_insn ("tst%.l %0", loperands);
else
{
#ifdef SGS_CMP_ORDER
output_asm_insn ("cmp%.w %0,%#0", loperands);
#else
output_asm_insn ("cmp%.w %#0,%0", loperands);
#endif
}
#ifdef MOTOROLA
output_asm_insn ("jbne %l4", loperands);
#else
output_asm_insn ("jne %l4", loperands);
#endif
if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[1]))
output_asm_insn ("tst%.l %1", loperands);
else
{
#ifdef SGS_CMP_ORDER
output_asm_insn ("cmp%.w %1,%#0", loperands);
#else
output_asm_insn ("cmp%.w %#0,%1", loperands);
#endif
}
}
loperands[5] = dest;
switch (op_code)
{
case EQ:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("seq %5", loperands);
break;
case NE:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("sne %5", loperands);
break;
case GT:
loperands[6] = gen_label_rtx();
#ifdef MOTOROLA
output_asm_insn ("shi %5\n\tjbra %l6", loperands);
#else
output_asm_insn ("shi %5\n\tjra %l6", loperands);
#endif
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("sgt %5", loperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[6]));
break;
case GTU:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("shi %5", loperands);
break;
case LT:
loperands[6] = gen_label_rtx();
#ifdef MOTOROLA
output_asm_insn ("scs %5\n\tjbra %l6", loperands);
#else
output_asm_insn ("scs %5\n\tjra %l6", loperands);
#endif
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("slt %5", loperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[6]));
break;
case LTU:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("scs %5", loperands);
break;
case GE:
loperands[6] = gen_label_rtx();
#ifdef MOTOROLA
output_asm_insn ("scc %5\n\tjbra %l6", loperands);
#else
output_asm_insn ("scc %5\n\tjra %l6", loperands);
#endif
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("sge %5", loperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[6]));
break;
case GEU:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("scc %5", loperands);
break;
case LE:
loperands[6] = gen_label_rtx();
#ifdef MOTOROLA
output_asm_insn ("sls %5\n\tjbra %l6", loperands);
#else
output_asm_insn ("sls %5\n\tjra %l6", loperands);
#endif
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("sle %5", loperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[6]));
break;
case LEU:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (loperands[4]));
output_asm_insn ("sls %5", loperands);
break;
default:
abort ();
}
return "";
}
const char *
output_btst (operands, countop, dataop, insn, signpos)
rtx *operands;
rtx countop, dataop;
rtx insn;
int signpos;
{
operands[0] = countop;
operands[1] = dataop;
if (GET_CODE (countop) == CONST_INT)
{
register int count = INTVAL (countop);
if (count > signpos)
{
int offset = (count & ~signpos) / 8;
count = count & signpos;
operands[1] = dataop = adjust_address (dataop, QImode, offset);
}
if (count == signpos)
cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
else
cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
if (count == 31
&& next_insn_tests_no_inequality (insn))
return "tst%.l %1";
if (count == 15
&& next_insn_tests_no_inequality (insn))
return "tst%.w %1";
if (count == 7
&& next_insn_tests_no_inequality (insn))
return "tst%.b %1";
cc_status.flags = CC_NOT_NEGATIVE;
}
return "btst %0,%1";
}
int
symbolic_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
#if 0
case CONST_DOUBLE:
return GET_MODE (op) == mode;
#endif
default:
return 0;
}
}
int
extend_operator(x, mode)
rtx x;
enum machine_mode mode;
{
if (mode != VOIDmode && GET_MODE(x) != mode)
return 0;
switch (GET_CODE(x))
{
case SIGN_EXTEND :
case ZERO_EXTEND :
return 1;
default :
return 0;
}
}
rtx
legitimize_pic_address (orig, mode, reg)
rtx orig, reg;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx pic_ref = orig;
if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
{
if (reg == 0)
abort ();
pic_ref = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode,
pic_offset_table_rtx, orig));
current_function_uses_pic_offset_table = 1;
RTX_UNCHANGING_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;
if (reg == 0)
abort ();
if (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);
}
else abort ();
if (GET_CODE (orig) == CONST_INT)
return plus_constant (base, INTVAL (orig));
pic_ref = gen_rtx_PLUS (Pmode, base, orig);
}
return pic_ref;
}
typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;
static CONST_METHOD const_method PARAMS ((rtx));
#define USE_MOVQ(i) ((unsigned)((i) + 128) <= 255)
static CONST_METHOD
const_method (constant)
rtx constant;
{
int i;
unsigned u;
i = INTVAL (constant);
if (USE_MOVQ (i))
return MOVQ;
if (!TARGET_5200)
{
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;
}
return MOVL;
}
int
const_int_cost (constant)
rtx constant;
{
switch (const_method (constant))
{
case MOVQ :
return 0;
case NOTB :
case NOTW :
case NEGW :
case SWAP :
return 1;
case MOVL :
return 2;
default :
abort ();
}
}
const char *
output_move_const_into_data_reg (operands)
rtx *operands;
{
int i;
i = INTVAL (operands[1]);
switch (const_method (operands[1]))
{
case MOVQ :
#if defined (MOTOROLA) && !defined (CRDS)
return "moveq%.l %1,%0";
#else
return "moveq %1,%0";
#endif
case NOTB :
operands[1] = GEN_INT (i ^ 0xff);
#if defined (MOTOROLA) && !defined (CRDS)
return "moveq%.l %1,%0\n\tnot%.b %0";
#else
return "moveq %1,%0\n\tnot%.b %0";
#endif
case NOTW :
operands[1] = GEN_INT (i ^ 0xffff);
#if defined (MOTOROLA) && !defined (CRDS)
return "moveq%.l %1,%0\n\tnot%.w %0";
#else
return "moveq %1,%0\n\tnot%.w %0";
#endif
case NEGW :
#if defined (MOTOROLA) && !defined (CRDS)
return "moveq%.l %#-128,%0\n\tneg%.w %0";
#else
return "moveq %#-128,%0\n\tneg%.w %0";
#endif
case SWAP :
{
unsigned u = i;
operands[1] = GEN_INT ((u << 16) | (u >> 16));
#if defined (MOTOROLA) && !defined (CRDS)
return "moveq%.l %1,%0\n\tswap %0";
#else
return "moveq %1,%0\n\tswap %0";
#endif
}
case MOVL :
return "move%.l %1,%0";
default :
abort ();
}
}
const char *
output_move_simode_const (operands)
rtx *operands;
{
if (operands[1] == const0_rtx
&& (DATA_REG_P (operands[0])
|| GET_CODE (operands[0]) == MEM)
&& ((TARGET_68020 || TARGET_5200)
|| !(GET_CODE (operands[0]) == MEM
&& MEM_VOLATILE_P (operands[0]))))
return "clr%.l %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)
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)
return "pea %a1";
return "move%.l %1,%0";
}
const char *
output_move_simode (operands)
rtx *operands;
{
if (GET_CODE (operands[1]) == CONST_INT)
return output_move_simode_const (operands);
else if ((GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST)
&& push_operand (operands[0], SImode))
return "pea %a1";
else if ((GET_CODE (operands[1]) == SYMBOL_REF
|| GET_CODE (operands[1]) == CONST)
&& ADDRESS_REG_P (operands[0]))
return "lea %a1,%0";
return "move%.l %1,%0";
}
const char *
output_move_himode (operands)
rtx *operands;
{
if (GET_CODE (operands[1]) == CONST_INT)
{
if (operands[1] == const0_rtx
&& (DATA_REG_P (operands[0])
|| GET_CODE (operands[0]) == MEM)
&& ((TARGET_68020 || TARGET_5200)
|| !(GET_CODE (operands[0]) == MEM
&& MEM_VOLATILE_P (operands[0]))))
return "clr%.w %0";
else if (operands[1] == const0_rtx
&& ADDRESS_REG_P (operands[0]))
return "sub%.l %0,%0";
else if (DATA_REG_P (operands[0])
&& INTVAL (operands[1]) < 128
&& INTVAL (operands[1]) >= -128)
{
#if defined(MOTOROLA) && !defined(CRDS)
return "moveq%.l %1,%0";
#else
return "moveq %1,%0";
#endif
}
else if (INTVAL (operands[1]) < 0x8000
&& INTVAL (operands[1]) >= -0x8000)
return "move%.w %1,%0";
}
else if (CONSTANT_P (operands[1]))
return "move%.l %1,%0";
#ifndef SGS_NO_LI
if (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) == PLUS
&& GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS)
{
rtx labelref = XEXP (XEXP (operands[1], 0), 1);
#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES)
#ifdef SGS
asm_fprintf (asm_out_file, "\tset %LLI%d,.+2\n",
CODE_LABEL_NUMBER (XEXP (labelref, 0)));
#else
asm_fprintf (asm_out_file, "\t.set %LLI%d,.+2\n",
CODE_LABEL_NUMBER (XEXP (labelref, 0)));
#endif
#else
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LI",
CODE_LABEL_NUMBER (XEXP (labelref, 0)));
#ifdef SGS_SWITCH_TABLES
switch_table_difference_label_flag = 1;
#endif
#endif
}
#endif
return "move%.w %1,%0";
}
const char *
output_move_qimode (operands)
rtx *operands;
{
rtx xoperands[4];
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
&& XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx
&& ! ADDRESS_REG_P (operands[1])
&& ! TARGET_5200)
{
xoperands[1] = operands[1];
xoperands[2]
= gen_rtx_MEM (QImode,
gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, const1_rtx));
if (!reg_mentioned_p (stack_pointer_rtx, operands[1]))
{
xoperands[3] = stack_pointer_rtx;
#ifndef NO_ADDSUB_Q
output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
#else
output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands);
#endif
}
else
output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands);
return "";
}
if (!ADDRESS_REG_P (operands[0])
&& ((TARGET_68020 || TARGET_5200)
|| !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
{
if (operands[1] == const0_rtx)
return "clr%.b %0";
if ((!TARGET_5200 || DATA_REG_P (operands[0]))
&& GET_CODE (operands[1]) == CONST_INT
&& (INTVAL (operands[1]) & 255) == 255)
{
CC_STATUS_INIT;
return "st %0";
}
}
if (GET_CODE (operands[1]) == CONST_INT
&& DATA_REG_P (operands[0])
&& INTVAL (operands[1]) < 128
&& INTVAL (operands[1]) >= -128)
{
#if defined(MOTOROLA) && !defined(CRDS)
return "moveq%.l %1,%0";
#else
return "moveq %1,%0";
#endif
}
if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0]))
return "sub%.l %0,%0";
if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
return "move%.l %1,%0";
if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
return "move%.w %1,%0";
return "move%.b %1,%0";
}
const char *
output_move_stricthi (operands)
rtx *operands;
{
if (operands[1] == const0_rtx
&& ((TARGET_68020 || TARGET_5200)
|| !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
return "clr%.w %0";
return "move%.w %1,%0";
}
const char *
output_move_strictqi (operands)
rtx *operands;
{
if (operands[1] == const0_rtx
&& ((TARGET_68020 || TARGET_5200)
|| !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))))
return "clr%.b %0";
return "move%.b %1,%0";
}
static const char *
singlemove_string (operands)
rtx *operands;
{
#ifdef SUPPORT_SUN_FPA
if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
return "fpmoves %1,%0";
#endif
if (GET_CODE (operands[1]) == CONST_INT)
return output_move_simode_const (operands);
return "move%.l %1,%0";
}
const char *
output_move_double (operands)
rtx *operands;
{
enum
{
REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP
} optype0, optype1;
rtx latehalf[2];
rtx middlehalf[2];
rtx xops[2];
rtx addreg0 = 0, addreg1 = 0;
int dest_overlapped_low = 0;
int size = GET_MODE_SIZE (GET_MODE (operands[0]));
middlehalf[0] = 0;
middlehalf[1] = 0;
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1]))
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
if (optype0 == RNDOP || optype1 == RNDOP)
abort ();
if (optype0 == PUSHOP && optype1 == POPOP)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
if (size == 12)
output_asm_insn ("sub%.l %#12,%0", operands);
else
output_asm_insn ("subq%.l %#8,%0", operands);
if (GET_MODE (operands[1]) == XFmode)
operands[0] = gen_rtx_MEM (XFmode, operands[0]);
else if (GET_MODE (operands[0]) == DFmode)
operands[0] = gen_rtx_MEM (DFmode, operands[0]);
else
operands[0] = gen_rtx_MEM (DImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
if (size == 12)
output_asm_insn ("sub%.l %#12,%1", operands);
else
output_asm_insn ("subq%.l %#8,%1", operands);
if (GET_MODE (operands[1]) == XFmode)
operands[1] = gen_rtx_MEM (XFmode, operands[1]);
else if (GET_MODE (operands[1]) == DFmode)
operands[1] = gen_rtx_MEM (DFmode, operands[1]);
else
operands[1] = gen_rtx_MEM (DImode, operands[1]);
optype1 = OFFSOP;
}
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
if (size == 12)
{
if (optype0 == REGOP)
{
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
}
else if (optype0 == OFFSOP)
{
middlehalf[0] = adjust_address (operands[0], SImode, 4);
latehalf[0] = adjust_address (operands[0], SImode, size - 4);
}
else
{
middlehalf[0] = operands[0];
latehalf[0] = operands[0];
}
if (optype1 == REGOP)
{
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
}
else if (optype1 == OFFSOP)
{
middlehalf[1] = adjust_address (operands[1], SImode, 4);
latehalf[1] = adjust_address (operands[1], SImode, size - 4);
}
else if (optype1 == CNSTOP)
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long l[3];
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
operands[1] = GEN_INT (l[0]);
middlehalf[1] = GEN_INT (l[1]);
latehalf[1] = GEN_INT (l[2]);
}
else if (CONSTANT_P (operands[1]))
{
abort ();
if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0)
latehalf[1] = constm1_rtx;
else
latehalf[1] = const0_rtx;
}
}
else
{
middlehalf[1] = operands[1];
latehalf[1] = operands[1];
}
}
else
{
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], SImode, size - 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], SImode, size - 4);
else if (optype1 == CNSTOP)
split_double (operands[1], &operands[1], &latehalf[1]);
else
latehalf[1] = operands[1];
}
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
operands[1] = middlehalf[1] = latehalf[1];
if (optype0 == REGOP
&& (optype1 == OFFSOP || optype1 == MEMOP))
{
rtx testlow = gen_rtx_REG (SImode, REGNO (operands[0]));
if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
&& reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
{
compadr:
xops[0] = latehalf[0];
xops[1] = XEXP (operands[1], 0);
output_asm_insn ("lea %a1,%0", xops);
if (GET_MODE (operands[1]) == XFmode )
{
operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
middlehalf[1] = adjust_address (operands[1], DImode, size - 8);
latehalf[1] = adjust_address (operands[1], DImode, size - 4);
}
else
{
operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
latehalf[1] = adjust_address (operands[1], DImode, size - 4);
}
}
else if (size == 12
&& reg_overlap_mentioned_p (middlehalf[0],
XEXP (operands[1], 0)))
{
if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
|| reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
goto compadr;
if (addreg0 || addreg1)
abort ();
output_asm_insn (singlemove_string (operands), operands);
output_asm_insn (singlemove_string (latehalf), latehalf);
output_asm_insn (singlemove_string (middlehalf), middlehalf);
return "";
}
else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
dest_overlapped_low = 1;
}
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
|| REGNO (operands[0]) == REGNO (latehalf[1])))
|| dest_overlapped_low)
{
if (addreg0)
{
if (size == 12)
output_asm_insn ("addq%.l %#8,%0", &addreg0);
else
output_asm_insn ("addq%.l %#4,%0", &addreg0);
}
if (addreg1)
{
if (size == 12)
output_asm_insn ("addq%.l %#8,%0", &addreg1);
else
output_asm_insn ("addq%.l %#4,%0", &addreg1);
}
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
output_asm_insn ("subq%.l %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("subq%.l %#4,%0", &addreg1);
if (size == 12)
{
output_asm_insn (singlemove_string (middlehalf), middlehalf);
if (addreg0)
output_asm_insn ("subq%.l %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("subq%.l %#4,%0", &addreg1);
}
return singlemove_string (operands);
}
output_asm_insn (singlemove_string (operands), operands);
if (size == 12)
{
if (addreg0)
output_asm_insn ("addq%.l %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("addq%.l %#4,%0", &addreg1);
output_asm_insn (singlemove_string (middlehalf), middlehalf);
}
if (addreg0)
output_asm_insn ("addq%.l %#4,%0", &addreg0);
if (addreg1)
output_asm_insn ("addq%.l %#4,%0", &addreg1);
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
{
if (size == 12)
output_asm_insn ("subq%.l %#8,%0", &addreg0);
else
output_asm_insn ("subq%.l %#4,%0", &addreg0);
}
if (addreg1)
{
if (size == 12)
output_asm_insn ("subq%.l %#8,%0", &addreg1);
else
output_asm_insn ("subq%.l %#4,%0", &addreg1);
}
return "";
}
static rtx
find_addr_reg (addr)
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
abort ();
}
if (GET_CODE (addr) == REG)
return addr;
abort ();
}
const char *
output_addsi3 (operands)
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]) + 0x8000 >= (unsigned) 0x10000)
return "move%.l %2,%0\n\tadd%.l %1,%0";
#ifdef SGS
if (GET_CODE (operands[2]) == REG)
return "lea 0(%1,%2.l),%0";
else
return "lea %c2(%1),%0";
#else
#ifdef MOTOROLA
if (GET_CODE (operands[2]) == REG)
return "lea (%1,%2.l),%0";
else
return "lea (%c2,%1),%0";
#else
if (GET_CODE (operands[2]) == REG)
return "lea %1@(0,%2:l),%0";
else
return "lea %1@(%c2),%0";
#endif
#endif
}
if (GET_CODE (operands[2]) == CONST_INT)
{
#ifndef NO_ADDSUB_Q
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";
}
}
#endif
if (ADDRESS_REG_P (operands[0])
&& INTVAL (operands[2]) >= -0x8000
&& INTVAL (operands[2]) < 0x8000)
{
if (TARGET_68040)
return "add%.w %2,%0";
else
#ifdef MOTOROLA
return "lea (%c2,%0),%0";
#else
return "lea %0@(%c2),%0";
#endif
}
}
return "add%.l %2,%0";
}
void
notice_update_cc (exp, insn)
rtx exp;
rtx insn;
{
if (((cc_status.value1 && FPA_REG_P (cc_status.value1))
|| (cc_status.value2 && FPA_REG_P (cc_status.value2)))
&& !(GET_CODE (exp) == PARALLEL
&& GET_CODE (XVECEXP (exp, 0, 0)) == SET
&& XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx))
{
CC_STATUS_INIT;
}
else if (GET_CODE (exp) == SET)
{
if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
}
else if (ADDRESS_REG_P (SET_DEST (exp)))
{
if (cc_status.value1 && modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2 && modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
}
else if (!FP_REG_P (SET_DEST (exp))
&& SET_DEST (exp) != cc0_rtx
&& (FP_REG_P (SET_SRC (exp))
|| GET_CODE (SET_SRC (exp)) == FIX
|| GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE
|| GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND))
{
CC_STATUS_INIT;
}
else if (!FP_REG_P (SET_DEST (exp))
&& !FP_REG_P (SET_SRC (exp))
&& GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4
&& (GET_CODE (SET_SRC (exp)) == REG
|| GET_CODE (SET_SRC (exp)) == MEM
|| GET_CODE (SET_SRC (exp)) == CONST_DOUBLE))
{
CC_STATUS_INIT;
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
}
else if (XEXP (exp, 0) != pc_rtx)
{
cc_status.flags = 0;
cc_status.value1 = XEXP (exp, 0);
cc_status.value2 = XEXP (exp, 1);
}
}
else if (GET_CODE (exp) == PARALLEL
&& GET_CODE (XVECEXP (exp, 0, 0)) == SET)
{
if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0)))
CC_STATUS_INIT;
else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx)
{
cc_status.flags = 0;
cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1);
}
}
else
CC_STATUS_INIT;
if (cc_status.value2 != 0
&& ADDRESS_REG_P (cc_status.value2)
&& GET_MODE (cc_status.value2) == QImode)
CC_STATUS_INIT;
if (cc_status.value2 != 0
&& !(cc_status.value1 && FPA_REG_P (cc_status.value1)))
switch (GET_CODE (cc_status.value2))
{
case PLUS: case MINUS: case MULT:
case DIV: case UDIV: case MOD: case UMOD: case NEG:
#if 0
case ASHIFT: case ASHIFTRT: case LSHIFTRT:
case ROTATE: case ROTATERT:
#endif
if (GET_MODE (cc_status.value2) != VOIDmode)
cc_status.flags |= CC_NO_OVERFLOW;
break;
case ZERO_EXTEND:
cc_status.flags |= CC_NOT_NEGATIVE;
default:
break;
}
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
if (((cc_status.value1 && FP_REG_P (cc_status.value1))
|| (cc_status.value2 && FP_REG_P (cc_status.value2)))
&& !((cc_status.value1 && FPA_REG_P (cc_status.value1))
|| (cc_status.value2 && FPA_REG_P (cc_status.value2))))
cc_status.flags = CC_IN_68881;
}
const char *
output_move_const_double (operands)
rtx *operands;
{
#ifdef SUPPORT_SUN_FPA
if (TARGET_FPA && FPA_REG_P (operands[0]))
{
int code = standard_sun_fpa_constant_p (operands[1]);
if (code != 0)
{
static char buf[40];
sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff);
return buf;
}
return "fpmove%.d %1,%0";
}
else
#endif
{
int code = standard_68881_constant_p (operands[1]);
if (code != 0)
{
static char buf[40];
sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
return buf;
}
return "fmove%.d %1,%0";
}
}
const char *
output_move_const_single (operands)
rtx *operands;
{
#ifdef SUPPORT_SUN_FPA
if (TARGET_FPA)
{
int code = standard_sun_fpa_constant_p (operands[1]);
if (code != 0)
{
static char buf[40];
sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff);
return buf;
}
return "fpmove%.s %1,%0";
}
else
#endif
{
int code = standard_68881_constant_p (operands[1]);
if (code != 0)
{
static char buf[40];
sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
return buf;
}
return "fmove%.s %f1,%0";
}
}
static int inited_68881_table = 0;
static const char *const strings_68881[7] = {
"0.0",
"1.0",
"10.0",
"100.0",
"10000.0",
"1e8",
"1e16"
};
static const int codes_68881[7] = {
0x0f,
0x32,
0x33,
0x34,
0x35,
0x36,
0x37
};
REAL_VALUE_TYPE values_68881[7];
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;
}
int
standard_68881_constant_p (x)
rtx x;
{
REAL_VALUE_TYPE r;
int i;
#ifdef NO_ASM_FMOVECR
return 0;
#endif
if (TARGET_68040 || TARGET_68060)
return 0;
if (! inited_68881_table)
init_68881_table ();
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
for (i = 0; i < 6; i++)
{
if (REAL_VALUES_IDENTICAL (r, values_68881[i]))
return (codes_68881[i]);
}
if (GET_MODE (x) == SFmode)
return 0;
if (REAL_VALUES_EQUAL (r, values_68881[6]))
return (codes_68881[6]);
return 0;
}
int
floating_exact_log2 (x)
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;
}
#ifdef SUPPORT_SUN_FPA
static int inited_FPA_table = 0;
static const char *const strings_FPA[38] = {
"0.0",
"1.0",
"0.5",
"-1.0",
"2.0",
"3.0",
"4.0",
"8.0",
"0.25",
"0.125",
"10.0",
"-0.5",
"2.718281828459045091",
"6.283185307179586477",
"3.141592653589793116",
"1.570796326794896619",
"1.414213562373095145",
"0.7071067811865475244",
"-1.570796326794896619",
"1.442695040888963387",
"3.321928024887362182",
"0.6931471805599452862",
"2.302585092994045901",
"0.3010299956639811980",
"0.4342944819032518167",
"2.718281745910644531",
"6.283185307179586477",
"3.141592741012573242",
"1.570796326794896619",
"1.414213538169860840",
"0.7071067811865475244",
"-1.570796326794896619",
"1.442695021629333496",
"3.321928024291992188",
"0.6931471824645996094",
"2.302585124969482442",
"0.3010300099849700928",
"0.4342944920063018799",
};
static const int codes_FPA[38] = {
0x200,
0xe,
0xf,
0x10,
0x11,
0xb1,
0x12,
0x13,
0x15,
0x16,
0x17,
0x2e,
0x8,
0x9,
0xa,
0xb,
0xc,
0xd,
0x27,
0x28,
0x29,
0x2a,
0x2b,
0x2c,
0x2d,
0x8,
0x9,
0xa,
0xb,
0xc,
0xd,
0x27,
0x28,
0x29,
0x2a,
0x2b,
0x2c,
0x2d
};
REAL_VALUE_TYPE values_FPA[38];
static void init_FPA_table PARAMS ((void));
static void
init_FPA_table ()
{
enum machine_mode mode;
int i;
REAL_VALUE_TYPE r;
mode = DFmode;
for (i = 0; i < 38; i++)
{
if (i == 25)
mode = SFmode;
r = REAL_VALUE_ATOF (strings_FPA[i], mode);
values_FPA[i] = r;
}
inited_FPA_table = 1;
}
int
standard_sun_fpa_constant_p (x)
rtx x;
{
REAL_VALUE_TYPE r;
int i;
if (! inited_FPA_table)
init_FPA_table ();
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
for (i=0; i<12; i++)
{
if (REAL_VALUES_EQUAL (r, values_FPA[i]))
return (codes_FPA[i]);
}
if (GET_MODE (x) == SFmode)
{
for (i=25; i<38; i++)
{
if (REAL_VALUES_EQUAL (r, values_FPA[i]))
return (codes_FPA[i]);
}
}
else
{
for (i=12; i<25; i++)
{
if (REAL_VALUES_EQUAL (r, values_FPA[i]))
return (codes_FPA[i]);
}
}
return 0x0;
}
#endif
void
print_operand (file, op, letter)
FILE *file;
rtx op;
int letter;
{
#ifdef SUPPORT_SUN_FPA
int i;
#endif
if (letter == '.')
{
#if defined (MOTOROLA) && !defined (CRDS)
fprintf (file, ".");
#endif
}
else if (letter == '#')
{
asm_fprintf (file, "%0I");
}
else if (letter == '-')
{
#ifdef MOTOROLA
asm_fprintf (file, "-(%Rsp)");
#else
asm_fprintf (file, "%Rsp@-");
#endif
}
else if (letter == '+')
{
#ifdef MOTOROLA
asm_fprintf (file, "(%Rsp)+");
#else
asm_fprintf (file, "%Rsp@+");
#endif
}
else if (letter == '@')
{
#ifdef MOTOROLA
asm_fprintf (file, "(%Rsp)");
#else
asm_fprintf (file, "%Rsp@");
#endif
}
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')
{
if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF
|| !TARGET_PCREL)
abort ();
output_addr_const (file, XEXP (op, 0));
}
else if (GET_CODE (op) == REG)
{
#ifdef SUPPORT_SUN_FPA
if (REGNO (op) < 16
&& (letter == 'y' || letter == 'x')
&& GET_MODE (op) == DFmode)
{
fprintf (file, "%s:%s", reg_names[REGNO (op)],
reg_names[REGNO (op)+1]);
}
else
#endif
{
if (letter == 'R')
fputs (reg_names[REGNO (op) + 1], file);
else
fputs (reg_names[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))
{
#ifdef MOTOROLA
fprintf (file, ".l");
#else
fprintf (file, ":l");
#endif
}
}
#ifdef SUPPORT_SUN_FPA
else if ((letter == 'y' || letter == 'w')
&& GET_CODE (op) == CONST_DOUBLE
&& (i = standard_sun_fpa_constant_p (op)))
{
fprintf (file, "%%%d", i & 0x1ff);
}
#endif
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, "%0I");
if (TARGET_PCREL
&& (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST))
print_operand_address (file, op);
else
output_addr_const (file, op);
}
}
#ifndef ASM_OUTPUT_CASE_FETCH
#ifdef MOTOROLA
#ifdef SGS
#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname)
#else
#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname)
#endif
#else
#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\
asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname)
#endif
#endif
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
register rtx reg1, reg2, breg, ireg;
rtx offset;
switch (GET_CODE (addr))
{
case REG:
#ifdef MOTOROLA
fprintf (file, "(%s)", reg_names[REGNO (addr)]);
#else
fprintf (file, "%s@", reg_names[REGNO (addr)]);
#endif
break;
case PRE_DEC:
#ifdef MOTOROLA
fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
#else
fprintf (file, "%s@-", reg_names[REGNO (XEXP (addr, 0))]);
#endif
break;
case POST_INC:
#ifdef MOTOROLA
fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
#else
fprintf (file, "%s@+", reg_names[REGNO (XEXP (addr, 0))]);
#endif
break;
case PLUS:
reg1 = reg2 = ireg = breg = offset = 0;
if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
{
offset = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
{
offset = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) != PLUS)
{
;
}
else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND)
{
reg1 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND)
{
reg1 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
else if (GET_CODE (XEXP (addr, 0)) == MULT)
{
reg1 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == MULT)
{
reg1 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
else if (GET_CODE (XEXP (addr, 0)) == REG)
{
reg1 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == REG)
{
reg1 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT
|| GET_CODE (addr) == SIGN_EXTEND)
{
if (reg1 == 0)
{
reg1 = addr;
}
else
{
reg2 = addr;
}
addr = 0;
}
#if 0
else if (GET_CODE (addr) == PLUS)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
{
reg2 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == REG)
{
reg2 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
}
#endif
if (offset != 0)
{
if (addr != 0)
{
abort ();
}
addr = offset;
}
if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND
|| GET_CODE (reg1) == MULT))
|| (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
{
breg = reg2;
ireg = reg1;
}
else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
{
breg = reg1;
ireg = reg2;
}
if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF
&& ! (flag_pic && ireg == pic_offset_table_rtx))
{
int scale = 1;
if (GET_CODE (ireg) == MULT)
{
scale = INTVAL (XEXP (ireg, 1));
ireg = XEXP (ireg, 0);
}
if (GET_CODE (ireg) == SIGN_EXTEND)
{
ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (XEXP (ireg, 0))]);
fprintf (file, "w");
}
else
{
ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (ireg)]);
fprintf (file, "l");
}
if (scale != 1)
{
#ifdef MOTOROLA
fprintf (file, "*%d", scale);
#else
fprintf (file, ":%d", scale);
#endif
}
putc (')', file);
break;
}
if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
&& ! (flag_pic && breg == pic_offset_table_rtx))
{
ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (breg)]);
fprintf (file, "l)");
break;
}
if (ireg != 0 || breg != 0)
{
int scale = 1;
if (breg == 0)
{
abort ();
}
if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF)
{
abort ();
}
#ifdef MOTOROLA
if (addr != 0)
{
output_addr_const (file, addr);
if (flag_pic && (breg == pic_offset_table_rtx))
{
fprintf (file, "@GOT");
if (flag_pic == 1)
fprintf (file, ".w");
}
}
fprintf (file, "(%s", reg_names[REGNO (breg)]);
if (ireg != 0)
{
putc (',', file);
}
#else
fprintf (file, "%s@(", reg_names[REGNO (breg)]);
if (addr != 0)
{
output_addr_const (file, addr);
if ((flag_pic == 1) && (breg == pic_offset_table_rtx))
fprintf (file, ":w");
if ((flag_pic == 2) && (breg == pic_offset_table_rtx))
fprintf (file, ":l");
}
if (addr != 0 && ireg != 0)
{
putc (',', file);
}
#endif
if (ireg != 0 && GET_CODE (ireg) == MULT)
{
scale = INTVAL (XEXP (ireg, 1));
ireg = XEXP (ireg, 0);
}
if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND)
{
#ifdef MOTOROLA
fprintf (file, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]);
#else
fprintf (file, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]);
#endif
}
else if (ireg != 0)
{
#ifdef MOTOROLA
fprintf (file, "%s.l", reg_names[REGNO (ireg)]);
#else
fprintf (file, "%s:l", reg_names[REGNO (ireg)]);
#endif
}
if (scale != 1)
{
#ifdef MOTOROLA
fprintf (file, "*%d", scale);
#else
fprintf (file, ":%d", scale);
#endif
}
putc (')', file);
break;
}
else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
&& ! (flag_pic && reg1 == pic_offset_table_rtx))
{
ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (reg1)]);
fprintf (file, "l)");
break;
}
default:
if (GET_CODE (addr) == CONST_INT
&& INTVAL (addr) < 0x8000
&& INTVAL (addr) >= -0x8000)
{
#ifdef MOTOROLA
#ifdef SGS
fprintf (file, "%d", (int) INTVAL (addr));
#else
fprintf (file, "%d.w", (int) INTVAL (addr));
#endif
#else
fprintf (file, "%d:w", (int) INTVAL (addr));
#endif
}
else if (GET_CODE (addr) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
}
else if (TARGET_PCREL)
{
fputc ('(', file);
output_addr_const (file, addr);
if (flag_pic == 1)
asm_fprintf (file, ":w,%Rpc)");
else
asm_fprintf (file, ":l,%Rpc)");
}
else
{
if (GET_CODE (addr) == SYMBOL_REF
&& strlen (XSTR (addr, 0)) > 2
&& XSTR (addr, 0)[strlen (XSTR (addr, 0)) - 2] == '.')
{
putc ('(', file);
output_addr_const (file, addr);
putc (')', file);
}
else
output_addr_const (file, addr);
}
break;
}
}
int
strict_low_part_peephole_ok (mode, first_insn, target)
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 0;
if (reg_set_p (target, p))
{
rtx set = single_set (p);
rtx dest;
if (! set)
return 0;
dest = SET_DEST (set);
if (rtx_equal_p (dest, target)
&& SET_SRC (set) == const0_rtx)
return 1;
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 0;
}
p = prev_nonnote_insn (p);
}
return 0;
}
int
const_uint32_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_MODE_BITSIZE (mode) <= 32)
abort ();
#if HOST_BITS_PER_WIDE_INT > 32
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL));
#else
return (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));
#endif
}
int
const_sint32_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_MODE_BITSIZE (mode) <= 32)
abort ();
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
}
int
general_src_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (TARGET_PCREL
&& GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF
|| GET_CODE (XEXP (op, 0)) == CONST))
return 1;
return general_operand (op, mode);
}
int
nonimmediate_src_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (TARGET_PCREL && GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF
|| GET_CODE (XEXP (op, 0)) == CONST))
return 1;
return nonimmediate_operand (op, mode);
}
int
memory_src_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (TARGET_PCREL && GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF
|| GET_CODE (XEXP (op, 0)) == CONST))
return 1;
return memory_operand (op, mode);
}
int
pcrel_address (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF
|| GET_CODE (op) == CONST);
}
const char *
output_andsi3 (operands)
rtx *operands;
{
int logval;
if (GET_CODE (operands[2]) == CONST_INT
&& (INTVAL (operands[2]) | 0xffff) == 0xffffffff
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0]))
&& !TARGET_5200)
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adjust_address (operands[0], HImode, 2);
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
CC_STATUS_INIT;
if (operands[2] == const0_rtx)
return "clr%.w %0";
return "and%.w %2,%0";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (logval = exact_log2 (~ INTVAL (operands[2]))) >= 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (DATA_REG_P (operands[0]))
{
operands[1] = GEN_INT (logval);
}
else
{
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
CC_STATUS_INIT;
return "bclr %1,%0";
}
return "and%.l %2,%0";
}
const char *
output_iorsi3 (operands)
rtx *operands;
{
register int logval;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0]))
&& !TARGET_5200)
{
if (GET_CODE (operands[0]) != REG)
operands[0] = adjust_address (operands[0], HImode, 2);
CC_STATUS_INIT;
if (INTVAL (operands[2]) == 0xffff)
return "mov%.w %2,%0";
return "or%.w %2,%0";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (logval = exact_log2 (INTVAL (operands[2]))) >= 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (DATA_REG_P (operands[0]))
operands[1] = GEN_INT (logval);
else
{
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
CC_STATUS_INIT;
return "bset %1,%0";
}
return "or%.l %2,%0";
}
const char *
output_xorsi3 (operands)
rtx *operands;
{
register int logval;
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) >> 16 == 0
&& (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))
&& !TARGET_5200)
{
if (! DATA_REG_P (operands[0]))
operands[0] = adjust_address (operands[0], HImode, 2);
CC_STATUS_INIT;
if (INTVAL (operands[2]) == 0xffff)
return "not%.w %0";
return "eor%.w %2,%0";
}
if (GET_CODE (operands[2]) == CONST_INT
&& (logval = exact_log2 (INTVAL (operands[2]))) >= 0
&& (DATA_REG_P (operands[0])
|| offsettable_memref_p (operands[0])))
{
if (DATA_REG_P (operands[0]))
operands[1] = GEN_INT (logval);
else
{
operands[0] = adjust_address (operands[0], SImode, 3 - (logval / 8));
operands[1] = GEN_INT (logval % 8);
}
CC_STATUS_INIT;
return "bchg %1,%0";
}
return "eor%.l %2,%0";
}
static void
m68k_coff_asm_named_section (name, flags)
const char *name;
unsigned int flags;
{
char flagchar;
if (flags & SECTION_WRITE)
flagchar = 'd';
else
flagchar = 'x';
fprintf (asm_out_file, "\t.section\t%s,\"%c\"\n", name, flagchar);
}
#ifdef CTOR_LIST_BEGIN
static void
m68k_svr3_asm_out_constructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
rtx xop[2];
xop[1] = symbol;
xop[0] = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
init_section ();
output_asm_insn (output_move_simode (xop), xop);
}
#endif
static void
m68k_output_mi_thunk (file, thunk, delta, vcall_offset, function)
FILE *file;
tree thunk ATTRIBUTE_UNUSED;
HOST_WIDE_INT delta;
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
tree function;
{
rtx xops[1];
const char *fmt;
if (delta > 0 && delta <= 8)
asm_fprintf (file, "\taddq.l %I%d,4(%Rsp)\n", (int) delta);
else if (delta < 0 && delta >= -8)
asm_fprintf (file, "\tsubq.l %I%d,4(%Rsp)\n", (int) -delta);
else
{
asm_fprintf (file, "\tadd.l %I");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta);
asm_fprintf (file, ",4(%Rsp)\n");
}
xops[0] = DECL_RTL (function);
if (flag_pic)
{
if (TARGET_PCREL)
fmt = "bra.l %o0";
else
{
#ifdef MOTOROLA
#ifdef HPUX_ASM
fmt = "bra.l %0";
#else
#ifdef USE_GAS
fmt = "bra.l %0@PLTPC";
#else
fmt = "bra %0@PLTPC";
#endif
#endif
#else
#ifdef USE_GAS
fmt = "bra.l %0";
#else
fmt = "jbra %0,a1";
#endif
#endif
}
}
else
{
#if defined (MOTOROLA) && !defined (USE_GAS)
#ifdef MOTOROLA_BSR
fmt = "bra %0";
#else
fmt = "jmp %0";
#endif
#else
fmt = "jbra %0";
#endif
}
output_asm_insn (fmt, xops);
}