/* Subroutines for insn-output.c for Motorola 68000 family.
- Copyright (C) 1987, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* Some output-actions in m68k.md need these. */
rtx legitimize_pic_address ();
\f
+/* Alignment to use for loops and jumps */
+/* Specify power of two alignment used for loops. */
+char *m68k_align_loops_string;
+/* Specify power of two alignment used for non-loop jumps. */
+char *m68k_align_jumps_string;
+/* Specify power of two alignment used for functions. */
+char *m68k_align_funcs_string;
+
+/* Specify power of two alignment used for loops. */
+int m68k_align_loops;
+/* Specify power of two alignment used for non-loop jumps. */
+int m68k_align_jumps;
+/* Specify power of two alignment used for functions. */
+int m68k_align_funcs;
+
+/* Nonzero if the last compare/test insn had FP operands. The
+ sCC expanders peek at this to determine what to do for the
+ 68060, which has no fsCC instructions. */
+int m68k_last_compare_had_fp_operands;
+
+/* Sometimes certain combinations of command options do not make
+ sense on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ Don't use this macro to turn on various extra optimizations for
+ `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
+
+void
+override_options ()
+{
+ int def_align;
+
+ def_align = 1;
+
+ /* Validate -malign-loops= value, or provide default */
+ if (m68k_align_loops_string)
+ {
+ m68k_align_loops = atoi (m68k_align_loops_string);
+ if (m68k_align_loops < 1 || m68k_align_loops > MAX_CODE_ALIGN)
+ fatal ("-malign-loops=%d is not between 1 and %d",
+ m68k_align_loops, MAX_CODE_ALIGN);
+ }
+ else
+ m68k_align_loops = def_align;
+
+ /* Validate -malign-jumps= value, or provide default */
+ if (m68k_align_jumps_string)
+ {
+ m68k_align_jumps = atoi (m68k_align_jumps_string);
+ if (m68k_align_jumps < 1 || m68k_align_jumps > MAX_CODE_ALIGN)
+ fatal ("-malign-jumps=%d is not between 1 and %d",
+ m68k_align_jumps, MAX_CODE_ALIGN);
+ }
+ else
+ m68k_align_jumps = def_align;
+
+ /* Validate -malign-functions= value, or provide default */
+ if (m68k_align_funcs_string)
+ {
+ m68k_align_funcs = atoi (m68k_align_funcs_string);
+ if (m68k_align_funcs < 1 || m68k_align_funcs > MAX_CODE_ALIGN)
+ fatal ("-malign-functions=%d is not between 1 and %d",
+ m68k_align_funcs, MAX_CODE_ALIGN);
+ }
+ else
+ m68k_align_funcs = def_align;
+}
+\f
/* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the
function at any time during the compilation process. In the future
we should try and eliminate the USE if we can easily determine that
all PIC references were deleted from the current function. That would
save an address register */
+void
finalize_pic ()
{
if (flag_pic && current_function_uses_pic_offset_table)
- emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
+ {
+ rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx);
+ emit_insn_after (insn, get_insns ());
+ emit_insn (insn);
+ }
}
\f
if (frame_pointer_needed)
{
- /* Adding negative number is faster on the 68040. */
- if (fsize < 0x8000 && !TARGET_68040)
+ if (fsize == 0 && TARGET_68040)
+ {
+ /* on the 68040, pea + move is faster than link.w 0 */
+#ifdef MOTOROLA
+ asm_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
+ asm_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",
}
else
{
+ /* Adding negative number is faster on the 68040. */
#ifdef MOTOROLA
asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n",
reg_names[FRAME_POINTER_REGNUM], -fsize);
}
else if (fsize)
{
- /* Adding negative number is faster on the 68040. */
if (fsize + 4 < 0x8000)
{
+#ifdef NO_ADDSUB_Q
+ if (fsize + 4 <= 8)
+ {
+ if (!TARGET_5200)
+ {
+ /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+ asm_fprintf (stream, "\tsubq.w %OI%d,%Rsp\n", fsize + 4);
+#else
+ asm_fprintf (stream, "\tsubqw %OI%d,%Rsp\n", fsize + 4);
+#endif
+ }
+ else
+ {
+ /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+ asm_fprintf (stream, "\tsubq.l %OI%d,%Rsp\n", fsize + 4);
+#else
+ asm_fprintf (stream, "\tsubql %OI%d,%Rsp\n", fsize + 4);
+#endif
+ }
+ }
+ else if (fsize + 4 <= 16 && TARGET_CPU32)
+ {
+ /* On the CPU32 it is faster to use two subqw instructions to
+ subtract a small integer (8 < N <= 16) to a register. */
+ /* asm_fprintf() cannot handle %. */
#ifdef MOTOROLA
- asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
+ asm_fprintf (stream, "\tsubq.w %OI8,%Rsp\n\tsubq.w %OI%d,%Rsp\n",
+ fsize + 4);
#else
- asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
+ asm_fprintf (stream, "\tsubqw %OI8,%Rsp\n\tsubqw %OI%d,%Rsp\n",
+ fsize + 4);
#endif
+ }
+ else
+#endif /* NO_ADDSUB_Q */
+ if (TARGET_68040)
+ {
+ /* Adding negative number is faster on the 68040. */
+ /* asm_fprintf() cannot handle %. */
+#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
{
+ /* asm_fprintf() cannot handle %. */
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));
#else
#endif
}
#endif
- for (regno = 16; regno < 24; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- mask |= 1 << (regno - 16);
- if ((mask & 0xff) != 0)
+ if (TARGET_68881)
{
+ for (regno = 16; regno < 24; regno++)
+ if (regs_ever_live[regno] && ! call_used_regs[regno])
+ mask |= 1 << (regno - 16);
+ if ((mask & 0xff) != 0)
+ {
#ifdef MOTOROLA
- asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
+ asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);
#else
- asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
+ asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
#endif
+ }
+ mask = 0;
}
- mask = 0;
for (regno = 0; regno < 16; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
{
}
#if NEED_PROBE
- fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
+#ifdef MOTOROLA
+#ifdef CRDS
+ asm_fprintf (stream, "\ttstl %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
+#else
+ asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);
+#endif
+#else
+ asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
+#endif
#endif
if (num_saved_regs <= 2)
}
else if (mask)
{
+ if (TARGET_5200)
+ {
+ /* The coldfire does not support the predecrement form of the
+ movml instruction, so we must adjust the stack pointer and
+ then use the plain address register indirect mode. We also
+ have to invert the register save mask to use the new mode.
+
+ FIXME: if num_saved_regs was calculated earlier, we could
+ combine the stack pointer adjustment with any adjustment
+ done when the initial stack frame is created. This would
+ save an instruction */
+
+ 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);
+ asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
#else
- asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
+ asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
#endif
+ }
}
if (flag_pic && current_function_uses_pic_offset_table)
{
int fsize = (size + 3) & -4;
int big = 0;
rtx insn = get_last_insn ();
+ int restore_from_sp = 0;
/* If the last insn was a BARRIER, we don't have to write any code. */
if (GET_CODE (insn) == NOTE)
return;
}
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+ if (profile_block_flag == 2)
+ {
+ FUNCTION_BLOCK_PROFILER_EXIT (stream);
+ }
+#endif
+
#ifdef FUNCTION_EXTRA_EPILOGUE
FUNCTION_EXTRA_EPILOGUE (stream, size);
#endif
fpoffset = nregs * 8;
#endif
nregs = 0;
- for (regno = 16; regno < 24; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- {
- nregs++;
- fmask |= 1 << (23 - regno);
- }
+ if (TARGET_68881)
+ {
+ for (regno = 16; regno < 24; regno++)
+ if (regs_ever_live[regno] && ! call_used_regs[regno])
+ {
+ nregs++;
+ fmask |= 1 << (23 - regno);
+ }
+ }
foffset = fpoffset + nregs * 12;
nregs = 0; mask = 0;
if (frame_pointer_needed)
mask |= 1 << regno;
}
offset = foffset + nregs * 4;
+ /* FIXME : leaf_function_p below is too strong.
+ What we really need to know there is if there could be pending
+ stack adjustment needed at that point. */
+ restore_from_sp = ! frame_pointer_needed
+ || (! current_function_calls_alloca && leaf_function_p ());
if (offset + fsize >= 0x8000
- && frame_pointer_needed
+ && ! restore_from_sp
&& (mask || fmask || fpoffset))
{
#ifdef MOTOROLA
- asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra0\n", -fsize);
+ asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize);
#else
- asm_fprintf (stream, "\tmovel %0I%d,%Ra0\n", -fsize);
+ asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize);
#endif
fsize = 0, big = 1;
}
- if (nregs <= 2)
+ if (TARGET_5200 || nregs <= 2)
{
/* Restore each separately in the same order moveml does.
Using two movel instructions instead of a single moveml
if (big)
{
#ifdef MOTOROLA
- asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra0.l),%s\n",
+ 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,%Ra0:l),%s\n",
+ asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, reg_names[i]);
#endif
}
- else if (! frame_pointer_needed)
+ else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n",
if (big)
{
#ifdef MOTOROLA
- asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra0.l),%0I0x%x\n",
+ 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,%Ra0:l),%0I0x%x\n",
+ asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
offset + fsize, mask);
#endif
}
- else if (! frame_pointer_needed)
+ else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);
if (big)
{
#ifdef MOTOROLA
- asm_fprintf (stream, "\tfmovm -%d(%s,%Ra0.l),%0I0x%x\n",
+ 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,%Ra0:l),%0I0x%x\n",
+ asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n",
reg_names[FRAME_POINTER_REGNUM],
foffset + fsize, fmask);
#endif
}
- else if (! frame_pointer_needed)
+ else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);
if (big)
{
#ifdef MOTOROLA
- asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra0.l), %s\n",
+ 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,%Ra0:l), %s\n",
+ asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n",
reg_names[FRAME_POINTER_REGNUM],
fpoffset + fsize, reg_names[regno]);
#endif
}
- else if (! frame_pointer_needed)
+ else if (restore_from_sp)
{
#ifdef MOTOROLA
asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n",
reg_names[FRAME_POINTER_REGNUM]);
else if (fsize)
{
+#ifdef NO_ADDSUB_Q
+ if (fsize + 4 <= 8)
+ {
+ if (!TARGET_5200)
+ {
+#ifdef MOTOROLA
+ asm_fprintf (stream, "\taddq.w %OI%d,%Rsp\n", fsize + 4);
+#else
+ asm_fprintf (stream, "\taddqw %OI%d,%Rsp\n", fsize + 4);
+#endif
+ }
+ else
+ {
+#ifdef MOTOROLA
+ asm_fprintf (stream, "\taddq.l %OI%d,%Rsp\n", fsize + 4);
+#else
+ asm_fprintf (stream, "\taddql %OI%d,%Rsp\n", fsize + 4);
+#endif
+ }
+ }
+ else if (fsize + 4 <= 16 && TARGET_CPU32)
+ {
+ /* On the CPU32 it is faster to use two addqw instructions to
+ add a small integer (8 < N <= 16) to a register. */
+ /* asm_fprintf() cannot handle %. */
+#ifdef MOTOROLA
+ asm_fprintf (stream, "\taddq.w %OI8,%Rsp\n\taddq.w %OI%d,%Rsp\n",
+ fsize + 4);
+#else
+ asm_fprintf (stream, "\taddqw %OI8,%Rsp\n\taddqw %OI%d,%Rsp\n",
+ fsize + 4);
+#endif
+ }
+ else
+#endif /* NO_ADDSUB_Q */
if (fsize + 4 < 0x8000)
{
+ if (TARGET_68040)
+ {
+ /* asm_fprintf() cannot handle %. */
+#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, "\tadd.w %0I%d,%Rsp\n", fsize + 4);
+ asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4);
#else
- asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);
+ asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4);
#endif
+ }
}
else
{
+ /* asm_fprintf() cannot handle %. */
#ifdef MOTOROLA
asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);
#else
rtx x;
enum machine_mode mode;
{
- /* We could add support for these in the future */
- if (cc_prev_status.flags & CC_IN_68881)
- return 0;
-
switch (GET_CODE (x))
{
-
case EQ: case NE: case GTU: case LTU:
case GEU: case LEU:
return 1;
}
}
+/* Return non-zero if flags are currently in the 68881 flag register. */
+int
+flags_in_68881 ()
+{
+ /* We could add support for these in the future */
+ return cc_status.flags & CC_IN_68881;
+}
+
/* 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 will kick
- those out before we get here. */
+ set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will
+ kick those out before we get here. */
output_dbcc_and_branch (operands)
rtx *operands;
{
-
switch (GET_CODE (operands[3]))
{
case EQ:
}
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);
+
+ /* This does not produce a usefull cc. */
+ CC_STATUS_INIT;
+
+ /* The m68k cmp.l instruction requires operand1 to be a reg as used
+ below. Swap the operands and change the op if these requirements
+ are not fulfilled. */
+ 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] = adj_offsettable_operand (operand1, 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] = adj_offsettable_operand (operand2, 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
+#ifdef MOTOROLA
+ output_asm_insn ("tst%.l %0\n\tjbne %l4\n\ttst%.l %1", loperands);
+#else
+ output_asm_insn ("tst%.l %0\n\tjne %l4\n\ttst%.l %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 "";
+}
+
+char *
output_btst (operands, countop, dataop, insn, signpos)
rtx *operands;
rtx countop, dataop;
return 0;
}
}
+\f
+/* Check for sign_extend or zero_extend. Used for bit-count operands. */
+
+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;
+ }
+}
\f
/* Legitimize PIC addresses. If the address is already
}
\f
-/* Return the best assembler insn template
- for moving operands[1] into operands[0] as a fullword. */
+typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;
-static char *
-singlemove_string (operands)
+#define USE_MOVQ(i) ((unsigned)((i) + 128) <= 255)
+
+CONST_METHOD
+const_method (constant)
+ rtx constant;
+{
+ int i;
+ unsigned u;
+
+ i = INTVAL (constant);
+ if (USE_MOVQ (i))
+ return MOVQ;
+
+ /* The Coldfire doesn't have byte or word operations. */
+ /* FIXME: This may not be useful for the m68060 either */
+ if (!TARGET_5200)
+ {
+ /* if -256 < N < 256 but N is not in range for a moveq
+ N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */
+ if (USE_MOVQ (i ^ 0xff))
+ return NOTB;
+ /* Likewise, try with not.w */
+ if (USE_MOVQ (i ^ 0xffff))
+ return NOTW;
+ /* This is the only value where neg.w is useful */
+ if (i == -65408)
+ return NEGW;
+ /* Try also with swap */
+ u = i;
+ if (USE_MOVQ ((u >> 16) | (u << 16)))
+ return SWAP;
+ }
+ /* Otherwise, use move.l */
+ return MOVL;
+}
+
+const_int_cost (constant)
+ rtx constant;
+{
+ switch (const_method (constant))
+ {
+ case MOVQ :
+ /* Constants between -128 and 127 are cheap due to moveq */
+ return 0;
+ case NOTB :
+ case NOTW :
+ case NEGW :
+ case SWAP :
+ /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */
+ return 1;
+ case MOVL :
+ return 2;
+ default :
+ abort ();
+ }
+}
+
+char *
+output_move_const_into_data_reg (operands)
rtx *operands;
{
-#ifdef SUPPORT_SUN_FPA
- if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1]))
- return "fpmoves %1,%0";
+ 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_rtx (CONST_INT, VOIDmode, 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_rtx (CONST_INT, VOIDmode, 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_rtx (CONST_INT, VOIDmode, (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 ();
+ }
+}
+
+char *
+output_move_simode_const (operands)
+ rtx *operands;
+{
+ if (operands[1] == const0_rtx
+ && (DATA_REG_P (operands[0])
+ || GET_CODE (operands[0]) == MEM)
+ /* clr insns on 68000 read before writing.
+ This isn't so on the 68010, but we have no TARGET_68010. */
+ && ((TARGET_68020 || TARGET_5200)
+ || !(GET_CODE (operands[0]) == MEM
+ && MEM_VOLATILE_P (operands[0]))))
+ return "clr%.l %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";
+}
+
+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";
+}
+
+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)
+ /* clr insns on 68000 read before writing.
+ This isn't so on the 68010, but we have no TARGET_68010. */
+ && ((TARGET_68020 || TARGET_5200)
+ || !(GET_CODE (operands[0]) == MEM
+ && MEM_VOLATILE_P (operands[0]))))
+ return "clr%.w %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
+ /* Recognize the insn before a tablejump, one that refers
+ to a table of offsets. Such an insn will need to refer
+ to a label on the insn. So output one. Use the label-number
+ of the table of offsets to generate this label. This code,
+ and similar code below, assumes that there will be at most one
+ reference to each table. */
+ 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 /* not SGS */
+ asm_fprintf (asm_out_file, "\t.set %LLI%d,.+2\n",
+ CODE_LABEL_NUMBER (XEXP (labelref, 0)));
+#endif /* not SGS */
+#else /* SGS_SWITCH_TABLES or not MOTOROLA */
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LI",
+ CODE_LABEL_NUMBER (XEXP (labelref, 0)));
+#ifdef SGS_SWITCH_TABLES
+ /* Set flag saying we need to define the symbol
+ LD%n (with value L%n-LI%n) at the end of the switch table. */
+ switch_table_difference_label_flag = 1;
+#endif /* SGS_SWITCH_TABLES */
+#endif /* SGS_SWITCH_TABLES or not MOTOROLA */
+ }
+#endif /* SGS_NO_LI */
+ return "move%.w %1,%0";
+}
+
+char *
+output_move_qimode (operands)
+ rtx *operands;
+{
+ rtx xoperands[4];
+
+ /* This is probably useless, since it loses for pushing a struct
+ of several bytes a byte at a time. */
+ 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]))
+ {
+ xoperands[1] = operands[1];
+ xoperands[2]
+ = gen_rtx (MEM, QImode,
+ gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx));
+ /* Just pushing a byte puts it in the high byte of the halfword. */
+ /* We must put it in the low-order, high-numbered byte. */
+ 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
- if (DATA_REG_P (operands[0])
- && GET_CODE (operands[1]) == CONST_INT
+ }
+ else
+ output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands);
+ return "";
+ }
+
+ /* clr and st insns on 68000 read before writing.
+ This isn't so on the 68010, but we have no TARGET_68010. */
+ 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)
+#if defined(MOTOROLA) && !defined(CRDS)
return "moveq%.l %1,%0";
#else
return "moveq %1,%0";
#endif
}
- if (operands[1] != const0_rtx)
+ if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1]))
return "move%.l %1,%0";
- if (! ADDRESS_REG_P (operands[0]))
- return "clr%.l %0";
- return "sub%.l %0,%0";
+ if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1]))
+ return "move%.w %1,%0";
+ return "move%.b %1,%0";
+}
+
+/* Return the best assembler insn template
+ for moving operands[1] into operands[0] as a fullword. */
+
+static 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";
}
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
- operands[1] = latehalf[1];
+ operands[1] = middlehalf[1] = latehalf[1];
/* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
if the upper part of reg N does not appear in the MEM, arrange to
if (optype0 == REGOP
&& (optype1 == OFFSOP || optype1 == MEMOP))
{
- if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
- && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
+ 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)))
{
/* If both halves of dest are used in the src memory address,
- compute the address into latehalf of dest. */
+ compute the address into latehalf of dest.
+ Note that this can't happen if the dest is two data regs. */
compadr:
xops[0] = latehalf[0];
xops[1] = XEXP (operands[1], 0);
- output_asm_insn ("lea%L0,%a1,%0", xops);
+ output_asm_insn ("lea %a1,%0", xops);
if( GET_MODE (operands[1]) == XFmode )
{
operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
}
}
else if (size == 12
- && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
+ && reg_overlap_mentioned_p (middlehalf[0],
+ XEXP (operands[1], 0)))
{
- /* Check for two regs used by both source and dest. */
- if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
- || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
- goto compadr;
+ /* Check for two regs used by both source and dest.
+ Note that this can't happen if the dest is all data regs.
+ It can happen if the dest is d6, d7, a0.
+ But in that case, latehalf is an addr reg, so
+ the code at compadr does ok. */
+
+ if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))
+ || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
+ goto compadr;
/* JRV says this can't happen: */
if (addreg0 || addreg1)
- abort();
+ abort ();
/* Only the middle reg conflicts; simply put it last. */
output_asm_insn (singlemove_string (operands), operands);
output_asm_insn (singlemove_string (middlehalf), middlehalf);
return "";
}
- else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
+ else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)))
/* If the low half of dest is mentioned in the source memory
address, the arrange to emit the move late half first. */
dest_overlapped_low = 1;
if (addreg0)
{
if (size == 12)
- output_asm_insn ("addql %#8,%0", &addreg0);
+ output_asm_insn ("addq%.l %#8,%0", &addreg0);
else
- output_asm_insn ("addql %#4,%0", &addreg0);
+ output_asm_insn ("addq%.l %#4,%0", &addreg0);
}
if (addreg1)
{
if (size == 12)
- output_asm_insn ("addql %#8,%0", &addreg1);
+ output_asm_insn ("addq%.l %#8,%0", &addreg1);
else
- output_asm_insn ("addql %#4,%0", &addreg1);
+ output_asm_insn ("addq%.l %#4,%0", &addreg1);
}
/* Do that word. */
/* Undo the adds we just did. */
if (addreg0)
- output_asm_insn ("subql %#4,%0", &addreg0);
+ output_asm_insn ("subq%.l %#4,%0", &addreg0);
if (addreg1)
- output_asm_insn ("subql %#4,%0", &addreg1);
+ output_asm_insn ("subq%.l %#4,%0", &addreg1);
if (size == 12)
{
output_asm_insn (singlemove_string (middlehalf), middlehalf);
if (addreg0)
- output_asm_insn ("subql %#4,%0", &addreg0);
+ output_asm_insn ("subq%.l %#4,%0", &addreg0);
if (addreg1)
- output_asm_insn ("subql %#4,%0", &addreg1);
+ output_asm_insn ("subq%.l %#4,%0", &addreg1);
}
/* Do low-numbered word. */
if (size == 12)
{
if (addreg0)
- output_asm_insn ("addql %#4,%0", &addreg0);
+ output_asm_insn ("addq%.l %#4,%0", &addreg0);
if (addreg1)
- output_asm_insn ("addql %#4,%0", &addreg1);
+ output_asm_insn ("addq%.l %#4,%0", &addreg1);
output_asm_insn (singlemove_string (middlehalf), middlehalf);
}
/* Make any unoffsettable addresses point at high-numbered word. */
if (addreg0)
- output_asm_insn ("addql %#4,%0", &addreg0);
+ output_asm_insn ("addq%.l %#4,%0", &addreg0);
if (addreg1)
- output_asm_insn ("addql %#4,%0", &addreg1);
+ output_asm_insn ("addq%.l %#4,%0", &addreg1);
/* Do that word. */
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
{
if (size == 12)
- output_asm_insn ("subql %#8,%0", &addreg0);
+ output_asm_insn ("subq%.l %#8,%0", &addreg0);
else
- output_asm_insn ("subql %#4,%0", &addreg0);
+ output_asm_insn ("subq%.l %#4,%0", &addreg0);
}
if (addreg1)
{
if (size == 12)
- output_asm_insn ("subql %#8,%0", &addreg1);
+ output_asm_insn ("subq%.l %#8,%0", &addreg1);
else
- output_asm_insn ("subql %#4,%0", &addreg1);
+ output_asm_insn ("subq%.l %#4,%0", &addreg1);
}
return "";
return addr;
abort ();
}
+
+/* Output assembler code to perform a 32 bit 3 operand add. */
+
+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;
+ }
+
+ /* These insns can result from reloads to access
+ stack slots over 64k from the frame pointer. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000)
+ return "move%.l %2,%0\\;add%.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 /* not SGS */
+#ifdef MOTOROLA
+ if (GET_CODE (operands[2]) == REG)
+ return "lea (%1,%2.l),%0";
+ else
+ return "lea (%c2,%1),%0";
+#else /* not MOTOROLA (MIT syntax) */
+ if (GET_CODE (operands[2]) == REG)
+ return "lea %1@(0,%2:l),%0";
+ else
+ return "lea %1@(%c2),%0";
+#endif /* not MOTOROLA */
+#endif /* not SGS */
+ }
+ 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_rtx (CONST_INT, VOIDmode,
+ - INTVAL (operands[2]));
+ return "subq%.l %2,%0";
+ }
+ /* On the CPU32 it is faster to use two addql instructions to
+ add a small integer (8 < N <= 16) to a register.
+ Likewise for subql. */
+ if (TARGET_CPU32 && REG_P (operands[0]))
+ {
+ if (INTVAL (operands[2]) > 8
+ && INTVAL (operands[2]) <= 16)
+ {
+ operands[2] = gen_rtx (CONST_INT, VOIDmode,
+ INTVAL (operands[2]) - 8);
+ return "addq%.l %#8,%0\\;addq%.l %2,%0";
+ }
+ if (INTVAL (operands[2]) < -8
+ && INTVAL (operands[2]) >= -16)
+ {
+ operands[2] = gen_rtx (CONST_INT, VOIDmode,
+ - INTVAL (operands[2]) - 8);
+ return "subq%.l %#8,%0\\;subq%.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";
+}
\f
/* Store in cc_status the expressions that the condition codes will
describe after execution of an instruction whose pattern is EXP.
{
case PLUS: case MINUS: case MULT:
case DIV: case UDIV: case MOD: case UMOD: case NEG:
- case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT:
+#if 0 /* These instructions always clear the overflow bit */
+ 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;
REAL_VALUE_TYPE r;
enum machine_mode mode;
- mode = DFmode;
+ mode = SFmode;
for (i = 0; i < 7; i++)
{
if (i == 6)
- mode = SFmode;
+ mode = DFmode;
r = REAL_VALUE_ATOF (strings_68881[i], mode);
values_68881[i] = r;
}
int i;
enum machine_mode mode;
+#ifdef NO_ASM_FMOVECR
+ return 0;
+#endif
+
/* fmovecr must be emulated on the 68040, so it shouldn't be used at all. */
if (TARGET_68040)
return 0;
'@' for a reference to the top word on the stack:
sp@, (sp) or (%sp) depending on the style of syntax.
'#' for an immediate operand prefix (# in MIT and Motorola syntax
- but & in SGS syntax).
+ but & in SGS syntax, $ in CRDS/UNOS syntax).
'!' for the cc register (used in an `and to cc' insn).
'$' for the letter `s' in an op code, but only on the 68040.
'&' for the letter `d' in an op code, but only on the 68040.
if (letter == '.')
{
-#ifdef MOTOROLA
+#if defined (MOTOROLA) && !defined (CRDS)
asm_fprintf (file, ".");
#endif
}
}
else if (GET_CODE (op) == REG)
{
+#ifdef SUPPORT_SUN_FPA
if (REGNO (op) < 16
&& (letter == 'y' || letter == 'x')
&& GET_MODE (op) == DFmode)
reg_names[REGNO (op)+1]);
}
else
+#endif
{
- fprintf (file, "%s", reg_names[REGNO (op)]);
+ if (letter == 'R')
+ /* Print out the second register name of a register pair.
+ I.e., R (6) => 7. */
+ fputs (reg_names[REGNO (op) + 1], file);
+ else
+ fputs (reg_names[REGNO (op)], file);
}
}
else if (GET_CODE (op) == MEM)
&& INTVAL (XEXP (op, 0)) < 0x8000
&& INTVAL (XEXP (op, 0)) >= -0x8000))
{
+#ifdef MOTOROLA
+ fprintf (file, ".l");
+#else
fprintf (file, ":l");
+#endif
}
}
#ifdef SUPPORT_SUN_FPA
define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other
string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END
macro. See m68k/sgs.h for an example; for versions without the bug.
+ Some assemblers refuse all the above solutions. The workaround is to
+ emit "K(pc,d0.l*2)" with K being a small constant known to give the
+ right behaviour.
They also do not like things like "pea 1.w", so we simple leave off
the .w on small constants.
offset is output in word mode (eg movel a5@(_foo:w), a0). When generating
-fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */
+#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 /* ASM_OUTPUT_CASE_FETCH */
+
void
print_operand_address (file, addr)
FILE *file;
}
if (GET_CODE (ireg) == SIGN_EXTEND)
{
-#ifdef MOTOROLA
-#ifdef SGS
- asm_fprintf (file, "%LLD%d(%Rpc,%s.w",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (XEXP (ireg, 0))]);
-#else
- asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.w",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
+ ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (XEXP (ireg, 0))]);
-#endif
-#else
- asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:w",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (XEXP (ireg, 0))]);
-#endif
+ fprintf (file, "w");
}
else
{
-#ifdef MOTOROLA
-#ifdef SGS
- asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
+ ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (ireg)]);
-#else
- asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (ireg)]);
-#endif
-#else
- asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (ireg)]);
-#endif
+ fprintf (file, "l");
}
if (scale != 1)
{
if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF
&& ! (flag_pic && breg == pic_offset_table_rtx))
{
-#ifdef MOTOROLA
-#ifdef SGS
- asm_fprintf (file, "%LLD%d(%Rpc,%s.l",
+ ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (breg)]);
-#else
- asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (breg)]);
-#endif
-#else
- asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (breg)]);
-#endif
- putc (')', file);
+ fprintf (file, "l)");
break;
}
if (ireg != 0 || breg != 0)
else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF
&& ! (flag_pic && reg1 == pic_offset_table_rtx))
{
-#ifdef MOTOROLA
-#ifdef SGS
- asm_fprintf (file, "%LLD%d(%Rpc,%s.l)",
+ ASM_OUTPUT_CASE_FETCH (file,
CODE_LABEL_NUMBER (XEXP (addr, 0)),
reg_names[REGNO (reg1)]);
-#else
- asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l)",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (reg1)]);
-#endif
-#else
- asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l)",
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- CODE_LABEL_NUMBER (XEXP (addr, 0)),
- reg_names[REGNO (reg1)]);
-#endif
+ fprintf (file, "l)");
break;
}
/* FALL-THROUGH (is this really what we want? */
return 0;
}
-\f
-/* Emit the machine-code interface trampoline at the beginning of a byte
- coded function. The argument is a label name of the interpreter
- bytecode callinfo structure; the return value is a label name for
- the beginning of the actual bytecode. */
-char *
-bc_emit_trampoline (callinfo)
- char *callinfo;
+
+/* Accept integer operands in the range 0..0xffffffff. We have to check the
+ range carefully since this predicate is used in DImode contexts. Also, we
+ need some extra crud to make it work when hosted on 64-bit machines. */
+
+int
+const_uint32_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+#if HOST_BITS_PER_WIDE_INT > 32
+ /* All allowed constants will fit a CONST_INT. */
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL));
+#else
+ return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0)
+ || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0));
+#endif
+}
+
+/* Accept integer operands in the range -0x80000000..0x7fffffff. We have
+ to check the range carefully since this predicate is used in DImode
+ contexts. */
+
+int
+const_sint32_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
{
- short insn;
- int zero = 0;
- char mylab[256];
- static int n;
-
- sprintf (mylab, "*LB%d", n++);
-
- /* Push a reference to the callinfo structure. */
- insn = 0x4879; /* pea xxx.L */
- seg_data (trampoline, (char *) &insn, sizeof insn);
- seg_refsym (trampoline, callinfo, 0);
-
- /* Call __interp, pop arguments, and return. */
- insn = 0x4EB9; /* jsr xxx.L */
- seg_data (trampoline, (char *) &insn, sizeof insn);
- seg_refsym (trampoline, "__callint", 0);
- insn = 0x588F; /* addql #4, sp */
- seg_data (trampoline, (char *) &insn, sizeof insn);
- insn = 0x4E75; /* rts */
- seg_data (trampoline, (char *) &insn, sizeof insn);
- seg_defsym (bytecode, mylab);
- return sym_lookup (mylab)->name;
+ /* All allowed constants will fit a CONST_INT. */
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
}