diff options
author | Joseph Myers <joseph@codesourcery.com> | 2008-06-07 19:00:15 +0100 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2008-06-07 19:00:15 +0100 |
commit | cd985f6672bb3c399c03118a7a2426e2210c690a (patch) | |
tree | 0b3f6bdde3fd6779fef4d162dd5a25868787d722 /gcc/config/mt/mt.c | |
parent | 4b92fd3cc91f9406ba26c73aaa03ef0f5871fa99 (diff) | |
download | gcc-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.c | 2493 |
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, ®no); - - 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, ®no); - - * 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 (¤t_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" |