aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/m68k/m68k.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/m68k/m68k.c')
-rw-r--r--gcc/config/m68k/m68k.c2632
1 files changed, 0 insertions, 2632 deletions
diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
deleted file mode 100644
index 2daf05da61c..00000000000
--- a/gcc/config/m68k/m68k.c
+++ /dev/null
@@ -1,2632 +0,0 @@
-/* Subroutines for insn-output.c for Motorola 68000 family.
- Copyright (C) 1987, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-
-/* Some output-actions in m68k.md need these. */
-#include <stdio.h>
-#include "config.h"
-#include "rtl.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "real.h"
-#include "insn-config.h"
-#include "conditions.h"
-#include "insn-flags.h"
-#include "output.h"
-#include "insn-attr.h"
-
-/* Needed for use_return_insn. */
-#include "flags.h"
-
-#ifdef SUPPORT_SUN_FPA
-
-/* Index into this array by (register number >> 3) to find the
- smallest class which contains that register. */
-enum reg_class regno_reg_class[]
- = { DATA_REGS, ADDR_REGS, FP_REGS,
- LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };
-
-#endif /* defined SUPPORT_SUN_FPA */
-
-/* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END,
- if SGS_SWITCH_TABLE. */
-int switch_table_difference_label_flag;
-
-static rtx find_addr_reg ();
-rtx legitimize_pic_address ();
-
-
-/* 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)
- {
- rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx);
- emit_insn_after (insn, get_insns ());
- emit_insn (insn);
- }
-}
-
-
-/* This function generates the assembly code for function entry.
- STREAM is a stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This function is responsible for
- knowing which registers should not be saved even if used. */
-
-
-/* Note that the order of the bit mask for fmovem is the opposite
- of the order for movem! */
-
-
-void
-output_function_prologue (stream, size)
- FILE *stream;
- int size;
-{
- register int regno;
- register int mask = 0;
- int num_saved_regs = 0;
- extern char call_used_regs[];
- int fsize = (size + 3) & -4;
-
-
- if (frame_pointer_needed)
- {
- 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",
- 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
- {
- /* 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
- asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n",
- reg_names[FRAME_POINTER_REGNUM], -fsize);
-#endif
- }
- }
- else if (fsize)
- {
- /* Adding negative number is faster on the 68040. */
- if (fsize + 4 < 0x8000)
- {
- /* 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
- {
- /* asm_fprintf() cannot handle %. */
-#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
- }
- }
-#ifdef SUPPORT_SUN_FPA
- for (regno = 24; regno < 56; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[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
- }
-#endif
- 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);
-#else
- asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);
-#endif
- }
- mask = 0;
- for (regno = 0; regno < 16; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- {
- mask |= 1 << (15 - regno);
- num_saved_regs++;
- }
- if (frame_pointer_needed)
- {
- mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM));
- num_saved_regs--;
- }
-
-#if NEED_PROBE
- fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);
-#endif
-
- if (num_saved_regs <= 2)
- {
- /* Store each separately in the same order moveml uses.
- Using two movel instructions instead of a single moveml
- is about 15% faster for the 68020 and 68030 at no expense
- in code size */
-
- int i;
-
- /* Undo the work from above. */
- 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]);
- }
- else if (mask)
- {
-#ifdef MOTOROLA
- asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);
-#else
- asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);
-#endif
- }
- 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
- }
-}
-
-/* Return true if this function's epilogue can be output as RTL. */
-
-int
-use_return_insn ()
-{
- int regno;
-
- if (!reload_completed || frame_pointer_needed || get_frame_size () != 0)
- return 0;
-
- /* Copied from output_function_epilogue (). We should probably create a
- separate layout routine to perform the common work. */
-
- for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- return 0;
-
- return 1;
-}
-
-/* This function generates the assembly code for function exit,
- on machines that need it. Args are same as for FUNCTION_PROLOGUE.
-
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only, if there is a frame pointer.
- This is mandatory because of alloca; we also take advantage of it to
- omit stack adjustments before returning. */
-
-void
-output_function_epilogue (stream, size)
- FILE *stream;
- int size;
-{
- register int regno;
- register int mask, fmask;
- register int nregs;
- int offset, foffset, fpoffset;
- extern char call_used_regs[];
- 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)
- insn = prev_nonnote_insn (insn);
- if (insn && GET_CODE (insn) == BARRIER)
- {
- /* Output just a no-op so that debuggers don't get confused
- about which function the pc is in at this address. */
- asm_fprintf (stream, "\tnop\n");
- 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
- nregs = 0; fmask = 0; fpoffset = 0;
-#ifdef SUPPORT_SUN_FPA
- for (regno = 24 ; regno < 56 ; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[regno])
- nregs++;
- 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);
- }
- foffset = fpoffset + nregs * 12;
- nregs = 0; mask = 0;
- if (frame_pointer_needed)
- regs_ever_live[FRAME_POINTER_REGNUM] = 0;
- for (regno = 0; regno < 16; regno++)
- if (regs_ever_live[regno] && ! call_used_regs[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 (nregs <= 2)
- {
- /* Restore each separately in the same order moveml does.
- Using two movel instructions instead of a single moveml
- is about 15% faster for the 68020 and 68030 at no expense
- in code size. */
-
- int i;
-
- /* Undo the work from above. */
- 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
- asm_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 (regs_ever_live[regno] && ! call_used_regs[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
- asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n",
- fpoffset + fsize,
- reg_names[FRAME_POINTER_REGNUM],
- reg_names[regno]);
-#else
- asm_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)
- {
- if (fsize + 4 < 0x8000)
- {
- /* 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
- {
- /* asm_fprintf() cannot handle %. */
-#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_pops_args)
- asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args);
- else
- fprintf (stream, "\trts\n");
-}
-
-/* Similar to general_operand, but exclude stack_pointer_rtx. */
-
-int
-not_sp_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- return op != stack_pointer_rtx && general_operand (op, mode);
-}
-
-/* Return TRUE if X is a valid comparison operator for the dbcc
- instruction.
-
- Note it rejects floating point comparison operators.
- (In the future we could use Fdbcc).
-
- It also rejects some comparisons when CC_NO_OVERFLOW is set. */
-
-int
-valid_dbcc_comparison_p (x, mode)
- rtx x;
- enum machine_mode mode;
-{
- switch (GET_CODE (x))
- {
- case EQ: case NE: case GTU: case LTU:
- case GEU: case LEU:
- return 1;
-
- /* Reject some when CC_NO_OVERFLOW is set. This may be over
- conservative */
- case GT: case LT: case GE: case LE:
- return ! (cc_prev_status.flags & CC_NO_OVERFLOW);
- default:
- return 0;
- }
-}
-
-/* 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 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:
-#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 ();
- }
-
- /* If the decrement is to be done in SImode, then we have
- to compensate for the fact that dbcc decrements in HImode. */
- 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 ();
- }
-}
-
-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);
-
- /* 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;
- rtx insn;
- int signpos;
-{
- operands[0] = countop;
- operands[1] = dataop;
-
- if (GET_CODE (countop) == CONST_INT)
- {
- register int count = INTVAL (countop);
- /* If COUNT is bigger than size of storage unit in use,
- advance to the containing unit of same size. */
- if (count > signpos)
- {
- int offset = (count & ~signpos) / 8;
- count = count & signpos;
- operands[1] = dataop = adj_offsettable_operand (dataop, 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;
-
- /* These three statements used to use next_insns_test_no...
- but it appears that this should do the same job. */
- 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";
-}
-
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
- reference and a constant. */
-
-int
-symbolic_operand (op, mode)
- register rtx op;
- enum machine_mode mode;
-{
- 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 /* Deleted, with corresponding change in m68k.h,
- so as to fit the specs. No CONST_DOUBLE is ever symbolic. */
- case CONST_DOUBLE:
- return GET_MODE (op) == mode;
-#endif
-
- default:
- return 0;
- }
-}
-
-/* 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;
- }
-}
-
-
-/* Legitimize PIC addresses. If the address is already
- position-independent, we return ORIG. Newly generated
- position-independent addresses go to REG. If we need more
- than one register, we lose.
-
- An address is legitimized by making an indirect reference
- through the Global Offset Table with the name of the symbol
- used as an offset.
-
- The assembler and linker are responsible for placing the
- address of the symbol in the GOT. The function prologue
- is responsible for initializing a5 to the starting address
- of the GOT.
-
- The assembler is also responsible for translating a symbol name
- into a constant displacement from the start of the GOT.
-
- A quick example may make things a little clearer:
-
- When not generating PIC code to store the value 12345 into _foo
- we would generate the following code:
-
- movel #12345, _foo
-
- When generating PIC two transformations are made. First, the compiler
- loads the address of foo into a register. So the first transformation makes:
-
- lea _foo, a0
- movel #12345, a0@
-
- The code in movsi will intercept the lea instruction and call this
- routine which will transform the instructions into:
-
- movel a5@(_foo:w), a0
- movel #12345, a0@
-
-
- That (in a nutshell) is how *all* symbol and label references are
- handled. */
-
-rtx
-legitimize_pic_address (orig, mode, reg)
- rtx orig, reg;
- enum machine_mode mode;
-{
- rtx pic_ref = orig;
-
- /* First handle a simple SYMBOL_REF or LABEL_REF */
- 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, offset;
-
- /* Make sure this is CONST has not already been legitimized */
- if (GET_CODE (XEXP (orig, 0)) == PLUS
- && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
- return orig;
-
- if (reg == 0)
- abort ();
-
- /* legitimize both operands of the PLUS */
- 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_for_output (base, INTVAL (orig));
- pic_ref = gen_rtx (PLUS, Pmode, base, orig);
- /* Likewise, should we set special REG_NOTEs here? */
- }
- return pic_ref;
-}
-
-
-typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD;
-
-#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;
- /* 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;
-{
- 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 ();
- }
-}
-
-/* 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 (DATA_REG_P (operands[0])
- && GET_CODE (operands[1]) == CONST_INT)
- return output_move_const_into_data_reg (operands);
- if (operands[1] != const0_rtx)
- return "move%.l %1,%0";
- if (! ADDRESS_REG_P (operands[0]))
- return "clr%.l %0";
- return "sub%.l %0,%0";
-}
-
-
-/* Output assembler code to perform a doubleword move insn
- with operands OPERANDS. */
-
-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;
-
- /* First classify both operands. */
-
- 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;
-
- /* Check for the cases that the operand constraints are not
- supposed to allow to happen. Abort if we get one,
- because generating code for these cases is painful. */
-
- if (optype0 == RNDOP || optype1 == RNDOP)
- abort ();
-
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
-
- 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 an operand is an unoffsettable memory ref, find a register
- we can increment temporarily to make it refer to the second word. */
-
- if (optype0 == MEMOP)
- addreg0 = find_addr_reg (XEXP (operands[0], 0));
-
- if (optype1 == MEMOP)
- addreg1 = find_addr_reg (XEXP (operands[1], 0));
-
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- 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] = adj_offsettable_operand (operands[0], 4);
- latehalf[0] = adj_offsettable_operand (operands[0], 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] = adj_offsettable_operand (operands[1], 4);
- latehalf[1] = adj_offsettable_operand (operands[1], 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]))
- {
- /* actually, no non-CONST_DOUBLE constant should ever
- appear here. */
- 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
- /* size is not 12: */
- {
- if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- else if (optype0 == OFFSOP)
- latehalf[0] = adj_offsettable_operand (operands[0], 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] = adj_offsettable_operand (operands[1], size - 4);
- else if (optype1 == CNSTOP)
- split_double (operands[1], &operands[1], &latehalf[1]);
- else
- latehalf[1] = operands[1];
- }
-
- /* If insn is effectively movd N(sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1 (which is N+4(sp))
- for the low word as well, to compensate for the first decrement of sp. */
- 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];
-
- /* 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
- emit the move late-half first. Otherwise, compute the MEM address
- into the upper part of N and use that as a pointer to the memory
- operand. */
- 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)))
- {
- /* If both halves of dest are used in the src memory address,
- 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 %a1,%0", xops);
- if( GET_MODE (operands[1]) == XFmode )
- {
- operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
- middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
- latehalf[1] = adj_offsettable_operand (operands[1], size-4);
- }
- else
- {
- operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
- latehalf[1] = adj_offsettable_operand (operands[1], size-4);
- }
- }
- else if (size == 12
- && reg_overlap_mentioned_p (middlehalf[0],
- XEXP (operands[1], 0)))
- {
- /* 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 ();
-
- /* Only the middle reg conflicts; simply put it last. */
- 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)))
- /* 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 one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
- 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)
- {
- /* Make any unoffsettable addresses point at high-numbered word. */
- 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);
- }
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- 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);
- }
-
- /* Do low-numbered word. */
- return singlemove_string (operands);
- }
-
- /* Normal case: do the two words, low-numbered first. */
-
- output_asm_insn (singlemove_string (operands), operands);
-
- /* Do the middle one of the three words for long double */
- 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);
- }
-
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("addq%.l %#4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("addq%.l %#4,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- 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 "";
-}
-
-/* Return a REG that occurs in ADDR with coefficient 1.
- ADDR can be effectively incremented by incrementing REG. */
-
-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 ();
-}
-
-/* Store in cc_status the expressions that the condition codes will
- describe after execution of an instruction whose pattern is EXP.
- Do not alter them if the instruction would not alter the cc's. */
-
-/* On the 68000, all the insns to store in an address register fail to
- set the cc's. However, in some cases these instructions can make it
- possibly invalid to use the saved cc's. In those cases we clear out
- some or all of the saved cc's so they won't be used. */
-
-notice_update_cc (exp, insn)
- rtx exp;
- rtx insn;
-{
- /* If the cc is being set from the fpa and the expression is not an
- explicit floating point test instruction (which has code to deal with
- this), reinit the CC. */
- 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
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
- cc_status.value1 = 0;
- if (cc_status.value2
- && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
- 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;
- }
- /* A pair of move insns doesn't produce a useful overall cc. */
- 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:
- case ASHIFT: case ASHIFTRT: case LSHIFTRT:
- case ROTATE: case ROTATERT:
- if (GET_MODE (cc_status.value2) != VOIDmode)
- cc_status.flags |= CC_NO_OVERFLOW;
- break;
- case ZERO_EXTEND:
- /* (SET r1 (ZERO_EXTEND r2)) on this machine
- ends with a move insn moving r2 in r2's mode.
- Thus, the cc's are set for r2.
- This can set N bit spuriously. */
- cc_status.flags |= CC_NOT_NEGATIVE;
- }
- 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;
-}
-
-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";
- }
-}
-
-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 /* defined SUPPORT_SUN_FPA */
- {
- 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";
- }
-}
-
-/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
- from the "fmovecr" instruction.
- The value, anded with 0xff, gives the code to use in fmovecr
- to get the desired constant. */
-
-/* This code has been fixed for cross-compilation. */
-
-static int inited_68881_table = 0;
-
-char *strings_68881[7] = {
- "0.0",
- "1.0",
- "10.0",
- "100.0",
- "10000.0",
- "1e8",
- "1e16"
- };
-
-int codes_68881[7] = {
- 0x0f,
- 0x32,
- 0x33,
- 0x34,
- 0x35,
- 0x36,
- 0x37
- };
-
-REAL_VALUE_TYPE values_68881[7];
-
-/* Set up values_68881 array by converting the decimal values
- strings_68881 to binary. */
-
-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;
- 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;
-
-#ifndef REAL_ARITHMETIC
-#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
- if (! flag_pretend_float)
- return 0;
-#endif
-#endif
-
- if (! inited_68881_table)
- init_68881_table ();
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-
- for (i = 0; i < 6; i++)
- {
- if (REAL_VALUES_EQUAL (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]);
-
- /* larger powers of ten in the constants ram are not used
- because they are not equal to a `double' C constant. */
- return 0;
-}
-
-/* If X is a floating-point constant, return the logarithm of X base 2,
- or 0 if X is not a power of 2. */
-
-int
-floating_exact_log2 (x)
- rtx x;
-{
- REAL_VALUE_TYPE r, r1;
- int i;
-
-#ifndef REAL_ARITHMETIC
-#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
- if (! flag_pretend_float)
- return 0;
-#endif
-#endif
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-
- if (REAL_VALUES_LESS (r, dconst0))
- return 0;
-
- r1 = dconst1;
- i = 0;
- while (REAL_VALUES_LESS (r1, r))
- {
- r1 = REAL_VALUE_LDEXP (dconst1, i);
- if (REAL_VALUES_EQUAL (r1, r))
- return i;
- i = i + 1;
- }
- return 0;
-}
-
-#ifdef SUPPORT_SUN_FPA
-/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
- from the Sun FPA's constant RAM.
- The value returned, anded with 0x1ff, gives the code to use in fpmove
- to get the desired constant. */
-
-static int inited_FPA_table = 0;
-
-char *strings_FPA[38] = {
-/* small rationals */
- "0.0",
- "1.0",
- "0.5",
- "-1.0",
- "2.0",
- "3.0",
- "4.0",
- "8.0",
- "0.25",
- "0.125",
- "10.0",
- "-0.5",
-/* Decimal equivalents of double precision values */
- "2.718281828459045091", /* D_E */
- "6.283185307179586477", /* 2 pi */
- "3.141592653589793116", /* D_PI */
- "1.570796326794896619", /* pi/2 */
- "1.414213562373095145", /* D_SQRT2 */
- "0.7071067811865475244", /* 1/sqrt(2) */
- "-1.570796326794896619", /* -pi/2 */
- "1.442695040888963387", /* D_LOG2ofE */
- "3.321928024887362182", /* D_LOG2of10 */
- "0.6931471805599452862", /* D_LOGEof2 */
- "2.302585092994045901", /* D_LOGEof10 */
- "0.3010299956639811980", /* D_LOG10of2 */
- "0.4342944819032518167", /* D_LOG10ofE */
-/* Decimal equivalents of single precision values */
- "2.718281745910644531", /* S_E */
- "6.283185307179586477", /* 2 pi */
- "3.141592741012573242", /* S_PI */
- "1.570796326794896619", /* pi/2 */
- "1.414213538169860840", /* S_SQRT2 */
- "0.7071067811865475244", /* 1/sqrt(2) */
- "-1.570796326794896619", /* -pi/2 */
- "1.442695021629333496", /* S_LOG2ofE */
- "3.321928024291992188", /* S_LOG2of10 */
- "0.6931471824645996094", /* S_LOGEof2 */
- "2.302585124969482442", /* S_LOGEof10 */
- "0.3010300099849700928", /* S_LOG10of2 */
- "0.4342944920063018799", /* S_LOG10ofE */
-};
-
-
-int codes_FPA[38] = {
-/* small rationals */
- 0x200,
- 0xe,
- 0xf,
- 0x10,
- 0x11,
- 0xb1,
- 0x12,
- 0x13,
- 0x15,
- 0x16,
- 0x17,
- 0x2e,
-/* double precision */
- 0x8,
- 0x9,
- 0xa,
- 0xb,
- 0xc,
- 0xd,
- 0x27,
- 0x28,
- 0x29,
- 0x2a,
- 0x2b,
- 0x2c,
- 0x2d,
-/* single precision */
- 0x8,
- 0x9,
- 0xa,
- 0xb,
- 0xc,
- 0xd,
- 0x27,
- 0x28,
- 0x29,
- 0x2a,
- 0x2b,
- 0x2c,
- 0x2d
- };
-
-REAL_VALUE_TYPE values_FPA[38];
-
-/* This code has been fixed for cross-compilation. */
-
-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;
-
-#ifndef REAL_ARITHMETIC
-#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
- if (! flag_pretend_float)
- return 0;
-#endif
-#endif
-
- 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 /* define SUPPORT_SUN_FPA */
-
-/* A C compound statement to output to stdio stream STREAM the
- assembler syntax for an instruction operand X. X is an RTL
- expression.
-
- CODE is a value that can be used to specify one of several ways
- of printing the operand. It is used when identical operands
- must be printed differently depending on the context. CODE
- comes from the `%' specification that was used to request
- printing of the operand. If the specification was just `%DIGIT'
- then CODE is 0; if the specification was `%LTR DIGIT' then CODE
- is the ASCII code for LTR.
-
- If X is a register, this macro should print the register's name.
- The names can be found in an array `reg_names' whose type is
- `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
-
- When the machine description has a specification `%PUNCT' (a `%'
- followed by a punctuation character), this macro is called with
- a null pointer for X and the punctuation character for CODE.
-
- The m68k specific codes are:
-
- '.' for dot needed in Motorola-style opcode names.
- '-' for an operand pushing on the stack:
- sp@-, -(sp) or -(%sp) depending on the style of syntax.
- '+' for an operand pushing on the stack:
- sp@+, (sp)+ or (%sp)+ depending on the style of syntax.
- '@' 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).
- '!' 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.
- '/' for register prefix needed by longlong.h.
-
- 'b' for byte insn (no effect, on the Sun; this is for the ISI).
- 'd' to force memory addressing to be absolute, not relative.
- 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex)
- 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather
- than directly). Second part of 'y' below.
- 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex),
- or print pair of registers as rx:ry.
- 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs
- CONST_DOUBLE's as SunFPA constant RAM registers if
- possible, so it should not be used except for the SunFPA.
-
- */
-
-void
-print_operand (file, op, letter)
- FILE *file; /* file to write to */
- rtx op; /* operand to print */
- int letter; /* %<letter> or 0 */
-{
- int i;
-
- if (letter == '.')
- {
-#ifdef MOTOROLA
- asm_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 (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')
- /* 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)
- {
- 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"); output_addr_const (file, op);
- }
-}
-
-
-/* A C compound statement to output to stdio stream STREAM the
- assembler syntax for an instruction operand that is a memory
- reference whose address is ADDR. ADDR is an RTL expression.
-
- Note that this contains a kludge that knows that the only reason
- we have an address (plus (label_ref...) (reg...)) when not generating
- PIC code is in the insn before a tablejump, and we know that m68k.md
- generates a label LInnn: on such an insn.
-
- It is possible for PIC to generate a (plus (label_ref...) (reg...))
- and we handle that just like we would a (plus (symbol_ref...) (reg...)).
-
- Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)"
- fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results
- we want. This difference can be accommodated by using an assembler
- 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.
-
- This routine is responsible for distinguishing between -fpic and -fPIC
- style relocations in an address. When generating -fpic code the
- 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;
- 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 /* for OLD_INDEXING */
- 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");
- }
- 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;
- }
- /* FALL-THROUGH (is this really what we want? */
- default:
- if (GET_CODE (addr) == CONST_INT
- && INTVAL (addr) < 0x8000
- && INTVAL (addr) >= -0x8000)
- {
-#ifdef MOTOROLA
-#ifdef SGS
- /* Many SGS assemblers croak on size specifiers for constants. */
- fprintf (file, "%d", INTVAL (addr));
-#else
- fprintf (file, "%d.w", INTVAL (addr));
-#endif
-#else
- fprintf (file, "%d:w", INTVAL (addr));
-#endif
- }
- else
- {
- output_addr_const (file, addr);
- }
- break;
- }
-}
-
-/* Check for cases where a clr insns can be omitted from code using
- strict_low_part sets. For example, the second clrl here is not needed:
- clrl d0; movw a0@+,d0; use d0; clrl d0; movw a0@+; use d0; ...
-
- MODE is the mode of this STRICT_LOW_PART set. FIRST_INSN is the clear
- insn we are checking for redundancy. TARGET is the register set by the
- clear insn. */
-
-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 it isn't an insn, then give up. */
- if (GET_CODE (p) != INSN)
- return 0;
-
- if (reg_set_p (target, p))
- {
- rtx set = single_set (p);
- rtx dest;
-
- /* If it isn't an easy to recognize insn, then give up. */
- if (! set)
- return 0;
-
- dest = SET_DEST (set);
-
- /* If this sets the entire target register to zero, then our
- first_insn is redundant. */
- 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)))
- /* This is a strict low part set which modifies less than
- we are using, so it is safe. */
- ;
- else
- return 0;
- }
-
- p = prev_nonnote_insn (p);
-
- }
-
- 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));
-}