/* 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
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, "\tsubq.w %OI8,%Rsp\n\tsubq.w %OI%d,%Rsp\n",
+ fsize + 4);
+#else
+ 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));
+ asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));
#else
- asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));
+ 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;
}
+
+/* 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;
+{
+ /* All allowed constants will fit a CONST_INT. */
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff));
+}