aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mt/mt.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2008-06-07 19:00:15 +0100
committerJoseph Myers <jsm28@gcc.gnu.org>2008-06-07 19:00:15 +0100
commitcd985f6672bb3c399c03118a7a2426e2210c690a (patch)
tree0b3f6bdde3fd6779fef4d162dd5a25868787d722 /gcc/config/mt/mt.c
parent4b92fd3cc91f9406ba26c73aaa03ef0f5871fa99 (diff)
downloadgcc-cd985f6672bb3c399c03118a7a2426e2210c690a.zip
gcc-cd985f6672bb3c399c03118a7a2426e2210c690a.tar.gz
gcc-cd985f6672bb3c399c03118a7a2426e2210c690a.tar.bz2
MAINTAINERS (mt port): Remove.
* MAINTAINERS (mt port): Remove. (sco5, unixware, sco udk): Remove. (Kean Johnston): Add to Write After Approval. fixincludes: * inclhack.def (AAB_svr4_replace_byteorder, AAB_ultrix_ansi_compat, AAB_ultrix_limits, AAB_ultrix_memory, libc1_G_va_list, libc1_ifdefd_memx, nested_motorola, ptx_sys_mc_param_h, sco_regset, sco_static_func, sco_utime, solaris_mutex_init_1, solaris_socket, solaris_unistd, solaris_widec, svr4_krnl, ultrix_atexit_param, ultrix_atof_param, ultrix_const3, ultrix_fix_fixproto, ultrix_ifdef, ultrix_locale, ultrix_math_ifdef, ultrix_nested_ioctl, ultrix_nested_svc, ultrix_stat, ultrix_static, ultrix_stdlib, ultrix_strings, ultrix_strings2, ultrix_sys_time, ultrix_unistd, unicosmk_restrict, uw7_byteorder_fix, windiss_math1, windiss_math2, windiss_valist): Remove. * fixincl.x: Regenerate. * mkfixinc.sh: (arm-semi-aof, hppa1.1-*-osf*, hppa1.1-*-bsd*, i370-*-openedition, i?86-*-moss*, i?86-*-uwin*, powerpc-*-eabiaix*): Remove. * tests/base/math.h: Update. * tests/base/pthread.h: Update. * tests/base/stdio.h: Update. * tests/base/stdlib.h: Update. * tests/base/string.h: Update. * tests/base/strings.h: Update. * tests/base/sys/file.h: Update. * tests/base/sys/limits.h: Update. * tests/base/sys/socket.h: Update. * tests/base/sys/stat.h: Update. * tests/base/sys/time.h: Update. * tests/base/testing.h: Update. * tests/base/unistd.h: Update. * tests/base/_G_config.h: Remove. * tests/base/arpa: Remove directory. * tests/base/fs: Remove directory. * tests/base/locale.h: Remove. * tests/base/machine: Remove directory. * tests/base/rpc/svc.h: Remove. * tests/base/sys/ioctl.h: Remove. * tests/base/sys/regset.h: Remove. * tests/base/sys/times.h: Remove. * tests/base/sys/utsname.h: Remove. * tests/base/widec.h: Remove. gcc: * config.gcc (Obsolete configurations): Remove list of configurations. (Unsupported targets list): Add *-*-linux*aout*, *-*-linux*libc1*, *-*-solaris2.[0-6], *-*-solaris2.[0-6].*, *-*-sysv*. Remove other targets matched by those patterns. (strongarm*-*-*, ep9312*-*-*, xscale-*-*, parisc*-*-*, m680[012]0-*-*, *-*-linux*libc1*, *-*-linux*aout*, alpha*-*-unicosmk*, strongarm*-*-freebsd*, ep9312-*-elf, arm*-*-kaos*, cris-*-aout, parisc*64*-*-linux*, parisc*-*-linux*, hppa1.1-*-pro*, hppa1.1-*-osf*, hppa1.1-*-bsd*, i[34567]86-sequent-ptx4*, i[34567]86-sequent-sysv4*, i[34567]86-*-beoself*, i[34567]86-*-beos*, i[34567]86-*-sco3.2v5*, i[34567]86-*-sysv5*, i[34567]86-*-sysv4*, i[34567]86-*-uwin*, i[34567]86-*-kaos*, m68020-*-elf*, m68010-*-netbsdelf*, mips-wrs-windiss, mt-*-elf, powerpc-*-beos*, powerpc-*-chorusos*, powerpc-wrs-windiss*, powerpcle-*-sysv*, powerpc-*-kaos*, powerpcle-*-kaos*, sh*-*-kaos*, sparc-*-sysv4*, strongarm-*-elf*, strongarm-*-pe, strongarm-*-kaos*, vax-*-bsd*, vax-*-sysv*, vax-*-ultrix*, xscale-*-elf, xscale-*-coff, i[34567]86-*-linux*aout*, i[34567]86-*-linux*libc1): Remove. Make code for Solaris 7 and greater unconditional for Solaris. (ep9312-*-*, parisc1*, m680[012]0-*-*, parisc*-*-*, mt-*-*): Remove --with-* handling. * config/rs6000/sysv4.h (-mwindiss): Remove from all specs. (LIB_WINDISS_SPEC, CPP_OS_WINDISS_SPEC, STARTFILE_WINDISS_SPEC, ENDFILE_WINDISS_SPEC, LINK_START_WINDISS_SPEC, LINK_OS_WINDISS_SPEC): Remove. * config/rs6000/sysv4.opt (mwindiss): Remove. * configure.ac (strongarm*-*-*, xscale*-*-*): Remove. * configure: Regenerate. * doc/cpp.texi: Don't mention BeOS. * doc/extend.texi (interrupt): Don't mention MS1. * doc/install.texi: (i386-@var{any}-sysv, m68k-bull-sysv, m68k-hp-hpux, m68000-hp-hpux, m68000-att-sysv, alphaev5-cray-unicosmk*, xscale-*-*, i?86-*-linux*aout, i?86-*-sco3.2v5*, i?86-*-udk, m68k-hp-hpux, powerpc-*-sysv4, powerpc-*-sysv4, powerpcle-*-sysv4, *-*-sysv*, vax-dec-ultrix): Remove. * doc/invoke.texi (MT Options): Remove. (-mwindiss): Remove. (CRIS Options): Remove cris-axis-aout references. (HPPA Options): Don't mention hppa1.1-*-pro. * doc/md.texi: (MorphoTech family): Remove. * libgcc2.c: Don't handle UWIN. * config/alpha/t-unicosmk: Remove. * config/alpha/unicosmk.h: Remove. * config/arm/kaos-arm.h: Remove. * config/arm/kaos-strongarm.h: Remove. * config/arm/strongarm-coff.h: Remove. * config/arm/strongarm-elf.h: Remove. * config/arm/strongarm-pe.h: Remove. * config/arm/t-strongarm-pe: Remove. * config/arm/t-xscale-coff: Remove. * config/arm/t-xscale-elf: Remove. * config/arm/xscale-coff.h: Remove. * config/arm/xscale-elf.h: Remove. * config/chorus.h: Remove. * config/cris/aout.h: Remove. * config/cris/aout.opt: Remove. * config/cris/t-aout: Remove. * config/i386/beos-elf.h: Remove. * config/i386/kaos-i386.h: Remove. * config/i386/ptx4-i.h: Remove. * config/i386/sco5.h: Remove. * config/i386/sco5.opt: Remove. * config/i386/sysv4-cpp.h: Remove. * config/i386/sysv5.h: Remove. * config/i386/t-beos: Remove. * config/i386/t-sco5: Remove. * config/i386/t-uwin: Remove. * config/i386/uwin.asm: Remove. * config/i386/uwin.h: Remove. * config/kaos.h: Remove. * config/mips/windiss.h: Remove. * config/mt: Remove directory. * config/pa/pa-osf.h: Remove. * config/pa/pa-pro-end.h: Remove. * config/pa/t-pro: Remove. * config/ptx4.h: Remove. * config/rs6000/beos.h: Remove. * config/rs6000/kaos-ppc.h: Remove. * config/rs6000/t-beos: Remove. * config/rs6000/windiss.h: Remove. * config/sh/kaos-sh.h: Remove. * config/sol2-6.h: Remove. * config/sparc/sol26-sld.h: Remove. * config/sparc/sysv4-only.h: Remove. * config/vax/bsd.h: Remove. * config/vax/t-memfuncs: Remove. * config/vax/ultrix.h: Remove. * config/vax/vaxv.h: Remove. * config/windiss.h: Remove. gcc/testsuite: * g++.dg/abi/arm_cxa_vec1.C: Don't handle xscale*-*-*. * g++.dg/eh/spbp.C: Don't handle *-*-solaris2.[56]*. * g++.dg/warn/miss-format-1.C: Don't handle Solaris before Solaris 7. * gcc.c-torture/compile/981006-1.c: Don't handle xscale*-*-*, strongarm*-*-* and cris-*-aout*. * gcc.c-torture/execute/941014-1.x: Don't handle xscale*-*-* and strongarm*-*-*. * gcc.dg/20030909-1.c: Don't handle xscale*-*-* and strongarm*-*-*. * gcc.dg/20031108-1.c: Don't handle xscale*-*-* and strongarm*-*-*. * gcc.dg/20040813-1.c: Don't handle *-*-sysv5*. * gcc.dg/arm-asm.c: Don't handle strongarm*-*-* and xscale*-*-*. * gcc.dg/arm-scd42-1.c: Use target arm*-*-*. * gcc.dg/arm-scd42-3.c: Use target arm*-*-*. * gcc.dg/cpp/assert4.c: Don't handle BeOS. * gcc.dg/debug/pr35154.c: Don't handle *-*-sysv5*. * gcc.dg/intmax_t-1.c: Don't handle *-*-solaris2.5.1 and xscale*-*-elf*. * gcc.dg/pragma-align.c: Don't handle i?86-*-sco3.2v5*. * gcc.dg/pthread-init-2.c: Don't handle *-*-solaris2.5.1. * gcc.misc-tests/arm-isr.exp: Use target arm*-*-*. * gcc.target/powerpc/ppc-sdata-1.c: Don't handle powerpc-*-sysv*. * gcc.target/powerpc/ppc-sdata-2.c: Don't handle powerpc-*-sysv*. * gcc.target/powerpc/ppc-stackalign-1.c: Don't handle powerpc-*-sysv*. * gfortran.dg/debug/pr35154-stabs.f: Don't handle *-*-sysv5*. * lib/target-supports.exp: Don't handle strongarm*-*-elf, xscale*-*-elf and *-*-windiss. * obj-c++.dg/dwarf-2.mm: Don't handle *-*-solaris2.[56]*. * objc.dg/dwarf-1.m: Don't handle *-*-solaris2.[56]*. * objc.dg/dwarf-2.m: Don't handle *-*-solaris2.[56]*. * gcc.dg/mt-loopi1.c: Remove. gnattools: * configure.ac (xscale*-wrs-vx*, xscale*-wrs-coff): Remove. * configure: Regenerate. libcpp: * configure.ac (parisc*64*-*-*): Remove. * configure: Regenerate. libffi: * configure.ac (parisc*-*-linux*, powerpc-*-sysv*, powerpc-*-beos*): Remove. * configure: Regenerate. libgcc: * config.host (strongarm*-*-*, ep9312*-*-*, xscale-*-*, parisc*-*-*, m680[012]0-*-*, *-*-linux*libc1*, *-*-linux*aout*, alpha*-*-unicosmk*, strongarm*-*-freebsd*, ep9312-*-elf, arm*-*-kaos*, cris-*-aout, parisc*64*-*-linux*, parisc*-*-linux*, hppa1.1-*-pro*, hppa1.1-*-osf*, hppa1.1-*-bsd*, i[34567]86-sequent-ptx4*, i[34567]86-sequent-sysv4*, i[34567]86-*-beoself*, i[34567]86-*-beos*, i[34567]86-*-sco3.2v5*, i[34567]86-*-sysv5*, i[34567]86-*-sysv4*, i[34567]86-*-uwin*, i[34567]86-*-kaos*, m68020-*-elf*, m68010-*-netbsdelf*, mips-wrs-windiss, mt-*-elf, powerpc-*-beos*, powerpc-*-chorusos*, powerpc-wrs-windiss*, powerpcle-*-sysv*, powerpc-*-kaos*, powerpcle-*-kaos*, sh*-*-kaos*, sparc-*-sysv4*, strongarm-*-elf*, strongarm-*-pe, strongarm-*-kaos*, vax-*-bsd*, vax-*-sysv*, vax-*-ultrix*, xscale-*-elf, xscale-*-coff): Remove. libjava: * configure.host (strongarm*-elf, xscale*-elf): Remove. libstdc++-v3: * configure.host (xscale, ep9312, m680[246]0, solaris2.5, solaris2.5.[0-9], solaris2.6, windiss*): Remove. * crossconfig.m4 (*-solaris2.5, *-solaris2.6, *-windiss*): Remove. * configure: Regenerate. * config/os/solaris/solaris2.5: Remove directory. * config/os/solaris/solaris2.6: Remove directory. * config/os/windiss: Remove directory. From-SVN: r136534
Diffstat (limited to 'gcc/config/mt/mt.c')
-rw-r--r--gcc/config/mt/mt.c2493
1 files changed, 0 insertions, 2493 deletions
diff --git a/gcc/config/mt/mt.c b/gcc/config/mt/mt.c
deleted file mode 100644
index c7fc0d1..0000000
--- a/gcc/config/mt/mt.c
+++ /dev/null
@@ -1,2493 +0,0 @@
-/* Target definitions for the MorphoRISC1
- Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
- Contributed by Red Hat, Inc.
-
- This file is part of GCC.
-
- GCC 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 3, or (at your
- option) any later version.
-
- GCC 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 GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "real.h"
-#include "insn-config.h"
-#include "conditions.h"
-#include "insn-attr.h"
-#include "recog.h"
-#include "toplev.h"
-#include "output.h"
-#include "integrate.h"
-#include "tree.h"
-#include "function.h"
-#include "expr.h"
-#include "optabs.h"
-#include "libfuncs.h"
-#include "flags.h"
-#include "tm_p.h"
-#include "ggc.h"
-#include "insn-flags.h"
-#include "obstack.h"
-#include "except.h"
-#include "target.h"
-#include "target-def.h"
-#include "basic-block.h"
-
-/* Frame pointer register mask. */
-#define FP_MASK (1 << (GPR_FP))
-
-/* Link register mask. */
-#define LINK_MASK (1 << (GPR_LINK))
-
-/* Given a SIZE in bytes, advance to the next word. */
-#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-
-/* A C structure for machine-specific, per-function data.
- This is added to the cfun structure. */
-struct machine_function GTY(())
-{
- /* Flags if __builtin_return_address (n) with n >= 1 was used. */
- int ra_needs_full_frame;
- struct rtx_def * eh_stack_adjust;
- int interrupt_handler;
- int has_loops;
-};
-
-/* Define the information needed to generate branch and scc insns.
- This is stored from the compare operation. */
-struct rtx_def * mt_compare_op0;
-struct rtx_def * mt_compare_op1;
-
-/* Current frame information calculated by compute_frame_size. */
-struct mt_frame_info current_frame_info;
-
-/* Zero structure to initialize current_frame_info. */
-struct mt_frame_info zero_frame_info;
-
-/* mt doesn't have unsigned compares need a library call for this. */
-struct rtx_def * mt_ucmpsi3_libcall;
-
-static int mt_flag_delayed_branch;
-
-
-static rtx
-mt_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED,
- int incoming ATTRIBUTE_UNUSED)
-{
- return gen_rtx_REG (Pmode, RETVAL_REGNUM);
-}
-
-/* Implement RETURN_ADDR_RTX. */
-rtx
-mt_return_addr_rtx (int count)
-{
- if (count != 0)
- return NULL_RTX;
-
- return get_hard_reg_initial_val (Pmode, GPR_LINK);
-}
-
-/* The following variable value indicates the number of nops required
- between the current instruction and the next instruction to avoid
- any pipeline hazards. */
-static int mt_nops_required = 0;
-static const char * mt_nop_reasons = "";
-
-/* Implement ASM_OUTPUT_OPCODE. */
-const char *
-mt_asm_output_opcode (FILE *f ATTRIBUTE_UNUSED, const char *ptr)
-{
- if (mt_nops_required)
- fprintf (f, ";# need %d nops because of %s\n\t",
- mt_nops_required, mt_nop_reasons);
-
- while (mt_nops_required)
- {
- fprintf (f, "nop\n\t");
- -- mt_nops_required;
- }
-
- return ptr;
-}
-
-/* Given an insn, return whether it's a memory operation or a branch
- operation, otherwise return TYPE_ARITH. */
-static enum attr_type
-mt_get_attr_type (rtx complete_insn)
-{
- rtx insn = PATTERN (complete_insn);
-
- if (JUMP_P (complete_insn))
- return TYPE_BRANCH;
- if (CALL_P (complete_insn))
- return TYPE_BRANCH;
-
- if (GET_CODE (insn) != SET)
- return TYPE_ARITH;
-
- if (SET_DEST (insn) == pc_rtx)
- return TYPE_BRANCH;
-
- if (GET_CODE (SET_DEST (insn)) == MEM)
- return TYPE_STORE;
-
- if (GET_CODE (SET_SRC (insn)) == MEM)
- return TYPE_LOAD;
-
- return TYPE_ARITH;
-}
-
-/* A helper routine for insn_dependent_p called through note_stores. */
-
-static void
-insn_dependent_p_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
-{
- rtx * pinsn = (rtx *) data;
-
- if (*pinsn && reg_mentioned_p (x, *pinsn))
- *pinsn = NULL_RTX;
-}
-
-/* Return true if anything in insn X is (anti,output,true)
- dependent on anything in insn Y. */
-
-static bool
-insn_dependent_p (rtx x, rtx y)
-{
- rtx tmp;
-
- if (! INSN_P (x) || ! INSN_P (y))
- return 0;
-
- tmp = PATTERN (y);
- note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
- if (tmp == NULL_RTX)
- return true;
-
- tmp = PATTERN (x);
- note_stores (PATTERN (y), insn_dependent_p_1, &tmp);
- return (tmp == NULL_RTX);
-}
-
-
-/* Return true if anything in insn X is true dependent on anything in
- insn Y. */
-static bool
-insn_true_dependent_p (rtx x, rtx y)
-{
- rtx tmp;
-
- if (! INSN_P (x) || ! INSN_P (y))
- return 0;
-
- tmp = PATTERN (y);
- note_stores (PATTERN (x), insn_dependent_p_1, &tmp);
- return (tmp == NULL_RTX);
-}
-
-/* The following determines the number of nops that need to be
- inserted between the previous instructions and current instruction
- to avoid pipeline hazards on the mt processor. Remember that
- the function is not called for asm insns. */
-
-void
-mt_final_prescan_insn (rtx insn,
- rtx * opvec ATTRIBUTE_UNUSED,
- int noperands ATTRIBUTE_UNUSED)
-{
- rtx prev_i;
- enum attr_type prev_attr;
-
- mt_nops_required = 0;
- mt_nop_reasons = "";
-
- /* ms2 constraints are dealt with in reorg. */
- if (TARGET_MS2)
- return;
-
- /* Only worry about real instructions. */
- if (! INSN_P (insn))
- return;
-
- /* Find the previous real instructions. */
- for (prev_i = PREV_INSN (insn);
- prev_i != NULL
- && (! INSN_P (prev_i)
- || GET_CODE (PATTERN (prev_i)) == USE
- || GET_CODE (PATTERN (prev_i)) == CLOBBER);
- prev_i = PREV_INSN (prev_i))
- {
- /* If we meet a barrier, there is no flow through here. */
- if (BARRIER_P (prev_i))
- return;
- }
-
- /* If there isn't one then there is nothing that we need do. */
- if (prev_i == NULL || ! INSN_P (prev_i))
- return;
-
- prev_attr = mt_get_attr_type (prev_i);
-
- /* Delayed branch slots already taken care of by delay branch scheduling. */
- if (prev_attr == TYPE_BRANCH)
- return;
-
- switch (mt_get_attr_type (insn))
- {
- case TYPE_LOAD:
- case TYPE_STORE:
- /* Avoid consecutive memory operation. */
- if ((prev_attr == TYPE_LOAD || prev_attr == TYPE_STORE)
- && TARGET_MS1_64_001)
- {
- mt_nops_required = 1;
- mt_nop_reasons = "consecutive mem ops";
- }
- /* Drop through. */
-
- case TYPE_ARITH:
- case TYPE_COMPLEX:
- /* One cycle of delay is required between load
- and the dependent arithmetic instruction. */
- if (prev_attr == TYPE_LOAD
- && insn_true_dependent_p (prev_i, insn))
- {
- mt_nops_required = 1;
- mt_nop_reasons = "load->arith dependency delay";
- }
- break;
-
- case TYPE_BRANCH:
- if (insn_dependent_p (prev_i, insn))
- {
- if (prev_attr == TYPE_ARITH && TARGET_MS1_64_001)
- {
- /* One cycle of delay between arith
- instructions and branch dependent on arith. */
- mt_nops_required = 1;
- mt_nop_reasons = "arith->branch dependency delay";
- }
- else if (prev_attr == TYPE_LOAD)
- {
- /* Two cycles of delay are required
- between load and dependent branch. */
- if (TARGET_MS1_64_001)
- mt_nops_required = 2;
- else
- mt_nops_required = 1;
- mt_nop_reasons = "load->branch dependency delay";
- }
- }
- break;
-
- default:
- fatal_insn ("mt_final_prescan_insn, invalid insn #1", insn);
- break;
- }
-}
-
-/* Print debugging information for a frame. */
-static void
-mt_debug_stack (struct mt_frame_info * info)
-{
- int regno;
-
- if (!info)
- {
- error ("info pointer NULL");
- gcc_unreachable ();
- }
-
- fprintf (stderr, "\nStack information for function %s:\n",
- ((current_function_decl && DECL_NAME (current_function_decl))
- ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
- : "<unknown>"));
-
- fprintf (stderr, "\ttotal_size = %d\n", info->total_size);
- fprintf (stderr, "\tpretend_size = %d\n", info->pretend_size);
- fprintf (stderr, "\targs_size = %d\n", info->args_size);
- fprintf (stderr, "\textra_size = %d\n", info->extra_size);
- fprintf (stderr, "\treg_size = %d\n", info->reg_size);
- fprintf (stderr, "\tvar_size = %d\n", info->var_size);
- fprintf (stderr, "\tframe_size = %d\n", info->frame_size);
- fprintf (stderr, "\treg_mask = 0x%x\n", info->reg_mask);
- fprintf (stderr, "\tsave_fp = %d\n", info->save_fp);
- fprintf (stderr, "\tsave_lr = %d\n", info->save_lr);
- fprintf (stderr, "\tinitialized = %d\n", info->initialized);
- fprintf (stderr, "\tsaved registers =");
-
- /* Print out reg_mask in a more readable format. */
- for (regno = GPR_R0; regno <= GPR_LAST; regno++)
- if ( (1 << regno) & info->reg_mask)
- fprintf (stderr, " %s", reg_names[regno]);
-
- putc ('\n', stderr);
- fflush (stderr);
-}
-
-/* Print a memory address as an operand to reference that memory location. */
-
-static void
-mt_print_operand_simple_address (FILE * file, rtx addr)
-{
- if (!addr)
- error ("PRINT_OPERAND_ADDRESS, null pointer");
-
- else
- switch (GET_CODE (addr))
- {
- case REG:
- fprintf (file, "%s, #0", reg_names[REGNO (addr)]);
- break;
-
- case PLUS:
- {
- rtx reg = 0;
- rtx offset = 0;
- rtx arg0 = XEXP (addr, 0);
- rtx arg1 = XEXP (addr, 1);
-
- if (GET_CODE (arg0) == REG)
- {
- reg = arg0;
- offset = arg1;
- if (GET_CODE (offset) == REG)
- fatal_insn ("PRINT_OPERAND_ADDRESS, 2 regs", addr);
- }
-
- else if (GET_CODE (arg1) == REG)
- reg = arg1, offset = arg0;
- else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
- {
- fprintf (file, "%s, #", reg_names[GPR_R0]);
- output_addr_const (file, addr);
- break;
- }
- fprintf (file, "%s, #", reg_names[REGNO (reg)]);
- output_addr_const (file, offset);
- break;
- }
-
- case LABEL_REF:
- case SYMBOL_REF:
- case CONST_INT:
- case CONST:
- output_addr_const (file, addr);
- break;
-
- default:
- fatal_insn ("PRINT_OPERAND_ADDRESS, invalid insn #1", addr);
- break;
- }
-}
-
-/* Implement PRINT_OPERAND_ADDRESS. */
-void
-mt_print_operand_address (FILE * file, rtx addr)
-{
- if (GET_CODE (addr) == AND
- && GET_CODE (XEXP (addr, 1)) == CONST_INT
- && INTVAL (XEXP (addr, 1)) == -3)
- mt_print_operand_simple_address (file, XEXP (addr, 0));
- else
- mt_print_operand_simple_address (file, addr);
-}
-
-/* Implement PRINT_OPERAND. */
-void
-mt_print_operand (FILE * file, rtx x, int code)
-{
- switch (code)
- {
- case '#':
- /* Output a nop if there's nothing for the delay slot. */
- if (dbr_sequence_length () == 0)
- fputs ("\n\tnop", file);
- return;
-
- case 'H':
- fprintf(file, "#%%hi16(");
- output_addr_const (file, x);
- fprintf(file, ")");
- return;
-
- case 'L':
- fprintf(file, "#%%lo16(");
- output_addr_const (file, x);
- fprintf(file, ")");
- return;
-
- case 'N':
- fprintf(file, "#%ld", ~INTVAL (x));
- return;
-
- case 'z':
- if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
- {
- fputs (reg_names[GPR_R0], file);
- return;
- }
-
- case 0:
- /* Handled below. */
- break;
-
- default:
- /* output_operand_lossage ("mt_print_operand: unknown code"); */
- fprintf (file, "unknown code");
- return;
- }
-
- switch (GET_CODE (x))
- {
- case REG:
- fputs (reg_names[REGNO (x)], file);
- break;
-
- case CONST:
- case CONST_INT:
- fprintf(file, "#%ld", INTVAL (x));
- break;
-
- case MEM:
- mt_print_operand_address(file, XEXP (x,0));
- break;
-
- case LABEL_REF:
- case SYMBOL_REF:
- output_addr_const (file, x);
- break;
-
- default:
- fprintf(file, "Uknown code: %d", GET_CODE (x));
- break;
- }
-
- return;
-}
-
-/* Implement INIT_CUMULATIVE_ARGS. */
-void
-mt_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, rtx libname,
- tree fndecl ATTRIBUTE_UNUSED, int incoming)
-{
- *cum = 0;
-
- if (TARGET_DEBUG_ARG)
- {
- fprintf (stderr, "\nmt_init_cumulative_args:");
-
- if (incoming)
- fputs (" incoming", stderr);
-
- if (fntype)
- {
- tree ret_type = TREE_TYPE (fntype);
- fprintf (stderr, " return = %s,",
- tree_code_name[ (int)TREE_CODE (ret_type) ]);
- }
-
- if (libname && GET_CODE (libname) == SYMBOL_REF)
- fprintf (stderr, " libname = %s", XSTR (libname, 0));
-
- if (cfun->returns_struct)
- fprintf (stderr, " return-struct");
-
- putc ('\n', stderr);
- }
-}
-
-/* Compute the slot number to pass an argument in.
- Returns the slot number or -1 if passing on the stack.
-
- CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called.
- MODE is the argument's machine mode.
- TYPE is the data type of the argument (as a tree).
- This is null for libcalls where that information may
- not be available.
- NAMED is nonzero if this argument is a named parameter
- (otherwise it is an extra parameter matching an ellipsis).
- INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
- *PREGNO records the register number to use if scalar type. */
-
-static int
-mt_function_arg_slotno (const CUMULATIVE_ARGS * cum,
- enum machine_mode mode,
- tree type,
- int named ATTRIBUTE_UNUSED,
- int incoming_p ATTRIBUTE_UNUSED,
- int * pregno)
-{
- int regbase = FIRST_ARG_REGNUM;
- int slotno = * cum;
-
- if (mode == VOIDmode || targetm.calls.must_pass_in_stack (mode, type))
- return -1;
-
- if (slotno >= MT_NUM_ARG_REGS)
- return -1;
-
- * pregno = regbase + slotno;
-
- return slotno;
-}
-
-/* Implement FUNCTION_ARG. */
-rtx
-mt_function_arg (const CUMULATIVE_ARGS * cum,
- enum machine_mode mode,
- tree type,
- int named,
- int incoming_p)
-{
- int slotno, regno;
- rtx reg;
-
- slotno = mt_function_arg_slotno (cum, mode, type, named, incoming_p, &regno);
-
- if (slotno == -1)
- reg = NULL_RTX;
- else
- reg = gen_rtx_REG (mode, regno);
-
- return reg;
-}
-
-/* Implement FUNCTION_ARG_ADVANCE. */
-void
-mt_function_arg_advance (CUMULATIVE_ARGS * cum,
- enum machine_mode mode,
- tree type ATTRIBUTE_UNUSED,
- int named)
-{
- int slotno, regno;
-
- /* We pass 0 for incoming_p here, it doesn't matter. */
- slotno = mt_function_arg_slotno (cum, mode, type, named, 0, &regno);
-
- * cum += (mode != BLKmode
- ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
- : ROUND_ADVANCE (int_size_in_bytes (type)));
-
- if (TARGET_DEBUG_ARG)
- fprintf (stderr,
- "mt_function_arg_advance: words = %2d, mode = %4s, named = %d, size = %3d\n",
- *cum, GET_MODE_NAME (mode), named,
- (*cum) * UNITS_PER_WORD);
-}
-
-/* Implement hook TARGET_ARG_PARTIAL_BYTES.
-
- Returns the number of bytes at the beginning of an argument that
- must be put in registers. The value must be zero for arguments
- that are passed entirely in registers or that are entirely pushed
- on the stack. */
-static int
-mt_arg_partial_bytes (CUMULATIVE_ARGS * pcum,
- enum machine_mode mode,
- tree type,
- bool named ATTRIBUTE_UNUSED)
-{
- int cum = * pcum;
- int words;
-
- if (mode == BLKmode)
- words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
- / UNITS_PER_WORD);
- else
- words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-
- if (! targetm.calls.pass_by_reference (&cum, mode, type, named)
- && cum < MT_NUM_ARG_REGS
- && (cum + words) > MT_NUM_ARG_REGS)
- {
- int bytes = (MT_NUM_ARG_REGS - cum) * UNITS_PER_WORD;
-
- if (TARGET_DEBUG)
- fprintf (stderr, "function_arg_partial_nregs = %d\n", bytes);
- return bytes;
- }
-
- return 0;
-}
-
-
-/* Implement TARGET_PASS_BY_REFERENCE hook. */
-static bool
-mt_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- const_tree type,
- bool named ATTRIBUTE_UNUSED)
-{
- return (type && int_size_in_bytes (type) > 4 * UNITS_PER_WORD);
-}
-
-/* Implement FUNCTION_ARG_BOUNDARY. */
-int
-mt_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type ATTRIBUTE_UNUSED)
-{
- return BITS_PER_WORD;
-}
-
-/* Implement REG_OK_FOR_BASE_P. */
-int
-mt_reg_ok_for_base_p (rtx x, int strict)
-{
- if (strict)
- return (((unsigned) REGNO (x)) < FIRST_PSEUDO_REGISTER);
- return 1;
-}
-
-/* Helper function of mt_legitimate_address_p. Return true if XINSN
- is a simple address, otherwise false. */
-static bool
-mt_legitimate_simple_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
- rtx xinsn, int strict)
-{
- if (TARGET_DEBUG)
- {
- fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
- strict ? "" : "not ");
- debug_rtx (xinsn);
- }
-
- if (GET_CODE (xinsn) == REG && mt_reg_ok_for_base_p (xinsn, strict))
- return true;
-
- if (GET_CODE (xinsn) == PLUS
- && GET_CODE (XEXP (xinsn, 0)) == REG
- && mt_reg_ok_for_base_p (XEXP (xinsn, 0), strict)
- && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
- && SMALL_INT (XEXP (xinsn, 1)))
- return true;
-
- return false;
-}
-
-
-/* Helper function of GO_IF_LEGITIMATE_ADDRESS. Return nonzero if
- XINSN is a legitimate address on MT. */
-int
-mt_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict)
-{
- if (mt_legitimate_simple_address_p (mode, xinsn, strict))
- return 1;
-
- if ((mode) == SImode
- && GET_CODE (xinsn) == AND
- && GET_CODE (XEXP (xinsn, 1)) == CONST_INT
- && INTVAL (XEXP (xinsn, 1)) == -3)
- return mt_legitimate_simple_address_p (mode, XEXP (xinsn, 0), strict);
- else
- return 0;
-}
-
-/* Return truth value of whether OP can be used as an operands where a
- register or 16-bit unsigned integer is needed. */
-
-int
-uns_arith_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
- return 1;
-
- return register_operand (op, mode);
-}
-
-/* Return truth value of whether OP can be used as an operands where a
- 16-bit integer is needed. */
-
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
- return 1;
-
- return register_operand (op, mode);
-}
-
-/* Return truth value of whether OP is a register or the constant 0. */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
- switch (GET_CODE (op))
- {
- case CONST_INT:
- return INTVAL (op) == 0;
-
- case REG:
- case SUBREG:
- return register_operand (op, mode);
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Return truth value of whether OP is a constant that requires two
- loads to put in a register. */
-
-int
-big_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
- return 1;
-
- return 0;
-}
-
-/* Return truth value of whether OP is a constant that require only
- one load to put in a register. */
-
-int
-single_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (big_const_operand (op, mode)
- || GET_CODE (op) == CONST
- || GET_CODE (op) == LABEL_REF
- || GET_CODE (op) == SYMBOL_REF)
- return 0;
-
- return 1;
-}
-
-/* True if the current function is an interrupt handler
- (either via #pragma or an attribute specification). */
-int interrupt_handler;
-enum processor_type mt_cpu;
-
-static struct machine_function *
-mt_init_machine_status (void)
-{
- struct machine_function *f;
-
- f = ggc_alloc_cleared (sizeof (struct machine_function));
-
- return f;
-}
-
-/* Implement OVERRIDE_OPTIONS. */
-void
-mt_override_options (void)
-{
- if (mt_cpu_string != NULL)
- {
- if (!strcmp (mt_cpu_string, "ms1-64-001"))
- mt_cpu = PROCESSOR_MS1_64_001;
- else if (!strcmp (mt_cpu_string, "ms1-16-002"))
- mt_cpu = PROCESSOR_MS1_16_002;
- else if (!strcmp (mt_cpu_string, "ms1-16-003"))
- mt_cpu = PROCESSOR_MS1_16_003;
- else if (!strcmp (mt_cpu_string, "ms2"))
- mt_cpu = PROCESSOR_MS2;
- else
- error ("bad value (%s) for -march= switch", mt_cpu_string);
- }
- else
- mt_cpu = PROCESSOR_MS1_16_002;
-
- if (flag_exceptions)
- {
- flag_omit_frame_pointer = 0;
- flag_gcse = 0;
- }
-
- /* We do delayed branch filling in machine dependent reorg */
- mt_flag_delayed_branch = flag_delayed_branch;
- flag_delayed_branch = 0;
-
- init_machine_status = mt_init_machine_status;
-}
-
-/* Do what is necessary for `va_start'. We look at the current function
- to determine if stdarg or varargs is used and return the address of the
- first unnamed parameter. */
-
-static void
-mt_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type ATTRIBUTE_UNUSED,
- int *pretend_size, int no_rtl)
-{
- int regno;
- int regs = MT_NUM_ARG_REGS - *cum;
-
- *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs;
-
- if (no_rtl)
- return;
-
- for (regno = *cum; regno < MT_NUM_ARG_REGS; regno++)
- {
- rtx reg = gen_rtx_REG (SImode, FIRST_ARG_REGNUM + regno);
- rtx slot = gen_rtx_PLUS (Pmode,
- gen_rtx_REG (SImode, ARG_POINTER_REGNUM),
- GEN_INT (UNITS_PER_WORD * regno));
-
- emit_move_insn (gen_rtx_MEM (SImode, slot), reg);
- }
-}
-
-/* Returns the number of bytes offset between the frame pointer and the stack
- pointer for the current function. SIZE is the number of bytes of space
- needed for local variables. */
-
-unsigned int
-mt_compute_frame_size (int size)
-{
- int regno;
- unsigned int total_size;
- unsigned int var_size;
- unsigned int args_size;
- unsigned int pretend_size;
- unsigned int extra_size;
- unsigned int reg_size;
- unsigned int frame_size;
- unsigned int reg_mask;
-
- var_size = size;
- args_size = crtl->outgoing_args_size;
- pretend_size = crtl->args.pretend_args_size;
- extra_size = FIRST_PARM_OFFSET (0);
- total_size = extra_size + pretend_size + args_size + var_size;
- reg_size = 0;
- reg_mask = 0;
-
- /* Calculate space needed for registers. */
- for (regno = GPR_R0; regno <= GPR_LAST; regno++)
- {
- if (MUST_SAVE_REGISTER (regno))
- {
- reg_size += UNITS_PER_WORD;
- reg_mask |= 1 << regno;
- }
- }
-
- current_frame_info.save_fp = (df_regs_ever_live_p (GPR_FP)
- || frame_pointer_needed
- || interrupt_handler);
- current_frame_info.save_lr = (df_regs_ever_live_p (GPR_LINK)
- || profile_flag
- || interrupt_handler);
-
- reg_size += (current_frame_info.save_fp + current_frame_info.save_lr)
- * UNITS_PER_WORD;
- total_size += reg_size;
- total_size = ((total_size + 3) & ~3);
-
- frame_size = total_size;
-
- /* Save computed information. */
- current_frame_info.pretend_size = pretend_size;
- current_frame_info.var_size = var_size;
- current_frame_info.args_size = args_size;
- current_frame_info.reg_size = reg_size;
- current_frame_info.frame_size = args_size + var_size;
- current_frame_info.total_size = total_size;
- current_frame_info.extra_size = extra_size;
- current_frame_info.reg_mask = reg_mask;
- current_frame_info.initialized = reload_completed;
-
- return total_size;
-}
-
-/* Emit code to save REG in stack offset pointed to by MEM.
- STACK_OFFSET is the offset from the SP where the save will happen.
- This function sets the REG_FRAME_RELATED_EXPR note accordingly. */
-static void
-mt_emit_save_restore (enum save_direction direction,
- rtx reg, rtx mem, int stack_offset)
-{
- if (direction == FROM_PROCESSOR_TO_MEM)
- {
- rtx insn;
-
- insn = emit_move_insn (mem, reg);
- RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST
- (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (SImode,
- gen_rtx_PLUS (SImode,
- stack_pointer_rtx,
- GEN_INT (stack_offset))),
- reg),
- REG_NOTES (insn));
- }
- else
- emit_move_insn (reg, mem);
-}
-
-
-/* Emit code to save the frame pointer in the prologue and restore
- frame pointer in epilogue. */
-
-static void
-mt_emit_save_fp (enum save_direction direction,
- struct mt_frame_info info)
-{
- rtx base_reg;
- int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
- int offset = info.total_size;
- int stack_offset = info.total_size;
-
- /* If there is nothing to save, get out now. */
- if (! info.save_fp && ! info.save_lr && ! reg_mask)
- return;
-
- /* If offset doesn't fit in a 15-bit signed integer,
- uses a scratch registers to get a smaller offset. */
- if (CONST_OK_FOR_LETTER_P(offset, 'O'))
- base_reg = stack_pointer_rtx;
- else
- {
- /* Use the scratch register R9 that holds old stack pointer. */
- base_reg = gen_rtx_REG (SImode, GPR_R9);
- offset = 0;
- }
-
- if (info.save_fp)
- {
- offset -= UNITS_PER_WORD;
- stack_offset -= UNITS_PER_WORD;
- mt_emit_save_restore
- (direction, gen_rtx_REG (SImode, GPR_FP),
- gen_rtx_MEM (SImode,
- gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
- stack_offset);
- }
-}
-
-/* Emit code to save registers in the prologue and restore register
- in epilogue. */
-
-static void
-mt_emit_save_regs (enum save_direction direction,
- struct mt_frame_info info)
-{
- rtx base_reg;
- int regno;
- int reg_mask = info.reg_mask & ~(FP_MASK | LINK_MASK);
- int offset = info.total_size;
- int stack_offset = info.total_size;
-
- /* If there is nothing to save, get out now. */
- if (! info.save_fp && ! info.save_lr && ! reg_mask)
- return;
-
- /* If offset doesn't fit in a 15-bit signed integer,
- uses a scratch registers to get a smaller offset. */
- if (CONST_OK_FOR_LETTER_P(offset, 'O'))
- base_reg = stack_pointer_rtx;
- else
- {
- /* Use the scratch register R9 that holds old stack pointer. */
- base_reg = gen_rtx_REG (SImode, GPR_R9);
- offset = 0;
- }
-
- if (info.save_fp)
- {
- /* This just records the space for it, the actual move generated in
- mt_emit_save_fp (). */
- offset -= UNITS_PER_WORD;
- stack_offset -= UNITS_PER_WORD;
- }
-
- if (info.save_lr)
- {
- offset -= UNITS_PER_WORD;
- stack_offset -= UNITS_PER_WORD;
- mt_emit_save_restore
- (direction, gen_rtx_REG (SImode, GPR_LINK),
- gen_rtx_MEM (SImode,
- gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
- stack_offset);
- }
-
- /* Save any needed call-saved regs. */
- for (regno = GPR_R0; regno <= GPR_LAST; regno++)
- {
- if ((reg_mask & (1 << regno)) != 0)
- {
- offset -= UNITS_PER_WORD;
- stack_offset -= UNITS_PER_WORD;
- mt_emit_save_restore
- (direction, gen_rtx_REG (SImode, regno),
- gen_rtx_MEM (SImode,
- gen_rtx_PLUS (SImode, base_reg, GEN_INT (offset))),
- stack_offset);
- }
- }
-}
-
-/* Return true if FUNC is a function with the 'interrupt' attribute. */
-static bool
-mt_interrupt_function_p (tree func)
-{
- tree a;
-
- if (TREE_CODE (func) != FUNCTION_DECL)
- return false;
-
- a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
- return a != NULL_TREE;
-}
-
-/* Generate prologue code. */
-void
-mt_expand_prologue (void)
-{
- rtx size_rtx, insn;
- unsigned int frame_size;
-
- if (mt_interrupt_function_p (current_function_decl))
- {
- interrupt_handler = 1;
- if (cfun->machine)
- cfun->machine->interrupt_handler = 1;
- }
-
- mt_compute_frame_size (get_frame_size ());
-
- if (TARGET_DEBUG_STACK)
- mt_debug_stack (&current_frame_info);
-
- /* Compute size of stack adjustment. */
- frame_size = current_frame_info.total_size;
-
- /* If offset doesn't fit in a 15-bit signed integer,
- uses a scratch registers to get a smaller offset. */
- if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
- size_rtx = GEN_INT (frame_size);
- else
- {
- /* We do not have any scratch registers. */
- gcc_assert (!interrupt_handler);
-
- size_rtx = gen_rtx_REG (SImode, GPR_R9);
- insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
- insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
- GEN_INT (frame_size & 0x0000ffff)));
- }
-
- /* Allocate stack for this frame. */
- /* Make stack adjustment and use scratch register if constant too
- large to fit as immediate. */
- if (frame_size)
- {
- insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- size_rtx));
- RTX_FRAME_RELATED_P (insn) = 1;
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_MINUS (SImode,
- stack_pointer_rtx,
- GEN_INT (frame_size))),
- REG_NOTES (insn));
- }
-
- /* Set R9 to point to old sp if required for access to register save
- area. */
- if ( current_frame_info.reg_size != 0
- && !CONST_OK_FOR_LETTER_P (frame_size, 'O'))
- emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
-
- /* Save the frame pointer. */
- mt_emit_save_fp (FROM_PROCESSOR_TO_MEM, current_frame_info);
-
- /* Now put the frame pointer into the frame pointer register. */
- if (frame_pointer_needed)
- {
- insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- /* Save the registers. */
- mt_emit_save_regs (FROM_PROCESSOR_TO_MEM, current_frame_info);
-
- /* If we are profiling, make sure no instructions are scheduled before
- the call to mcount. */
- if (profile_flag)
- emit_insn (gen_blockage ());
-}
-
-/* Implement EPILOGUE_USES. */
-int
-mt_epilogue_uses (int regno)
-{
- if (cfun->machine && cfun->machine->interrupt_handler && reload_completed)
- return 1;
- return regno == GPR_LINK;
-}
-
-/* Generate epilogue. EH_MODE is NORMAL_EPILOGUE when generating a
- function epilogue, or EH_EPILOGUE when generating an EH
- epilogue. */
-void
-mt_expand_epilogue (enum epilogue_type eh_mode)
-{
- rtx size_rtx, insn;
- unsigned frame_size;
-
- mt_compute_frame_size (get_frame_size ());
-
- if (TARGET_DEBUG_STACK)
- mt_debug_stack (& current_frame_info);
-
- /* Compute size of stack adjustment. */
- frame_size = current_frame_info.total_size;
-
- /* If offset doesn't fit in a 15-bit signed integer,
- uses a scratch registers to get a smaller offset. */
- if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
- size_rtx = GEN_INT (frame_size);
- else
- {
- /* We do not have any scratch registers. */
- gcc_assert (!interrupt_handler);
-
- size_rtx = gen_rtx_REG (SImode, GPR_R9);
- insn = emit_move_insn (size_rtx, GEN_INT (frame_size & 0xffff0000));
- insn = emit_insn (gen_iorsi3 (size_rtx, size_rtx,
- GEN_INT (frame_size & 0x0000ffff)));
- /* Set R9 to point to old sp if required for access to register
- save area. */
- emit_insn (gen_addsi3 (size_rtx, size_rtx, stack_pointer_rtx));
- }
-
- /* Restore sp if there was some possible change to it. */
- if (frame_pointer_needed)
- insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
-
- /* Restore the registers. */
- mt_emit_save_fp (FROM_MEM_TO_PROCESSOR, current_frame_info);
- mt_emit_save_regs (FROM_MEM_TO_PROCESSOR, current_frame_info);
-
- /* Make stack adjustment and use scratch register if constant too
- large to fit as immediate. */
- if (frame_size)
- {
- if (CONST_OK_FOR_LETTER_P(frame_size, 'O'))
- /* Can handle this with simple add. */
- insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- size_rtx));
- else
- /* Scratch reg R9 has the old sp value. */
- insn = emit_move_insn (stack_pointer_rtx,
- gen_rtx_REG (SImode, GPR_R9));
-
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode,
- stack_pointer_rtx,
- gen_rtx_PLUS (SImode,
- stack_pointer_rtx,
- GEN_INT (frame_size))),
- REG_NOTES (insn));
- }
-
- if (cfun->machine && cfun->machine->eh_stack_adjust != NULL_RTX)
- /* Perform the additional bump for __throw. */
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- cfun->machine->eh_stack_adjust));
-
- /* Generate the appropriate return. */
- if (eh_mode == EH_EPILOGUE)
- {
- emit_jump_insn (gen_eh_return_internal ());
- emit_barrier ();
- }
- else if (interrupt_handler)
- emit_jump_insn (gen_return_interrupt_internal ());
- else
- emit_jump_insn (gen_return_internal ());
-
- /* Reset state info for each function. */
- interrupt_handler = 0;
- current_frame_info = zero_frame_info;
- if (cfun->machine)
- cfun->machine->eh_stack_adjust = NULL_RTX;
-}
-
-
-/* Generate code for the "eh_return" pattern. */
-void
-mt_expand_eh_return (rtx * operands)
-{
- if (GET_CODE (operands[0]) != REG
- || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
- {
- rtx sp = EH_RETURN_STACKADJ_RTX;
-
- emit_move_insn (sp, operands[0]);
- operands[0] = sp;
- }
-
- emit_insn (gen_eh_epilogue (operands[0]));
-}
-
-/* Generate code for the "eh_epilogue" pattern. */
-void
-mt_emit_eh_epilogue (rtx * operands ATTRIBUTE_UNUSED)
-{
- cfun->machine->eh_stack_adjust = EH_RETURN_STACKADJ_RTX; /* operands[0]; */
- mt_expand_epilogue (EH_EPILOGUE);
-}
-
-/* Handle an "interrupt" attribute. */
-static tree
-mt_handle_interrupt_attribute (tree * node,
- tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool * no_add_attrs)
-{
- if (TREE_CODE (*node) != FUNCTION_DECL)
- {
- warning (OPT_Wattributes,
- "%qs attribute only applies to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Table of machine attributes. */
-const struct attribute_spec mt_attribute_table[] =
-{
- /* name, min, max, decl?, type?, func?, handler */
- { "interrupt", 0, 0, false, false, false, mt_handle_interrupt_attribute },
- { NULL, 0, 0, false, false, false, NULL }
-};
-
-/* Implement INITIAL_ELIMINATION_OFFSET. */
-int
-mt_initial_elimination_offset (int from, int to)
-{
- mt_compute_frame_size (get_frame_size ());
-
- if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
- return 0;
-
- else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
- return current_frame_info.total_size;
-
- else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
- return current_frame_info.total_size;
-
- else
- gcc_unreachable ();
-}
-
-/* Generate a compare for CODE. Return a brand-new rtx that
- represents the result of the compare. */
-
-static rtx
-mt_generate_compare (enum rtx_code code, rtx op0, rtx op1)
-{
- rtx scratch0, scratch1, const_scratch;
-
- switch (code)
- {
- case GTU:
- case LTU:
- case GEU:
- case LEU:
- /* Need to adjust ranges for faking unsigned compares. */
- scratch0 = gen_reg_rtx (SImode);
- scratch1 = gen_reg_rtx (SImode);
- const_scratch = force_reg (SImode, GEN_INT(MT_MIN_INT));
- emit_insn (gen_addsi3 (scratch0, const_scratch, op0));
- emit_insn (gen_addsi3 (scratch1, const_scratch, op1));
- break;
- default:
- scratch0 = op0;
- scratch1 = op1;
- break;
- }
-
- /* Adjust compare operator to fake unsigned compares. */
- switch (code)
- {
- case GTU:
- code = GT; break;
- case LTU:
- code = LT; break;
- case GEU:
- code = GE; break;
- case LEU:
- code = LE; break;
- default:
- /* do nothing */
- break;
- }
-
- /* Generate the actual compare. */
- return gen_rtx_fmt_ee (code, VOIDmode, scratch0, scratch1);
-}
-
-/* Emit a branch of kind CODE to location LOC. */
-
-void
-mt_emit_cbranch (enum rtx_code code, rtx loc, rtx op0, rtx op1)
-{
- rtx condition_rtx, loc_ref;
-
- if (! reg_or_0_operand (op0, SImode))
- op0 = copy_to_mode_reg (SImode, op0);
-
- if (! reg_or_0_operand (op1, SImode))
- op1 = copy_to_mode_reg (SImode, op1);
-
- condition_rtx = mt_generate_compare (code, op0, op1);
- loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
- emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
- gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
- loc_ref, pc_rtx)));
-}
-
-/* Subfunction of the following function. Update the flags of any MEM
- found in part of X. */
-
-static void
-mt_set_memflags_1 (rtx x, int in_struct_p, int volatile_p)
-{
- int i;
-
- switch (GET_CODE (x))
- {
- case SEQUENCE:
- case PARALLEL:
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- mt_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p);
- break;
-
- case INSN:
- mt_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p);
- break;
-
- case SET:
- mt_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p);
- mt_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p);
- break;
-
- case MEM:
- MEM_IN_STRUCT_P (x) = in_struct_p;
- MEM_VOLATILE_P (x) = volatile_p;
- /* Sadly, we cannot use alias sets because the extra aliasing
- produced by the AND interferes. Given that two-byte quantities
- are the only thing we would be able to differentiate anyway,
- there does not seem to be any point in convoluting the early
- out of the alias check. */
- /* set_mem_alias_set (x, alias_set); */
- break;
-
- default:
- break;
- }
-}
-
-/* Look for any MEMs in the current sequence of insns and set the
- in-struct, unchanging, and volatile flags from the flags in REF.
- If REF is not a MEM, don't do anything. */
-
-void
-mt_set_memflags (rtx ref)
-{
- rtx insn;
- int in_struct_p, volatile_p;
-
- if (GET_CODE (ref) != MEM)
- return;
-
- in_struct_p = MEM_IN_STRUCT_P (ref);
- volatile_p = MEM_VOLATILE_P (ref);
-
- /* This is only called from mt.md, after having had something
- generated from one of the insn patterns. So if everything is
- zero, the pattern is already up-to-date. */
- if (! in_struct_p && ! volatile_p)
- return;
-
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- mt_set_memflags_1 (insn, in_struct_p, volatile_p);
-}
-
-/* Implement SECONDARY_RELOAD_CLASS. */
-enum reg_class
-mt_secondary_reload_class (enum reg_class class ATTRIBUTE_UNUSED,
- enum machine_mode mode,
- rtx x)
-{
- if ((mode == QImode && (!TARGET_BYTE_ACCESS)) || mode == HImode)
- {
- if (GET_CODE (x) == MEM
- || (GET_CODE (x) == REG && true_regnum (x) == -1)
- || (GET_CODE (x) == SUBREG
- && (GET_CODE (SUBREG_REG (x)) == MEM
- || (GET_CODE (SUBREG_REG (x)) == REG
- && true_regnum (SUBREG_REG (x)) == -1))))
- return GENERAL_REGS;
- }
-
- return NO_REGS;
-}
-
-/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE
- macros. */
-rtx
-mt_function_value (const_tree valtype, enum machine_mode mode, const_tree func_decl ATTRIBUTE_UNUSED)
-{
- if ((mode) == DImode || (mode) == DFmode)
- return gen_rtx_MEM (mode, gen_rtx_REG (mode, RETURN_VALUE_REGNUM));
-
- if (valtype)
- mode = TYPE_MODE (valtype);
-
- return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
-}
-
-/* Split a move into two smaller pieces.
- MODE indicates the reduced mode. OPERANDS[0] is the original destination
- OPERANDS[1] is the original src. The new destinations are
- OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3]
- and OPERANDS[5]. */
-
-void
-mt_split_words (enum machine_mode nmode,
- enum machine_mode omode,
- rtx *operands)
-{
- rtx dl,dh; /* src/dest pieces. */
- rtx sl,sh;
- int move_high_first = 0; /* Assume no overlap. */
-
- switch (GET_CODE (operands[0])) /* Dest. */
- {
- case SUBREG:
- case REG:
- if ((GET_CODE (operands[1]) == REG
- || GET_CODE (operands[1]) == SUBREG)
- && true_regnum (operands[0]) <= true_regnum (operands[1]))
- move_high_first = 1;
-
- if (GET_CODE (operands[0]) == SUBREG)
- {
- dl = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]),
- SUBREG_BYTE (operands[0]) + GET_MODE_SIZE (nmode));
- dh = gen_rtx_SUBREG (nmode, SUBREG_REG (operands[0]), SUBREG_BYTE (operands[0]));
- }
- else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
- {
- int r = REGNO (operands[0]);
- dh = gen_rtx_REG (nmode, r);
- dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
- }
- else
- {
- dh = gen_rtx_SUBREG (nmode, operands[0], 0);
- dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
- }
- break;
-
- case MEM:
- switch (GET_CODE (XEXP (operands[0], 0)))
- {
- case POST_INC:
- case POST_DEC:
- gcc_unreachable ();
- default:
- dl = operand_subword (operands[0],
- GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
- 0, omode);
- dh = operand_subword (operands[0], 0, 0, omode);
- }
- break;
- default:
- gcc_unreachable ();
- }
-
- switch (GET_CODE (operands[1]))
- {
- case REG:
- if (! IS_PSEUDO_P (operands[1]))
- {
- int r = REGNO (operands[1]);
-
- sh = gen_rtx_REG (nmode, r);
- sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
- }
- else
- {
- sh = gen_rtx_SUBREG (nmode, operands[1], 0);
- sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
- }
- break;
-
- case CONST_DOUBLE:
- if (operands[1] == const0_rtx)
- sh = sl = const0_rtx;
- else
- split_double (operands[1], & sh, & sl);
- break;
-
- case CONST_INT:
- if (operands[1] == const0_rtx)
- sh = sl = const0_rtx;
- else
- {
- int vl, vh;
-
- switch (nmode)
- {
- default:
- gcc_unreachable ();
- }
-
- sl = GEN_INT (vl);
- sh = GEN_INT (vh);
- }
- break;
-
- case SUBREG:
- sl = gen_rtx_SUBREG (nmode,
- SUBREG_REG (operands[1]),
- SUBREG_BYTE (operands[1]) + GET_MODE_SIZE (nmode));
- sh = gen_rtx_SUBREG (nmode,
- SUBREG_REG (operands[1]),
- SUBREG_BYTE (operands[1]));
- break;
-
- case MEM:
- switch (GET_CODE (XEXP (operands[1], 0)))
- {
- case POST_DEC:
- case POST_INC:
- gcc_unreachable ();
- break;
- default:
- sl = operand_subword (operands[1],
- GET_MODE_SIZE (nmode)/UNITS_PER_WORD,
- 0, omode);
- sh = operand_subword (operands[1], 0, 0, omode);
-
- /* Check if the DF load is going to clobber the register
- used for the address, and if so make sure that is going
- to be the second move. */
- if (GET_CODE (dl) == REG
- && true_regnum (dl)
- == true_regnum (XEXP (XEXP (sl, 0 ), 0)))
- move_high_first = 1;
- }
- break;
- default:
- gcc_unreachable ();
- }
-
- if (move_high_first)
- {
- operands[2] = dh;
- operands[3] = sh;
- operands[4] = dl;
- operands[5] = sl;
- }
- else
- {
- operands[2] = dl;
- operands[3] = sl;
- operands[4] = dh;
- operands[5] = sh;
- }
- return;
-}
-
-/* Implement TARGET_MUST_PASS_IN_STACK hook. */
-static bool
-mt_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, const_tree type)
-{
- return (((type) != 0
- && (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
- || TREE_ADDRESSABLE (type))));
-}
-
-/* Increment the counter for the number of loop instructions in the
- current function. */
-
-void mt_add_loop (void)
-{
- cfun->machine->has_loops++;
-}
-
-
-/* Maximum loop nesting depth. */
-#define MAX_LOOP_DEPTH 4
-/* Maximum size of a loop (allows some headroom for delayed branch slot
- filling. */
-#define MAX_LOOP_LENGTH (200 * 4)
-
-/* We need to keep a vector of loops */
-typedef struct loop_info *loop_info;
-DEF_VEC_P (loop_info);
-DEF_VEC_ALLOC_P (loop_info,heap);
-
-/* Information about a loop we have found (or are in the process of
- finding). */
-struct loop_info GTY (())
-{
- /* loop number, for dumps */
- int loop_no;
-
- /* Predecessor block of the loop. This is the one that falls into
- the loop and contains the initialization instruction. */
- basic_block predecessor;
-
- /* First block in the loop. This is the one branched to by the dbnz
- insn. */
- basic_block head;
-
- /* Last block in the loop (the one with the dbnz insn */
- basic_block tail;
-
- /* The successor block of the loop. This is the one the dbnz insn
- falls into. */
- basic_block successor;
-
- /* The dbnz insn. */
- rtx dbnz;
-
- /* The initialization insn. */
- rtx init;
-
- /* The new initialization instruction. */
- rtx loop_init;
-
- /* The new ending instruction. */
- rtx loop_end;
-
- /* The new label placed at the end of the loop. */
- rtx end_label;
-
- /* The nesting depth of the loop. Set to -1 for a bad loop. */
- int depth;
-
- /* The length of the loop. */
- int length;
-
- /* Next loop in the graph. */
- struct loop_info *next;
-
- /* Vector of blocks only within the loop, (excluding those within
- inner loops). */
- VEC (basic_block,heap) *blocks;
-
- /* Vector of inner loops within this loop */
- VEC (loop_info,heap) *loops;
-};
-
-/* Information used during loop detection. */
-typedef struct loop_work GTY(())
-{
- /* Basic block to be scanned. */
- basic_block block;
-
- /* Loop it will be within. */
- loop_info loop;
-} loop_work;
-
-/* Work list. */
-DEF_VEC_O (loop_work);
-DEF_VEC_ALLOC_O (loop_work,heap);
-
-/* Determine the nesting and length of LOOP. Return false if the loop
- is bad. */
-
-static bool
-mt_loop_nesting (loop_info loop)
-{
- loop_info inner;
- unsigned ix;
- int inner_depth = 0;
-
- if (!loop->depth)
- {
- /* Make sure we only have one entry point. */
- if (EDGE_COUNT (loop->head->preds) == 2)
- {
- loop->predecessor = EDGE_PRED (loop->head, 0)->src;
- if (loop->predecessor == loop->tail)
- /* We wanted the other predecessor. */
- loop->predecessor = EDGE_PRED (loop->head, 1)->src;
-
- /* We can only place a loop insn on a fall through edge of a
- single exit block. */
- if (EDGE_COUNT (loop->predecessor->succs) != 1
- || !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU))
- loop->predecessor = NULL;
- }
-
- /* Mark this loop as bad for now. */
- loop->depth = -1;
- if (loop->predecessor)
- {
- for (ix = 0; VEC_iterate (loop_info, loop->loops, ix++, inner);)
- {
- if (!inner->depth)
- mt_loop_nesting (inner);
-
- if (inner->depth < 0)
- {
- inner_depth = -1;
- break;
- }
-
- if (inner_depth < inner->depth)
- inner_depth = inner->depth;
- loop->length += inner->length;
- }
-
- /* Set the proper loop depth, if it was good. */
- if (inner_depth >= 0)
- loop->depth = inner_depth + 1;
- }
- }
- return (loop->depth > 0
- && loop->predecessor
- && loop->depth < MAX_LOOP_DEPTH
- && loop->length < MAX_LOOP_LENGTH);
-}
-
-/* Determine the length of block BB. */
-
-static int
-mt_block_length (basic_block bb)
-{
- int length = 0;
- rtx insn;
-
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- if (!INSN_P (insn))
- continue;
- if (CALL_P (insn))
- {
- /* Calls are not allowed in loops. */
- length = MAX_LOOP_LENGTH + 1;
- break;
- }
-
- length += get_attr_length (insn);
- }
- return length;
-}
-
-/* Scan the blocks of LOOP (and its inferiors) looking for uses of
- REG. Return true, if we find any. Don't count the loop's dbnz
- insn if it matches DBNZ. */
-
-static bool
-mt_scan_loop (loop_info loop, rtx reg, rtx dbnz)
-{
- unsigned ix;
- loop_info inner;
- basic_block bb;
-
- for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
- {
- rtx insn;
-
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- if (!INSN_P (insn))
- continue;
- if (insn == dbnz)
- continue;
- if (reg_mentioned_p (reg, PATTERN (insn)))
- return true;
- }
- }
- for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
- if (mt_scan_loop (inner, reg, NULL_RTX))
- return true;
-
- return false;
-}
-
-/* MS2 has a loop instruction which needs to be placed just before the
- loop. It indicates the end of the loop and specifies the number of
- loop iterations. It can be nested with an automatically maintained
- stack of counter and end address registers. It's an ideal
- candidate for doloop. Unfortunately, gcc presumes that loops
- always end with an explicit instruction, and the doloop_begin
- instruction is not a flow control instruction so it can be
- scheduled earlier than just before the start of the loop. To make
- matters worse, the optimization pipeline can duplicate loop exit
- and entrance blocks and fails to track abnormally exiting loops.
- Thus we cannot simply use doloop.
-
- What we do is emit a dbnz pattern for the doloop optimization, and
- let that be optimized as normal. Then in machine dependent reorg
- we have to repeat the loop searching algorithm. We use the
- flow graph to find closed loops ending in a dbnz insn. We then try
- and convert it to use the loop instruction. The conditions are,
-
- * the loop has no abnormal exits, duplicated end conditions or
- duplicated entrance blocks
-
- * the loop counter register is only used in the dbnz instruction
- within the loop
-
- * we can find the instruction setting the initial value of the loop
- counter
-
- * the loop is not executed more than 65535 times. (This might be
- changed to 2^32-1, and would therefore allow variable initializers.)
-
- * the loop is not nested more than 4 deep 5) there are no
- subroutine calls in the loop. */
-
-static void
-mt_reorg_loops (FILE *dump_file)
-{
- basic_block bb;
- loop_info loops = NULL;
- loop_info loop;
- int nloops = 0;
- unsigned dwork = 0;
- VEC (loop_work,heap) *works = VEC_alloc (loop_work,heap,20);
- loop_work *work;
- edge e;
- edge_iterator ei;
- bool replaced = false;
-
- /* Find all the possible loop tails. This means searching for every
- dbnz instruction. For each one found, create a loop_info
- structure and add the head block to the work list. */
- FOR_EACH_BB (bb)
- {
- rtx tail = BB_END (bb);
-
- while (GET_CODE (tail) == NOTE)
- tail = PREV_INSN (tail);
-
- bb->aux = NULL;
- if (recog_memoized (tail) == CODE_FOR_decrement_and_branch_until_zero)
- {
- /* A possible loop end */
-
- loop = XNEW (struct loop_info);
- loop->next = loops;
- loops = loop;
- loop->tail = bb;
- loop->head = BRANCH_EDGE (bb)->dest;
- loop->successor = FALLTHRU_EDGE (bb)->dest;
- loop->predecessor = NULL;
- loop->dbnz = tail;
- loop->depth = 0;
- loop->length = mt_block_length (bb);
- loop->blocks = VEC_alloc (basic_block, heap, 20);
- VEC_quick_push (basic_block, loop->blocks, bb);
- loop->loops = NULL;
- loop->loop_no = nloops++;
-
- loop->init = loop->end_label = NULL_RTX;
- loop->loop_init = loop->loop_end = NULL_RTX;
-
- work = VEC_safe_push (loop_work, heap, works, NULL);
- work->block = loop->head;
- work->loop = loop;
-
- bb->aux = loop;
-
- if (dump_file)
- {
- fprintf (dump_file, ";; potential loop %d ending at\n",
- loop->loop_no);
- print_rtl_single (dump_file, tail);
- }
- }
- }
-
- /* Now find all the closed loops.
- until work list empty,
- if block's auxptr is set
- if != loop slot
- if block's loop's start != block
- mark loop as bad
- else
- append block's loop's fallthrough block to worklist
- increment this loop's depth
- else if block is exit block
- mark loop as bad
- else
- set auxptr
- for each target of block
- add to worklist */
- while (VEC_iterate (loop_work, works, dwork++, work))
- {
- loop = work->loop;
- bb = work->block;
- if (bb == EXIT_BLOCK_PTR)
- /* We've reached the exit block. The loop must be bad. */
- loop->depth = -1;
- else if (!bb->aux)
- {
- /* We've not seen this block before. Add it to the loop's
- list and then add each successor to the work list. */
- bb->aux = loop;
- loop->length += mt_block_length (bb);
- VEC_safe_push (basic_block, heap, loop->blocks, bb);
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (!VEC_space (loop_work, works, 1))
- {
- if (dwork)
- {
- VEC_block_remove (loop_work, works, 0, dwork);
- dwork = 0;
- }
- else
- VEC_reserve (loop_work, heap, works, 1);
- }
- work = VEC_quick_push (loop_work, works, NULL);
- work->block = EDGE_SUCC (bb, ei.index)->dest;
- work->loop = loop;
- }
- }
- else if (bb->aux != loop)
- {
- /* We've seen this block in a different loop. If it's not
- the other loop's head, then this loop must be bad.
- Otherwise, the other loop might be a nested loop, so
- continue from that loop's successor. */
- loop_info other = bb->aux;
-
- if (other->head != bb)
- loop->depth = -1;
- else
- {
- VEC_safe_push (loop_info, heap, loop->loops, other);
- work = VEC_safe_push (loop_work, heap, works, NULL);
- work->loop = loop;
- work->block = other->successor;
- }
- }
- }
- VEC_free (loop_work, heap, works);
-
- /* Now optimize the loops. */
- for (loop = loops; loop; loop = loop->next)
- {
- rtx iter_reg, insn, init_insn;
- rtx init_val, loop_end, loop_init, end_label, head_label;
-
- if (!mt_loop_nesting (loop))
- {
- if (dump_file)
- fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
- continue;
- }
-
- /* Get the loop iteration register. */
- iter_reg = SET_DEST (XVECEXP (PATTERN (loop->dbnz), 0, 1));
-
- if (!REG_P (iter_reg))
- {
- /* Spilled */
- if (dump_file)
- fprintf (dump_file, ";; loop %d has spilled iteration count\n",
- loop->loop_no);
- continue;
- }
-
- /* Look for the initializing insn */
- init_insn = NULL_RTX;
- for (insn = BB_END (loop->predecessor);
- insn != PREV_INSN (BB_HEAD (loop->predecessor));
- insn = PREV_INSN (insn))
- {
- if (!INSN_P (insn))
- continue;
- if (reg_mentioned_p (iter_reg, PATTERN (insn)))
- {
- rtx set = single_set (insn);
-
- if (set && rtx_equal_p (iter_reg, SET_DEST (set)))
- init_insn = insn;
- break;
- }
- }
-
- if (!init_insn)
- {
- if (dump_file)
- fprintf (dump_file, ";; loop %d has no initializer\n",
- loop->loop_no);
- continue;
- }
- if (dump_file)
- {
- fprintf (dump_file, ";; loop %d initialized by\n",
- loop->loop_no);
- print_rtl_single (dump_file, init_insn);
- }
-
- init_val = PATTERN (init_insn);
- if (GET_CODE (init_val) == SET)
- init_val = SET_SRC (init_val);
- if (GET_CODE (init_val) != CONST_INT || INTVAL (init_val) >= 65535)
- {
- if (dump_file)
- fprintf (dump_file, ";; loop %d has complex initializer\n",
- loop->loop_no);
- continue;
- }
-
- /* Scan all the blocks to make sure they don't use iter_reg. */
- if (mt_scan_loop (loop, iter_reg, loop->dbnz))
- {
- if (dump_file)
- fprintf (dump_file, ";; loop %d uses iterator\n",
- loop->loop_no);
- continue;
- }
-
- /* The loop is good for replacement. */
-
- /* loop is 1 based, dbnz is zero based. */
- init_val = GEN_INT (INTVAL (init_val) + 1);
-
- iter_reg = gen_rtx_REG (SImode, LOOP_FIRST + loop->depth - 1);
- end_label = gen_label_rtx ();
- head_label = XEXP (SET_SRC (XVECEXP (PATTERN (loop->dbnz), 0, 0)), 1);
- loop_end = gen_loop_end (iter_reg, head_label);
- loop_init = gen_loop_init (iter_reg, init_val, end_label);
- loop->init = init_insn;
- loop->end_label = end_label;
- loop->loop_init = loop_init;
- loop->loop_end = loop_end;
- replaced = true;
-
- if (dump_file)
- {
- fprintf (dump_file, ";; replacing loop %d initializer with\n",
- loop->loop_no);
- print_rtl_single (dump_file, loop->loop_init);
- fprintf (dump_file, ";; replacing loop %d terminator with\n",
- loop->loop_no);
- print_rtl_single (dump_file, loop->loop_end);
- }
- }
-
- /* Now apply the optimizations. Do it this way so we don't mess up
- the flow graph half way through. */
- for (loop = loops; loop; loop = loop->next)
- if (loop->loop_init)
- {
- emit_jump_insn_after (loop->loop_init, BB_END (loop->predecessor));
- delete_insn (loop->init);
- emit_label_before (loop->end_label, loop->dbnz);
- emit_jump_insn_before (loop->loop_end, loop->dbnz);
- delete_insn (loop->dbnz);
- }
-
- /* Free up the loop structures */
- while (loops)
- {
- loop = loops;
- loops = loop->next;
- VEC_free (loop_info, heap, loop->loops);
- VEC_free (basic_block, heap, loop->blocks);
- XDELETE (loop);
- }
-
- if (replaced && dump_file)
- {
- fprintf (dump_file, ";; Replaced loops\n");
- print_rtl (dump_file, get_insns ());
- }
-}
-
-/* Structures to hold branch information during reorg. */
-typedef struct branch_info
-{
- rtx insn; /* The branch insn. */
-
- struct branch_info *next;
-} branch_info;
-
-typedef struct label_info
-{
- rtx label; /* The label. */
- branch_info *branches; /* branches to this label. */
- struct label_info *next;
-} label_info;
-
-/* Chain of labels found in current function, used during reorg. */
-static label_info *mt_labels;
-
-/* If *X is a label, add INSN to the list of branches for that
- label. */
-
-static int
-mt_add_branches (rtx *x, void *insn)
-{
- if (GET_CODE (*x) == LABEL_REF)
- {
- branch_info *branch = xmalloc (sizeof (*branch));
- rtx label = XEXP (*x, 0);
- label_info *info;
-
- for (info = mt_labels; info; info = info->next)
- if (info->label == label)
- break;
-
- if (!info)
- {
- info = xmalloc (sizeof (*info));
- info->next = mt_labels;
- mt_labels = info;
-
- info->label = label;
- info->branches = NULL;
- }
-
- branch->next = info->branches;
- info->branches = branch;
- branch->insn = insn;
- }
- return 0;
-}
-
-/* If BRANCH has a filled delay slot, check if INSN is dependent upon
- it. If so, undo the delay slot fill. Returns the next insn, if
- we patch out the branch. Returns the branch insn, if we cannot
- patch out the branch (due to anti-dependency in the delay slot).
- In that case, the caller must insert nops at the branch target. */
-
-static rtx
-mt_check_delay_slot (rtx branch, rtx insn)
-{
- rtx slot;
- rtx tmp;
- rtx p;
- rtx jmp;
-
- gcc_assert (GET_CODE (PATTERN (branch)) == SEQUENCE);
- if (INSN_DELETED_P (branch))
- return NULL_RTX;
- slot = XVECEXP (PATTERN (branch), 0, 1);
-
- tmp = PATTERN (insn);
- note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
- if (tmp)
- /* Not dependent. */
- return NULL_RTX;
-
- /* Undo the delay slot. */
- jmp = XVECEXP (PATTERN (branch), 0, 0);
-
- tmp = PATTERN (jmp);
- note_stores (PATTERN (slot), insn_dependent_p_1, &tmp);
- if (!tmp)
- /* Anti dependent. */
- return branch;
-
- p = PREV_INSN (branch);
- NEXT_INSN (p) = slot;
- PREV_INSN (slot) = p;
- NEXT_INSN (slot) = jmp;
- PREV_INSN (jmp) = slot;
- NEXT_INSN (jmp) = branch;
- PREV_INSN (branch) = jmp;
- XVECEXP (PATTERN (branch), 0, 0) = NULL_RTX;
- XVECEXP (PATTERN (branch), 0, 1) = NULL_RTX;
- delete_insn (branch);
- return jmp;
-}
-
-/* Insert nops to satisfy pipeline constraints. We only deal with ms2
- constraints here. Earlier CPUs are dealt with by inserting nops with
- final_prescan (but that can lead to inferior code, and is
- impractical with ms2's JAL hazard).
-
- ms2 dynamic constraints
- 1) a load and a following use must be separated by one insn
- 2) an insn and a following dependent call must be separated by two insns
-
- only arith insns are placed in delay slots so #1 cannot happen with
- a load in a delay slot. #2 can happen with an arith insn in the
- delay slot. */
-
-static void
-mt_reorg_hazard (void)
-{
- rtx insn, next;
-
- /* Find all the branches */
- for (insn = get_insns ();
- insn;
- insn = NEXT_INSN (insn))
- {
- rtx jmp;
-
- if (!INSN_P (insn))
- continue;
-
- jmp = PATTERN (insn);
-
- if (GET_CODE (jmp) != SEQUENCE)
- /* If it's not got a filled delay slot, then it can't
- conflict. */
- continue;
-
- jmp = XVECEXP (jmp, 0, 0);
-
- if (recog_memoized (jmp) == CODE_FOR_tablejump)
- for (jmp = XEXP (XEXP (XVECEXP (PATTERN (jmp), 0, 1), 0), 0);
- !JUMP_TABLE_DATA_P (jmp);
- jmp = NEXT_INSN (jmp))
- continue;
-
- for_each_rtx (&PATTERN (jmp), mt_add_branches, insn);
- }
-
- /* Now scan for dependencies. */
- for (insn = get_insns ();
- insn && !INSN_P (insn);
- insn = NEXT_INSN (insn))
- continue;
-
- for (;
- insn;
- insn = next)
- {
- rtx jmp, tmp;
- enum attr_type attr;
-
- gcc_assert (INSN_P (insn) && !INSN_DELETED_P (insn));
- for (next = NEXT_INSN (insn);
- next;
- next = NEXT_INSN (next))
- {
- if (!INSN_P (next))
- continue;
- if (GET_CODE (PATTERN (next)) != USE)
- break;
- }
-
- jmp = insn;
- if (GET_CODE (PATTERN (insn)) == SEQUENCE)
- jmp = XVECEXP (PATTERN (insn), 0, 0);
-
- attr = recog_memoized (jmp) >= 0 ? get_attr_type (jmp) : TYPE_UNKNOWN;
-
- if (next && attr == TYPE_LOAD)
- {
- /* A load. See if NEXT is dependent, and if so insert a
- nop. */
-
- tmp = PATTERN (next);
- if (GET_CODE (tmp) == SEQUENCE)
- tmp = PATTERN (XVECEXP (tmp, 0, 0));
- note_stores (PATTERN (insn), insn_dependent_p_1, &tmp);
- if (!tmp)
- emit_insn_after (gen_nop (), insn);
- }
-
- if (attr == TYPE_CALL)
- {
- /* A call. Make sure we're not dependent on either of the
- previous two dynamic instructions. */
- int nops = 0;
- int count;
- rtx prev = insn;
- rtx rescan = NULL_RTX;
-
- for (count = 2; count && !nops;)
- {
- int type;
-
- prev = PREV_INSN (prev);
- if (!prev)
- {
- /* If we reach the start of the function, we must
- presume the caller set the address in the delay
- slot of the call instruction. */
- nops = count;
- break;
- }
-
- if (BARRIER_P (prev))
- break;
- if (LABEL_P (prev))
- {
- /* Look at branches to this label. */
- label_info *label;
- branch_info *branch;
-
- for (label = mt_labels;
- label;
- label = label->next)
- if (label->label == prev)
- {
- for (branch = label->branches;
- branch;
- branch = branch->next)
- {
- tmp = mt_check_delay_slot (branch->insn, jmp);
-
- if (tmp == branch->insn)
- {
- nops = count;
- break;
- }
-
- if (tmp && branch->insn == next)
- rescan = tmp;
- }
- break;
- }
- continue;
- }
- if (!INSN_P (prev) || GET_CODE (PATTERN (prev)) == USE)
- continue;
-
- if (GET_CODE (PATTERN (prev)) == SEQUENCE)
- {
- /* Look at the delay slot. */
- tmp = mt_check_delay_slot (prev, jmp);
- if (tmp == prev)
- nops = count;
- break;
- }
-
- type = (INSN_CODE (prev) >= 0 ? get_attr_type (prev)
- : TYPE_COMPLEX);
- if (type == TYPE_CALL || type == TYPE_BRANCH)
- break;
-
- if (type == TYPE_LOAD
- || type == TYPE_ARITH
- || type == TYPE_COMPLEX)
- {
- tmp = PATTERN (jmp);
- note_stores (PATTERN (prev), insn_dependent_p_1, &tmp);
- if (!tmp)
- {
- nops = count;
- break;
- }
- }
-
- if (INSN_CODE (prev) >= 0)
- count--;
- }
-
- if (rescan)
- for (next = NEXT_INSN (rescan);
- next && !INSN_P (next);
- next = NEXT_INSN (next))
- continue;
- while (nops--)
- emit_insn_before (gen_nop (), insn);
- }
- }
-
- /* Free the data structures. */
- while (mt_labels)
- {
- label_info *label = mt_labels;
- branch_info *branch, *next;
-
- mt_labels = label->next;
- for (branch = label->branches; branch; branch = next)
- {
- next = branch->next;
- free (branch);
- }
- free (label);
- }
-}
-
-/* Fixup the looping instructions, do delayed branch scheduling, fixup
- scheduling hazards. */
-
-static void
-mt_machine_reorg (void)
-{
- if (cfun->machine->has_loops && TARGET_MS2)
- mt_reorg_loops (dump_file);
-
- if (mt_flag_delayed_branch)
- dbr_schedule (get_insns ());
-
- if (TARGET_MS2)
- {
- /* Force all instructions to be split into their final form. */
- split_all_insns_noflow ();
- mt_reorg_hazard ();
- }
-}
-
-int
-mt_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
- return (int_size_in_bytes (type) > UNITS_PER_WORD);
-}
-
-
-/* Initialize the GCC target structure. */
-const struct attribute_spec mt_attribute_table[];
-
-#undef TARGET_ATTRIBUTE_TABLE
-#define TARGET_ATTRIBUTE_TABLE mt_attribute_table
-#undef TARGET_STRUCT_VALUE_RTX
-#define TARGET_STRUCT_VALUE_RTX mt_struct_value_rtx
-#undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
-#undef TARGET_PASS_BY_REFERENCE
-#define TARGET_PASS_BY_REFERENCE mt_pass_by_reference
-#undef TARGET_MUST_PASS_IN_STACK
-#define TARGET_MUST_PASS_IN_STACK mt_pass_in_stack
-#undef TARGET_ARG_PARTIAL_BYTES
-#define TARGET_ARG_PARTIAL_BYTES mt_arg_partial_bytes
-#undef TARGET_SETUP_INCOMING_VARARGS
-#define TARGET_SETUP_INCOMING_VARARGS mt_setup_incoming_varargs
-#undef TARGET_MACHINE_DEPENDENT_REORG
-#define TARGET_MACHINE_DEPENDENT_REORG mt_machine_reorg
-
-struct gcc_target targetm = TARGET_INITIALIZER;
-
-#include "gt-mt.h"