diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-01-21 22:01:24 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-01-21 22:01:24 +0000 |
commit | ffde65b31066f17eef243be882bb89a6e19370aa (patch) | |
tree | ea876d041c0a63eefccdac5416a8678e75da4cfc /gcc/config/sh | |
parent | a8c7acc4db08ce7c8ac3ddcb943f9219e2893792 (diff) | |
download | gcc-ffde65b31066f17eef243be882bb89a6e19370aa.tar.gz |
[.]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk -i.e. GCC5.0 in stage4- using
svn merge -r209216:219879 svn+ssh://bstarynk@gcc.gnu.org/svn/gcc/trunk
but should probably have used
svn merge -r209216:219879 ^/trunk
we don't use svnmerge.py anymore since our svn is version 1.8.10
}}
VERY UNSTABLE
2015-01-20 Basile Starynkevitch <basile@starynkevitch.net>
Move previous topdir ChangeLog.MELT to ChangeLog.MELT.2008-2014
[contrib/]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
* MELT-Plugin-Makefile: Able to make upgrade-melt as a
plugin. Works for GCC 5.0. Remove GCC 4.7 old stuff.
Move previous contrib/ChangeLog.MELT to ChangeLog.MELT.2008-2014
[gcc/]
2015-01-21 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk -i.e. GCC5.0 in stage4- using
svn merge -r209216:219879 svn+ssh://bstarynk@gcc.gnu.org/svn/gcc/trunk
but should probably have used
svn merge -r209216:219879 ^/trunk
**@@@ UNSTABLE since libmelt-ana-gimple.melt not compiling, but
translator painfully bootstrapping!!@@@@ }}
* toplev.c: Merged manually by keeping MELT extra stuff.
* toplev.h: Likewise.
* gengtype.c: Add "melt-runtime.h" in list, but merged with trunk.
* melt-runtime.h (MELT_VERSION_STRING): Bump to "1.2-pre-merged".
(meltgc_walk_gimple_seq): Remove.
(gt_ggc_mx_gimple_statement_d): Same for GCC 4.9 & 5.0
* melt-runtime.cc: Update copyright year.
(ggc_alloc_cleared_melt_valuevector_st, melt_resize_scangcvect):
Call ggc_internal_cleared_alloc.
(melt_val2passflag): Skip TODO_verify_ssa, TODO_verify_flow,
TODO_verify_stmts, TODO_verify_rtl_sharing for GCC 5.0.
(meltgc_walkstmt_cb, meltgc_walktree_cb)
(melt_tree_walk_frame_size, meltgc_walk_gimple_seq): Remove.
(melt_gt_ggc_mx_gimple_seq_d): Call
gt_ggc_mx_gimple_statement_base.
* melt-build-script.tpl: Update copyright year. Don't symlink
meltrunsup.h anymore.
* melt-build-script.sh: Regenerate.
* melt/warmelt-base.melt: Update copyright year.
(valdesc_object, valdesc_mapobjects, valdesc_mapstrings)
(valdesc_multiple, valdesc_closure, valdesc_routine, valdesc_hook)
(valdesc_bucketlongs, valdesc_jsonobject, valdesc_string)
(valdesc_strbuf, valdesc_pair, valdesc_list, valdesc_int)
(valdesc_double, valdesc_mixint, valdesc_mixloc)
(valdesc_mixbigint, valdesc_real, valdesc_special_data): Use
ggc_internal_alloc & ggc_internal_cleared_alloc for GCC 5.0.
(json_canonical_name): Use ISUPPER, ISALPHA, TOUPPER instead of
their standard <ctype.h> lowercase macros.
* melt/warmelt-modes.melt: Update copyright year.
(generate_runtypesupport_forwcopy_fun): Emit both GCC 4.9 & 5.0
compatible code.
* melt/libmelt-ana-base.melt: Update copyright year.
* melt/libmelt-ana-gimple.melt: TO BE IMPROVED
* melt/generated/*: Painfully regenerated several times thru GCC
4.9 MELT plugin.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@219975 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sh')
39 files changed, 2813 insertions, 1572 deletions
diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md index 17a448fc0cf..5ef3db6dcb3 100644 --- a/gcc/config/sh/constraints.md +++ b/gcc/config/sh/constraints.md @@ -1,5 +1,5 @@ ;; Constraint definitions for Renesas / SuperH SH. -;; Copyright (C) 2007-2014 Free Software Foundation, Inc. +;; Copyright (C) 2007-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -55,7 +55,7 @@ ;; Z: zero in any mode ;; ;; unused CONST_INT constraint letters: LO -;; unused EXTRA_CONSTRAINT letters: D T U Y +;; unused "extra" constraint letters: D T U Y ;; Register constraints (define_register_constraint "a" "ALL_REGS" @@ -210,12 +210,12 @@ (define_constraint "G" "Double constant 0." (and (match_code "const_double") - (match_test "fp_zero_operand (op) && fldi_ok ()"))) + (match_test "fp_zero_operand (op)"))) (define_constraint "H" "Double constant 1." (and (match_code "const_double") - (match_test "fp_one_operand (op) && fldi_ok ()"))) + (match_test "fp_one_operand (op)"))) ;; Extra constraints (define_constraint "Q" diff --git a/gcc/config/sh/divcost-analysis b/gcc/config/sh/divcost-analysis index 9fb6e6fa542..7e103cdecc8 100644 --- a/gcc/config/sh/divcost-analysis +++ b/gcc/config/sh/divcost-analysis @@ -81,7 +81,7 @@ jmp @r0 ; 2 cycles worse than SFUNC_STATIC -Copyright (C) 2006-2014 Free Software Foundation, Inc. +Copyright (C) 2006-2015 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/gcc/config/sh/divtab-sh4-300.c b/gcc/config/sh/divtab-sh4-300.c index 4941626a85a..5b6d4fdc0f4 100644 --- a/gcc/config/sh/divtab-sh4-300.c +++ b/gcc/config/sh/divtab-sh4-300.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004-2014 Free Software Foundation, Inc. +/* Copyright (C) 2004-2015 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the diff --git a/gcc/config/sh/divtab-sh4.c b/gcc/config/sh/divtab-sh4.c index 421571e1e79..1a41c98bec5 100644 --- a/gcc/config/sh/divtab-sh4.c +++ b/gcc/config/sh/divtab-sh4.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004-2014 Free Software Foundation, Inc. +/* Copyright (C) 2004-2015 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the diff --git a/gcc/config/sh/divtab.c b/gcc/config/sh/divtab.c index 40a26eb74ef..b80b25cc8e0 100644 --- a/gcc/config/sh/divtab.c +++ b/gcc/config/sh/divtab.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003-2014 Free Software Foundation, Inc. +/* Copyright (C) 2003-2015 Free Software Foundation, Inc. This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the diff --git a/gcc/config/sh/elf.h b/gcc/config/sh/elf.h index 24b5c981508..3bcfbbe2208 100644 --- a/gcc/config/sh/elf.h +++ b/gcc/config/sh/elf.h @@ -1,5 +1,5 @@ /* Definitions of target machine for gcc for Renesas / SuperH SH using ELF. - Copyright (C) 1996-2014 Free Software Foundation, Inc. + Copyright (C) 1996-2015 Free Software Foundation, Inc. Contributed by Ian Lance Taylor <ian@cygnus.com>. This file is part of GCC. diff --git a/gcc/config/sh/embed-elf.h b/gcc/config/sh/embed-elf.h index 38042575141..b43cd721f23 100644 --- a/gcc/config/sh/embed-elf.h +++ b/gcc/config/sh/embed-elf.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GNU compiler for Renesas / SuperH SH non-Linux embedded targets. - Copyright (C) 2002-2014 Free Software Foundation, Inc. + Copyright (C) 2002-2015 Free Software Foundation, Inc. Contributed by J"orn Rennecke <joern.rennecke@superh.com> This file is part of GCC. diff --git a/gcc/config/sh/iterators.md b/gcc/config/sh/iterators.md index 5f020c72aa1..d1578a45dcf 100644 --- a/gcc/config/sh/iterators.md +++ b/gcc/config/sh/iterators.md @@ -1,5 +1,5 @@ ;; Iterator definitions for GCC SH machine description files. -;; Copyright (C) 2012-2014 Free Software Foundation, Inc. +;; Copyright (C) 2012-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; diff --git a/gcc/config/sh/linux.h b/gcc/config/sh/linux.h index c0a4ebd3e47..0f5d614c096 100644 --- a/gcc/config/sh/linux.h +++ b/gcc/config/sh/linux.h @@ -1,5 +1,5 @@ /* Definitions for SH running Linux-based GNU systems using ELF - Copyright (C) 1999-2014 Free Software Foundation, Inc. + Copyright (C) 1999-2015 Free Software Foundation, Inc. Contributed by Kazumoto Kojima <kkojima@rr.iij4u.or.jp> This file is part of GCC. diff --git a/gcc/config/sh/little.h b/gcc/config/sh/little.h index 8ab61ea5a7a..179338f3b45 100644 --- a/gcc/config/sh/little.h +++ b/gcc/config/sh/little.h @@ -1,6 +1,6 @@ /* Definition of little endian SH machine for GNU compiler. - Copyright (C) 2002-2014 Free Software Foundation, Inc. + Copyright (C) 2002-2015 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/config/sh/netbsd-elf.h b/gcc/config/sh/netbsd-elf.h index 8100cee5d5b..39b6d6ce2ea 100644 --- a/gcc/config/sh/netbsd-elf.h +++ b/gcc/config/sh/netbsd-elf.h @@ -1,5 +1,5 @@ /* Definitions for SH running NetBSD using ELF - Copyright (C) 2002-2014 Free Software Foundation, Inc. + Copyright (C) 2002-2015 Free Software Foundation, Inc. Contributed by Wasabi Systems, Inc. This file is part of GCC. diff --git a/gcc/config/sh/newlib.h b/gcc/config/sh/newlib.h index d3fcf150c8b..66ae6d694bf 100644 --- a/gcc/config/sh/newlib.h +++ b/gcc/config/sh/newlib.h @@ -1,5 +1,5 @@ /* Definitions of target machine for gcc for Super-H using sh-superh-elf. - Copyright (C) 2001-2014 Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. This file is part of GNU CC. diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 31f2e1f5a0b..db678b66abb 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -1,5 +1,5 @@ ;; Predicate definitions for Renesas / SuperH SH. -;; Copyright (C) 2005-2014 Free Software Foundation, Inc. +;; Copyright (C) 2005-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -154,7 +154,7 @@ return (regno != T_REG && regno != PR_REG && ! TARGET_REGISTER_P (regno) - && regno != FPUL_REG + && regno != FPUL_REG && regno != FPSCR_REG && regno != MACH_REG && regno != MACL_REG); } /* Allow a no-op sign extension - compare LOAD_EXTEND_OP. @@ -182,6 +182,19 @@ return 0; }) +;; Likewise arith_operand but always permits const_int. +(define_predicate "arith_or_int_operand" + (match_code "subreg,reg,const_int,const_vector") +{ + if (arith_operand (op, mode)) + return 1; + + if (CONST_INT_P (op)) + return 1; + + return 0; +}) + ;; Returns 1 if OP is a valid source operand for a compare insn. (define_predicate "arith_reg_or_0_operand" (match_code "subreg,reg,const_int,const_vector") @@ -347,13 +360,27 @@ ;; Returns true if OP is the FPSCR. (define_predicate "fpscr_operand" - (match_code "reg") + (and (match_code "reg") + (match_test "REGNO (op) == FPSCR_REG"))) + +;; Returns true if OP is a valid source operand for a FPSCR move insn. +(define_predicate "fpscr_movsrc_operand" + (match_code "reg,subreg,mem") { - return (REG_P (op) - && (REGNO (op) == FPSCR_REG - || (REGNO (op) >= FIRST_PSEUDO_REGISTER - && !(reload_in_progress || reload_completed))) - && GET_MODE (op) == PSImode); + if (arith_reg_operand (op, mode)) + return true; + + return MEM_P (op) && GET_CODE (XEXP (op, 0)) == POST_INC; +}) + +;; Returns true if OP is a valid destination operand for a FPSCR move insn. +(define_predicate "fpscr_movdst_operand" + (match_code "reg,subreg,mem") +{ + if (arith_reg_dest (op, mode)) + return true; + + return MEM_P (op) && GET_CODE (XEXP (op, 0)) == PRE_DEC; }) ;; Returns true if OP is an operand that is either the fpul hard reg or @@ -398,7 +425,7 @@ (define_predicate "general_extend_operand" (match_code "subreg,reg,mem,truncate") { - if (GET_CODE (op) == TRUNCATE) + if (reload_completed && GET_CODE (op) == TRUNCATE) return arith_operand (op, mode); if (MEM_P (op) || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op)))) @@ -451,6 +478,9 @@ if (t_reg_operand (op, mode)) return 0; + if (fpscr_operand (op, mode)) + return false; + /* Disallow PC relative QImode loads, since these is no insn to do that and an imm8 load should be used instead. */ if (IS_PC_RELATIVE_LOAD_ADDR_P (op) && GET_MODE (op) == QImode) @@ -489,7 +519,29 @@ rtx mem_rtx = MEM_P (op) ? op : SUBREG_REG (op); rtx x = XEXP (mem_rtx, 0); - if ((mode == QImode || mode == HImode) + if (! ALLOW_INDEXED_ADDRESS + && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) + return false; + + if (GET_CODE (x) == PLUS) + { + rtx y = XEXP (x, 0); + + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)))) + return false; + y = XEXP (x, 1); + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))) + && ! CONST_INT_P (y)) + return false; + } + + /* LRA will try to satisfy the constraints for the memory displacements + and thus we must not reject invalid displacements in the predicate, + or else LRA will bail out. + FIXME: maybe remove this check completely? */ + if (!lra_in_progress && (mode == QImode || mode == HImode) && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) @@ -542,6 +594,9 @@ if (t_reg_operand (op, mode)) return 0; + if (fpscr_operand (op, mode)) + return false; + if (MEM_P (op)) { rtx inside = XEXP (op, 0); @@ -567,7 +622,29 @@ rtx mem_rtx = MEM_P (op) ? op : SUBREG_REG (op); rtx x = XEXP (mem_rtx, 0); - if ((mode == QImode || mode == HImode) + if (! ALLOW_INDEXED_ADDRESS + && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) + return false; + + if (GET_CODE (x) == PLUS) + { + rtx y = XEXP (x, 0); + + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)))) + return false; + y = XEXP (x, 1); + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))) + && ! CONST_INT_P (y)) + return false; + } + + /* LRA will try to satisfy the constraints for the memory displacements + and thus we must not reject invalid displacements in the predicate, + or else LRA will bail out. + FIXME: maybe remove this check completely? */ + if (!lra_in_progress && (mode == QImode || mode == HImode) && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) @@ -682,7 +759,7 @@ ;;(define_special_predicate "int_gpr_dest" ;; (match_code "subreg,reg") ;;{ -;; enum machine_mode op_mode = GET_MODE (op); +;; machine_mode op_mode = GET_MODE (op); ;; ;; if (GET_MODE_CLASS (op_mode) != MODE_INT ;; || GET_MODE_SIZE (op_mode) >= UNITS_PER_WORD) @@ -994,7 +1071,7 @@ (define_special_predicate "trunc_hi_operand" (match_code "subreg,reg,truncate") { - enum machine_mode op_mode = GET_MODE (op); + machine_mode op_mode = GET_MODE (op); if (op_mode != SImode && op_mode != DImode && op_mode != V4HImode && op_mode != V2SImode) @@ -1066,14 +1143,14 @@ (and (match_test "satisfies_constraint_I08 (op)") (match_test "mode != QImode") (match_test "mode != HImode") - (match_test "TARGET_SH4A_ARCH")))) + (match_test "TARGET_SH4A")))) (define_predicate "atomic_logical_operand" (ior (match_code "subreg,reg") (and (match_test "satisfies_constraint_K08 (op)") (match_test "mode != QImode") (match_test "mode != HImode") - (match_test "TARGET_SH4A_ARCH")))) + (match_test "TARGET_SH4A")))) ;; A predicate describing the T bit register in any form. (define_predicate "t_reg_operand" @@ -1089,6 +1166,8 @@ case ZERO_EXTEND: case SIGN_EXTEND: + if (REG_P (XEXP (op, 0)) && REGNO (XEXP (op, 0)) == T_REG) + return true; return GET_CODE (XEXP (op, 0)) == SUBREG && REG_P (SUBREG_REG (XEXP (op, 0))) && REGNO (SUBREG_REG (XEXP (op, 0))) == T_REG; @@ -1119,10 +1198,8 @@ ;; A predicate that returns true if OP is a valid construct around the T bit ;; that can be used as an operand for conditional branches. (define_predicate "cbranch_treg_value" - (match_code "eq,ne,reg,subreg,xor,sign_extend,zero_extend") -{ - return sh_eval_treg_value (op) >= 0; -}) + (and (match_code "eq,ne,reg,subreg,xor,sign_extend,zero_extend") + (match_test "sh_eval_treg_value (op) >= 0"))) ;; Returns true if OP is arith_reg_operand or t_reg_operand. (define_predicate "arith_reg_or_t_reg_operand" @@ -1134,6 +1211,28 @@ (define_predicate "negt_reg_shl31_operand" (match_code "plus,minus,if_then_else") { + /* (minus:SI (const_int -2147483648) ;; 0xffffffff80000000 + (ashift:SI (match_operand:SI 1 "t_reg_operand") + (const_int 31))) + */ + if (GET_CODE (op) == MINUS && satisfies_constraint_Jhb (XEXP (op, 0)) + && GET_CODE (XEXP (op, 1)) == ASHIFT + && t_reg_operand (XEXP (XEXP (op, 1), 0), SImode) + && CONST_INT_P (XEXP (XEXP (op, 1), 1)) + && INTVAL (XEXP (XEXP (op, 1), 1)) == 31) + return true; + + /* (plus:SI (ashift:SI (match_operand:SI 1 "t_reg_operand") + (const_int 31)) + (const_int -2147483648)) ;; 0xffffffff80000000 + */ + if (GET_CODE (op) == PLUS && satisfies_constraint_Jhb (XEXP (op, 1)) + && GET_CODE (XEXP (op, 0)) == ASHIFT + && t_reg_operand (XEXP (XEXP (op, 0), 0), SImode) + && CONST_INT_P (XEXP (XEXP (op, 0), 1)) + && INTVAL (XEXP (XEXP (op, 0), 1)) == 31) + return true; + /* (plus:SI (mult:SI (match_operand:SI 1 "t_reg_operand") (const_int -2147483648)) ;; 0xffffffff80000000 (const_int -2147483648)) diff --git a/gcc/config/sh/rtems.h b/gcc/config/sh/rtems.h index bbedc5b3ac5..b95c31aaea8 100644 --- a/gcc/config/sh/rtems.h +++ b/gcc/config/sh/rtems.h @@ -1,5 +1,5 @@ /* Definitions for rtems targeting a SH using COFF. - Copyright (C) 1997-2014 Free Software Foundation, Inc. + Copyright (C) 1997-2015 Free Software Foundation, Inc. Contributed by Joel Sherrill (joel@OARcorp.com). This file is part of GCC. diff --git a/gcc/config/sh/rtemself.h b/gcc/config/sh/rtemself.h index 25d8b27c421..0a0a6b6bc74 100644 --- a/gcc/config/sh/rtemself.h +++ b/gcc/config/sh/rtemself.h @@ -1,5 +1,5 @@ /* Definitions for rtems targeting a SH using elf. - Copyright (C) 1997-2014 Free Software Foundation, Inc. + Copyright (C) 1997-2015 Free Software Foundation, Inc. Contributed by Joel Sherrill (joel@OARcorp.com). This file is part of GCC. diff --git a/gcc/config/sh/sh-c.c b/gcc/config/sh/sh-c.c index 43ff7ad22c2..8aa056dda43 100644 --- a/gcc/config/sh/sh-c.c +++ b/gcc/config/sh/sh-c.c @@ -1,5 +1,5 @@ /* Pragma handling for GCC for Renesas / SuperH SH. - Copyright (C) 1993-2014 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. Contributed by Joern Rennecke <joern.rennecke@st.com>. This file is part of GCC. @@ -22,6 +22,15 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" #include "stringpool.h" #include "attribs.h" diff --git a/gcc/config/sh/sh-mem.cc b/gcc/config/sh/sh-mem.cc index 45af23acb48..d09209004a6 100644 --- a/gcc/config/sh/sh-mem.cc +++ b/gcc/config/sh/sh-mem.cc @@ -1,5 +1,5 @@ /* Helper routines for memory move and comparison insns. - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -23,9 +23,40 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "machmode.h" #include "rtl.h" +#include "hash-set.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" +#include "hashtab.h" +#include "hard-reg-set.h" +#include "function.h" +#include "flags.h" +#include "statistics.h" +#include "real.h" +#include "fixed-value.h" +#include "insn-config.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "calls.h" +#include "emit-rtl.h" +#include "varasm.h" +#include "stmt.h" #include "expr.h" #include "tm_p.h" +#include "predict.h" +#include "dominance.h" +#include "cfg.h" +#include "cfgrtl.h" +#include "cfganal.h" +#include "lcm.h" +#include "cfgbuild.h" +#include "cfgcleanup.h" #include "basic-block.h" /* Like force_operand, but guarantees that VALUE ends up in TARGET. */ @@ -56,7 +87,7 @@ expand_block_move (rtx *operands) /* If we could use mov.l to move words and dest is word-aligned, we can use movua.l for loads and still generate a relatively short and efficient sequence. */ - if (TARGET_SH4A_ARCH && align < 4 + if (TARGET_SH4A && align < 4 && MEM_ALIGN (operands[0]) >= 32 && can_move_by_pieces (bytes, 32)) { @@ -179,8 +210,8 @@ expand_block_move (rtx *operands) return false; } -static int prob_unlikely = REG_BR_PROB_BASE / 10; -static int prob_likely = REG_BR_PROB_BASE / 4; +static const int prob_unlikely = REG_BR_PROB_BASE / 10; +static const int prob_likely = REG_BR_PROB_BASE / 4; /* Emit code to perform a strcmp. @@ -201,11 +232,11 @@ sh_expand_cmpstr (rtx *operands) rtx tmp3 = gen_reg_rtx (SImode); rtx jump; - rtx L_return = gen_label_rtx (); - rtx L_loop_byte = gen_label_rtx (); - rtx L_end_loop_byte = gen_label_rtx (); - rtx L_loop_long = gen_label_rtx (); - rtx L_end_loop_long = gen_label_rtx (); + rtx_code_label *L_return = gen_label_rtx (); + rtx_code_label *L_loop_byte = gen_label_rtx (); + rtx_code_label *L_end_loop_byte = gen_label_rtx (); + rtx_code_label *L_loop_long = gen_label_rtx (); + rtx_code_label *L_end_loop_long = gen_label_rtx (); int align = INTVAL (operands[3]); @@ -214,7 +245,7 @@ sh_expand_cmpstr (rtx *operands) if (align < 4) { emit_insn (gen_iorsi3 (tmp1, s1_addr, s2_addr)); - emit_insn (gen_tstsi_t (GEN_INT (3), tmp1)); + emit_insn (gen_tstsi_t (tmp1, GEN_INT (3))); jump = emit_jump_insn (gen_branch_false (L_loop_byte)); add_int_reg_note (jump, REG_BR_PROB, prob_likely); } @@ -226,7 +257,7 @@ sh_expand_cmpstr (rtx *operands) emit_move_insn (tmp3, addr2); emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, 4)); - /*start long loop. */ + /* start long loop. */ emit_label (L_loop_long); emit_move_insn (tmp2, tmp3); @@ -328,160 +359,168 @@ sh_expand_cmpnstr (rtx *operands) rtx tmp2 = gen_reg_rtx (SImode); rtx jump; - rtx L_return = gen_label_rtx (); - rtx L_loop_byte = gen_label_rtx (); - rtx L_end_loop_byte = gen_label_rtx (); + rtx_code_label *L_return = gen_label_rtx (); + rtx_code_label *L_loop_byte = gen_label_rtx (); + rtx_code_label *L_end_loop_byte = gen_label_rtx (); rtx len = force_reg (SImode, operands[3]); int constp = CONST_INT_P (operands[3]); - /* Loop on a register count. */ + /* Loop on a register count. */ if (constp) { rtx tmp0 = gen_reg_rtx (SImode); rtx tmp3 = gen_reg_rtx (SImode); rtx lenw = gen_reg_rtx (SImode); - rtx L_loop_long = gen_label_rtx (); - rtx L_end_loop_long = gen_label_rtx (); + rtx_code_label *L_loop_long = gen_label_rtx (); + rtx_code_label *L_end_loop_long = gen_label_rtx (); int align = INTVAL (operands[4]); int bytes = INTVAL (operands[3]); int witers = bytes / 4; if (witers > 1) - { - addr1 = adjust_automodify_address (addr1, SImode, s1_addr, 0); - addr2 = adjust_automodify_address (addr2, SImode, s2_addr, 0); - - emit_move_insn (tmp0, const0_rtx); - - if (align < 4) - { - emit_insn (gen_iorsi3 (tmp1, s1_addr, s2_addr)); - emit_insn (gen_tstsi_t (GEN_INT (3), tmp1)); - jump = emit_jump_insn (gen_branch_false (L_loop_byte)); - add_int_reg_note (jump, REG_BR_PROB, prob_likely); - } - - /* word count. Do we have iterations ? */ - emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2))); - - /*start long loop. */ - emit_label (L_loop_long); - - /* tmp2 is aligned, OK to load. */ - emit_move_insn (tmp2, addr2); - emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, - GET_MODE_SIZE (SImode))); - - /* tmp1 is aligned, OK to load. */ - emit_move_insn (tmp1, addr1); - emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, - GET_MODE_SIZE (SImode))); - - /* Is there a 0 byte ? */ - emit_insn (gen_andsi3 (tmp3, tmp2, tmp1)); - - emit_insn (gen_cmpstr_t (tmp0, tmp3)); - jump = emit_jump_insn (gen_branch_true (L_end_loop_long)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); - jump = emit_jump_insn (gen_branch_false (L_end_loop_long)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - if (TARGET_SH2) - emit_insn (gen_dect (lenw, lenw)); - else - { - emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1))); - emit_insn (gen_tstsi_t (lenw, lenw)); - } - - jump = emit_jump_insn (gen_branch_false (L_loop_long)); - add_int_reg_note (jump, REG_BR_PROB, prob_likely); - - int sbytes = bytes % 4; - - /* end loop. Reached max iterations. */ - if (! sbytes) - { - jump = emit_jump_insn (gen_jump_compact (L_return)); - emit_barrier_after (jump); - } - else - { - /* Remaining bytes to check. */ - - addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0); - addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0); - - while (sbytes--) - { - emit_insn (gen_extendqisi2 (tmp1, addr1)); - emit_insn (gen_extendqisi2 (tmp2, addr2)); - - emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx)); - jump = emit_jump_insn (gen_branch_true (L_end_loop_byte)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); - if (flag_delayed_branch) - emit_insn (gen_zero_extendqisi2 (tmp2, - gen_lowpart (QImode, - tmp2))); - jump = emit_jump_insn (gen_branch_false (L_end_loop_byte)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - addr1 = adjust_address (addr1, QImode, - GET_MODE_SIZE (QImode)); - addr2 = adjust_address (addr2, QImode, - GET_MODE_SIZE (QImode)); - } - - jump = emit_jump_insn (gen_jump_compact( L_end_loop_byte)); - emit_barrier_after (jump); - } - - emit_label (L_end_loop_long); - - /* Found last word. Restart it byte per byte. */ - - emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, - -GET_MODE_SIZE (SImode))); - emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, - -GET_MODE_SIZE (SImode))); - - /* fall thru. */ - } + { + addr1 = adjust_automodify_address (addr1, SImode, s1_addr, 0); + addr2 = adjust_automodify_address (addr2, SImode, s2_addr, 0); + + emit_move_insn (tmp0, const0_rtx); + + if (align < 4) + { + emit_insn (gen_iorsi3 (tmp1, s1_addr, s2_addr)); + emit_insn (gen_tstsi_t (tmp1, GEN_INT (3))); + jump = emit_jump_insn (gen_branch_false (L_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + } + + /* word count. Do we have iterations ? */ + emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2))); + + /* start long loop. */ + emit_label (L_loop_long); + + /* tmp2 is aligned, OK to load. */ + emit_move_insn (tmp2, addr2); + emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, + GET_MODE_SIZE (SImode))); + + /* tmp1 is aligned, OK to load. */ + emit_move_insn (tmp1, addr1); + emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, + GET_MODE_SIZE (SImode))); + + /* Is there a 0 byte ? */ + emit_insn (gen_andsi3 (tmp3, tmp2, tmp1)); + + emit_insn (gen_cmpstr_t (tmp0, tmp3)); + jump = emit_jump_insn (gen_branch_true (L_end_loop_long)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); + jump = emit_jump_insn (gen_branch_false (L_end_loop_long)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + if (TARGET_SH2) + emit_insn (gen_dect (lenw, lenw)); + else + { + emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1))); + emit_insn (gen_tstsi_t (lenw, lenw)); + } + + jump = emit_jump_insn (gen_branch_false (L_loop_long)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + + int sbytes = bytes % 4; + + /* end loop. Reached max iterations. */ + if (sbytes == 0) + { + emit_insn (gen_subsi3 (operands[0], tmp1, tmp2)); + jump = emit_jump_insn (gen_jump_compact (L_return)); + emit_barrier_after (jump); + } + else + { + /* Remaining bytes to check. */ + + addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0); + addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0); + + while (sbytes--) + { + emit_insn (gen_extendqisi2 (tmp1, addr1)); + emit_insn (gen_extendqisi2 (tmp2, addr2)); + + emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx)); + jump = emit_jump_insn (gen_branch_true (L_end_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); + if (flag_delayed_branch) + emit_insn (gen_zero_extendqisi2 (tmp2, + gen_lowpart (QImode, + tmp2))); + jump = emit_jump_insn (gen_branch_false (L_end_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + addr1 = adjust_address (addr1, QImode, + GET_MODE_SIZE (QImode)); + addr2 = adjust_address (addr2, QImode, + GET_MODE_SIZE (QImode)); + } + + jump = emit_jump_insn (gen_jump_compact( L_end_loop_byte)); + emit_barrier_after (jump); + } + + emit_label (L_end_loop_long); + + /* Found last word. Restart it byte per byte. */ + + emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, + -GET_MODE_SIZE (SImode))); + emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, + -GET_MODE_SIZE (SImode))); + + /* fall thru. */ + } addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0); addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0); while (bytes--) - { - emit_insn (gen_extendqisi2 (tmp1, addr1)); - emit_insn (gen_extendqisi2 (tmp2, addr2)); - - emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx)); - jump = emit_jump_insn (gen_branch_true (L_end_loop_byte)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); - if (flag_delayed_branch) - emit_insn (gen_zero_extendqisi2 (tmp2, - gen_lowpart (QImode, tmp2))); - jump = emit_jump_insn (gen_branch_false (L_end_loop_byte)); - add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); - - addr1 = adjust_address (addr1, QImode, GET_MODE_SIZE (QImode)); - addr2 = adjust_address (addr2, QImode, GET_MODE_SIZE (QImode)); - } + { + emit_insn (gen_extendqisi2 (tmp1, addr1)); + emit_insn (gen_extendqisi2 (tmp2, addr2)); + + emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx)); + jump = emit_jump_insn (gen_branch_true (L_end_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + emit_insn (gen_cmpeqsi_t (tmp1, tmp2)); + if (flag_delayed_branch) + emit_insn (gen_zero_extendqisi2 (tmp2, + gen_lowpart (QImode, tmp2))); + jump = emit_jump_insn (gen_branch_false (L_end_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + + addr1 = adjust_address (addr1, QImode, GET_MODE_SIZE (QImode)); + addr2 = adjust_address (addr2, QImode, GET_MODE_SIZE (QImode)); + } jump = emit_jump_insn (gen_jump_compact( L_end_loop_byte)); emit_barrier_after (jump); } + else + { + emit_insn (gen_cmpeqsi_t (len, const0_rtx)); + emit_move_insn (operands[0], const0_rtx); + jump = emit_jump_insn (gen_branch_true (L_return)); + add_int_reg_note (jump, REG_BR_PROB, prob_unlikely); + } addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0); addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0); @@ -522,14 +561,14 @@ sh_expand_cmpnstr (rtx *operands) emit_insn (gen_zero_extendqisi2 (tmp2, gen_lowpart (QImode, tmp2))); emit_insn (gen_zero_extendqisi2 (tmp1, gen_lowpart (QImode, tmp1))); - emit_label (L_return); - emit_insn (gen_subsi3 (operands[0], tmp1, tmp2)); + emit_label (L_return); + return true; } -/* Emit code to perform a strlen +/* Emit code to perform a strlen. OPERANDS[0] is the destination. OPERANDS[1] is the string. @@ -543,12 +582,12 @@ sh_expand_strlen (rtx *operands) rtx start_addr = gen_reg_rtx (Pmode); rtx tmp0 = gen_reg_rtx (SImode); rtx tmp1 = gen_reg_rtx (SImode); - rtx L_return = gen_label_rtx (); - rtx L_loop_byte = gen_label_rtx (); + rtx_code_label *L_return = gen_label_rtx (); + rtx_code_label *L_loop_byte = gen_label_rtx (); rtx jump; - rtx L_loop_long = gen_label_rtx (); - rtx L_end_loop_long = gen_label_rtx (); + rtx_code_label *L_loop_long = gen_label_rtx (); + rtx_code_label *L_end_loop_long = gen_label_rtx (); int align = INTVAL (operands[3]); @@ -559,7 +598,7 @@ sh_expand_strlen (rtx *operands) if (align < 4) { - emit_insn (gen_tstsi_t (GEN_INT (3), current_addr)); + emit_insn (gen_tstsi_t (current_addr, GEN_INT (3))); jump = emit_jump_insn (gen_branch_false (L_loop_byte)); add_int_reg_note (jump, REG_BR_PROB, prob_likely); } @@ -568,7 +607,7 @@ sh_expand_strlen (rtx *operands) addr1 = adjust_automodify_address (addr1, SImode, current_addr, 0); - /*start long loop. */ + /* start long loop. */ emit_label (L_loop_long); /* tmp1 is aligned, OK to load. */ @@ -586,9 +625,21 @@ sh_expand_strlen (rtx *operands) emit_move_insn (current_addr, plus_constant (Pmode, current_addr, -4)); - /* start byte loop. */ addr1 = adjust_address (addr1, QImode, 0); + /* unroll remaining bytes. */ + for (int i = 0; i < 4; ++i) + { + emit_insn (gen_extendqisi2 (tmp1, addr1)); + emit_move_insn (current_addr, plus_constant (Pmode, current_addr, 1)); + emit_insn (gen_cmpeqsi_t (tmp1, const0_rtx)); + jump = emit_jump_insn (gen_branch_true (L_return)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + } + + emit_barrier_after (jump); + + /* start byte loop. */ emit_label (L_loop_byte); emit_insn (gen_extendqisi2 (tmp1, addr1)); @@ -603,8 +654,107 @@ sh_expand_strlen (rtx *operands) emit_label (L_return); emit_insn (gen_addsi3 (start_addr, start_addr, GEN_INT (1))); - emit_insn (gen_subsi3 (operands[0], current_addr, start_addr)); return true; } + +/* Emit code to perform a memset. + + OPERANDS[0] is the destination. + OPERANDS[1] is the size; + OPERANDS[2] is the char to search. + OPERANDS[3] is the alignment. */ +void +sh_expand_setmem (rtx *operands) +{ + rtx_code_label *L_loop_byte = gen_label_rtx (); + rtx_code_label *L_loop_word = gen_label_rtx (); + rtx_code_label *L_return = gen_label_rtx (); + rtx jump; + rtx dest = copy_rtx (operands[0]); + rtx dest_addr = copy_addr_to_reg (XEXP (dest, 0)); + rtx val = force_reg (SImode, operands[2]); + int align = INTVAL (operands[3]); + rtx len = force_reg (SImode, operands[1]); + + if (! CONST_INT_P (operands[1])) + return; + + int count = INTVAL (operands[1]); + + if (CONST_INT_P (operands[2]) + && (INTVAL (operands[2]) == 0 || INTVAL (operands[2]) == -1) && count > 8) + { + rtx lenw = gen_reg_rtx (SImode); + + if (align < 4) + { + emit_insn (gen_tstsi_t (dest_addr, GEN_INT (3))); + jump = emit_jump_insn (gen_branch_false (L_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + } + + /* word count. Do we have iterations ? */ + emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2))); + + dest = adjust_automodify_address (dest, SImode, dest_addr, 0); + + /* start loop. */ + emit_label (L_loop_word); + + if (TARGET_SH2) + emit_insn (gen_dect (lenw, lenw)); + else + { + emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1))); + emit_insn (gen_tstsi_t (lenw, lenw)); + } + + emit_move_insn (dest, val); + emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr, + GET_MODE_SIZE (SImode))); + + + jump = emit_jump_insn (gen_branch_false (L_loop_word)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + count = count % 4; + + dest = adjust_address (dest, QImode, 0); + + val = gen_lowpart (QImode, val); + + while (count--) + { + emit_move_insn (dest, val); + emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr, + GET_MODE_SIZE (QImode))); + } + + jump = emit_jump_insn (gen_jump_compact (L_return)); + emit_barrier_after (jump); + } + + dest = adjust_automodify_address (dest, QImode, dest_addr, 0); + + /* start loop. */ + emit_label (L_loop_byte); + + if (TARGET_SH2) + emit_insn (gen_dect (len, len)); + else + { + emit_insn (gen_addsi3 (len, len, GEN_INT (-1))); + emit_insn (gen_tstsi_t (len, len)); + } + + val = gen_lowpart (QImode, val); + emit_move_insn (dest, val); + emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr, + GET_MODE_SIZE (QImode))); + + jump = emit_jump_insn (gen_branch_false (L_loop_byte)); + add_int_reg_note (jump, REG_BR_PROB, prob_likely); + + emit_label (L_return); +} diff --git a/gcc/config/sh/sh-modes.def b/gcc/config/sh/sh-modes.def index 3aa3046e37f..724a0443a5e 100644 --- a/gcc/config/sh/sh-modes.def +++ b/gcc/config/sh/sh-modes.def @@ -1,5 +1,5 @@ /* SH extra machine modes. - Copyright (C) 2003-2014 Free Software Foundation, Inc. + Copyright (C) 2003-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -17,8 +17,6 @@ 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/>. */ -/* The SH uses a partial integer mode to represent the FPSCR register. */ -PARTIAL_INT_MODE (SI, 22, PSI); /* PDI mode is used to represent a function address in a target register. */ PARTIAL_INT_MODE (DI, 64, PDI); diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index defc76a3243..bc2b3b30667 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler for Renesas / SuperH SH. - Copyright (C) 1993-2014 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -94,39 +94,38 @@ extern rtx sh_fsca_int2sf (void); /* Declare functions defined in sh.c and used in templates. */ -extern const char *output_branch (int, rtx, rtx *); -extern const char *output_ieee_ccmpeq (rtx, rtx *); -extern const char *output_branchy_insn (enum rtx_code, const char *, rtx, rtx *); -extern const char *output_movedouble (rtx, rtx[], enum machine_mode); -extern const char *output_movepcrel (rtx, rtx[], enum machine_mode); -extern const char *output_far_jump (rtx, rtx); - -extern rtx sfunc_uses_reg (rtx); -extern int barrier_align (rtx); -extern int sh_loop_align (rtx); +extern const char *output_branch (int, rtx_insn *, rtx *); +extern const char *output_ieee_ccmpeq (rtx_insn *, rtx *); +extern const char *output_branchy_insn (enum rtx_code, const char *, + rtx_insn *, rtx *); +extern const char *output_movedouble (rtx, rtx[], machine_mode); +extern const char *output_movepcrel (rtx, rtx[], machine_mode); +extern const char *output_far_jump (rtx_insn *, rtx); + +extern rtx sfunc_uses_reg (rtx_insn *); +extern int barrier_align (rtx_insn *); +extern int sh_loop_align (rtx_insn *); extern bool fp_zero_operand (rtx); extern bool fp_one_operand (rtx); -extern rtx get_fpscr_rtx (void); -extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool); -extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int); -extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); +extern bool sh_legitimate_index_p (machine_mode, rtx, bool, bool); +extern bool sh_legitimize_reload_address (rtx *, machine_mode, int, int); +extern rtx legitimize_pic_address (rtx, machine_mode, rtx); extern bool nonpic_symbol_mentioned_p (rtx); -extern void emit_sf_insn (rtx); -extern void emit_df_insn (rtx); extern void output_pic_addr_const (FILE *, rtx); extern bool expand_block_move (rtx *); -extern void prepare_move_operands (rtx[], enum machine_mode mode); +extern void prepare_move_operands (rtx[], machine_mode mode); extern bool sh_expand_cmpstr (rtx *); extern bool sh_expand_cmpnstr (rtx *); extern bool sh_expand_strlen (rtx *); -extern enum rtx_code prepare_cbranch_operands (rtx *, enum machine_mode mode, +extern void sh_expand_setmem (rtx *); +extern enum rtx_code prepare_cbranch_operands (rtx *, machine_mode mode, enum rtx_code comparison); extern void expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int); extern bool expand_cbranchdi4 (rtx *operands, enum rtx_code comparison); extern void sh_emit_scc_to_t (enum rtx_code, rtx, rtx); -extern rtx sh_emit_cheap_store_flag (enum machine_mode, enum rtx_code, rtx, rtx); -extern void sh_emit_compare_and_branch (rtx *, enum machine_mode); -extern void sh_emit_compare_and_set (rtx *, enum machine_mode); +extern rtx sh_emit_cheap_store_flag (machine_mode, enum rtx_code, rtx, rtx); +extern void sh_emit_compare_and_branch (rtx *, machine_mode); +extern void sh_emit_compare_and_set (rtx *, machine_mode); extern bool sh_ashlsi_clobbers_t_reg_p (rtx); extern bool sh_lshrsi_clobbers_t_reg_p (rtx); extern void gen_shifty_op (int, rtx *); @@ -142,35 +141,32 @@ extern int shl_sext_length (rtx); extern bool gen_shl_sext (rtx, rtx, rtx, rtx); extern rtx gen_datalabel_ref (rtx); extern int regs_used (rtx, int); -extern void fixup_addr_diff_vecs (rtx); +extern void fixup_addr_diff_vecs (rtx_insn *); extern int get_dest_uid (rtx, int); -extern void final_prescan_insn (rtx, rtx *, int); -extern enum tls_model tls_symbolic_operand (rtx, enum machine_mode); -extern bool system_reg_operand (rtx, enum machine_mode); -extern bool reg_unused_after (rtx, rtx); -extern void expand_sf_unop (rtx (*)(rtx, rtx, rtx), rtx *); -extern void expand_sf_binop (rtx (*)(rtx, rtx, rtx, rtx), rtx *); -extern void expand_df_unop (rtx (*)(rtx, rtx, rtx), rtx *); -extern void expand_df_binop (rtx (*)(rtx, rtx, rtx, rtx), rtx *); -extern int sh_insn_length_adjustment (rtx); -extern bool sh_can_redirect_branch (rtx, rtx); +extern void final_prescan_insn (rtx_insn *, rtx *, int); +extern enum tls_model tls_symbolic_operand (rtx, machine_mode); +extern bool system_reg_operand (rtx, machine_mode); +extern bool reg_unused_after (rtx, rtx_insn *); +extern int sh_insn_length_adjustment (rtx_insn *); +extern bool sh_can_redirect_branch (rtx_insn *, rtx_insn *); extern void sh_expand_unop_v2sf (enum rtx_code, rtx, rtx); extern void sh_expand_binop_v2sf (enum rtx_code, rtx, rtx, rtx); extern bool sh_expand_t_scc (rtx *); -extern rtx sh_gen_truncate (enum machine_mode, rtx, int); -extern bool sh_vector_mode_supported_p (enum machine_mode); +extern rtx sh_gen_truncate (machine_mode, rtx, int); +extern bool sh_vector_mode_supported_p (machine_mode); extern bool sh_cfun_trap_exit_p (void); -extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem); +extern rtx sh_find_equiv_gbr_addr (rtx_insn* cur_insn, rtx mem); extern int sh_eval_treg_value (rtx op); extern HOST_WIDE_INT sh_disp_addr_displacement (rtx mem_op); extern int sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a); +extern bool sh_movsf_ie_ra_split_p (rtx, rtx, rtx); /* Result value of sh_find_set_of_reg. */ struct set_of_reg { /* The insn where sh_find_set_of_reg stopped looking. Can be NULL_RTX if the end of the insn list was reached. */ - rtx insn; + rtx_insn* insn; /* The set rtx of the specified reg if found, NULL_RTX otherwise. */ const_rtx set_rtx; @@ -180,32 +176,133 @@ struct set_of_reg rtx set_src; }; -extern set_of_reg sh_find_set_of_reg (rtx reg, rtx insn, rtx(*stepfunc)(rtx)); -extern bool sh_is_logical_t_store_expr (rtx op, rtx insn); -extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx insn); +/* Given a reg rtx and a start insn, try to find the insn that sets the + specified reg by using the specified insn stepping function, such as + 'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx + of the reg set. */ +template <typename F> inline set_of_reg +sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc, + bool ignore_reg_reg_copies = false) +{ + set_of_reg result; + result.insn = insn; + result.set_rtx = NULL_RTX; + result.set_src = NULL_RTX; + + if (!REG_P (reg) || insn == NULL_RTX) + return result; + + rtx_insn* previnsn = insn; + + for (result.insn = stepfunc (insn); result.insn != NULL_RTX; + previnsn = result.insn, result.insn = stepfunc (result.insn)) + { + if (BARRIER_P (result.insn)) + break; + if (!NONJUMP_INSN_P (result.insn)) + continue; + if (reg_set_p (reg, result.insn)) + { + result.set_rtx = set_of (reg, result.insn); + + if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET) + break; + + result.set_src = XEXP (result.set_rtx, 1); + + if (ignore_reg_reg_copies && REG_P (result.set_src)) + { + reg = result.set_src; + continue; + } + if (ignore_reg_reg_copies && SUBREG_P (result.set_src) + && REG_P (SUBREG_REG (result.set_src))) + { + reg = SUBREG_REG (result.set_src); + continue; + } + + break; + } + } + + /* If the loop above stopped at the first insn in the list, + result.insn will be null. Use the insn from the previous iteration + in this case. */ + if (result.insn == NULL) + result.insn = previnsn; + + if (result.set_src != NULL) + gcc_assert (result.insn != NULL && result.set_rtx != NULL); + + return result; +} + +/* Result value of sh_find_extending_set_of_reg. */ +struct sh_extending_set_of_reg : public set_of_reg +{ + /* The mode the set is extending from (QImode or HImode), or VOIDmode if + this is not a zero/sign extending set. */ + machine_mode from_mode; + + /* ZERO_EXTEND, SIGN_EXTEND or UNKNOWN. */ + rtx_code ext_code; + + sh_extending_set_of_reg (rtx_insn* i) + { + insn = i; + set_rtx = NULL; + set_src = NULL; + from_mode = VOIDmode; + ext_code = UNKNOWN; + } + + sh_extending_set_of_reg (const set_of_reg& rhs) + { + *((set_of_reg*)this) = rhs; + from_mode = VOIDmode; + ext_code = UNKNOWN; + } + + /* Returns the reg rtx of the sign or zero extending result, that can be + safely used at the specified insn in SImode. If the set source is an + implicitly sign extending mem load, the mem load is converted into an + explicitly sign extending mem load. */ + rtx use_as_extended_reg (rtx_insn* use_at_insn) const; +}; + +extern sh_extending_set_of_reg sh_find_extending_set_of_reg (rtx reg, + rtx_insn* insn); + +extern bool sh_is_logical_t_store_expr (rtx op, rtx_insn* insn); +extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn); +extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, + rtx operands[]); +extern void sh_split_tst_subregs (rtx_insn* curr_insn, + machine_mode subreg_mode, int subreg_offset, + rtx operands[]); +extern void sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno); #endif /* RTX_CODE */ extern void sh_cpu_cpp_builtins (cpp_reader* pfile); extern const char *output_jump_label_table (void); extern rtx get_t_reg_rtx (void); -extern rtx get_fpscr_rtx (void); extern int sh_media_register_for_return (void); extern void sh_expand_prologue (void); extern void sh_expand_epilogue (bool); extern void sh_set_return_address (rtx, rtx); extern int initial_elimination_offset (int, int); -extern bool fldi_ok (void); extern bool sh_hard_regno_rename_ok (unsigned int, unsigned int); extern bool sh_cfun_interrupt_handler_p (void); extern bool sh_cfun_resbank_handler_p (void); extern bool sh_attr_renesas_p (const_tree); extern bool sh_cfun_attr_renesas_p (void); extern bool sh_cannot_change_mode_class - (enum machine_mode, enum machine_mode, enum reg_class); -extern bool sh_small_register_classes_for_mode_p (enum machine_mode); + (machine_mode, machine_mode, enum reg_class); +extern bool sh_small_register_classes_for_mode_p (machine_mode); extern void sh_mark_label (rtx, int); -extern bool check_use_sfunc_addr (rtx, rtx); +extern bool check_use_sfunc_addr (rtx_insn *, rtx); #ifdef HARD_CONST extern void fpscr_set_from_mem (int, HARD_REG_SET); @@ -218,11 +315,11 @@ extern rtx function_symbol (rtx, const char *, enum sh_function_kind); extern rtx sh_get_pr_initial_val (void); extern void sh_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, - signed int, enum machine_mode); + signed int, machine_mode); extern rtx sh_dwarf_register_span (rtx); extern rtx replace_n_hard_rtx (rtx, rtx *, int , int); -extern int shmedia_cleanup_truncate (rtx *, void *); +extern int shmedia_cleanup_truncate (rtx); extern bool sh_contains_memref_p (rtx); extern bool sh_loads_bankedreg_p (rtx); @@ -230,6 +327,8 @@ extern rtx shmedia_prepare_call_address (rtx fnaddr, int is_sibcall); extern int sh2a_get_function_vector_number (rtx); extern bool sh2a_is_function_vector_call (rtx); extern void sh_fix_range (const char *); -extern bool sh_hard_regno_mode_ok (unsigned int, enum machine_mode); +extern bool sh_hard_regno_mode_ok (unsigned int, machine_mode); +extern machine_mode sh_hard_regno_caller_save_mode (unsigned int, unsigned int, + machine_mode); extern bool sh_can_use_simple_return_p (void); #endif /* ! GCC_SH_PROTOS_H */ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 6d909c79ef7..bde95f6a587 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -1,5 +1,5 @@ /* Output routines for GCC for Renesas / SuperH SH. - Copyright (C) 1993-2014 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -19,24 +19,47 @@ 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 <sstream> +#include <vector> + #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "insn-config.h" #include "rtl.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" +#include "fold-const.h" #include "stringpool.h" #include "stor-layout.h" #include "calls.h" #include "varasm.h" #include "flags.h" +#include "hashtab.h" +#include "hard-reg-set.h" +#include "function.h" +#include "statistics.h" +#include "real.h" +#include "fixed-value.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "emit-rtl.h" +#include "stmt.h" #include "expr.h" +#include "insn-codes.h" #include "optabs.h" #include "reload.h" -#include "function.h" #include "regs.h" -#include "hard-reg-set.h" #include "output.h" #include "insn-attr.h" #include "diagnostic-core.h" @@ -46,13 +69,20 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "target-def.h" #include "langhooks.h" +#include "predict.h" +#include "dominance.h" +#include "cfg.h" +#include "cfgrtl.h" +#include "cfganal.h" +#include "lcm.h" +#include "cfgbuild.h" +#include "cfgcleanup.h" #include "basic-block.h" #include "df.h" #include "intl.h" #include "sched-int.h" #include "params.h" #include "ggc.h" -#include "pointer-set.h" #include "hash-table.h" #include "tree-ssa-alias.h" #include "internal-fn.h" @@ -69,10 +99,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "pass_manager.h" #include "context.h" - -#include <sstream> -#include <vector> -#include <algorithm> +#include "builtins.h" +#include "rtl-iter.h" int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch; @@ -182,26 +210,34 @@ int assembler_dialect; static bool shmedia_space_reserved_for_target_registers; -static void split_branches (rtx); +static void split_branches (rtx_insn *); static int branch_dest (rtx); -static void print_slot (rtx); -static rtx add_constant (rtx, enum machine_mode, rtx); -static void dump_table (rtx, rtx); -static bool broken_move (rtx); -static bool mova_p (rtx); -static rtx find_barrier (int, rtx, rtx); -static bool noncall_uses_reg (rtx, rtx, rtx *); -static rtx gen_block_redirect (rtx, int, int); +static void print_slot (rtx_sequence *); +static rtx_code_label *add_constant (rtx, machine_mode, rtx); +static void dump_table (rtx_insn *, rtx_insn *); +static bool broken_move (rtx_insn *); +static bool mova_p (rtx_insn *); +static rtx_insn *find_barrier (int, rtx_insn *, rtx_insn *); +static bool noncall_uses_reg (rtx, rtx_insn *, rtx *); +static rtx_insn *gen_block_redirect (rtx_insn *, int, int); static void sh_reorg (void); static void sh_option_override (void); static void output_stack_adjust (int, rtx, int, HARD_REG_SET *, bool); -static rtx frame_insn (rtx); +static rtx_insn *frame_insn (rtx); static rtx push (int); static void pop (int); static void push_regs (HARD_REG_SET *, int); static int calc_live_regs (HARD_REG_SET *); static HOST_WIDE_INT rounded_frame_size (int); static bool sh_frame_pointer_required (void); +static void sh_emit_mode_set (int, int, int, HARD_REG_SET); +static int sh_mode_needed (int, rtx_insn *); +static int sh_mode_after (int, int, rtx_insn *); +static int sh_mode_entry (int); +static int sh_mode_exit (int); +static int sh_mode_priority (int entity, int n); +static bool sh_lra_p (void); + static rtx mark_constant_pool_use (rtx); static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *); @@ -219,24 +255,24 @@ static bool sh_asm_output_addr_const_extra (FILE *file, rtx x); static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT); static void sh_insert_attributes (tree, tree *); static const char *sh_check_pch_target_flags (int); -static int sh_register_move_cost (enum machine_mode, reg_class_t, reg_class_t); -static int sh_adjust_cost (rtx, rtx, rtx, int); +static int sh_register_move_cost (machine_mode, reg_class_t, reg_class_t); +static int sh_adjust_cost (rtx_insn *, rtx, rtx_insn *, int); static int sh_issue_rate (void); -static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p); -static short find_set_regmode_weight (rtx, enum machine_mode); -static short find_insn_regmode_weight (rtx, enum machine_mode); -static void find_regmode_weight (basic_block, enum machine_mode); +static int sh_dfa_new_cycle (FILE *, int, rtx_insn *, int, int, int *sort_p); +static short find_set_regmode_weight (rtx, machine_mode); +static short find_insn_regmode_weight (rtx, machine_mode); +static void find_regmode_weight (basic_block, machine_mode); static int find_r0_life_regions (basic_block); static void sh_md_init_global (FILE *, int, int); static void sh_md_finish_global (FILE *, int); static int rank_for_reorder (const void *, const void *); -static void swap_reorder (rtx *, int); -static void ready_reorder (rtx *, int); -static bool high_pressure (enum machine_mode); -static int sh_reorder (FILE *, int, rtx *, int *, int); -static int sh_reorder2 (FILE *, int, rtx *, int *, int); +static void swap_reorder (rtx_insn **, int); +static void ready_reorder (rtx_insn **, int); +static bool high_pressure (machine_mode); +static int sh_reorder (FILE *, int, rtx_insn **, int *, int); +static int sh_reorder2 (FILE *, int, rtx_insn **, int *, int); static void sh_md_init (FILE *, int, int); -static int sh_variable_issue (FILE *, int, rtx, int); +static int sh_variable_issue (FILE *, int, rtx_insn *, int); static bool sh_function_ok_for_sibcall (tree, tree); @@ -247,7 +283,7 @@ static bool sh_ms_bitfield_layout_p (const_tree); static void sh_init_builtins (void); static tree sh_builtin_decl (unsigned, bool); -static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +static rtx sh_expand_builtin (tree, rtx, rtx, machine_mode, int); static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static void sh_file_start (void); @@ -258,18 +294,20 @@ static int and_xor_ior_costs (rtx, int); static int addsubcosts (rtx); static int multcosts (rtx); static bool unspec_caller_rtx_p (rtx); -static bool sh_cannot_copy_insn_p (rtx); +static bool sh_cannot_copy_insn_p (rtx_insn *); static bool sh_rtx_costs (rtx, int, int, int, int *, bool); -static int sh_address_cost (rtx, enum machine_mode, addr_space_t, bool); +static int sh_address_cost (rtx, machine_mode, addr_space_t, bool); static int sh_pr_n_sets (void); static rtx sh_allocate_initial_value (rtx); static reg_class_t sh_preferred_reload_class (rtx, reg_class_t); static reg_class_t sh_secondary_reload (bool, rtx, reg_class_t, - enum machine_mode, + machine_mode, struct secondary_reload_info *); -static bool sh_legitimate_address_p (enum machine_mode, rtx, bool); -static rtx sh_legitimize_address (rtx, rtx, enum machine_mode); +static bool sh_legitimate_address_p (machine_mode, rtx, bool); +static rtx sh_legitimize_address (rtx, rtx, machine_mode); static rtx sh_delegitimize_address (rtx); +static bool sh_cannot_substitute_mem_equiv_p (rtx); +static bool sh_legitimize_address_displacement (rtx *, rtx *, machine_mode); static int shmedia_target_regs_stack_space (HARD_REG_SET *); static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); @@ -281,46 +319,51 @@ static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *, static rtx sh_struct_value_rtx (tree, int); static rtx sh_function_value (const_tree, const_tree, bool); static bool sh_function_value_regno_p (const unsigned int); -static rtx sh_libcall_value (enum machine_mode, const_rtx); +static rtx sh_libcall_value (machine_mode, const_rtx); static bool sh_return_in_memory (const_tree, const_tree); static rtx sh_builtin_saveregs (void); -static void sh_setup_incoming_varargs (cumulative_args_t, enum machine_mode, +static void sh_setup_incoming_varargs (cumulative_args_t, machine_mode, tree, int *, int); static bool sh_strict_argument_naming (cumulative_args_t); static bool sh_pretend_outgoing_varargs_named (cumulative_args_t); +static void sh_atomic_assign_expand_fenv (tree *, tree *, tree *); static tree sh_build_builtin_va_list (void); static void sh_va_start (tree, rtx); static tree sh_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); static bool sh_promote_prototypes (const_tree); -static enum machine_mode sh_promote_function_mode (const_tree type, - enum machine_mode, +static machine_mode sh_promote_function_mode (const_tree type, + machine_mode, int *punsignedp, const_tree funtype, int for_return); -static bool sh_pass_by_reference (cumulative_args_t, enum machine_mode, +static bool sh_pass_by_reference (cumulative_args_t, machine_mode, const_tree, bool); -static bool sh_callee_copies (cumulative_args_t, enum machine_mode, +static bool sh_callee_copies (cumulative_args_t, machine_mode, const_tree, bool); -static int sh_arg_partial_bytes (cumulative_args_t, enum machine_mode, +static int sh_arg_partial_bytes (cumulative_args_t, machine_mode, tree, bool); -static void sh_function_arg_advance (cumulative_args_t, enum machine_mode, +static void sh_function_arg_advance (cumulative_args_t, machine_mode, const_tree, bool); -static rtx sh_function_arg (cumulative_args_t, enum machine_mode, +static rtx sh_function_arg (cumulative_args_t, machine_mode, const_tree, bool); -static bool sh_scalar_mode_supported_p (enum machine_mode); +static bool sh_scalar_mode_supported_p (machine_mode); static int sh_dwarf_calling_convention (const_tree); static void sh_encode_section_info (tree, rtx, int); static bool sh2a_function_vector_p (tree); static void sh_trampoline_init (rtx, tree, rtx); static rtx sh_trampoline_adjust_address (rtx); static void sh_conditional_register_usage (void); -static bool sh_legitimate_constant_p (enum machine_mode, rtx); -static int mov_insn_size (enum machine_mode, bool); -static int mov_insn_alignment_mask (enum machine_mode, bool); -static bool sequence_insn_p (rtx); +static bool sh_legitimate_constant_p (machine_mode, rtx); +static int mov_insn_size (machine_mode, bool); +static int mov_insn_alignment_mask (machine_mode, bool); +static bool sh_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT, + unsigned int, + enum by_pieces_operation, + bool); +static bool sequence_insn_p (rtx_insn *); static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool); static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&, - enum machine_mode, bool); + machine_mode, bool); static bool sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2); static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED; @@ -543,6 +586,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_FUNCTION_ARG_ADVANCE #define TARGET_FUNCTION_ARG_ADVANCE sh_function_arg_advance +#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV +#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV sh_atomic_assign_expand_fenv + #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list #undef TARGET_EXPAND_BUILTIN_VA_START @@ -564,6 +610,24 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_FRAME_POINTER_REQUIRED #define TARGET_FRAME_POINTER_REQUIRED sh_frame_pointer_required +#undef TARGET_MODE_EMIT +#define TARGET_MODE_EMIT sh_emit_mode_set + +#undef TARGET_MODE_NEEDED +#define TARGET_MODE_NEEDED sh_mode_needed + +#undef TARGET_MODE_AFTER +#define TARGET_MODE_AFTER sh_mode_after + +#undef TARGET_MODE_ENTRY +#define TARGET_MODE_ENTRY sh_mode_entry + +#undef TARGET_MODE_EXIT +#define TARGET_MODE_EXIT sh_mode_exit + +#undef TARGET_MODE_PRIORITY +#define TARGET_MODE_PRIORITY sh_mode_priority + /* Return regmode weight for insn. */ #define INSN_REGMODE_WEIGHT(INSN, MODE)\ regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] @@ -575,6 +639,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO sh_encode_section_info +#undef TARGET_LRA_P +#define TARGET_LRA_P sh_lra_p + #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD sh_secondary_reload @@ -587,6 +654,13 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P sh_legitimate_address_p +#undef TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P +#define TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P sh_cannot_substitute_mem_equiv_p + +#undef TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT +#define TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT \ + sh_legitimize_address_displacement + #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT sh_trampoline_init #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS @@ -601,6 +675,10 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_FIXED_CONDITION_CODE_REGS #define TARGET_FIXED_CONDITION_CODE_REGS sh_fixed_condition_code_regs +#undef TARGET_USE_BY_PIECES_INFRASTRUCTURE_P +#define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P \ + sh_use_by_pieces_infrastructure_p + /* Machine-specific symbol_ref flags. */ #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -793,7 +871,7 @@ sh_option_override (void) assembler_dialect = 1; sh_cpu = PROCESSOR_SH4; } - if (TARGET_SH4A_ARCH) + if (TARGET_SH4A) { assembler_dialect = 1; sh_cpu = PROCESSOR_SH4A; @@ -861,6 +939,12 @@ sh_option_override (void) targetm.asm_out.aligned_op.di = NULL; targetm.asm_out.unaligned_op.di = NULL; } + + /* User/priviledged mode is supported only on SH3*, SH4* and SH5*. + Disable it for everything else. */ + if (! (TARGET_SH3 || TARGET_SH5) && TARGET_USERMODE) + TARGET_USERMODE = false; + if (TARGET_SH1) { if (! strcmp (sh_div_str, "call-div1")) @@ -904,15 +988,16 @@ sh_option_override (void) sh_divsi3_libfunc = "__sdivsi3_1"; else sh_divsi3_libfunc = "__sdivsi3"; + if (sh_branch_cost == -1) { - sh_branch_cost = 1; - /* The SH1 does not have delay slots, hence we get a pipeline stall at every branch. The SH4 is superscalar, so the single delay slot - is not sufficient to keep both pipelines filled. */ - if (! TARGET_SH2 || TARGET_HARD_SH4) - sh_branch_cost = 2; + is not sufficient to keep both pipelines filled. + In any case, set the default branch cost to '2', as it results in + slightly overall smaller code and also enables some if conversions + that are required for matching special T bit related insns. */ + sh_branch_cost = 2; } /* Set -mzdcbranch for SH4 / SH4A if not otherwise specified by the user. */ @@ -1165,7 +1250,7 @@ static void sh_print_operand (FILE *stream, rtx x, int code) { int regno; - enum machine_mode mode; + machine_mode mode; switch (code) { @@ -1173,8 +1258,8 @@ sh_print_operand (FILE *stream, rtx x, int code) case '.': if (final_sequence - && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) - && get_attr_length (XVECEXP (final_sequence, 0, 1))) + && ! INSN_ANNULLED_BRANCH_P (final_sequence->insn (0)) + && get_attr_length (final_sequence->insn (1))) fprintf (stream, ASSEMBLER_DIALECT ? "/s" : ".s"); break; case ',': @@ -1427,7 +1512,7 @@ sh_print_operand (FILE *stream, rtx x, int code) { rtx inner = XEXP (x, 0); int offset = 0; - enum machine_mode inner_mode; + machine_mode inner_mode; /* We might see SUBREGs with vector mode registers inside. */ if (GET_CODE (inner) == SUBREG @@ -1645,7 +1730,7 @@ sh_encode_section_info (tree decl, rtx rtl, int first) /* Prepare operands for a move define_expand; specifically, one of the operands must be in a register. */ void -prepare_move_operands (rtx operands[], enum machine_mode mode) +prepare_move_operands (rtx operands[], machine_mode mode) { if ((mode == SImode || mode == DImode) && flag_pic @@ -1706,11 +1791,43 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) reload will fail to find a spill register for rX, since r0 is already being used for the source. */ else if (TARGET_SH1 - && refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0) + && refers_to_regno_p (R0_REG, operands[1]) && MEM_P (operands[0]) && GET_CODE (XEXP (operands[0], 0)) == PLUS && REG_P (XEXP (XEXP (operands[0], 0), 1))) operands[1] = copy_to_mode_reg (mode, operands[1]); + + /* When the displacement addressing is used, RA will assign r0 to + the pseudo register operand for the QI/HImode load/store. + This tends to make a long live range for R0 and might cause + anomalous register spills in some case with LRA. See PR + target/55212. + We split possible load/store to two move insns via r0 so as to + shorten R0 live range. It will make some codes worse but will + win on avarage for LRA. */ + else if (sh_lra_p () + && TARGET_SH1 && ! TARGET_SH2A + && (mode == QImode || mode == HImode) + && ((REG_P (operands[0]) && MEM_P (operands[1])) + || (REG_P (operands[1]) && MEM_P (operands[0])))) + { + bool load_p = REG_P (operands[0]); + rtx reg = operands[load_p ? 0 : 1]; + rtx adr = XEXP (operands[load_p ? 1 : 0], 0); + + if (REGNO (reg) >= FIRST_PSEUDO_REGISTER + && GET_CODE (adr) == PLUS + && REG_P (XEXP (adr, 0)) + && (REGNO (XEXP (adr, 0)) >= FIRST_PSEUDO_REGISTER) + && CONST_INT_P (XEXP (adr, 1)) + && INTVAL (XEXP (adr, 1)) != 0 + && sh_legitimate_index_p (mode, XEXP (adr, 1), false, true)) + { + rtx r0_rtx = gen_rtx_REG (mode, R0_REG); + emit_move_insn (r0_rtx, operands[1]); + operands[1] = r0_rtx; + } + } } if (mode == Pmode || mode == ptr_mode) @@ -1731,7 +1848,8 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) else opc = NULL_RTX; - if ((tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE) + if (! reload_in_progress && ! reload_completed + && (tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE) { rtx tga_op1, tga_ret, tmp, tmp2; @@ -1814,7 +1932,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) canonicalize comparisons in cbranch pattern expanders. */ static void sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1, - enum machine_mode mode, + machine_mode mode, bool op0_preserve_value) { /* When invoked from within the combine pass the mode is not specified, @@ -1935,7 +2053,7 @@ sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2) } enum rtx_code -prepare_cbranch_operands (rtx *operands, enum machine_mode mode, +prepare_cbranch_operands (rtx *operands, machine_mode mode, enum rtx_code comparison) { /* The scratch reg is only available when this is invoked from within @@ -1998,7 +2116,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability) emit_insn (gen_rtx_SET (VOIDmode, get_t_reg_rtx (), gen_rtx_fmt_ee (comparison, SImode, operands[1], operands[2]))); - rtx jump = emit_jump_insn (branch_expander (operands[3])); + rtx_insn *jump = emit_jump_insn (branch_expander (operands[3])); if (probability >= 0) add_int_reg_note (jump, REG_BR_PROB, probability); } @@ -2024,7 +2142,7 @@ bool expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) { enum rtx_code msw_taken, msw_skip, lsw_taken; - rtx skip_label = NULL_RTX; + rtx_code_label *skip_label = NULL; rtx op1h, op1l, op2h, op2l; int num_branches; int prob, rev_prob; @@ -2062,12 +2180,11 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) lsw_taken_prob = prob ? REG_BR_PROB_BASE : 0; else { - gcc_assert (HOST_BITS_PER_WIDEST_INT >= 64); lsw_taken_prob = (prob ? (REG_BR_PROB_BASE - - ((HOST_WIDEST_INT) REG_BR_PROB_BASE * rev_prob - / ((HOST_WIDEST_INT) prob << 32))) + - ((gcov_type) REG_BR_PROB_BASE * rev_prob + / ((gcov_type) prob << 32))) : 0); } } @@ -2224,7 +2341,12 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) int sh_eval_treg_value (rtx op) { - enum rtx_code code = GET_CODE (op); + if (t_reg_operand (op, GET_MODE (op))) + return 1; + if (negt_reg_operand (op, GET_MODE (op))) + return 0; + + rtx_code code = GET_CODE (op); if ((code != EQ && code != NE) || !CONST_INT_P (XEXP (op, 1))) return -1; @@ -2244,20 +2366,20 @@ sh_eval_treg_value (rtx op) return t ^ (cmpval == cmpop); } -/* Emit INSN, possibly in a PARALLEL with an USE of fpscr for SH4. */ - +/* Emit INSN, possibly in a PARALLEL with an USE/CLOBBER of FPSCR bits in case + of floating-point comparisons. */ static void -sh_emit_set_t_insn (rtx insn, enum machine_mode mode) +sh_emit_set_t_insn (rtx insn, machine_mode mode) { - if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT) + if (TARGET_FPU_ANY && GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_CODE (insn) != PARALLEL) { insn = gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, insn, - gen_rtx_USE (VOIDmode, get_fpscr_rtx ()))); - (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn); + gen_rtvec (3, insn, + gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, FPSCR_STAT_REG)), + gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FPSCR_MODES_REG)))); } - else - emit_insn (insn); + emit_insn (insn); } /* Prepare the operands for an scc instruction; make sure that the @@ -2267,7 +2389,7 @@ sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1) { rtx t_reg = get_t_reg_rtx (); enum rtx_code oldcode = code; - enum machine_mode mode; + machine_mode mode; /* First need a compare insn. */ switch (code) @@ -2291,11 +2413,7 @@ sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1) break; } if (code != oldcode) - { - rtx tmp = op0; - op0 = op1; - op1 = tmp; - } + std::swap (op0, op1); mode = GET_MODE (op0); if (mode == VOIDmode) @@ -2315,7 +2433,7 @@ sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1) } rtx -sh_emit_cheap_store_flag (enum machine_mode mode, enum rtx_code code, +sh_emit_cheap_store_flag (machine_mode mode, enum rtx_code code, rtx op0, rtx op1) { rtx target = gen_reg_rtx (SImode); @@ -2370,13 +2488,13 @@ sh_emit_cheap_store_flag (enum machine_mode mode, enum rtx_code code, /* Called from the md file, set up the operands of a compare instruction. */ void -sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode) +sh_emit_compare_and_branch (rtx *operands, machine_mode mode) { enum rtx_code code = GET_CODE (operands[0]); enum rtx_code branch_code; rtx op0 = operands[1]; rtx op1 = operands[2]; - rtx insn, tem; + rtx insn; bool need_ccmpeq = false; if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT) @@ -2401,7 +2519,7 @@ sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode) || (code == LE && TARGET_IEEE && TARGET_SH2E) || (code == GE && !(TARGET_IEEE && TARGET_SH2E))) { - tem = op0, op0 = op1, op1 = tem; + std::swap (op0, op1); code = swap_condition (code); } @@ -2453,14 +2571,13 @@ sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode) } void -sh_emit_compare_and_set (rtx *operands, enum machine_mode mode) +sh_emit_compare_and_set (rtx *operands, machine_mode mode) { enum rtx_code code = GET_CODE (operands[1]); rtx op0 = operands[2]; rtx op1 = operands[3]; - rtx lab = NULL_RTX; + rtx_code_label *lab = NULL; bool invert = false; - rtx tem; op0 = force_reg (mode, op0); if ((code != EQ && code != NE @@ -2474,8 +2591,8 @@ sh_emit_compare_and_set (rtx *operands, enum machine_mode mode) { if (code == LT || code == LE) { + std::swap (op0, op1); code = swap_condition (code); - tem = op0, op0 = op1, op1 = tem; } if (code == GE) { @@ -2517,7 +2634,7 @@ sh_emit_compare_and_set (rtx *operands, enum machine_mode mode) to take care when we see overlapping source and dest registers. */ const char * output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[], - enum machine_mode mode) + machine_mode mode) { rtx dst = operands[0]; rtx src = operands[1]; @@ -2604,22 +2721,22 @@ output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[], another instruction, but couldn't because the other instruction expanded into a sequence where putting the slot insn at the end wouldn't work. */ static void -print_slot (rtx insn) +print_slot (rtx_sequence *seq) { - final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 1, NULL); + final_scan_insn (seq->insn (1), asm_out_file, optimize, 1, NULL); - INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1; + seq->insn (1)->set_deleted (); } const char * -output_far_jump (rtx insn, rtx op) +output_far_jump (rtx_insn *insn, rtx op) { struct { rtx lab, reg, op; } this_jmp; - rtx braf_base_lab = NULL_RTX; + rtx_code_label *braf_base_lab = NULL; const char *jump; int far; int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn)); - rtx prev; + rtx_insn *prev; this_jmp.lab = gen_label_rtx (); @@ -2717,7 +2834,7 @@ static int lf = 100; /* Output code for ordinary branches. */ const char * -output_branch (int logic, rtx insn, rtx *operands) +output_branch (int logic, rtx_insn *insn, rtx *operands) { switch (get_attr_length (insn)) { @@ -2740,8 +2857,8 @@ output_branch (int logic, rtx insn, rtx *operands) place for it is after the label. final will do that by default. */ if (final_sequence - && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) - && get_attr_length (XVECEXP (final_sequence, 0, 1))) + && ! INSN_ANNULLED_BRANCH_P (final_sequence->insn (0)) + && get_attr_length (final_sequence->insn (1))) { asm_fprintf (asm_out_file, "\tb%s%ss\t%LLF%d\n", logic ? "f" : "t", ASSEMBLER_DIALECT ? "/" : ".", label); @@ -2809,9 +2926,9 @@ output_branch (int logic, rtx insn, rtx *operands) follow jmp and bt, if the address is in range. */ const char * output_branchy_insn (enum rtx_code code, const char *templ, - rtx insn, rtx *operands) + rtx_insn *insn, rtx *operands) { - rtx next_insn = NEXT_INSN (insn); + rtx_insn *next_insn = NEXT_INSN (insn); if (next_insn && JUMP_P (next_insn) && condjump_p (next_insn)) { @@ -2819,11 +2936,12 @@ output_branchy_insn (enum rtx_code code, const char *templ, if (GET_CODE (src) == IF_THEN_ELSE && GET_CODE (XEXP (src, 0)) != code) { /* Following branch not taken */ - operands[9] = gen_label_rtx (); - emit_label_after (operands[9], next_insn); - INSN_ADDRESSES_NEW (operands[9], + rtx_code_label *lab = gen_label_rtx (); + emit_label_after (lab, next_insn); + INSN_ADDRESSES_NEW (lab, INSN_ADDRESSES (INSN_UID (next_insn)) + get_attr_length (next_insn)); + operands[9] = lab; return templ; } else @@ -2840,16 +2958,17 @@ output_branchy_insn (enum rtx_code code, const char *templ, } } } - operands[9] = gen_label_rtx (); - emit_label_after (operands[9], insn); - INSN_ADDRESSES_NEW (operands[9], + rtx_code_label *lab = gen_label_rtx (); + emit_label_after (lab, insn); + INSN_ADDRESSES_NEW (lab, INSN_ADDRESSES (INSN_UID (insn)) + get_attr_length (insn)); + operands[9] = lab; return templ; } const char * -output_ieee_ccmpeq (rtx insn, rtx *operands) +output_ieee_ccmpeq (rtx_insn *insn, rtx *operands) { return output_branchy_insn (NE, "bt %l9" "\n" " fcmp/eq %1,%0", @@ -2911,7 +3030,7 @@ unspec_caller_rtx_p (rtx pat) /* Indicate that INSN cannot be duplicated. This is true for insn that generates a unique label. */ static bool -sh_cannot_copy_insn_p (rtx insn) +sh_cannot_copy_insn_p (rtx_insn *insn) { rtx pat; @@ -2951,7 +3070,7 @@ enum struct ashl_lshr_sequence { char insn_count; - char amount[6]; + signed char amount[6]; char clobbers_t; }; @@ -3313,7 +3432,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, && (register_operand (SET_SRC (x), VOIDmode) || satisfies_constraint_Z (SET_SRC (x)))) { - const enum machine_mode mode = GET_MODE (SET_DEST (x)); + const machine_mode mode = GET_MODE (SET_DEST (x)); *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) / mov_insn_size (mode, TARGET_SH2A)); return true; @@ -3567,7 +3686,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, /* Determine the size of the fundamental move insn that will be used for the specified mode. */ static inline int -mov_insn_size (enum machine_mode mode, bool consider_sh2a) +mov_insn_size (machine_mode mode, bool consider_sh2a) { const int mode_sz = GET_MODE_SIZE (mode); @@ -3615,7 +3734,7 @@ sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a) /* Determine the alignment mask for a move insn of the specified mode. */ static inline int -mov_insn_alignment_mask (enum machine_mode mode, bool consider_sh2a) +mov_insn_alignment_mask (machine_mode mode, bool consider_sh2a) { const int mov_insn_sz = mov_insn_size (mode, consider_sh2a); return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0; @@ -3631,7 +3750,7 @@ sh_disp_addr_displacement (rtx x) /* Compute the cost of an address. */ static int -sh_address_cost (rtx x, enum machine_mode mode, +sh_address_cost (rtx x, machine_mode mode, addr_space_t as ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED) { /* 'GBR + 0'. Account one more because of R0 restriction. */ @@ -4475,7 +4594,7 @@ static alloc_pool label_ref_list_pool; typedef struct label_ref_list_d { - rtx label; + rtx_code_label *label; struct label_ref_list_d *next; } *label_ref_list_t; @@ -4535,9 +4654,9 @@ typedef struct label_ref_list_d typedef struct { rtx value; /* Value in table. */ - rtx label; /* Label of value. */ + rtx_code_label *label; /* Label of value. */ label_ref_list_t wend; /* End of window. */ - enum machine_mode mode; /* Mode of value. */ + machine_mode mode; /* Mode of value. */ /* True if this constant is accessed as part of a post-increment sequence. Note that HImode constants are never accessed in this way. */ @@ -4551,7 +4670,7 @@ typedef struct #define MAX_POOL_SIZE 372 static pool_node pool_vector[MAX_POOL_SIZE]; static int pool_size; -static rtx pool_window_label; +static rtx_code_label *pool_window_label; static int pool_window_last; static int max_labelno_before_reorg; @@ -4567,11 +4686,11 @@ static int max_labelno_before_reorg; necessary. */ /* Add a constant to the pool and return its label. */ -static rtx -add_constant (rtx x, enum machine_mode mode, rtx last_value) +static rtx_code_label * +add_constant (rtx x, machine_mode mode, rtx last_value) { int i; - rtx lab, new_rtx; + rtx_code_label *lab, *new_rtx; label_ref_list_t ref, newref; /* First see if we've already got it. */ @@ -4646,9 +4765,9 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value) these insns at a 4-byte aligned position. BARRIER is the barrier after which we are to place the table. */ static void -dump_table (rtx start, rtx barrier) +dump_table (rtx_insn *start, rtx_insn *barrier) { - rtx scan = barrier; + rtx_insn *scan = barrier; int i; bool need_align = true; rtx lab; @@ -4700,7 +4819,7 @@ dump_table (rtx start, rtx barrier) } if (TARGET_FMOVD && TARGET_ALIGN_DOUBLE && have_df) { - rtx align_insn = NULL_RTX; + rtx_insn *align_insn = NULL; scan = emit_label_after (gen_label_rtx (), scan); scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan); @@ -4729,7 +4848,7 @@ dump_table (rtx start, rtx barrier) align_insn); } delete_insn (align_insn); - align_insn = NULL_RTX; + align_insn = NULL; continue; } else @@ -4823,7 +4942,7 @@ dump_table (rtx start, rtx barrier) scan = emit_insn_after (gen_consttable_end (), scan); scan = emit_barrier_after (scan); pool_size = 0; - pool_window_label = NULL_RTX; + pool_window_label = NULL; pool_window_last = 0; } @@ -4835,7 +4954,7 @@ dump_table (rtx start, rtx barrier) CONST_DOUBLE input value is CONST_OK_FOR_I08. For a SFmode move, we don't need to fix it if the input value is CONST_OK_FOR_I08. */ static bool -broken_move (rtx insn) +broken_move (rtx_insn *insn) { if (NONJUMP_INSN_P (insn)) { @@ -4882,7 +5001,7 @@ broken_move (rtx insn) /* Return true if the specified insn is a mova insn. */ static bool -mova_p (rtx insn) +mova_p (rtx_insn *insn) { return (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SET @@ -4894,7 +5013,7 @@ mova_p (rtx insn) /* Fix up a mova from a switch that went out of range. */ static void -fixup_mova (rtx mova) +fixup_mova (rtx_insn *mova) { PUT_MODE (XEXP (MOVA_LABELREF (mova), 0), QImode); if (! flag_pic) @@ -4904,8 +5023,8 @@ fixup_mova (rtx mova) } else { - rtx worker = mova; - rtx lab = gen_label_rtx (); + rtx_insn *worker = mova; + rtx_code_label *lab = gen_label_rtx (); rtx wpat, wpat0, wpat1, wsrc, target, base, diff; do @@ -4938,7 +5057,7 @@ fixup_mova (rtx mova) return 0 if *first_mova was replaced, 1 if new_mova was replaced, 2 if new_mova has been assigned to *first_mova, -1 otherwise.. */ static int -untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova) +untangle_mova (int *num_mova, rtx_insn **first_mova, rtx_insn *new_mova) { int n_addr = 0; /* Initialization to shut up spurious warning. */ int f_target, n_target = 0; /* Likewise. */ @@ -4987,8 +5106,8 @@ untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova) /* Find the last barrier from insn FROM which is close enough to hold the constant pool. If we can't find one, then create one near the end of the range. */ -static rtx -find_barrier (int num_mova, rtx mova, rtx from) +static rtx_insn * +find_barrier (int num_mova, rtx_insn *mova, rtx_insn *from) { int count_si = 0; int count_hi = 0; @@ -4998,14 +5117,14 @@ find_barrier (int num_mova, rtx mova, rtx from) int hi_align = 2; int si_align = 2; int leading_mova = num_mova; - rtx barrier_before_mova = NULL_RTX; - rtx found_barrier = NULL_RTX; - rtx good_barrier = NULL_RTX; + rtx_insn *barrier_before_mova = NULL; + rtx_insn *found_barrier = NULL; + rtx_insn *good_barrier = NULL; int si_limit; int hi_limit; - rtx orig = from; - rtx last_got = NULL_RTX; - rtx last_symoff = NULL_RTX; + rtx_insn *orig = from; + rtx_insn *last_got = NULL; + rtx_insn *last_symoff = NULL; /* For HImode: range is 510, add 4 because pc counts from address of second instruction after this one, subtract 2 for the jump instruction @@ -5065,7 +5184,7 @@ find_barrier (int num_mova, rtx mova, rtx from) if (BARRIER_P (from)) { - rtx next; + rtx_insn *next; found_barrier = from; @@ -5087,7 +5206,7 @@ find_barrier (int num_mova, rtx mova, rtx from) if (broken_move (from)) { rtx pat, src, dst; - enum machine_mode mode; + machine_mode mode; pat = PATTERN (from); if (GET_CODE (pat) == PARALLEL) @@ -5102,9 +5221,9 @@ find_barrier (int num_mova, rtx mova, rtx from) instructions. (plus add r0,r12). Remember if we see one without the other. */ if (GET_CODE (src) == UNSPEC && PIC_ADDR_P (XVECEXP (src, 0, 0))) - last_got = last_got ? NULL_RTX : from; + last_got = last_got ? NULL : from; else if (PIC_ADDR_P (src)) - last_got = last_got ? NULL_RTX : from; + last_got = last_got ? NULL : from; /* We must explicitly check the mode, because sometimes the front end will generate code to load unsigned constants into @@ -5260,7 +5379,7 @@ find_barrier (int num_mova, rtx mova, rtx from) { /* We didn't find a barrier in time to dump our stuff, so we'll make one. */ - rtx label = gen_label_rtx (); + rtx_code_label *label = gen_label_rtx (); /* Don't emit a constant table in the middle of insns for casesi_worker_2. This is a bit overkill but is enough @@ -5308,7 +5427,7 @@ find_barrier (int num_mova, rtx mova, rtx from) CALL_ARG_LOCATION note. */ if (CALL_P (from)) { - rtx next = NEXT_INSN (from); + rtx_insn *next = NEXT_INSN (from); if (next && NOTE_P (next) && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION) from = next; @@ -5329,7 +5448,7 @@ find_barrier (int num_mova, rtx mova, rtx from) register is not used anywhere else in this instruction - except as the destination of a set, return this register; else, return 0. */ rtx -sfunc_uses_reg (rtx insn) +sfunc_uses_reg (rtx_insn *insn) { int i; rtx pattern, part, reg_part, reg; @@ -5366,7 +5485,7 @@ sfunc_uses_reg (rtx insn) setting it while calling it. Set *SET to a SET rtx if the register is set by INSN. */ static bool -noncall_uses_reg (rtx reg, rtx insn, rtx *set) +noncall_uses_reg (rtx reg, rtx_insn *insn, rtx *set) { rtx pattern, reg2; @@ -5525,15 +5644,15 @@ regs_used (rtx x, int is_dest) pass 1. Pass 2 if a definite blocking insn is needed. -1 is used internally to avoid deep recursion. If a blocking instruction is made or recognized, return it. */ -static rtx -gen_block_redirect (rtx jump, int addr, int need_block) +static rtx_insn * +gen_block_redirect (rtx_insn *jump, int addr, int need_block) { int dead = 0; - rtx prev = prev_nonnote_insn (jump); + rtx_insn *prev = prev_nonnote_insn (jump); rtx dest; /* First, check if we already have an instruction that satisfies our need. */ - if (prev && NONJUMP_INSN_P (prev) && ! INSN_DELETED_P (prev)) + if (prev && NONJUMP_INSN_P (prev) && ! prev->deleted ()) { if (INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch) return prev; @@ -5562,7 +5681,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092 > 4092 + 4098)) { - rtx scan; + rtx_insn *scan; /* Don't look for the stack pointer as a scratch register, it would cause trouble if an interrupt occurred. */ unsigned attempt = 0x7fff, used; @@ -5576,7 +5695,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) { enum rtx_code code; - if (INSN_DELETED_P (scan)) + if (scan->deleted ()) continue; code = GET_CODE (scan); if (code == CODE_LABEL || code == JUMP_INSN) @@ -5590,12 +5709,12 @@ gen_block_redirect (rtx jump, int addr, int need_block) break; } } - for (used = dead = 0, scan = JUMP_LABEL (jump); + for (used = dead = 0, scan = JUMP_LABEL_AS_INSN (jump); (scan = NEXT_INSN (scan)); ) { enum rtx_code code; - if (INSN_DELETED_P (scan)) + if (scan->deleted ()) continue; code = GET_CODE (scan); if (INSN_P (scan)) @@ -5612,7 +5731,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) if (code == JUMP_INSN) { if (jump_left-- && simplejump_p (scan)) - scan = JUMP_LABEL (scan); + scan = JUMP_LABEL_AS_INSN (scan); else break; } @@ -5629,7 +5748,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) else if (optimize && need_block >= 0) { - rtx next = next_active_insn (next_active_insn (dest)); + rtx_insn *next = next_active_insn (next_active_insn (dest)); if (next && JUMP_P (next) && GET_CODE (PATTERN (next)) == SET && recog_memoized (next) == CODE_FOR_jump_compact) @@ -5653,9 +5772,9 @@ gen_block_redirect (rtx jump, int addr, int need_block) it should try to schedule instructions from the target of the branch; simplejump_p fails for indirect jumps even if they have a JUMP_LABEL. */ - rtx insn = emit_insn_before (gen_indirect_jump_scratch - (reg, GEN_INT (unspec_bbr_uid++)), - jump); + rtx_insn *insn = emit_insn_before (gen_indirect_jump_scratch + (reg, GEN_INT (unspec_bbr_uid++)), + jump); /* ??? We would like this to have the scope of the jump, but that scope will change when a delay slot insn of an inner scope is added. Hence, after delay slot scheduling, we'll have to expect @@ -5681,12 +5800,12 @@ struct far_branch { /* A label (to be placed) in front of the jump that jumps to our ultimate destination. */ - rtx near_label; + rtx_insn *near_label; /* Where we are going to insert it if we cannot move the jump any farther, or the jump itself if we have picked up an existing jump. */ - rtx insert_place; + rtx_insn *insert_place; /* The ultimate destination. */ - rtx far_label; + rtx_insn *far_label; struct far_branch *prev; /* If the branch has already been created, its address; else the address of its first prospective user. */ @@ -5698,9 +5817,9 @@ enum mdep_reorg_phase_e mdep_reorg_phase; static void gen_far_branch (struct far_branch *bp) { - rtx insn = bp->insert_place; - rtx jump; - rtx label = gen_label_rtx (); + rtx_insn *insn = bp->insert_place; + rtx_insn *jump; + rtx_code_label *label = gen_label_rtx (); int ok; emit_label_after (label, insn); @@ -5749,13 +5868,14 @@ gen_far_branch (struct far_branch *bp) /* Fix up ADDR_DIFF_VECs. */ void -fixup_addr_diff_vecs (rtx first) +fixup_addr_diff_vecs (rtx_insn *first) { - rtx insn; + rtx_insn *insn; for (insn = first; insn; insn = NEXT_INSN (insn)) { - rtx vec_lab, pat, prev, prevpat, x, braf_label; + rtx vec_lab, pat, prevpat, x, braf_label; + rtx_insn *prev; if (! JUMP_TABLE_DATA_P (insn) || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) @@ -5764,7 +5884,7 @@ fixup_addr_diff_vecs (rtx first) vec_lab = XEXP (XEXP (pat, 0), 0); /* Search the matching casesi_jump_2. */ - for (prev = vec_lab; ; prev = PREV_INSN (prev)) + for (prev = as_a <rtx_insn *> (vec_lab); ; prev = PREV_INSN (prev)) { if (!JUMP_P (prev)) continue; @@ -5797,7 +5917,7 @@ fixup_addr_diff_vecs (rtx first) /* BARRIER_OR_LABEL is either a BARRIER or a CODE_LABEL immediately following a barrier. Return the base 2 logarithm of the desired alignment. */ int -barrier_align (rtx barrier_or_label) +barrier_align (rtx_insn *barrier_or_label) { rtx next, pat; @@ -5862,7 +5982,7 @@ barrier_align (rtx barrier_or_label) /* Skip to the insn before the JUMP_INSN before the barrier under investigation. */ - rtx prev = prev_real_insn (prev_active_insn (barrier_or_label)); + rtx_insn *prev = prev_real_insn (prev_active_insn (barrier_or_label)); for (slot = 2, credit = (1 << (CACHE_LOG - 2)) + 2; credit >= 0 && prev && NONJUMP_INSN_P (prev); @@ -5872,9 +5992,9 @@ barrier_align (rtx barrier_or_label) if (GET_CODE (PATTERN (prev)) == USE || GET_CODE (PATTERN (prev)) == CLOBBER) continue; - if (GET_CODE (PATTERN (prev)) == SEQUENCE) + if (rtx_sequence *prev_seq = dyn_cast <rtx_sequence *> (PATTERN (prev))) { - prev = XVECEXP (PATTERN (prev), 0, 1); + prev = prev_seq->insn (1); if (INSN_UID (prev) == INSN_UID (next)) { /* Delay slot was filled with insn at jump target. */ @@ -5890,7 +6010,7 @@ barrier_align (rtx barrier_or_label) } if (prev && jump_to_label_p (prev)) { - rtx x; + rtx_insn *x; if (jump_to_next || next_real_insn (JUMP_LABEL (prev)) == next /* If relax_delay_slots() decides NEXT was redundant @@ -5925,9 +6045,9 @@ barrier_align (rtx barrier_or_label) Applying loop alignment to small constant or switch tables is a waste of space, so we suppress this too. */ int -sh_loop_align (rtx label) +sh_loop_align (rtx_insn *label) { - rtx next = label; + rtx_insn *next = label; if (! optimize || optimize_size) return 0; @@ -5949,7 +6069,7 @@ sh_loop_align (rtx label) static void sh_reorg (void) { - rtx first, insn, mova = NULL_RTX; + rtx_insn *first, *insn, *mova = NULL; int num_mova; rtx r0_rtx = gen_rtx_REG (Pmode, 0); rtx r0_inc_rtx = gen_rtx_POST_INC (Pmode, r0_rtx); @@ -5995,7 +6115,9 @@ sh_reorg (void) for (insn = first; insn; insn = NEXT_INSN (insn)) { - rtx pattern, reg, link, set, scan, dies, label; + rtx pattern, reg, set, dies; + rtx_code_label *label; + rtx_insn *link, *scan; int rescan = 0, foundinsn = 0; if (CALL_P (insn)) @@ -6209,7 +6331,7 @@ sh_reorg (void) || (prev_nonnote_insn (insn) == XEXP (MOVA_LABELREF (mova), 0)))) { - rtx scan; + rtx_insn *scan; int total; num_mova--; @@ -6235,11 +6357,12 @@ sh_reorg (void) || (NONJUMP_INSN_P (insn) && recog_memoized (insn) == CODE_FOR_casesi_worker_2)) { - rtx scan; + rtx_insn *scan; /* Scan ahead looking for a barrier to stick the constant table behind. */ - rtx barrier = find_barrier (num_mova, mova, insn); - rtx last_float_move = NULL_RTX, last_float = 0, *last_float_addr = NULL; + rtx_insn *barrier = find_barrier (num_mova, mova, insn); + rtx_insn *last_float_move = NULL; + rtx last_float = 0, *last_float_addr = NULL; int need_aligned_label = 0; if (num_mova && ! mova_p (mova)) @@ -6263,7 +6386,7 @@ sh_reorg (void) rtx src, dst; rtx lab; rtx newsrc; - enum machine_mode mode; + machine_mode mode; if (GET_CODE (pat) == PARALLEL) patp = &XVECEXP (pat, 0, 0), pat = *patp; @@ -6395,14 +6518,6 @@ sh_reorg (void) emit_insn_before (gen_use_sfunc_addr (reg), insn); } } -#if 0 - /* fpscr is not actually a user variable, but we pretend it is for the - sake of the previous optimization passes, since we want it handled like - one. However, we don't have any debugging information for it, so turn - it into a non-user variable now. */ - if (TARGET_SH4) - REG_USERVAR_P (get_fpscr_rtx ()) = 0; -#endif mdep_reorg_phase = SH_AFTER_MDEP_REORG; } @@ -6410,7 +6525,7 @@ sh_reorg (void) int get_dest_uid (rtx label, int max_uid) { - rtx dest = next_real_insn (label); + rtx_insn *dest = next_real_insn (label); int dest_uid; if (! dest) /* This can happen for an undefined label. */ @@ -6436,9 +6551,9 @@ get_dest_uid (rtx label, int max_uid) newly created instructions into account. It also allows us to find branches with common targets more easily. */ static void -split_branches (rtx first) +split_branches (rtx_insn *first) { - rtx insn; + rtx_insn *insn; struct far_branch **uid_branch, *far_branch_list = 0; int max_uid = get_max_uid (); int ok; @@ -6452,7 +6567,7 @@ split_branches (rtx first) for (insn = first; insn; insn = NEXT_INSN (insn)) if (! INSN_P (insn)) continue; - else if (INSN_DELETED_P (insn)) + else if (insn->deleted ()) { /* Shorten_branches would split this instruction again, so transform it into a note. */ @@ -6463,14 +6578,14 @@ split_branches (rtx first) enum attr_type type = get_attr_type (insn); if (type == TYPE_CBRANCH) { - rtx next, beyond; + rtx_insn *next, *beyond; if (get_attr_length (insn) > 4) { rtx src = SET_SRC (PATTERN (insn)); rtx olabel = XEXP (XEXP (src, 1), 0); int addr = INSN_ADDRESSES (INSN_UID (insn)); - rtx label = 0; + rtx_insn *label = 0; int dest_uid = get_dest_uid (olabel, max_uid); struct far_branch *bp = uid_branch[dest_uid]; @@ -6491,8 +6606,9 @@ split_branches (rtx first) uid_branch[dest_uid] = bp; bp->prev = far_branch_list; far_branch_list = bp; - bp->far_label - = XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0); + bp->far_label = as_a <rtx_insn *> ( + XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), + 0)); LABEL_NUSES (bp->far_label)++; } else @@ -6500,7 +6616,7 @@ split_branches (rtx first) label = bp->near_label; if (! label && bp->address - addr >= CONDJUMP_MIN) { - rtx block = bp->insert_place; + rtx_insn *block = bp->insert_place; if (GET_CODE (PATTERN (block)) == RETURN) block = PREV_INSN (block); @@ -6573,13 +6689,14 @@ split_branches (rtx first) else if (type == TYPE_JUMP || type == TYPE_RETURN) { int addr = INSN_ADDRESSES (INSN_UID (insn)); - rtx far_label = 0; + rtx_insn *far_label = 0; int dest_uid = 0; struct far_branch *bp; if (type == TYPE_JUMP) { - far_label = XEXP (SET_SRC (PATTERN (insn)), 0); + far_label = as_a <rtx_insn *> ( + XEXP (SET_SRC (PATTERN (insn)), 0)); dest_uid = get_dest_uid (far_label, max_uid); if (! dest_uid) { @@ -6657,7 +6774,7 @@ split_branches (rtx first) variable length. This is because the second pass of shorten_branches does not bother to update them. */ void -final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED, +final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED, int noperands ATTRIBUTE_UNUSED) { if (TARGET_DUMPISIZE) @@ -6753,7 +6870,7 @@ static void output_stack_adjust (int size, rtx reg, int epilogue_p, HARD_REG_SET *live_regs_mask, bool frame_p) { - rtx (*emit_fn) (rtx) = frame_p ? &frame_insn : &emit_insn; + rtx_insn *(*emit_fn) (rtx) = frame_p ? &frame_insn : &emit_insn; if (size) { HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; @@ -6800,7 +6917,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, int nreg = 0; if (crtl->return_rtx) { - enum machine_mode mode; + machine_mode mode; mode = GET_MODE (crtl->return_rtx); if (BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG) nreg = HARD_REGNO_NREGS (FIRST_RET_REG, mode); @@ -6913,12 +7030,12 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, /* Emit the specified insn and mark it as frame related. FIXME: Rename this to emit_frame_insn. */ -static rtx +static rtx_insn * frame_insn (rtx x) { - x = emit_insn (x); - RTX_FRAME_RELATED_P (x) = 1; - return x; + rtx_insn *insn = emit_insn (x); + RTX_FRAME_RELATED_P (insn) = 1; + return insn; } /* Output RTL to push register RN onto the stack. */ @@ -7205,6 +7322,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM && reg != RETURN_ADDRESS_POINTER_REGNUM && reg != T_REG && reg != GBR_REG + && reg != FPSCR_MODES_REG && reg != FPSCR_STAT_REG /* Push fpscr only on targets which have FPU */ && (reg != FPSCR_REG || TARGET_FPU_ANY)) : (/* Only push those regs which are used and need to be saved. */ @@ -7392,7 +7510,7 @@ sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule, for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) if (TEST_HARD_REG_BIT (*live_regs_mask, i)) { - enum machine_mode mode = REGISTER_NATURAL_MODE (i); + machine_mode mode = REGISTER_NATURAL_MODE (i); int reg = i; if (current_function_interrupt) @@ -7610,7 +7728,7 @@ sh_expand_prologue (void) tmp_pnt = schedule.temps; for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) { - enum machine_mode mode = (enum machine_mode) entry->mode; + machine_mode mode = (machine_mode) entry->mode; unsigned int reg = entry->reg; rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX; rtx orig_reg_rtx; @@ -7708,8 +7826,7 @@ sh_expand_prologue (void) { offset_in_r0 = -1; sp_in_r0 = 0; - gcc_assert (!refers_to_regno_p - (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0)); + gcc_assert (!refers_to_regno_p (R0_REG, mem_rtx)); } if (*++tmp_pnt <= 0) @@ -7910,7 +8027,7 @@ sh_expand_epilogue (bool sibcall_p) tmp_pnt = schedule.temps; for (; entry->mode != VOIDmode; entry--) { - enum machine_mode mode = (enum machine_mode) entry->mode; + machine_mode mode = (machine_mode) entry->mode; int reg = entry->reg; rtx reg_rtx, mem_rtx, post_inc = NULL_RTX; @@ -8574,7 +8691,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, pass_as_float = (TREE_CODE (eff_type) == REAL_TYPE && size == 4); } - addr = create_tmp_var (pptr_type_node, NULL); + addr = create_tmp_var (pptr_type_node); lab_false = create_artificial_label (UNKNOWN_LOCATION); lab_over = create_artificial_label (UNKNOWN_LOCATION); @@ -8582,7 +8699,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, if (pass_as_float) { - tree next_fp_tmp = create_tmp_var (TREE_TYPE (f_next_fp), NULL); + tree next_fp_tmp = create_tmp_var (TREE_TYPE (f_next_fp)); tree cmp; bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE; @@ -8723,8 +8840,8 @@ sh_dwarf_register_span (rtx reg) gen_rtx_REG (SFmode, regno))); } -static enum machine_mode -sh_promote_function_mode (const_tree type, enum machine_mode mode, +static machine_mode +sh_promote_function_mode (const_tree type, machine_mode mode, int *punsignedp, const_tree funtype, int for_return) { @@ -8750,7 +8867,7 @@ sh_promote_prototypes (const_tree type) registers are passed by reference, so that an SHmedia trampoline loads them into the full 64-bits registers. */ static int -shcompact_byref (const CUMULATIVE_ARGS *cum, enum machine_mode mode, +shcompact_byref (const CUMULATIVE_ARGS *cum, machine_mode mode, const_tree type, bool named) { unsigned HOST_WIDE_INT size; @@ -8774,7 +8891,7 @@ shcompact_byref (const CUMULATIVE_ARGS *cum, enum machine_mode mode, } static bool -sh_pass_by_reference (cumulative_args_t cum_v, enum machine_mode mode, +sh_pass_by_reference (cumulative_args_t cum_v, machine_mode mode, const_tree type, bool named) { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); @@ -8798,7 +8915,7 @@ sh_pass_by_reference (cumulative_args_t cum_v, enum machine_mode mode, } static bool -sh_callee_copies (cumulative_args_t cum, enum machine_mode mode, +sh_callee_copies (cumulative_args_t cum, machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { /* ??? How can it possibly be correct to return true only on the @@ -8809,22 +8926,70 @@ sh_callee_copies (cumulative_args_t cum, enum machine_mode mode, % SH_MIN_ALIGN_FOR_CALLEE_COPY == 0)); } +/* Round a register number up to a proper boundary for an arg of mode + MODE. + The SH doesn't care about double alignment, so we only + round doubles to even regs when asked to explicitly. */ static int -sh_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode, +sh_round_reg (const CUMULATIVE_ARGS& cum, machine_mode mode) +{ + /* FIXME: This used to be a macro and has been copy pasted into this + function as is. Make this more readable. */ + return + (((TARGET_ALIGN_DOUBLE + || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) + && (mode == DFmode || mode == DCmode) + && cum.arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (mode))) + && GET_MODE_UNIT_SIZE (mode) > UNITS_PER_WORD) + ? (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)] + + (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)] & 1)) + : cum.arg_count[(int) GET_SH_ARG_CLASS (mode)]); +} + +/* Return true if arg of the specified mode should be be passed in a register + or false otherwise. */ +static bool +sh_pass_in_reg_p (const CUMULATIVE_ARGS& cum, machine_mode mode, + const_tree type) +{ + /* FIXME: This used to be a macro and has been copy pasted into this + function as is. Make this more readable. */ + return + ((type == 0 + || (! TREE_ADDRESSABLE (type) + && (! (TARGET_HITACHI || cum.renesas_abi) + || ! (AGGREGATE_TYPE_P (type) + || (!TARGET_FPU_ANY + && (GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) > GET_MODE_SIZE (SFmode))))))) + && ! cum.force_mem + && (TARGET_SH2E + ? ((mode) == BLKmode + ? ((cum.arg_count[(int) SH_ARG_INT] * UNITS_PER_WORD + + int_size_in_bytes (type)) + <= NPARM_REGS (SImode) * UNITS_PER_WORD) + : ((sh_round_reg (cum, mode) + + HARD_REGNO_NREGS (BASE_ARG_REG (mode), mode)) + <= NPARM_REGS (mode))) + : sh_round_reg (cum, mode) < NPARM_REGS (mode))); +} + +static int +sh_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); int words = 0; if (!TARGET_SH5 - && PASS_IN_REG_P (*cum, mode, type) + && sh_pass_in_reg_p (*cum, mode, type) && !(TARGET_SH4 || TARGET_SH2A_DOUBLE) - && (ROUND_REG (*cum, mode) + && (sh_round_reg (*cum, mode) + (mode != BLKmode - ? ROUND_ADVANCE (GET_MODE_SIZE (mode)) - : ROUND_ADVANCE (int_size_in_bytes (type))) + ? CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD) + : CEIL (int_size_in_bytes (type), UNITS_PER_WORD)) > NPARM_REGS (mode))) - words = NPARM_REGS (mode) - ROUND_REG (*cum, mode); + words = NPARM_REGS (mode) - sh_round_reg (*cum, mode); else if (!TARGET_SHCOMPACT && SH5_WOULD_BE_PARTIAL_NREGS (*cum, mode, type, named)) @@ -8852,7 +9017,7 @@ sh_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode, NPARM_REGS words is at least partially passed in a register unless its data type forbids. */ static rtx -sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, +sh_function_arg (cumulative_args_t ca_v, machine_mode mode, const_tree type, bool named) { CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v); @@ -8861,23 +9026,23 @@ sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, return GEN_INT (ca->renesas_abi ? 1 : 0); if (! TARGET_SH5 - && PASS_IN_REG_P (*ca, mode, type) + && sh_pass_in_reg_p (*ca, mode, type) && (named || ! (TARGET_HITACHI || ca->renesas_abi))) { int regno; if (mode == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN - && (! FUNCTION_ARG_SCmode_WART || (ROUND_REG (*ca, mode) & 1))) + && (! FUNCTION_ARG_SCmode_WART || (sh_round_reg (*ca, mode) & 1))) { rtx r1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (SFmode, BASE_ARG_REG (mode) - + (ROUND_REG (*ca, mode) ^ 1)), + + (sh_round_reg (*ca, mode) ^ 1)), const0_rtx); rtx r2 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (SFmode, BASE_ARG_REG (mode) - + ((ROUND_REG (*ca, mode) + 1) ^ 1)), + + ((sh_round_reg (*ca, mode) + 1) ^ 1)), GEN_INT (4)); return gen_rtx_PARALLEL(SCmode, gen_rtvec(2, r1, r2)); } @@ -8890,7 +9055,7 @@ sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, && mode == SFmode) return gen_rtx_REG (mode, ca->free_single_fp_reg); - regno = (BASE_ARG_REG (mode) + ROUND_REG (*ca, mode)) + regno = (BASE_ARG_REG (mode) + sh_round_reg (*ca, mode)) ^ (mode == SFmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN && ! TARGET_HITACHI && ! ca->renesas_abi); @@ -8941,7 +9106,7 @@ sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, (TYPE is null for libcalls where that information may not be available.) */ static void -sh_function_arg_advance (cumulative_args_t ca_v, enum machine_mode mode, +sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode, const_tree type, bool named) { CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v); @@ -8953,7 +9118,7 @@ sh_function_arg_advance (cumulative_args_t ca_v, enum machine_mode mode, const_tree type2 = (ca->byref && type ? TREE_TYPE (type) : type); - enum machine_mode mode2 = (ca->byref && type + machine_mode mode2 = (ca->byref && type ? TYPE_MODE (type2) : mode); int dwords = ((ca->byref @@ -9070,20 +9235,20 @@ sh_function_arg_advance (cumulative_args_t ca_v, enum machine_mode mode, register, because the next SF value will use it, and not the SF that follows the DF. */ if (mode == DFmode - && ROUND_REG (*ca, DFmode) != ROUND_REG (*ca, SFmode)) + && sh_round_reg (*ca, DFmode) != sh_round_reg (*ca, SFmode)) { - ca->free_single_fp_reg = (ROUND_REG (*ca, SFmode) + ca->free_single_fp_reg = (sh_round_reg (*ca, SFmode) + BASE_ARG_REG (mode)); } } if (! ((TARGET_SH4 || TARGET_SH2A) || ca->renesas_abi) - || PASS_IN_REG_P (*ca, mode, type)) + || sh_pass_in_reg_p (*ca, mode, type)) (ca->arg_count[(int) GET_SH_ARG_CLASS (mode)] - = (ROUND_REG (*ca, mode) + = (sh_round_reg (*ca, mode) + (mode == BLKmode - ? ROUND_ADVANCE (int_size_in_bytes (type)) - : ROUND_ADVANCE (GET_MODE_SIZE (mode))))); + ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD) + : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD)))); } /* The Renesas calling convention doesn't quite fit into this scheme since @@ -9128,7 +9293,7 @@ sh_function_value (const_tree valtype, /* Worker function for TARGET_LIBCALL_VALUE. */ static rtx -sh_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +sh_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) { return gen_rtx_REG (mode, BASE_RETURN_VALUE_REG (mode)); } @@ -9168,7 +9333,7 @@ sh_return_in_memory (const_tree type, const_tree fndecl) function that tell if a function uses varargs or stdarg. */ static void sh_setup_incoming_varargs (cumulative_args_t ca, - enum machine_mode mode, + machine_mode mode, tree type, int *pretend_arg_size, int second_time ATTRIBUTE_UNUSED) @@ -9178,10 +9343,10 @@ sh_setup_incoming_varargs (cumulative_args_t ca, { int named_parm_regs, anon_parm_regs; - named_parm_regs = (ROUND_REG (*get_cumulative_args (ca), mode) + named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), mode) + (mode == BLKmode - ? ROUND_ADVANCE (int_size_in_bytes (type)) - : ROUND_ADVANCE (GET_MODE_SIZE (mode)))); + ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD) + : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD))); anon_parm_regs = NPARM_REGS (SImode) - named_parm_regs; if (anon_parm_regs > 0) *pretend_arg_size = anon_parm_regs * 4; @@ -9743,7 +9908,7 @@ sh_check_pch_target_flags (int old_flags) /* Returns true if OP is MACL, MACH or PR. The input must be a REG rtx. Used only in general_movsrc_operand. */ bool -system_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +system_reg_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED) { switch (REGNO (op)) { @@ -9781,22 +9946,9 @@ fp_one_operand (rtx op) return REAL_VALUES_EQUAL (r, dconst1); } -/* In general mode switching is used. If we are - compiling without -mfmovd, movsf_ie isn't taken into account for - mode switching. We could check in machine_dependent_reorg for - cases where we know we are in single precision mode, but there is - interface to find that out during reload, so we must avoid - choosing an fldi alternative during reload and thus failing to - allocate a scratch register for the constant loading. */ -bool -fldi_ok (void) -{ - return true; -} - /* Return the TLS type for TLS symbols. */ enum tls_model -tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +tls_symbolic_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED) { if (GET_CODE (op) != SYMBOL_REF) return TLS_MODEL_NONE; @@ -9821,7 +9973,7 @@ branch_dest (rtx branch) We assume REG is a reload reg, and therefore does not live past labels. It may live past calls or jumps though. */ bool -reg_unused_after (rtx reg, rtx insn) +reg_unused_after (rtx reg, rtx_insn *insn) { enum rtx_code code; rtx set; @@ -9861,12 +10013,13 @@ reg_unused_after (rtx reg, rtx insn) we must return 0. */ else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) { + rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn)); int i; int retval = 0; - for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) + for (i = 0; i < seq->len (); i++) { - rtx this_insn = XVECEXP (PATTERN (insn), 0, i); + rtx_insn *this_insn = seq->insn (i); rtx set = single_set (this_insn); if (CALL_P (this_insn)) @@ -9911,7 +10064,6 @@ reg_unused_after (rtx reg, rtx insn) return true; } -#include "ggc.h" static GTY(()) rtx t_reg_rtx; rtx @@ -9922,27 +10074,12 @@ get_t_reg_rtx (void) return t_reg_rtx; } -static GTY(()) rtx fpscr_rtx; -rtx -get_fpscr_rtx (void) -{ - if (! fpscr_rtx) - { - fpscr_rtx = gen_rtx_REG (PSImode, FPSCR_REG); - REG_USERVAR_P (fpscr_rtx) = 1; - mark_user_reg (fpscr_rtx); - } - if (! reload_completed || mdep_reorg_phase != SH_AFTER_MDEP_REORG) - mark_user_reg (fpscr_rtx); - return fpscr_rtx; -} - static GTY(()) tree fpscr_values; static void emit_fpu_switch (rtx scratch, int index) { - rtx dst, src; + rtx src; if (fpscr_values == NULL) { @@ -9968,51 +10105,12 @@ emit_fpu_switch (rtx scratch, int index) emit_move_insn (scratch, XEXP (src, 0)); if (index != 0) emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4))); - src = adjust_automodify_address (src, PSImode, scratch, index * 4); + src = adjust_automodify_address (src, SImode, scratch, index * 4); } else - src = adjust_address (src, PSImode, index * 4); - - dst = get_fpscr_rtx (); - emit_move_insn (dst, src); -} - -void -emit_sf_insn (rtx pat) -{ - emit_insn (pat); -} - -void -emit_df_insn (rtx pat) -{ - emit_insn (pat); -} - -void -expand_sf_unop (rtx (*fun) (rtx, rtx, rtx), rtx *operands) -{ - emit_sf_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ())); -} - -void -expand_sf_binop (rtx (*fun) (rtx, rtx, rtx, rtx), rtx *operands) -{ - emit_sf_insn ((*fun) (operands[0], operands[1], operands[2], - get_fpscr_rtx ())); -} + src = adjust_address (src, SImode, index * 4); -void -expand_df_unop (rtx (*fun) (rtx, rtx, rtx), rtx *operands) -{ - emit_df_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ())); -} - -void -expand_df_binop (rtx (*fun) (rtx, rtx, rtx, rtx), rtx *operands) -{ - emit_df_insn ((*fun) (operands[0], operands[1], operands[2], - get_fpscr_rtx ())); + emit_insn (gen_lds_fpscr (src)); } static rtx get_free_reg (HARD_REG_SET); @@ -10061,9 +10159,9 @@ fpscr_set_from_mem (int mode, HARD_REG_SET regs_live) #endif static bool -sequence_insn_p (rtx insn) +sequence_insn_p (rtx_insn *insn) { - rtx prev, next; + rtx_insn *prev, *next; prev = PREV_INSN (insn); if (prev == NULL) @@ -10077,7 +10175,7 @@ sequence_insn_p (rtx insn) } int -sh_insn_length_adjustment (rtx insn) +sh_insn_length_adjustment (rtx_insn *insn) { /* Instructions with unfilled delay slots take up an extra two bytes for the nop in the delay slot. */ @@ -10156,7 +10254,7 @@ sh_insn_length_adjustment (rtx insn) /* Return TRUE for a valid displacement for the REG+disp addressing with MODE. */ bool -sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a, +sh_legitimate_index_p (machine_mode mode, rtx op, bool consider_sh2a, bool allow_zero) { if (! CONST_INT_P (op)) @@ -10205,8 +10303,12 @@ sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a, GBR GBR+disp */ static bool -sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +sh_legitimate_address_p (machine_mode mode, rtx x, bool strict) { + if (! ALLOW_INDEXED_ADDRESS + && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) + return false; + if (REG_P (x) && REGNO (x) == GBR_REG) return true; @@ -10216,8 +10318,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) && ! TARGET_SHMEDIA && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) return true; - else if (GET_CODE (x) == PLUS - && (mode != PSImode || reload_completed)) + else if (GET_CODE (x) == PLUS) { rtx xop0 = XEXP (x, 0); rtx xop1 = XEXP (x, 1); @@ -10304,7 +10405,7 @@ nonpic_symbol_mentioned_p (rtx x) /* Convert a non-PIC address in `orig' to a PIC address using @GOT or @GOTOFF in `reg'. */ rtx -legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, +legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED, rtx reg) { if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE) @@ -10356,7 +10457,7 @@ struct disp_adjust }; static struct disp_adjust -sh_find_mov_disp_adjust (enum machine_mode mode, HOST_WIDE_INT offset) +sh_find_mov_disp_adjust (machine_mode mode, HOST_WIDE_INT offset) { struct disp_adjust res = { NULL_RTX, NULL_RTX }; @@ -10395,7 +10496,7 @@ sh_find_mov_disp_adjust (enum machine_mode mode, HOST_WIDE_INT offset) If we find one, return the new, valid address. Otherwise, return the original address. */ static rtx -sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) +sh_legitimize_address (rtx x, rtx oldx, machine_mode mode) { if (flag_pic) x = legitimize_pic_address (oldx, mode, NULL_RTX); @@ -10421,7 +10522,6 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) return gen_rtx_PLUS (Pmode, sum, adj.mov_disp); } } - return x; } @@ -10430,18 +10530,42 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) Like for sh_legitimize_address, for the SH we try to get a normal form of the address. That will allow inheritance of the address reloads. */ bool -sh_legitimize_reload_address (rtx *p, enum machine_mode mode, int opnum, +sh_legitimize_reload_address (rtx *p, machine_mode mode, int opnum, int itype) { enum reload_type type = (enum reload_type) itype; const int mode_sz = GET_MODE_SIZE (mode); + if (sh_lra_p ()) + return false; + + if (! ALLOW_INDEXED_ADDRESS + && GET_CODE (*p) == PLUS + && REG_P (XEXP (*p, 0)) && REG_P (XEXP (*p, 1))) + { + *p = copy_rtx (*p); + push_reload (*p, NULL_RTX, p, NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + return true; + } + + if (! ALLOW_INDEXED_ADDRESS + && GET_CODE (*p) == PLUS + && GET_CODE (XEXP (*p, 0)) == PLUS) + { + rtx sum = gen_rtx_PLUS (Pmode, XEXP (XEXP (*p, 0), 0), + XEXP (XEXP (*p, 0), 1)); + *p = gen_rtx_PLUS (Pmode, sum, XEXP (*p, 1)); + push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + return true; + } + if (TARGET_SHMEDIA) return false; if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1)) && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true) - && ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS) && (ALLOW_INDEXED_ADDRESS || XEXP (*p, 0) == stack_pointer_rtx || XEXP (*p, 0) == hard_frame_pointer_rtx)) @@ -10556,7 +10680,8 @@ sh_delegitimize_address (rtx orig_x) static rtx mark_constant_pool_use (rtx x) { - rtx insn, lab, pattern; + rtx_insn *insn, *lab; + rtx pattern; if (x == NULL_RTX) return x; @@ -10573,8 +10698,8 @@ mark_constant_pool_use (rtx x) /* Get the first label in the list of labels for the same constant and delete another labels in the list. */ - lab = x; - for (insn = PREV_INSN (x); insn; insn = PREV_INSN (insn)) + lab = as_a <rtx_insn *> (x); + for (insn = PREV_INSN (lab); insn; insn = PREV_INSN (insn)) { if (!LABEL_P (insn) || LABEL_REFS (insn) != NEXT_INSN (insn)) @@ -10582,11 +10707,11 @@ mark_constant_pool_use (rtx x) lab = insn; } - for (insn = LABEL_REFS (lab); insn; insn = LABEL_REFS (insn)) - INSN_DELETED_P (insn) = 1; + for (rtx insn = LABEL_REFS (lab); insn; insn = LABEL_REFS (insn)) + as_a<rtx_insn *> (insn)->set_deleted (); /* Mark constants in a window. */ - for (insn = NEXT_INSN (x); insn; insn = NEXT_INSN (insn)) + for (insn = NEXT_INSN (as_a <rtx_insn *> (x)); insn; insn = NEXT_INSN (insn)) { if (!NONJUMP_INSN_P (insn)) continue; @@ -10620,12 +10745,12 @@ mark_constant_pool_use (rtx x) of an unconditional jump BRANCH2. We only want to do this if the resulting branch will have a short displacement. */ bool -sh_can_redirect_branch (rtx branch1, rtx branch2) +sh_can_redirect_branch (rtx_insn *branch1, rtx_insn *branch2) { if (flag_expensive_optimizations && simplejump_p (branch2)) { rtx dest = XEXP (SET_SRC (single_set (branch2)), 0); - rtx insn; + rtx_insn *insn; int distance; for (distance = 0, insn = NEXT_INSN (branch1); @@ -10672,7 +10797,8 @@ sh_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, the same cost as a data-dependence. The return value should be the new value for COST. */ static int -sh_adjust_cost (rtx insn, rtx link ATTRIBUTE_UNUSED, rtx dep_insn, int cost) +sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED, + rtx_insn *dep_insn, int cost) { rtx reg, use_pat; @@ -10935,7 +11061,7 @@ sh_issue_rate (void) /* Get weight for mode for a set x. */ static short -find_set_regmode_weight (rtx x, enum machine_mode mode) +find_set_regmode_weight (rtx x, machine_mode mode) { if (GET_CODE (x) == CLOBBER && register_operand (SET_DEST (x), mode)) return 1; @@ -10955,7 +11081,7 @@ find_set_regmode_weight (rtx x, enum machine_mode mode) /* Get regmode weight for insn. */ static short -find_insn_regmode_weight (rtx insn, enum machine_mode mode) +find_insn_regmode_weight (rtx insn, machine_mode mode) { short reg_weight = 0; rtx x; @@ -10987,9 +11113,9 @@ find_insn_regmode_weight (rtx insn, enum machine_mode mode) /* Calculate regmode weights for all insns of a basic block. */ static void -find_regmode_weight (basic_block b, enum machine_mode mode) +find_regmode_weight (basic_block b, machine_mode mode) { - rtx insn, next_tail, head, tail; + rtx_insn *insn, *next_tail, *head, *tail; get_ebb_head_tail (b, b, &head, &tail); next_tail = NEXT_INSN (tail); @@ -11015,8 +11141,8 @@ find_regmode_weight (basic_block b, enum machine_mode mode) static int rank_for_reorder (const void *x, const void *y) { - rtx tmp = *(const rtx *) y; - rtx tmp2 = *(const rtx *) x; + rtx_insn *tmp = *(rtx_insn * const *) y; + rtx_insn *tmp2 = *(rtx_insn * const *) x; /* The insn in a schedule group should be issued the first. */ if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2)) @@ -11030,9 +11156,9 @@ rank_for_reorder (const void *x, const void *y) /* Resort the array A in which only element at index N may be out of order. */ static void -swap_reorder (rtx *a, int n) +swap_reorder (rtx_insn **a, int n) { - rtx insn = a[n - 1]; + rtx_insn *insn = a[n - 1]; int i = n - 2; while (i >= 0 && rank_for_reorder (a + i, &insn) >= 0) @@ -11045,19 +11171,19 @@ swap_reorder (rtx *a, int n) /* Sort the ready list by ascending priority. */ static void -ready_reorder (rtx *ready, int nready) +ready_reorder (rtx_insn **ready, int nready) { if (nready == 2) swap_reorder (ready, nready); else if (nready > 2) - qsort (ready, nready, sizeof (rtx), rank_for_reorder); + qsort (ready, nready, sizeof (rtx_insn *), rank_for_reorder); } /* Count life regions of r0 for a block. */ static int find_r0_life_regions (basic_block b) { - rtx end, insn; + rtx_insn *end, *insn; rtx pset; rtx r0_reg; int live; @@ -11147,7 +11273,7 @@ sh_md_finish_global (FILE *dump ATTRIBUTE_UNUSED, /* The scalar modes supported differs from the default version in TImode for 32-bit SHMEDIA. */ static bool -sh_scalar_mode_supported_p (enum machine_mode mode) +sh_scalar_mode_supported_p (machine_mode mode) { if (TARGET_SHMEDIA32 && mode == TImode) return false; @@ -11160,7 +11286,7 @@ sh_scalar_mode_supported_p (enum machine_mode mode) static int sh_variable_issue (FILE *dump ATTRIBUTE_UNUSED, int sched_verbose ATTRIBUTE_UNUSED, - rtx insn, + rtx_insn *insn, int can_issue_more) { if (GET_CODE (PATTERN (insn)) != USE @@ -11197,7 +11323,7 @@ sh_md_init (FILE *dump ATTRIBUTE_UNUSED, /* Return true if the pressure is high for MODE. */ static bool -high_pressure (enum machine_mode mode) +high_pressure (machine_mode mode) { /* Pressure on register r0 can lead to spill failures. so avoid sched1 for functions that already have high pressure on r0. */ @@ -11214,7 +11340,7 @@ high_pressure (enum machine_mode mode) static int sh_reorder (FILE *dump ATTRIBUTE_UNUSED, int sched_verbose ATTRIBUTE_UNUSED, - rtx *ready, + rtx_insn **ready, int *n_readyp, int clock_var ATTRIBUTE_UNUSED) { @@ -11233,7 +11359,7 @@ sh_reorder (FILE *dump ATTRIBUTE_UNUSED, static int sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED, int sched_verbose ATTRIBUTE_UNUSED, - rtx *ready ATTRIBUTE_UNUSED, + rtx_insn **ready ATTRIBUTE_UNUSED, int *n_readyp ATTRIBUTE_UNUSED, int clock_var ATTRIBUTE_UNUSED) { @@ -11257,7 +11383,7 @@ sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED, static int sh_dfa_new_cycle (FILE *sched_dump ATTRIBUTE_UNUSED, int sched_verbose ATTRIBUTE_UNUSED, - rtx insn ATTRIBUTE_UNUSED, + rtx_insn *insn ATTRIBUTE_UNUSED, int last_clock_var, int clock_var, int *sort_p) @@ -11475,7 +11601,7 @@ sh_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt) if (TARGET_HARD_SH4 || TARGET_SH5) { if (!TARGET_INLINE_IC_INVALIDATE - || (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE)) + || (!(TARGET_SH4A || TARGET_SH4_300) && TARGET_USERMODE)) emit_library_call (function_symbol (NULL, "__ic_invalidate", FUNCTION_ORDINARY), LCT_NORMAL, VOIDmode, 1, tramp, SImode); @@ -11530,13 +11656,12 @@ shmedia_builtin_p (void) } /* This function can be used if there are any built-ins that are not for - SHmedia. It's commented out to avoid the defined-but-unused warning. + SHmedia. It's commented out to avoid the defined-but-unused warning. */ static bool sh1_builtin_p (void) { return TARGET_SH1; } -*/ /* describe number and signedness of arguments; arg[0] == result (1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */ @@ -11597,6 +11722,10 @@ static const char signature_args[][4] = { 0, 8 }, #define SH_BLTIN_VP 24 { 8, 0 }, +#define SH_BLTIN_UV 25 + { 1, 0 }, +#define SH_BLTIN_VU 26 + { 0, 1 }, }; /* mcmv: operands considered unsigned. */ /* mmulsum_wq, msad_ubq: result considered unsigned long long. */ @@ -11772,8 +11901,16 @@ static struct builtin_description bdesc[] = CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 }, { shmedia_builtin_p, CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 }, + + { sh1_builtin_p, + CODE_FOR_sts_fpscr, "__builtin_sh_get_fpscr", SH_BLTIN_UV, 0 }, + { sh1_builtin_p, + CODE_FOR_set_fpscr, "__builtin_sh_set_fpscr", SH_BLTIN_VU, 0 }, }; +static tree sh_builtin_get_fpscr; +static tree sh_builtin_set_fpscr; + static void sh_init_builtins (void) { @@ -11832,12 +11969,87 @@ sh_init_builtins (void) d->fndecl = add_builtin_function (d->name, type, d - bdesc, BUILT_IN_MD, NULL, NULL_TREE); + /* Recode {sts,set}_fpscr decls for sh_atomic_assign_expand_fenv. */ + if (d->icode == CODE_FOR_sts_fpscr) + sh_builtin_get_fpscr = d->fndecl; + else if (d->icode == CODE_FOR_set_fpscr) + sh_builtin_set_fpscr = d->fndecl; } } +/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */ + +static void +sh_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) +{ + const unsigned SH_FE_INVALID = 64; + const unsigned SH_FE_DIVBYZERO = 32; + const unsigned SH_FE_OVERFLOW = 16; + const unsigned SH_FE_UNDERFLOW = 8; + const unsigned SH_FE_INEXACT = 4; + const unsigned HOST_WIDE_INT SH_FE_ALL_EXCEPT = (SH_FE_INVALID + | SH_FE_DIVBYZERO + | SH_FE_OVERFLOW + | SH_FE_UNDERFLOW + | SH_FE_INEXACT); + const unsigned HOST_WIDE_INT SH_FE_EXCEPT_SHIFT = 5; + tree fenv_var, mask, ld_fenv, masked_fenv; + tree new_fenv_var, reload_fenv, restore_fnenv; + tree update_call, atomic_feraiseexcept, hold_fnclex; + + if (! TARGET_FPU_ANY) + return; + + /* Generate the equivalent of : + unsigned int fenv_var; + fenv_var = __builtin_sh_get_fpscr (); + + unsigned int masked_fenv; + masked_fenv = fenv_var & mask; + + __builtin_sh_set_fpscr (masked_fenv); */ + + fenv_var = create_tmp_var (unsigned_type_node); + mask = build_int_cst (unsigned_type_node, + ~((SH_FE_ALL_EXCEPT << SH_FE_EXCEPT_SHIFT) + | SH_FE_ALL_EXCEPT)); + ld_fenv = build2 (MODIFY_EXPR, unsigned_type_node, + fenv_var, build_call_expr (sh_builtin_get_fpscr, 0)); + masked_fenv = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_var, mask); + hold_fnclex = build_call_expr (sh_builtin_set_fpscr, 1, masked_fenv); + *hold = build2 (COMPOUND_EXPR, void_type_node, + build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv), + hold_fnclex); + + /* Store the value of masked_fenv to clear the exceptions: + __builtin_sh_set_fpscr (masked_fenv); */ + + *clear = build_call_expr (sh_builtin_set_fpscr, 1, masked_fenv); + + /* Generate the equivalent of : + unsigned int new_fenv_var; + new_fenv_var = __builtin_sh_get_fpscr (); + + __builtin_sh_set_fpscr (fenv_var); + + __atomic_feraiseexcept (new_fenv_var); */ + + new_fenv_var = create_tmp_var (unsigned_type_node); + reload_fenv = build2 (MODIFY_EXPR, unsigned_type_node, new_fenv_var, + build_call_expr (sh_builtin_get_fpscr, 0)); + restore_fnenv = build_call_expr (sh_builtin_set_fpscr, 1, fenv_var); + atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); + update_call = build_call_expr (atomic_feraiseexcept, 1, + fold_convert (integer_type_node, + new_fenv_var)); + *update = build2 (COMPOUND_EXPR, void_type_node, + build2 (COMPOUND_EXPR, void_type_node, + reload_fenv, restore_fnenv), update_call); +} + /* Implements target hook vector_mode_supported_p. */ bool -sh_vector_mode_supported_p (enum machine_mode mode) +sh_vector_mode_supported_p (machine_mode mode) { if (TARGET_FPU_ANY && ((mode == V2SFmode) @@ -11900,7 +12112,7 @@ sh_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) IGNORE is nonzero if the value is to be ignored. */ static rtx sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, int ignore) + machine_mode mode ATTRIBUTE_UNUSED, int ignore) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); unsigned int fcode = DECL_FUNCTION_CODE (fndecl); @@ -11915,7 +12127,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, if (ignore) return NULL_RTX; - enum machine_mode tmode = insn_data[icode].operand[0].mode; + machine_mode tmode = insn_data[icode].operand[0].mode; if (! target || GET_MODE (target) != tmode || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); @@ -11927,7 +12139,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, for (int i = 1; i <= 3; i++, nop++) { tree arg; - enum machine_mode opmode, argmode; + machine_mode opmode, argmode; tree optype; if (! signature_args[signature][i]) @@ -12015,7 +12227,7 @@ sh_expand_binop_v2sf (enum rtx_code code, rtx op0, rtx op1, rtx op2) We want to allow TImode FP regs so that when V4SFmode is loaded as TImode, it won't be ferried through GP registers first. */ bool -sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) +sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode) { if (SPECIAL_REGISTER_P (regno)) return mode == SImode; @@ -12085,7 +12297,7 @@ sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) return mode == SImode; if (regno == FPSCR_REG) - return mode == PSImode; + return mode == SImode; /* FIXME. This works around PR target/37633 for -O0. */ if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4) @@ -12100,10 +12312,30 @@ sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) return true; } +/* Specify the modes required to caller save a given hard regno. + choose_hard_reg_mode chooses mode based on HARD_REGNO_MODE_OK + and returns ?Imode for float regs when sh_hard_regno_mode_ok + permits integer modes on them. That makes LRA's split process + unhappy. See PR55212. + */ +machine_mode +sh_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs, + machine_mode mode) +{ + if (FP_REGISTER_P (regno) + && (mode == SFmode + || mode == SCmode + || ((mode == DFmode || mode == DCmode) + && ((regno - FIRST_FP_REG) & 1) == 0))) + return mode; + + return choose_hard_reg_mode (regno, nregs, false); +} + /* Return the class of registers for which a mode change from FROM to TO is invalid. */ bool -sh_cannot_change_mode_class (enum machine_mode from, enum machine_mode to, +sh_cannot_change_mode_class (machine_mode from, machine_mode to, enum reg_class rclass) { /* We want to enable the use of SUBREGs as a means to @@ -12135,7 +12367,7 @@ sh_cannot_change_mode_class (enum machine_mode from, enum machine_mode to, /* Return true if registers in machine mode MODE will likely be allocated to registers in small register classes. */ bool -sh_small_register_classes_for_mode_p (enum machine_mode mode ATTRIBUTE_UNUSED) +sh_small_register_classes_for_mode_p (machine_mode mode ATTRIBUTE_UNUSED) { return (! TARGET_SHMEDIA); } @@ -12165,7 +12397,7 @@ sh_mark_label (rtx address, int nuses) uses this information. Hence, the general register <-> floating point register information here is not used for SFmode. */ static int -sh_register_move_cost (enum machine_mode mode, +sh_register_move_cost (machine_mode mode, reg_class_t srcclass, reg_class_t dstclass) { if (dstclass == T_REGS || dstclass == PR_REGS) @@ -12256,7 +12488,8 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, { CUMULATIVE_ARGS cum; int structure_value_byref = 0; - rtx this_rtx, this_value, sibcall, insns, funexp; + rtx this_rtx, this_value, sibcall, funexp; + rtx_insn *insns; tree funtype = TREE_TYPE (function); int simple_add = CONST_OK_FOR_ADD (delta); int did_load = 0; @@ -12588,7 +12821,7 @@ extract_sfunc_addr (rtx insn) INSN is the use_sfunc_addr instruction, and REG is the register it guards. */ bool -check_use_sfunc_addr (rtx insn, rtx reg) +check_use_sfunc_addr (rtx_insn *insn, rtx reg) { /* Search for the sfunc. It should really come right after INSN. */ while ((insn = NEXT_INSN (insn))) @@ -12598,8 +12831,8 @@ check_use_sfunc_addr (rtx insn, rtx reg) if (! INSN_P (insn)) continue; - if (GET_CODE (PATTERN (insn)) == SEQUENCE) - insn = XVECEXP (PATTERN (insn), 0, 0); + if (rtx_sequence *seq = dyn_cast<rtx_sequence *> (PATTERN (insn))) + insn = seq->insn (0); if (GET_CODE (PATTERN (insn)) != PARALLEL || get_attr_type (insn) != TYPE_SFUNC) continue; @@ -12654,7 +12887,7 @@ sh_init_cumulative_args (CUMULATIVE_ARGS * pcum, rtx libname ATTRIBUTE_UNUSED, tree fndecl, signed int n_named_args, - enum machine_mode mode) + machine_mode mode) { pcum->arg_count [(int) SH_ARG_FLOAT] = 0; pcum->free_single_fp_reg = 0; @@ -12858,14 +13091,14 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) } rtx -sh_gen_truncate (enum machine_mode mode, rtx x, int need_sign_ext) +sh_gen_truncate (machine_mode mode, rtx x, int need_sign_ext) { enum rtx_code code = TRUNCATE; if (GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) { rtx inner = XEXP (x, 0); - enum machine_mode inner_mode = GET_MODE (inner); + machine_mode inner_mode = GET_MODE (inner); if (inner_mode == mode) return inner; @@ -12881,25 +13114,30 @@ sh_gen_truncate (enum machine_mode mode, rtx x, int need_sign_ext) return gen_rtx_fmt_e (code, mode, x); } -/* Called via for_each_rtx after reload, to clean up truncates of - registers that span multiple actual hard registers. */ +/* Look through X cleaning up truncates of registers that span multiple + actual hard registers. Return the number of changes made. */ int -shmedia_cleanup_truncate (rtx *p, void *n_changes) +shmedia_cleanup_truncate (rtx x) { - rtx x = *p, reg; - - if (GET_CODE (x) != TRUNCATE) - return 0; - reg = XEXP (x, 0); - if (GET_MODE_SIZE (GET_MODE (reg)) > 8 && REG_P (reg)) + int n_changes = 0; + subrtx_var_iterator::array_type array; + FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST) { - enum machine_mode reg_mode = GET_MODE (reg); - XEXP (x, 0) = simplify_subreg (DImode, reg, reg_mode, - subreg_lowpart_offset (DImode, reg_mode)); - *(int*) n_changes += 1; - return -1; + rtx x = *iter; + if (GET_CODE (x) == TRUNCATE) + { + rtx reg = XEXP (x, 0); + machine_mode reg_mode = GET_MODE (reg); + if (REG_P (reg) && GET_MODE_SIZE (reg_mode) > 8) + { + int offset = subreg_lowpart_offset (DImode, reg_mode); + XEXP (x, 0) = simplify_subreg (DImode, reg, reg_mode, offset); + n_changes += 1; + iter.skip_subrtxes (); + } + } } - return 0; + return n_changes; } /* Load and store depend on the highpart of the address. However, @@ -12907,18 +13145,15 @@ shmedia_cleanup_truncate (rtx *p, void *n_changes) so we must look at the rtl ourselves to see if any of the feeding registers is used in a memref. - Called by sh_contains_memref_p via for_each_rtx. */ -static int -sh_contains_memref_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED) -{ - return (MEM_P (*loc)); -} - -/* Return true iff INSN contains a MEM. */ + Return true iff INSN contains a MEM. */ bool sh_contains_memref_p (rtx insn) { - return for_each_rtx (&PATTERN (insn), &sh_contains_memref_p_1, NULL); + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST) + if (MEM_P (*iter)) + return true; + return false; } /* Return true iff INSN loads a banked register. */ @@ -13000,7 +13235,7 @@ sh_preferred_reload_class (rtx x, reg_class_t rclass) /* Implement TARGET_SECONDARY_RELOAD. */ static reg_class_t sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, - enum machine_mode mode, secondary_reload_info *sri) + machine_mode mode, secondary_reload_info *sri) { enum reg_class rclass = (enum reg_class) rclass_i; @@ -13020,8 +13255,7 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, if (REGCLASS_HAS_FP_REG (rclass) && ! TARGET_SHMEDIA && immediate_operand ((x), mode) - && ! ((fp_zero_operand (x) || fp_one_operand (x)) - && mode == SFmode && fldi_ok ())) + && ! ((fp_zero_operand (x) || fp_one_operand (x)) && mode == SFmode)) switch (mode) { case SFmode: @@ -13095,7 +13329,7 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, { if (rclass == FPUL_REGS) return GENERAL_REGS; - return FPUL_REGS; + return NO_REGS; // LRA wants NO_REGS here, it used to be FPUL_REGS; } if ((rclass == TARGET_REGS || (TARGET_SHMEDIA && rclass == SIBCALL_REGS)) @@ -13142,6 +13376,76 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, return NO_REGS; } +/* Return true if SUBST can't safely replace its equivalent during RA. */ +static bool +sh_cannot_substitute_mem_equiv_p (rtx) +{ + if (TARGET_SHMEDIA) + return false; + + /* If SUBST is mem[base+index] or QI/HImode mem[base+disp], the insn + uses R0 and may cause spill failure when R0 is already used. + We have to return true for that case at least. + Moreover SH has strong R0 parity and also have not enough numbers of + the hard registers to make the equiv substitution win in the size + and the speed on average working sets. The pseudos produced to + hold the equiv values can't get good hard registers for bad cases + and end up memory save/restore insns which make the code worse. */ + return true; +} + +/* Return true if DISP can be legitimized. */ +static bool +sh_legitimize_address_displacement (rtx *disp, rtx *offs, + machine_mode mode) +{ + if (TARGET_SHMEDIA) + return false; + + if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) + || (TARGET_SH2E && mode == SFmode)) + return false; + + struct disp_adjust adj = sh_find_mov_disp_adjust (mode, INTVAL (*disp)); + if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) + { + *disp = adj.mov_disp; + *offs = adj.offset_adjust; + return true; + } + + return false; +} + +/* Return true if movsf insn should be splited with an additional + register. */ +bool +sh_movsf_ie_ra_split_p (rtx op0, rtx op1, rtx op2) +{ + /* op0 == op1 */ + if (rtx_equal_p (op0, op1)) + return true; + /* fy, FQ, reg */ + if (GET_CODE (op1) == CONST_DOUBLE + && ! satisfies_constraint_G (op1) + && ! satisfies_constraint_H (op1) + && REG_P (op0) + && REG_P (op2)) + return true; + /* f, r, y */ + if (REG_P (op0) && FP_REGISTER_P (REGNO (op0)) + && REG_P (op1) && GENERAL_REGISTER_P (REGNO (op1)) + && REG_P (op2) && (REGNO (op2) == FPUL_REG)) + return true; + /* r, f, y */ + if (REG_P (op1) && FP_REGISTER_P (REGNO (op1)) + && REG_P (op0) && GENERAL_REGISTER_P (REGNO (op0)) + && REG_P (op2) && (REGNO (op2) == FPUL_REG)) + return true; + + return false; +} + static void sh_conditional_register_usage (void) { @@ -13185,13 +13489,16 @@ sh_conditional_register_usage (void) for (regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++) if (! fixed_regs[regno] && call_really_used_regs[regno]) SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno); + + call_really_used_regs[FPSCR_MODES_REG] = 0; + call_really_used_regs[FPSCR_STAT_REG] = 0; } /* Implement TARGET_LEGITIMATE_CONSTANT_P can_store_by_pieces constructs VOIDmode CONST_DOUBLEs. */ static bool -sh_legitimate_constant_p (enum machine_mode mode, rtx x) +sh_legitimate_constant_p (machine_mode mode, rtx x) { return (TARGET_SHMEDIA ? ((mode != DFmode && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) @@ -13298,11 +13605,10 @@ base_reg_disp::disp (void) const } /* Find the base register and calculate the displacement for a given - address rtx 'x'. - This is done by walking the insn list backwards and following SET insns - that set the value of the specified reg 'x'. */ + address rtx 'x'. */ static base_reg_disp -sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL) +sh_find_base_reg_disp (rtx_insn* insn, rtx x, disp_t disp = 0, + rtx base_reg = NULL) { if (REG_P (x)) { @@ -13316,31 +13622,37 @@ sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL) if (REGNO (x) < FIRST_PSEUDO_REGISTER) return base_reg_disp (base_reg != NULL ? base_reg : x, disp); - /* Try to find the previous insn that sets the reg. */ - for (rtx i = prev_nonnote_insn (insn); i != NULL; - i = prev_nonnote_insn (i)) + /* Find the def of the reg and trace it. If there are more than one + defs and they are not the same, assume it's not safe to proceed. */ + rtx_insn* last_i = NULL; + rtx last_set = NULL; + for (df_ref d = DF_REG_DEF_CHAIN (REGNO (x)); d != NULL; + d = DF_REF_NEXT_REG (d)) { - if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG) - && CALL_P (i)) - break; + rtx set = const_cast<rtx> (set_of (x, DF_REF_INSN (d))); - if (!NONJUMP_INSN_P (i)) - continue; - - rtx p = PATTERN (i); - if (p != NULL && GET_CODE (p) == SET && REG_P (XEXP (p, 0)) - && REGNO (XEXP (p, 0)) == REGNO (x)) + /* Accept multiple defs, as long as they are equal. */ + if (last_set == NULL || rtx_equal_p (last_set, set)) { - /* If the recursion can't find out any more details about the - source of the set, then this reg becomes our new base reg. */ - return sh_find_base_reg_disp (i, XEXP (p, 1), disp, XEXP (p, 0)); + last_i = DF_REF_INSN (d); + last_set = set; + } + else + { + last_i = NULL; + last_set = NULL; + break; } } - /* When here, no previous insn was found that sets the reg. - The input reg is already the base reg. */ - return base_reg_disp (x, disp); - } + if (last_set != NULL && last_i != NULL) + return sh_find_base_reg_disp (last_i, XEXP (last_set, 1), disp, + XEXP (last_set, 0)); + + /* When here, no previous insn was found that sets the reg. + The input reg is already the base reg. */ + return base_reg_disp (x, disp); + } else if (GET_CODE (x) == PLUS) { @@ -13370,19 +13682,47 @@ sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL) based memory address and return the corresponding new memory address. Return NULL_RTX if not found. */ rtx -sh_find_equiv_gbr_addr (rtx insn, rtx mem) +sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem) { - if (!MEM_P (mem)) + if (!MEM_P (mem) || gbr_address_mem (mem, GET_MODE (mem))) return NULL_RTX; /* Leave post/pre inc/dec or any other side effect addresses alone. */ if (side_effects_p (XEXP (mem, 0))) return NULL_RTX; + /* When not optimizing there might be no dataflow available. */ + if (df == NULL) + return NULL_RTX; + base_reg_disp gbr_disp = sh_find_base_reg_disp (insn, XEXP (mem, 0)); if (gbr_disp.is_reg () && REGNO (gbr_disp.reg ()) == GBR_REG) { + /* If GBR is marked as call clobbered we bail out if we see a call. + FIXME: Actually should check if this mem refers to the gbr value + before or after the call. If there is a store_gbr preceeding this + mem, it's safe to use GBR for this mem. + + If GBR is not marked as call clobbered, but there is some other + def than a call, it's probably a load_gbr upon which we also + bail out to be on the safe side. + FIXME: Should check if we have a use-after-def case, such as + the call case above. */ + for (df_ref d = DF_REG_DEF_CHAIN (GBR_REG); d != NULL; + d = DF_REF_NEXT_REG (d)) + { + if (CALL_P (DF_REF_INSN (d))) + { + if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG)) + return NULL_RTX; + else + continue; + } + else + return NULL_RTX; + } + rtx disp = GEN_INT (gbr_disp.disp ()); if (gbr_displacement (disp, GET_MODE (mem))) return gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, GBR_REG), disp); @@ -13395,47 +13735,56 @@ sh_find_equiv_gbr_addr (rtx insn, rtx mem) Manual insn combine support code. */ -/* Given a reg rtx and a start insn, try to find the insn that sets the - specified reg by using the specified insn stepping function, such as - 'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx - of the reg set. */ -set_of_reg -sh_find_set_of_reg (rtx reg, rtx insn, rtx(*stepfunc)(rtx)) +/* Return true if the specified insn contains any UNSPECs or + UNSPEC_VOLATILEs. */ +static bool +sh_unspec_insn_p (rtx x) { - set_of_reg result; - result.insn = insn; - result.set_rtx = NULL_RTX; - result.set_src = NULL_RTX; + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (i, array, x, ALL) + if (*i != NULL + && (GET_CODE (*i) == UNSPEC || GET_CODE (*i) == UNSPEC_VOLATILE)) + return true; - if (!REG_P (reg) || insn == NULL_RTX) - return result; + return false; +} - for (result.insn = stepfunc (insn); result.insn != NULL_RTX; - result.insn = stepfunc (result.insn)) - { - if (BARRIER_P (result.insn)) - return result; - if (!NONJUMP_INSN_P (result.insn)) - continue; - if (reg_set_p (reg, result.insn)) - { - result.set_rtx = set_of (reg, result.insn); +/* Return true if the register operands of the specified insn are modified + between the specified from and to insns (exclusive of those two). */ +static bool +sh_insn_operands_modified_between_p (rtx_insn* operands_insn, + const rtx_insn* from, + const rtx_insn* to) +{ + /* FIXME: Return true for multiple sets for now. */ + rtx s = single_set (operands_insn); + if (s == NULL_RTX) + return true; - if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET) - return result; + subrtx_iterator::array_type array; + FOR_EACH_SUBRTX (i, array, SET_SRC (s), ALL) + if (*i != NULL && + ((REG_P (*i) || SUBREG_P (*i)) && reg_set_between_p (*i, from, to))) + return true; - result.set_src = XEXP (result.set_rtx, 1); - return result; - } - } + return false; +} - return result; +/* Given an insn and a reg number, remove reg dead or reg unused notes to + mark it as being used after the insn. */ +void +sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno) +{ + if (rtx n = find_regno_note (i, REG_DEAD, regno)) + remove_note (i, n); + if (rtx n = find_regno_note (i, REG_UNUSED, regno)) + remove_note (i, n); } /* Given an op rtx and an insn, try to find out whether the result of the specified op consists only of logical operations on T bit stores. */ bool -sh_is_logical_t_store_expr (rtx op, rtx insn) +sh_is_logical_t_store_expr (rtx op, rtx_insn* insn) { if (!logical_operator (op, SImode)) return false; @@ -13471,7 +13820,7 @@ sh_is_logical_t_store_expr (rtx op, rtx insn) by a simple reg-reg copy. If so, the replacement reg rtx is returned, NULL_RTX otherwise. */ rtx -sh_try_omit_signzero_extend (rtx extended_op, rtx insn) +sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn) { if (REG_P (extended_op)) extended_op = extended_op; @@ -13501,4 +13850,319 @@ sh_try_omit_signzero_extend (rtx extended_op, rtx insn) return NULL_RTX; } +/* Given the current insn, which is assumed to be a movrt_negc insn, try to + figure out whether it should be converted into a movt-xor sequence in + the movrt_negc splitter. + Returns true if insns have been modified and the splitter has succeeded. */ +bool +sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[]) +{ + /* In cases such as + tst r4,r4 + mov #-1,r1 + negc r1,r1 + tst r4,r4 + we can replace the T bit clobbering negc with a movt-xor sequence and + eliminate the redundant comparison. + Because the xor insn depends on register allocation results, allow this + only before reload. */ + if (!can_create_pseudo_p ()) + return false; + + set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn, + prev_nonnote_insn_bb); + set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn, + next_nonnote_insn_bb); + + if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX + && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx) + && !reg_used_between_p (get_t_reg_rtx (), curr_insn, t_after_negc.insn) + && !sh_insn_operands_modified_between_p (t_before_negc.insn, + t_before_negc.insn, + t_after_negc.insn) + && !sh_unspec_insn_p (t_after_negc.insn) + && !volatile_insn_p (PATTERN (t_after_negc.insn)) + && !side_effects_p (PATTERN (t_after_negc.insn)) + && !may_trap_or_fault_p (PATTERN (t_after_negc.insn))) + { + emit_insn (gen_movrt_xor (operands[0], get_t_reg_rtx ())); + set_insn_deleted (t_after_negc.insn); + return true; + } + else + return false; +} + +/* Given a reg and the current insn, see if the value of the reg originated + from a sign or zero extension and return the discovered information. */ +sh_extending_set_of_reg +sh_find_extending_set_of_reg (rtx reg, rtx_insn* curr_insn) +{ + if (reg == NULL) + return sh_extending_set_of_reg (curr_insn); + + if (SUBREG_P (reg)) + reg = SUBREG_REG (reg); + + if (!REG_P (reg)) + return sh_extending_set_of_reg (curr_insn); + + /* FIXME: Also search the predecessor basic blocks. It seems that checking + only the adjacent predecessor blocks would cover most of the cases. + Also try to look through the first extension that we hit. There are some + cases, where a zero_extend is followed an (implicit) sign_extend, and it + fails to see the sign_extend. */ + sh_extending_set_of_reg result = + sh_find_set_of_reg (reg, curr_insn, prev_nonnote_insn_bb, true); + + if (result.set_src != NULL) + { + if (GET_CODE (result.set_src) == SIGN_EXTEND + || GET_CODE (result.set_src) == ZERO_EXTEND) + { + if (dump_file) + fprintf (dump_file, "sh_find_extending_set_of_reg: reg %d is " + "explicitly sign/zero extended in insn %d\n", + REGNO (reg), INSN_UID (result.insn)); + result.from_mode = GET_MODE (XEXP (result.set_src, 0)); + result.ext_code = GET_CODE (result.set_src); + } + else if (MEM_P (result.set_src) + && (GET_MODE (result.set_src) == QImode + || GET_MODE (result.set_src) == HImode) + && !sh_unspec_insn_p (result.insn)) + { + /* On SH QIHImode memory loads always sign extend. However, in + some cases where it seems that the higher bits are not + interesting, the loads will not be expanded as sign extending + insns, but as QIHImode loads into QIHImode regs. We report that + the reg has been sign extended by the mem load. When it is used + as such, we must convert the mem load into a sign extending insn, + see also sh_extending_set_of_reg::use_as_extended_reg. */ + if (dump_file) + fprintf (dump_file, "sh_find_extending_set_of_reg: reg %d is " + "implicitly sign extended in insn %d\n", + REGNO (reg), INSN_UID (result.insn)); + result.from_mode = GET_MODE (result.set_src); + result.ext_code = SIGN_EXTEND; + } + } + + return result; +} + +/* Given a reg that is known to be sign or zero extended at some insn, + take the appropriate measures so that the extended value can be used as + a reg at the specified insn and return the resulting reg rtx. */ +rtx +sh_extending_set_of_reg::use_as_extended_reg (rtx_insn* use_at_insn) const +{ + gcc_assert (insn != NULL && set_src != NULL && set_rtx != NULL); + gcc_assert (ext_code == SIGN_EXTEND || ext_code == ZERO_EXTEND); + gcc_assert (from_mode == QImode || from_mode == HImode); + + if (MEM_P (set_src) && ext_code == SIGN_EXTEND) + { + if (dump_file) + fprintf (dump_file, + "use_as_extended_reg: converting non-extending mem load in " + "insn %d into sign-extending load\n", INSN_UID (insn)); + + rtx r = gen_reg_rtx (SImode); + rtx_insn* i0; + if (from_mode == QImode) + i0 = emit_insn_after (gen_extendqisi2 (r, set_src), insn); + else if (from_mode == HImode) + i0 = emit_insn_after (gen_extendhisi2 (r, set_src), insn); + else + gcc_unreachable (); + + emit_insn_after ( + gen_move_insn (XEXP (set_rtx, 0), + gen_lowpart (GET_MODE (set_src), r)), i0); + set_insn_deleted (insn); + return r; + } + else + { + rtx extension_dst = XEXP (set_rtx, 0); + if (modified_between_p (extension_dst, insn, use_at_insn)) + { + if (dump_file) + fprintf (dump_file, + "use_as_extended_reg: dest reg %d of extending insn %d is " + "modified, inserting a reg-reg copy\n", + REGNO (extension_dst), INSN_UID (insn)); + + rtx r = gen_reg_rtx (SImode); + emit_insn_after (gen_move_insn (r, extension_dst), insn); + return r; + } + else + { + sh_remove_reg_dead_or_unused_notes (insn, REGNO (extension_dst)); + return extension_dst; + } + } +} + +/* Given the current insn, which is assumed to be the *tst<mode>_t_subregs insn, + perform the necessary checks on the operands and split it accordingly. */ +void +sh_split_tst_subregs (rtx_insn* curr_insn, machine_mode subreg_mode, + int subreg_offset, rtx operands[]) +{ + gcc_assert (subreg_mode == QImode || subreg_mode == HImode); + + sh_extending_set_of_reg eop0 = sh_find_extending_set_of_reg (operands[0], + curr_insn); + sh_extending_set_of_reg eop1 = sh_find_extending_set_of_reg (operands[1], + curr_insn); + + /* If one of the operands is known to be zero extended, that's already + sufficient to mask out the unwanted high bits. */ + if (eop0.ext_code == ZERO_EXTEND && eop0.from_mode == subreg_mode) + { + emit_insn (gen_tstsi_t (eop0.use_as_extended_reg (curr_insn), + operands[1])); + return; + } + if (eop1.ext_code == ZERO_EXTEND && eop1.from_mode == subreg_mode) + { + emit_insn (gen_tstsi_t (operands[0], + eop1.use_as_extended_reg (curr_insn))); + return; + } + + /* None of the operands seem to be zero extended. + If both are sign extended it's OK, too. */ + if (eop0.ext_code == SIGN_EXTEND && eop1.ext_code == SIGN_EXTEND + && eop0.from_mode == subreg_mode && eop1.from_mode == subreg_mode) + { + emit_insn (gen_tstsi_t (eop0.use_as_extended_reg (curr_insn), + eop1.use_as_extended_reg (curr_insn))); + return; + } + + /* Otherwise we have to insert a zero extension on one of the operands to + mask out the unwanted high bits. + Prefer the operand that has no known extension. */ + if (eop0.ext_code != UNKNOWN && eop1.ext_code == UNKNOWN) + std::swap (operands[0], operands[1]); + + rtx tmp0 = gen_reg_rtx (SImode); + rtx tmp1 = simplify_gen_subreg (subreg_mode, operands[0], + GET_MODE (operands[0]), subreg_offset); + emit_insn (subreg_mode == QImode + ? gen_zero_extendqisi2 (tmp0, tmp1) + : gen_zero_extendhisi2 (tmp0, tmp1)); + emit_insn (gen_tstsi_t (tmp0, operands[1])); +} + +/*------------------------------------------------------------------------------ + Mode switching support code. +*/ + +static void +sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode, + int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED) +{ + if ((TARGET_SH4A_FP || TARGET_SH4_300) + && prev_mode != FP_MODE_NONE && prev_mode != mode) + { + emit_insn (gen_toggle_pr ()); + if (TARGET_FMOVD) + emit_insn (gen_toggle_sz ()); + } + else if (mode != FP_MODE_NONE) + { + rtx tmp = gen_reg_rtx (SImode); + emit_insn (gen_sts_fpscr (tmp)); + rtx i = NULL; + + const unsigned HOST_WIDE_INT fpbits = + TARGET_FMOVD ? (FPSCR_PR | FPSCR_SZ) : FPSCR_PR; + + if (prev_mode != FP_MODE_NONE && prev_mode != mode) + i = gen_xorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits))); + else if (mode == FP_MODE_SINGLE) + i = gen_andsi3 (tmp, tmp, force_reg (SImode, GEN_INT (~fpbits))); + else if (mode == FP_MODE_DOUBLE) + i = gen_iorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits))); + else + gcc_unreachable (); + + emit_insn (i); + emit_insn (gen_lds_fpscr (tmp)); + } +} + +static int +sh_mode_needed (int entity ATTRIBUTE_UNUSED, rtx_insn *insn) +{ + return recog_memoized (insn) >= 0 ? get_attr_fp_mode (insn) : FP_MODE_NONE; +} + +static int +sh_mode_after (int entity ATTRIBUTE_UNUSED, int mode, rtx_insn *insn) +{ + if (TARGET_HITACHI && recog_memoized (insn) >= 0 && + get_attr_fp_set (insn) != FP_SET_NONE) + return (int) get_attr_fp_set (insn); + else + return mode; +} + +static int +sh_mode_entry (int entity ATTRIBUTE_UNUSED) +{ + return NORMAL_MODE (entity); +} + +static int +sh_mode_exit (int entity ATTRIBUTE_UNUSED) +{ + return sh_cfun_attr_renesas_p () ? FP_MODE_NONE : NORMAL_MODE (entity); +} + +static int +sh_mode_priority (int entity ATTRIBUTE_UNUSED, int n) +{ + return ((TARGET_FPU_SINGLE != 0) ^ (n) ? FP_MODE_SINGLE : FP_MODE_DOUBLE); +} + +/*------------------------------------------------------------------------------ + Misc +*/ + +/* Return true if we use LRA instead of reload pass. */ +static bool +sh_lra_p (void) +{ + return sh_lra_flag; +} + +/* Implement TARGET_USE_BY_PIECES_INFRASTRUCTURE_P. */ + +static bool +sh_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size, + unsigned int align, + enum by_pieces_operation op, + bool speed_p) +{ + switch (op) + { + case MOVE_BY_PIECES: + return move_by_pieces_ninsns (size, align, MOVE_MAX_PIECES + 1) + < (!speed_p ? 2 : (align >= 32) ? 16 : 2); + case STORE_BY_PIECES: + case SET_BY_PIECES: + return move_by_pieces_ninsns (size, align, STORE_MAX_PIECES + 1) + < (!speed_p ? 2 : (align >= 32) ? 16 : 2); + default: + return default_use_by_pieces_infrastructure_p (size, align, + op, speed_p); + } +} + #include "gt-sh.h" diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 8819300116e..2de7381bd26 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler for Renesas / SuperH SH. - Copyright (C) 1993-2014 Free Software Foundation, Inc. + Copyright (C) 1993-2015 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -70,13 +70,9 @@ extern int code_for_indirect_jump_scratch; #undef TARGET_SH4 #define TARGET_SH4 ((target_flags & MASK_SH4) != 0 && TARGET_SH1) -/* Nonzero if we're generating code for the common subset of - instructions present on both SH4a and SH4al-dsp. */ -#define TARGET_SH4A_ARCH TARGET_SH4A - /* Nonzero if we're generating code for SH4a, unless the use of the FPU is disabled (which makes it compatible with SH4al-dsp). */ -#define TARGET_SH4A_FP (TARGET_SH4A_ARCH && TARGET_FPU_ANY) +#define TARGET_SH4A_FP (TARGET_SH4A && TARGET_FPU_ANY) /* Nonzero if we should generate code using the SHcompact instruction set and 32-bit ABI. */ @@ -267,9 +263,25 @@ extern int code_for_indirect_jump_scratch; #define SUBTARGET_ASM_RELAX_SPEC "%{m4*:-isa=sh4-up}" #endif +/* Define which ISA type to pass to the assembler. + For SH4 we pass SH4A to allow using some instructions that are available + on some SH4 variants, but officially are part of the SH4A ISA. */ #define SH_ASM_SPEC \ "%(subtarget_asm_endian_spec) %{mrelax:-relax %(subtarget_asm_relax_spec)} \ %(subtarget_asm_isa_spec) %(subtarget_asm_spec) \ +%{m1:--isa=sh} \ +%{m2:--isa=sh2} \ +%{m2e:--isa=sh2e} \ +%{m3:--isa=sh3} \ +%{m3e:--isa=sh3e} \ +%{m4:--isa=sh4a} \ +%{m4-single:--isa=sh4a} \ +%{m4-single-only:--isa=sh4a} \ +%{m4-nofpu:--isa=sh4a-nofpu} \ +%{m4a:--isa=sh4a} \ +%{m4a-single:--isa=sh4a} \ +%{m4a-single-only:--isa=sh4a} \ +%{m4a-nofpu:--isa=sh4a-nofpu} \ %{m2a:--isa=sh2a} \ %{m2a-single:--isa=sh2a} \ %{m2a-single-only:--isa=sh2a} \ @@ -562,7 +574,7 @@ extern enum sh_divide_strategy_e sh_div_strategy; fr4..fr11 fp args in fr12..fr15 call saved floating point registers */ -#define MAX_REGISTER_NAME_LENGTH 5 +#define MAX_REGISTER_NAME_LENGTH 6 extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1]; #define SH_REGISTER_NAMES_INITIALIZER \ @@ -586,7 +598,7 @@ extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1]; "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", \ "xd0", "xd2", "xd4", "xd6", "xd8", "xd10", "xd12", "xd14", \ "gbr", "ap", "pr", "t", "mach", "macl", "fpul", "fpscr", \ - "rap", "sfp" \ + "rap", "sfp", "fpscr0", "fpscr1" \ } #define REGNAMES_ARR_INDEX_1(index) \ @@ -611,7 +623,7 @@ extern char sh_register_names[][MAX_REGISTER_NAME_LENGTH + 1]; REGNAMES_ARR_INDEX_8 (128), \ REGNAMES_ARR_INDEX_8 (136), \ REGNAMES_ARR_INDEX_8 (144), \ - REGNAMES_ARR_INDEX_2 (152) \ + REGNAMES_ARR_INDEX_4 (152) \ } #define ADDREGNAMES_SIZE 32 @@ -699,7 +711,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ #define SPECIAL_REGISTER_P(REGNO) \ ((REGNO) == GBR_REG || (REGNO) == T_REG \ - || (REGNO) == MACH_REG || (REGNO) == MACL_REG) + || (REGNO) == MACH_REG || (REGNO) == MACL_REG \ + || (REGNO) == FPSCR_MODES_REG || (REGNO) == FPSCR_STAT_REG) #define TARGET_REGISTER_P(REGNO) \ ((int) (REGNO) >= FIRST_TARGET_REG && (int) (REGNO) <= LAST_TARGET_REG) @@ -726,10 +739,10 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ ? DImode \ : SImode) -#define FIRST_PSEUDO_REGISTER 154 +#define FIRST_PSEUDO_REGISTER 156 /* Don't count soft frame pointer. */ -#define DWARF_FRAME_REGISTERS (FIRST_PSEUDO_REGISTER - 1) +#define DWARF_FRAME_REGISTERS (153) /* 1 for registers that have pervasive standard uses and are not available for the register allocator. @@ -765,8 +778,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ 0, 0, 0, 0, 0, 0, 0, 0, \ /*"gbr", "ap", "pr", "t", "mach", "macl", "fpul", "fpscr", */ \ 1, 1, 1, 1, 1, 1, 0, 1, \ -/*"rap", "sfp" */ \ - 1, 1, \ +/*"rap", "sfp","fpscr0","fpscr1" */ \ + 1, 1, 1, 1, \ } /* 1 for registers not available across function calls. @@ -804,13 +817,46 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ 1, 1, 1, 1, 1, 1, 0, 0, \ /*"gbr", "ap", "pr", "t", "mach", "macl", "fpul", "fpscr", */ \ 1, 1, 1, 1, 1, 1, 1, 1, \ -/*"rap", "sfp" */ \ - 1, 1, \ +/*"rap", "sfp","fpscr0","fpscr1" */ \ + 1, 1, 1, 1, \ } -/* TARGET_CONDITIONAL_REGISTER_USAGE might want to make a register - call-used, yet fixed, like PIC_OFFSET_TABLE_REGNUM. */ -#define CALL_REALLY_USED_REGISTERS CALL_USED_REGISTERS +/* CALL_REALLY_USED_REGISTERS is used as a default setting, which is then + overridden by -fcall-saved-* and -fcall-used-* options and then by + TARGET_CONDITIONAL_REGISTER_USAGE. There we might want to make a + register call-used, yet fixed, like PIC_OFFSET_TABLE_REGNUM. */ +#define CALL_REALLY_USED_REGISTERS \ +{ \ +/* Regular registers. */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* R8 and R9 are call-clobbered on SH5, but not on earlier SH ABIs. \ + Only the lower 32bits of R10-R14 are guaranteed to be preserved \ + across SH5 function calls. */ \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 1, 1, 1, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 1, 1, 1, 1, \ +/* FP registers. */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ +/* Branch target registers. */ \ + 1, 1, 1, 1, 1, 0, 0, 0, \ +/* XD registers. */ \ + 1, 1, 1, 1, 1, 1, 0, 0, \ +/*"gbr", "ap", "pr", "t", "mach", "macl", "fpul", "fpscr", */ \ + 0, 1, 1, 1, 1, 1, 1, 1, \ +/*"rap", "sfp","fpscr0","fpscr1" */ \ + 1, 1, 0, 0, \ +} /* Only the lower 32-bits of R10-R14 are guaranteed to be preserved across SHcompact function calls. We can't tell whether a called @@ -859,6 +905,10 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ && (GET_MODE_SIZE (MODE2) <= 4)) \ : ((MODE1) != SFmode && (MODE2) != SFmode)))) +/* Specify the modes required to caller save a given hard regno. */ +#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ + sh_hard_regno_caller_save_mode ((REGNO), (NREGS), (MODE)) + /* A C expression that is nonzero if hard register NEW_REG can be considered for use as a rename register for OLD_REG register */ #define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \ @@ -1060,7 +1110,7 @@ enum reg_class /* TARGET_REGS: */ \ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000ff }, \ /* ALL_REGS: */ \ - { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x03ffffff }, \ + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0fffffff }, \ } /* The same information, inverted: @@ -1110,7 +1160,7 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; 128,129,130,131,132,133,134,135, \ /* Fixed registers */ \ 15, 16, 24, 25, 26, 27, 63,144, \ - 145,146,147,148,149,152,153 } + 145,146,147,148,149,152,153,154,155 } /* The class value for index registers, and the one for base regs. */ #define INDEX_REG_CLASS \ @@ -1361,24 +1411,6 @@ struct sh_args { || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ ? SH_ARG_FLOAT : SH_ARG_INT) -#define ROUND_ADVANCE(SIZE) \ - (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* Round a register number up to a proper boundary for an arg of mode - MODE. - - The SH doesn't care about double alignment, so we only - round doubles to even regs when asked to explicitly. */ -#define ROUND_REG(CUM, MODE) \ - (((TARGET_ALIGN_DOUBLE \ - || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) \ - && ((MODE) == DFmode || (MODE) == DCmode) \ - && (CUM).arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (MODE))) \ - && GET_MODE_UNIT_SIZE ((MODE)) > UNITS_PER_WORD) \ - ? ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \ - + ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] & 1)) \ - : (CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)]) - /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. @@ -1394,27 +1426,6 @@ struct sh_args { #define INIT_CUMULATIVE_LIBCALL_ARGS(CUM, MODE, LIBNAME) \ sh_init_cumulative_args (& (CUM), NULL_TREE, (LIBNAME), NULL_TREE, 0, (MODE)) -/* Return boolean indicating arg of mode MODE will be passed in a reg. - This macro is only used in this file. */ -#define PASS_IN_REG_P(CUM, MODE, TYPE) \ - (((TYPE) == 0 \ - || (! TREE_ADDRESSABLE ((TYPE)) \ - && (! (TARGET_HITACHI || (CUM).renesas_abi) \ - || ! (AGGREGATE_TYPE_P (TYPE) \ - || (!TARGET_FPU_ANY \ - && (GET_MODE_CLASS (MODE) == MODE_FLOAT \ - && GET_MODE_SIZE (MODE) > GET_MODE_SIZE (SFmode))))))) \ - && ! (CUM).force_mem \ - && (TARGET_SH2E \ - ? ((MODE) == BLKmode \ - ? (((CUM).arg_count[(int) SH_ARG_INT] * UNITS_PER_WORD \ - + int_size_in_bytes (TYPE)) \ - <= NPARM_REGS (SImode) * UNITS_PER_WORD) \ - : ((ROUND_REG((CUM), (MODE)) \ - + HARD_REGNO_NREGS (BASE_ARG_REG (MODE), (MODE))) \ - <= NPARM_REGS (MODE))) \ - : ROUND_REG ((CUM), (MODE)) < NPARM_REGS (MODE))) - /* By accident we got stuck with passing SCmode on SH4 little endian in two registers that are nominally successive - which is different from two single SFmode values, where we take endianness translation into @@ -1584,15 +1595,10 @@ struct sh_args { #define USE_STORE_PRE_DECREMENT(mode) ((mode == SImode || mode == DImode) \ ? 0 : TARGET_SH1) -#define MOVE_BY_PIECES_P(SIZE, ALIGN) \ - (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \ - < (optimize_size ? 2 : ((ALIGN >= 32) ? 16 : 2))) +/* If a memory clear move would take CLEAR_RATIO or more simple + move-instruction pairs, we will do a setmem instead. */ -#define STORE_BY_PIECES_P(SIZE, ALIGN) \ - (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \ - < (optimize_size ? 2 : ((ALIGN >= 32) ? 16 : 2))) - -#define SET_BY_PIECES_P(SIZE, ALIGN) STORE_BY_PIECES_P(SIZE, ALIGN) +#define CLEAR_RATIO(speed) ((speed) ? 15 : 3) /* Macros to check register numbers against specific register classes. */ @@ -2236,32 +2242,9 @@ extern int current_function_interrupt; ? (TARGET_FMOVD ? FP_MODE_DOUBLE : FP_MODE_NONE) \ : ACTUAL_NORMAL_MODE (ENTITY)) -#define MODE_ENTRY(ENTITY) NORMAL_MODE (ENTITY) - -#define MODE_EXIT(ENTITY) \ - (sh_cfun_attr_renesas_p () ? FP_MODE_NONE : NORMAL_MODE (ENTITY)) - #define EPILOGUE_USES(REGNO) ((TARGET_SH2E || TARGET_SH4) \ && (REGNO) == FPSCR_REG) -#define MODE_NEEDED(ENTITY, INSN) \ - (recog_memoized (INSN) >= 0 \ - ? get_attr_fp_mode (INSN) \ - : FP_MODE_NONE) - -#define MODE_AFTER(ENTITY, MODE, INSN) \ - (TARGET_HITACHI \ - && recog_memoized (INSN) >= 0 \ - && get_attr_fp_set (INSN) != FP_SET_NONE \ - ? (int) get_attr_fp_set (INSN) \ - : (MODE)) - -#define MODE_PRIORITY_TO_MODE(ENTITY, N) \ - ((TARGET_FPU_SINGLE != 0) ^ (N) ? FP_MODE_SINGLE : FP_MODE_DOUBLE) - -#define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \ - fpscr_set_from_mem ((MODE), (HARD_REGS_LIVE)) - #define MD_CAN_REDIRECT_BRANCH(INSN, SEQ) \ sh_can_redirect_branch ((INSN), (SEQ)) diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index ab1f0a51c22..50f374c9bf8 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -1,5 +1,5 @@ ;;- Machine description for Renesas / SuperH SH. -;; Copyright (C) 1993-2014 Free Software Foundation, Inc. +;; Copyright (C) 1993-2015 Free Software Foundation, Inc. ;; Contributed by Steve Chamberlain (sac@cygnus.com). ;; Improved by Jim Wilson (wilson@cygnus.com). @@ -76,6 +76,12 @@ (FPSCR_REG 151) + ;; Virtual FPSCR - bits that are used by FP ops. + (FPSCR_MODES_REG 154) + + ;; Virtual FPSCR - bits that are updated by FP ops. + (FPSCR_STAT_REG 155) + (PIC_REG 12) (FP_REG 14) (SP_REG 15) @@ -110,72 +116,79 @@ (XD0_REG 136) - ;; These are used with unspec. - (UNSPEC_COMPACT_ARGS 0) - (UNSPEC_MOVA 1) - (UNSPEC_CASESI 2) - (UNSPEC_DATALABEL 3) - (UNSPEC_BBR 4) - (UNSPEC_SFUNC 5) - (UNSPEC_PIC 6) - (UNSPEC_GOT 7) - (UNSPEC_GOTOFF 8) - (UNSPEC_PLT 9) - (UNSPEC_CALLER 10) - (UNSPEC_GOTPLT 11) - (UNSPEC_ICACHE 12) - (UNSPEC_INIT_TRAMP 13) - (UNSPEC_FCOSA 14) - (UNSPEC_FSRRA 15) - (UNSPEC_FSINA 16) - (UNSPEC_NSB 17) - (UNSPEC_ALLOCO 18) - (UNSPEC_TLSGD 20) - (UNSPEC_TLSLDM 21) - (UNSPEC_TLSIE 22) - (UNSPEC_DTPOFF 23) - (UNSPEC_GOTTPOFF 24) - (UNSPEC_TPOFF 25) - (UNSPEC_RA 26) - (UNSPEC_DIV_INV_M0 30) - (UNSPEC_DIV_INV_M1 31) - (UNSPEC_DIV_INV_M2 32) - (UNSPEC_DIV_INV_M3 33) - (UNSPEC_DIV_INV20 34) - (UNSPEC_DIV_INV_TABLE 37) - (UNSPEC_ASHIFTRT 35) - (UNSPEC_THUNK 36) - (UNSPEC_CHKADD 38) - (UNSPEC_SP_SET 40) - (UNSPEC_SP_TEST 41) - (UNSPEC_MOVUA 42) + (FPSCR_PR 524288) ;; 1 << 19 + (FPSCR_SZ 1048576) ;; 1 << 20 + (FPSCR_FR 2097152) ;; 1 << 21 +]) +(define_c_enum "unspec" [ + ;; These are used with unspec. + UNSPEC_COMPACT_ARGS + UNSPEC_MOVA + UNSPEC_CASESI + UNSPEC_DATALABEL + UNSPEC_BBR + UNSPEC_SFUNC + UNSPEC_PIC + UNSPEC_GOT + UNSPEC_GOTOFF + UNSPEC_PLT + UNSPEC_CALLER + UNSPEC_GOTPLT + UNSPEC_ICACHE + UNSPEC_INIT_TRAMP + UNSPEC_FCOSA + UNSPEC_FSRRA + UNSPEC_FSINA + UNSPEC_NSB + UNSPEC_ALLOCO + UNSPEC_TLSGD + UNSPEC_TLSLDM + UNSPEC_TLSIE + UNSPEC_DTPOFF + UNSPEC_GOTTPOFF + UNSPEC_TPOFF + UNSPEC_RA + UNSPEC_DIV_INV_M0 + UNSPEC_DIV_INV_M1 + UNSPEC_DIV_INV_M2 + UNSPEC_DIV_INV_M3 + UNSPEC_DIV_INV20 + UNSPEC_DIV_INV_TABLE + UNSPEC_ASHIFTRT + UNSPEC_THUNK + UNSPEC_CHKADD + UNSPEC_SP_SET + UNSPEC_SP_TEST + UNSPEC_MOVUA ;; (unspec [VAL SHIFT] UNSPEC_EXTRACT_S16) computes (short) (VAL >> SHIFT). ;; UNSPEC_EXTRACT_U16 is the unsigned equivalent. - (UNSPEC_EXTRACT_S16 43) - (UNSPEC_EXTRACT_U16 44) - + UNSPEC_EXTRACT_S16 + UNSPEC_EXTRACT_U16 ;; (unspec [TARGET ANCHOR] UNSPEC_SYMOFF) == TARGET - ANCHOR. - (UNSPEC_SYMOFF 45) - + UNSPEC_SYMOFF ;; (unspec [OFFSET ANCHOR] UNSPEC_PCREL_SYMOFF) == OFFSET - (ANCHOR - .). - (UNSPEC_PCREL_SYMOFF 46) - + UNSPEC_PCREL_SYMOFF ;; Misc builtins - (UNSPEC_BUILTIN_STRLEN 47) + UNSPEC_BUILTIN_STRLEN +]) +(define_c_enum "unspecv" [ ;; These are used with unspec_volatile. - (UNSPECV_BLOCKAGE 0) - (UNSPECV_ALIGN 1) - (UNSPECV_CONST2 2) - (UNSPECV_CONST4 4) - (UNSPECV_CONST8 6) - (UNSPECV_WINDOW_END 10) - (UNSPECV_CONST_END 11) - (UNSPECV_EH_RETURN 12) - (UNSPECV_GBR 13) - (UNSPECV_SP_SWITCH_B 14) - (UNSPECV_SP_SWITCH_E 15) + UNSPECV_BLOCKAGE + UNSPECV_ALIGN + UNSPECV_CONST2 + UNSPECV_CONST4 + UNSPECV_CONST8 + UNSPECV_WINDOW_END + UNSPECV_CONST_END + UNSPECV_EH_RETURN + UNSPECV_GBR + UNSPECV_SP_SWITCH_B + UNSPECV_SP_SWITCH_E + + UNSPECV_FPSCR_MODES + UNSPECV_FPSCR_STAT ]) ;; ------------------------------------------------------------------------- @@ -504,6 +517,7 @@ (define_attr "in_delay_slot" "yes,no" (cond [(eq_attr "type" "cbranch") (const_string "no") (eq_attr "type" "pcload,pcload_si") (const_string "no") + (eq_attr "type" "fpscr_toggle") (const_string "no") (eq_attr "needs_delay_slot" "yes") (const_string "no") (eq_attr "length" "2") (const_string "yes") ] (const_string "no"))) @@ -652,30 +666,40 @@ [(set_attr "type" "mt_group")]) ;; This pattern might be risky because it also tests the upper bits and not -;; only the subreg. However, it seems that combine will get to this only -;; when testing sign/zero extended values. In this case the extended upper -;; bits do not matter. -(define_insn "*tst<mode>_t_zero" +;; only the subreg. We have to check whether the operands have been sign +;; or zero extended. In the worst case, a zero extension has to be inserted +;; to mask out the unwanted bits. +(define_insn_and_split "*tst<mode>_t_subregs" [(set (reg:SI T_REG) (eq:SI (subreg:QIHI - (and:SI (match_operand:SI 0 "arith_reg_operand" "%r") - (match_operand:SI 1 "arith_reg_operand" "r")) <lowpart_le>) + (and:SI (match_operand:SI 0 "arith_reg_operand") + (match_operand:SI 1 "arith_reg_operand")) <lowpart_le>) (const_int 0)))] - "TARGET_SH1 && TARGET_LITTLE_ENDIAN" - "tst %0,%1" - [(set_attr "type" "mt_group")]) + "TARGET_SH1 && TARGET_LITTLE_ENDIAN && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + sh_split_tst_subregs (curr_insn, <MODE>mode, <lowpart_le>, operands); + DONE; +}) -(define_insn "*tst<mode>_t_zero" +(define_insn_and_split "*tst<mode>_t_subregs" [(set (reg:SI T_REG) (eq:SI (subreg:QIHI - (and:SI (match_operand:SI 0 "arith_reg_operand" "%r") - (match_operand:SI 1 "arith_reg_operand" "r")) <lowpart_be>) + (and:SI (match_operand:SI 0 "arith_reg_operand") + (match_operand:SI 1 "arith_reg_operand")) <lowpart_be>) (const_int 0)))] - "TARGET_SH1 && TARGET_BIG_ENDIAN" - "tst %0,%1" - [(set_attr "type" "mt_group")]) + "TARGET_SH1 && TARGET_BIG_ENDIAN && can_create_pseudo_p ()" + "#" + "&& 1" + [(const_int 0)] +{ + sh_split_tst_subregs (curr_insn, <MODE>mode, <lowpart_be>, operands); + DONE; +}) ;; Extract LSB, negate and store in T bit. (define_insn "tstsi_t_and_not" @@ -868,9 +892,9 @@ (define_insn "*cmp_div0s_0" [(set (reg:SI T_REG) - (eq:SI (lshiftrt:SI (match_operand:SI 0 "arith_reg_operand") + (eq:SI (lshiftrt:SI (match_operand:SI 0 "arith_reg_operand" "%r") (const_int 31)) - (ge:SI (match_operand:SI 1 "arith_reg_operand") + (ge:SI (match_operand:SI 1 "arith_reg_operand" "r") (const_int 0))))] "TARGET_SH1" "div0s %0,%1" @@ -1072,47 +1096,6 @@ (label_ref (match_dup 2)) (pc)))]) -;; Conditional move combine pattern for div0s comparisons. -;; This is used when TARGET_PRETEND_CMOVE is in effect. -(define_insn_and_split "*movsicc_div0s" - [(set (match_operand:SI 0 "arith_reg_dest" "") - (if_then_else:SI (ge (xor:SI (match_operand:SI 1 "arith_reg_operand" "") - (match_operand:SI 2 "arith_reg_operand" "")) - (const_int 0)) - (match_operand:SI 3 "arith_reg_operand" "") - (match_operand:SI 4 "general_movsrc_operand" ""))) - (clobber (reg:SI T_REG))] - "TARGET_PRETEND_CMOVE" - "#" - "&& 1" - [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2)) - (const_int 0))) - (set (match_dup 0) - (if_then_else (ne (reg:SI T_REG) (const_int 0)) - (match_dup 4) - (match_dup 3)))]) - -(define_insn_and_split "*movsicc_div0s" - [(set (match_operand:SI 0 "arith_reg_dest") - (if_then_else:SI (eq (lshiftrt:SI - (match_operand:SI 1 "arith_reg_operand") - (const_int 31)) - (lshiftrt:SI - (match_operand:SI 2 "arith_reg_operand") - (const_int 31))) - (match_operand:SI 3 "arith_reg_operand") - (match_operand:SI 4 "general_movsrc_operand"))) - (clobber (reg:SI T_REG))] - "TARGET_PRETEND_CMOVE" - "#" - "&& 1" - [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2)) - (const_int 0))) - (set (match_dup 0) - (if_then_else (ne (reg:SI T_REG) (const_int 0)) - (match_dup 4) - (match_dup 3)))]) - ;; ------------------------------------------------------------------------- ;; SImode unsigned integer comparisons ;; ------------------------------------------------------------------------- @@ -1565,7 +1548,8 @@ [(set (match_dup 0) (match_dup 3)) (set (match_dup 4) (match_dup 5))] { - rtx set1, set2, insn2; + rtx set1, set2; + rtx_insn *insn1, *insn2; rtx replacements[4]; /* We want to replace occurrences of operands[0] with operands[1] and @@ -1592,23 +1576,20 @@ /* ??? The last insn might be a jump insn, but the generic peephole2 code always uses emit_insn. */ /* Check that we don't violate matching constraints or earlyclobbers. */ - extract_insn (emit_insn (set1)); - if (! constrain_operands (1)) + basic_block bb = BLOCK_FOR_INSN (peep2_next_insn (2)); + insn1 = emit_insn (set1); + extract_insn (insn1); + if (! constrain_operands (1, get_preferred_alternatives (insn1, bb))) goto failure; insn2 = emit (set2); if (GET_CODE (insn2) == BARRIER) goto failure; extract_insn (insn2); - if (! constrain_operands (1)) + if (! constrain_operands (1, get_preferred_alternatives (insn2, bb))) { - rtx tmp; failure: - tmp = replacements[0]; - replacements[0] = replacements[1]; - replacements[1] = tmp; - tmp = replacements[2]; - replacements[2] = replacements[3]; - replacements[3] = tmp; + std::swap (replacements[0], replacements[1]); + std::swap (replacements[2], replacements[3]); replace_n_hard_rtx (SET_DEST (set1), replacements, 2, 1); replace_n_hard_rtx (SET_DEST (set2), replacements, 2, 1); replace_n_hard_rtx (SET_SRC (set2), replacements, 2, 1); @@ -1830,6 +1811,8 @@ ;; We allow a reg or 0 for one of the operands in order to be able to ;; do 'reg + T' sequences. Reload will load the constant 0 into the reg ;; as needed. +;; FIXME: The load of constant 0 should be split out before reload, or else +;; it will be difficult to hoist or combine the constant load. (define_insn "*addc" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%0") @@ -1898,10 +1881,10 @@ ;; can be scheduled much better since the load of the constant can be ;; done earlier, before any comparison insns that store the result in ;; the T bit. -(define_insn_and_split "*addc_r_1" - [(set (match_operand:SI 0 "arith_reg_dest" "") - (plus:SI (match_operand:SI 1 "t_reg_operand" "") - (match_operand:SI 2 "arith_reg_operand" ""))) +(define_insn_and_split "*addc_t_r" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (match_operand:SI 1 "t_reg_operand") + (match_operand:SI 2 "arith_reg_operand"))) (clobber (reg:SI T_REG))] "TARGET_SH1" "#" @@ -1911,6 +1894,19 @@ (match_dup 1))) (clobber (reg:SI T_REG))])]) +(define_insn_and_split "*addc_r_t" + [(set (match_operand:SI 0 "arith_reg_dest") + (plus:SI (match_operand:SI 1 "arith_reg_operand") + (match_operand:SI 2 "t_reg_operand"))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (plus:SI (plus:SI (match_dup 1) (const_int 0)) + (match_dup 2))) + (clobber (reg:SI T_REG))])]) + ;; Use shlr-addc to do 'reg + (reg & 1)'. (define_insn_and_split "*addc_r_lsb" [(set (match_operand:SI 0 "arith_reg_dest") @@ -2034,11 +2030,16 @@ (define_expand "addsi3" [(set (match_operand:SI 0 "arith_reg_operand" "") (plus:SI (match_operand:SI 1 "arith_operand" "") - (match_operand:SI 2 "arith_operand" "")))] + (match_operand:SI 2 "arith_or_int_operand" "")))] "" { if (TARGET_SHMEDIA) operands[1] = force_reg (SImode, operands[1]); + else if (! arith_operand (operands[2], SImode)) + { + if (reg_overlap_mentioned_p (operands[0], operands[1])) + FAIL; + } }) (define_insn "addsi3_media" @@ -2065,12 +2066,34 @@ [(set_attr "type" "arith_media") (set_attr "highpart" "ignore")]) -(define_insn "*addsi3_compact" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (plus:SI (match_operand:SI 1 "arith_operand" "%0") - (match_operand:SI 2 "arith_operand" "rI08")))] - "TARGET_SH1" - "add %2,%0" +;; The *addsi3_compact is made an insn_and_split and accepts actually +;; impossible constraints to make LRA's register elimination work well on SH. +;; The problem is that LRA expects something like +;; (set rA (plus rB (const_int N))) +;; to work. We can do that, but we have to split out an additional reg-reg +;; copy or constant load before the actual add insn. +;; Use u constraint for that case to avoid the invalid value in the stack +;; pointer. +(define_insn_and_split "*addsi3_compact" + [(set (match_operand:SI 0 "arith_reg_dest" "=r,&u") + (plus:SI (match_operand:SI 1 "arith_operand" "%0,r") + (match_operand:SI 2 "arith_or_int_operand" "rI08,rn")))] + "TARGET_SH1 + && ((rtx_equal_p (operands[0], operands[1]) + && arith_operand (operands[2], SImode)) + || ! reg_overlap_mentioned_p (operands[0], operands[1]))" + "@ + add %2,%0 + #" + "reload_completed + && ! reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] +{ + /* Prefer 'mov r0,r1; add #imm8,r1' over 'mov #imm8,r1; add r0,r1' */ + if (satisfies_constraint_I08 (operands[2])) + std::swap (operands[1], operands[2]); +} [(set_attr "type" "arith")]) ;; ------------------------------------------------------------------------- @@ -2378,8 +2401,9 @@ (clobber (reg:SI R1_REG)) (clobber (reg:SI R4_REG)) (clobber (reg:SI R5_REG)) - (use (reg:PSI FPSCR_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (match_operand:SI 1 "arith_reg_operand" "r")) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE" "jsr @%1%#" [(set_attr "type" "sfunc") @@ -2649,8 +2673,9 @@ (clobber (reg:SI PR_REG)) (clobber (reg:DF DR0_REG)) (clobber (reg:DF DR2_REG)) - (use (reg:PSI FPSCR_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (match_operand:SI 1 "arith_reg_operand" "r")) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE" "jsr @%1%#" [(set_attr "type" "sfunc") @@ -3319,7 +3344,8 @@ label: (reg:SI MACL_REG))] "TARGET_SH1" { - rtx insn, macl; + rtx_insn *insn; + rtx macl; macl = gen_rtx_REG (SImode, MACL_REG); start_sequence (); @@ -3348,7 +3374,8 @@ label: (reg:SI MACL_REG))] "TARGET_SH1" { - rtx insn, macl; + rtx_insn *insn; + rtx macl; macl = gen_rtx_REG (SImode, MACL_REG); start_sequence (); @@ -3596,7 +3623,8 @@ label: (reg:SI MACH_REG))] "TARGET_SH2" { - rtx insn, mach; + rtx_insn *insn; + rtx mach; mach = gen_rtx_REG (SImode, MACH_REG); start_sequence (); @@ -3642,7 +3670,8 @@ label: (reg:SI MACH_REG))] "TARGET_SH2" { - rtx insn, mach; + rtx_insn *insn; + rtx mach; mach = gen_rtx_REG (SImode, MACH_REG); start_sequence (); @@ -3953,7 +3982,7 @@ label: [(set (match_dup 5) (match_dup 4)) (set (match_dup 0) (sign_extend:DI (match_dup 5)))] { - enum machine_mode inmode = GET_MODE (operands[1]); + machine_mode inmode = GET_MODE (operands[1]); int offset = 0; if (GET_CODE (operands[0]) == SUBREG) @@ -4563,6 +4592,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashrsi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_ashlsi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -4803,6 +4838,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashrdi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_ashldi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -4896,6 +4937,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashlsi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_ashrsi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -4995,6 +5042,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashldi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_ashrdi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -5069,6 +5122,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashlsi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_lshrsi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -5263,6 +5322,12 @@ label: { if (TARGET_SHMEDIA) { + if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + emit_insn (gen_ashldi3_media (operands[0], operands[1], operands[2])); + DONE; + } emit_insn (gen_lshrdi3_media (operands[0], operands[1], operands[2])); DONE; } @@ -6295,10 +6360,9 @@ label: }) (define_expand "extendqihi2" - [(set (match_operand:HI 0 "arith_reg_dest" "") - (sign_extend:HI (match_operand:QI 1 "arith_reg_operand" "")))] - "" - "") + [(set (match_operand:HI 0 "arith_reg_dest") + (sign_extend:HI (match_operand:QI 1 "arith_reg_operand")))] + "TARGET_SH1") (define_insn "*extendqihi2_compact_reg" [(set (match_operand:HI 0 "arith_reg_dest" "=r") @@ -6387,7 +6451,7 @@ label: (define_expand "push_e" [(parallel [(set (mem:SF (pre_dec:SI (reg:SI SP_REG))) (match_operand:SF 0 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "TARGET_SH1 && ! TARGET_SH5" "") @@ -6405,7 +6469,7 @@ label: (define_expand "push_4" [(parallel [(set (mem:DF (pre_dec:SI (reg:SI SP_REG))) (match_operand:DF 0 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "TARGET_SH1 && ! TARGET_SH5" "") @@ -6413,7 +6477,7 @@ label: (define_expand "pop_e" [(parallel [(set (match_operand:SF 0 "" "") (mem:SF (post_inc:SI (reg:SI SP_REG)))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "TARGET_SH1 && ! TARGET_SH5" "") @@ -6428,7 +6492,7 @@ label: (define_expand "pop_4" [(parallel [(set (match_operand:DF 0 "" "") (mem:DF (post_inc:SI (reg:SI SP_REG)))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "TARGET_SH1 && ! TARGET_SH5" "") @@ -6437,11 +6501,11 @@ label: [(const_int 0)] "TARGET_SH2E" { - rtx insn = emit_insn (gen_fpu_switch (gen_frame_mem (PSImode, - gen_rtx_PRE_DEC (Pmode, - stack_pointer_rtx)), - get_fpscr_rtx ())); - add_reg_note (insn, REG_INC, stack_pointer_rtx); + add_reg_note ( + emit_insn ( + gen_sts_fpscr ( + gen_frame_mem (SImode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)))), + REG_INC, stack_pointer_rtx); DONE; }) @@ -6449,11 +6513,11 @@ label: [(const_int 0)] "TARGET_SH2E" { - rtx insn = emit_insn (gen_fpu_switch (get_fpscr_rtx (), - gen_frame_mem (PSImode, - gen_rtx_POST_INC (Pmode, - stack_pointer_rtx)))); - add_reg_note (insn, REG_INC, stack_pointer_rtx); + add_reg_note ( + emit_insn ( + gen_lds_fpscr ( + gen_frame_mem (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)))), + REG_INC, stack_pointer_rtx); DONE; }) @@ -6638,12 +6702,14 @@ label: ;; TARGET_FMOVD is in effect, and mode switching is done before reload. (define_insn "movsi_ie" [(set (match_operand:SI 0 "general_movdst_operand" - "=r,r,r,r,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y") + "=r,r,r,r,r,r,r,r,mr,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y") (match_operand:SI 1 "general_movsrc_operand" "Q,r,I08,I20,I28,mr,x,l,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))] "(TARGET_SH2E || TARGET_SH2A) - && (register_operand (operands[0], SImode) - || register_operand (operands[1], SImode))" + && ((register_operand (operands[0], SImode) + && !fpscr_operand (operands[0], SImode)) + || (register_operand (operands[1], SImode) + && !fpscr_operand (operands[1], SImode)))" "@ mov.l %1,%0 mov %1,%0 @@ -6881,7 +6947,7 @@ label: emit_insn (gen_ic_invalidate_line_compact (operands[0], operands[1])); DONE; } - else if (TARGET_SH4A_ARCH || TARGET_SH4_300) + else if (TARGET_SH4A || TARGET_SH4_300) { emit_insn (gen_ic_invalidate_line_sh4a (operands[0])); DONE; @@ -6914,7 +6980,7 @@ label: (define_insn "ic_invalidate_line_sh4a" [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPEC_ICACHE)] - "TARGET_SH4A_ARCH || TARGET_SH4_300" + "TARGET_SH4A || TARGET_SH4_300" { return "ocbwb @%0" "\n" " synco" "\n" @@ -6978,20 +7044,20 @@ label: [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) -(define_expand "movhi" - [(set (match_operand:HI 0 "general_movdst_operand" "") - (match_operand:HI 1 "general_movsrc_operand" ""))] +(define_expand "mov<mode>" + [(set (match_operand:QIHI 0 "general_movdst_operand") + (match_operand:QIHI 1 "general_movsrc_operand"))] "" { - prepare_move_operands (operands, HImode); -}) + if (can_create_pseudo_p () && CONST_INT_P (operands[1]) + && REG_P (operands[0]) && REGNO (operands[0]) != R0_REG) + { + rtx reg = gen_reg_rtx(SImode); + emit_move_insn (reg, operands[1]); + operands[1] = gen_lowpart (<MODE>mode, reg); + } -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" -{ - prepare_move_operands (operands, QImode); + prepare_move_operands (operands, <MODE>mode); }) ;; Specifying the displacement addressing load / store patterns separately @@ -7203,8 +7269,7 @@ label: gcc_unreachable (); } - if (regno == -1 - || ! refers_to_regno_p (regno, regno + 1, operands[1], 0)) + if (regno == -1 || ! refers_to_regno_p (regno, operands[1])) { operands[2] = operand_subword (operands[0], 0, 0, DImode); operands[3] = operand_subword (operands[1], 0, 0, DImode); @@ -7598,8 +7663,8 @@ label: (define_insn "movdf_i4" [(set (match_operand:DF 0 "general_movdst_operand" "=d,r,d,d,m,r,r,m,!??r,!???d") (match_operand:DF 1 "general_movsrc_operand" "d,r,F,m,d,FQ,m,r,d,r")) - (use (match_operand:PSI 2 "fpscr_operand" "c,c,c,c,c,c,c,c,c,c")) - (clobber (match_scratch:SI 3 "=X,X,&z,X,X,X,X,X,X,X"))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2 "=X,X,&z,X,X,X,X,X,X,X"))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && (arith_reg_operand (operands[0], DFmode) || arith_reg_operand (operands[1], DFmode))" @@ -7652,10 +7717,10 @@ label: ;; use that will prevent scheduling of other stack accesses beyond this ;; instruction. (define_split - [(set (match_operand:DF 0 "register_operand" "") - (match_operand:DF 1 "register_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 "=X"))] + [(set (match_operand:DF 0 "register_operand") + (match_operand:DF 1 "register_operand")) + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && reload_completed && (true_regnum (operands[0]) < 16) != (true_regnum (operands[1]) < 16)" [(const_int 0)] @@ -7671,7 +7736,7 @@ label: else tos = gen_tmp_stack_mem (DFmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)); - insn = emit_insn (gen_movdf_i4 (tos, operands[1], operands[2])); + insn = emit_insn (gen_movdf_i4 (tos, operands[1])); if (! (TARGET_SH5 && true_regnum (operands[1]) < 16)) add_reg_note (insn, REG_INC, stack_pointer_rtx); if (TARGET_SH5 && true_regnum (operands[0]) < 16) @@ -7679,7 +7744,7 @@ label: else tos = gen_tmp_stack_mem (DFmode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)); - insn = emit_insn (gen_movdf_i4 (operands[0], tos, operands[2])); + insn = emit_insn (gen_movdf_i4 (operands[0], tos)); if (TARGET_SH5 && true_regnum (operands[0]) < 16) emit_move_insn (stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, 8)); @@ -7695,8 +7760,8 @@ label: (define_split [(set (match_operand:DF 0 "general_movdst_operand" "") (match_operand:DF 1 "general_movsrc_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && reload_completed && true_regnum (operands[0]) < 16 @@ -7737,8 +7802,7 @@ label: alter_subreg (&word0, true); word1 = gen_rtx_SUBREG (SImode, regop, 4); alter_subreg (&word1, true); - if (store_p || ! refers_to_regno_p (REGNO (word0), - REGNO (word0) + 1, addr, 0)) + if (store_p || ! refers_to_regno_p (REGNO (word0), addr)) { emit_insn (store_p ? gen_movsi_ie (mem, word0) @@ -7767,18 +7831,18 @@ label: (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "memory_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI R0_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && reload_completed" [(parallel [(set (match_dup 0) (match_dup 1)) - (use (match_dup 2)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "") (define_expand "reload_indf__frn" [(parallel [(set (match_operand:DF 0 "register_operand" "=a") (match_operand:DF 1 "immediate_operand" "FQ")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (match_operand:SI 2 "register_operand" "=&z"))])] "TARGET_SH1" "") @@ -7794,8 +7858,8 @@ label: (define_split [(set (match_operand:SF 0 "register_operand" "") (match_operand:SF 1 "register_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "TARGET_SH2E && reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" [(set (match_dup 0) (match_dup 0))] @@ -7805,8 +7869,8 @@ label: (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "register_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "TARGET_SH4 && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[0])) && FP_OR_XD_REGISTER_P (true_regnum (operands[1]))" @@ -7814,17 +7878,17 @@ label: { int dst = true_regnum (operands[0]), src = true_regnum (operands[1]); emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, dst), - gen_rtx_REG (SFmode, src), operands[2])); + gen_rtx_REG (SFmode, src))); emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, dst + 1), - gen_rtx_REG (SFmode, src + 1), operands[2])); + gen_rtx_REG (SFmode, src + 1))); DONE; }) (define_split [(set (match_operand:DF 0 "register_operand" "") (mem:DF (match_operand:SI 1 "register_operand" ""))) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[0])) && find_regno_note (insn, REG_DEAD, true_regnum (operands[1]))" @@ -7837,20 +7901,19 @@ label: = change_address (mem, SFmode, gen_rtx_POST_INC (Pmode, operands[1])); insn = emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, regno + SH_REG_MSW_OFFSET), - mem2, operands[2])); + mem2)); add_reg_note (insn, REG_INC, operands[1]); insn = emit_insn (gen_movsf_ie (gen_rtx_REG (SFmode, regno + SH_REG_LSW_OFFSET), - change_address (mem, SFmode, NULL_RTX), - operands[2])); + change_address (mem, SFmode, NULL_RTX))); DONE; }) (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "memory_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[0]))" [(const_int 0)] @@ -7873,10 +7936,10 @@ label: if (! arith_reg_operand (operands[1], SFmode)) { XEXP (mem2, 0) = addr = gen_rtx_POST_INC (SImode, addr); - insn = emit_insn (gen_movsf_ie (reg0, mem2, operands[2])); + insn = emit_insn (gen_movsf_ie (reg0, mem2)); add_reg_note (insn, REG_INC, XEXP (addr, 0)); - emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + emit_insn (gen_movsf_ie (reg1, operands[1])); /* If we have modified the stack pointer, the value that we have read with post-increment might be modified by an interrupt, @@ -7891,17 +7954,17 @@ label: /* Fall through. */ case PLUS: - emit_insn (gen_movsf_ie (reg0, operands[1], operands[2])); + emit_insn (gen_movsf_ie (reg0, operands[1])); operands[1] = copy_rtx (operands[1]); XEXP (operands[1], 0) = plus_constant (Pmode, addr, 4); - emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + emit_insn (gen_movsf_ie (reg1, operands[1])); break; case POST_INC: - insn = emit_insn (gen_movsf_ie (reg0, operands[1], operands[2])); + insn = emit_insn (gen_movsf_ie (reg0, operands[1])); add_reg_note (insn, REG_INC, XEXP (addr, 0)); - insn = emit_insn (gen_movsf_ie (reg1, operands[1], operands[2])); + insn = emit_insn (gen_movsf_ie (reg1, operands[1])); add_reg_note (insn, REG_INC, XEXP (addr, 0)); break; @@ -7916,8 +7979,8 @@ label: (define_split [(set (match_operand:DF 0 "memory_operand" "") (match_operand:DF 1 "register_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) - (clobber (match_scratch:SI 3 ""))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && ! TARGET_FMOVD && reload_completed && FP_OR_XD_REGISTER_P (true_regnum (operands[1]))" [(const_int 0)] @@ -7940,12 +8003,12 @@ label: if (! arith_reg_operand (operands[0], SFmode)) { emit_insn (gen_addsi3 (addr, addr, GEN_INT (4))); - emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + emit_insn (gen_movsf_ie (operands[0], reg1)); operands[0] = copy_rtx (operands[0]); XEXP (operands[0], 0) = addr = gen_rtx_PRE_DEC (SImode, addr); - insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + insn = emit_insn (gen_movsf_ie (operands[0], reg0)); add_reg_note (insn, REG_INC, XEXP (addr, 0)); break; } @@ -7957,12 +8020,12 @@ label: register component of the address. Just emit the lower numbered register first, to the lower address, then the higher numbered register to the higher address. */ - emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + emit_insn (gen_movsf_ie (operands[0], reg0)); operands[0] = copy_rtx (operands[0]); XEXP (operands[0], 0) = plus_constant (Pmode, addr, 4); - emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + emit_insn (gen_movsf_ie (operands[0], reg1)); break; case PRE_DEC: @@ -7970,10 +8033,10 @@ label: first (ie the word in the higher numbered register) then the word to go to the lower address. */ - insn = emit_insn (gen_movsf_ie (operands[0], reg1, operands[2])); + insn = emit_insn (gen_movsf_ie (operands[0], reg1)); add_reg_note (insn, REG_INC, XEXP (addr, 0)); - insn = emit_insn (gen_movsf_ie (operands[0], reg0, operands[2])); + insn = emit_insn (gen_movsf_ie (operands[0], reg0)); add_reg_note (insn, REG_INC, XEXP (addr, 0)); break; @@ -8018,8 +8081,7 @@ label: gcc_unreachable (); } - if (regno == -1 - || ! refers_to_regno_p (regno, regno + 1, operands[1], 0)) + if (regno == -1 || ! refers_to_regno_p (regno, operands[1])) { operands[2] = operand_subword (operands[0], 0, 0, DFmode); operands[3] = operand_subword (operands[1], 0, 0, DFmode); @@ -8055,7 +8117,7 @@ label: } if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - emit_df_insn (gen_movdf_i4 (operands[0], operands[1], get_fpscr_rtx ())); + emit_insn (gen_movdf_i4 (operands[0], operands[1])); DONE; } }) @@ -8300,12 +8362,12 @@ label: "=f,r,f,f,fy,f,m,r,r,m,f,y,y,rf,r,y,<,y,y") (match_operand:SF 1 "general_movsrc_operand" "f,r,G,H,FQ,mf,f,FQ,mr,r,y,f,>,fr,y,r,y,>,y")) - (use (match_operand:PSI 2 "fpscr_operand" "c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c")) - (clobber (match_scratch:SI 3 "=X,X,Bsc,Bsc,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))] + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SI 2 "=X,X,X,X,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))] "TARGET_SH2E && (arith_reg_operand (operands[0], SFmode) || fpul_operand (operands[0], SFmode) || arith_reg_operand (operands[1], SFmode) || fpul_operand (operands[1], SFmode) - || arith_reg_operand (operands[3], SImode))" + || arith_reg_operand (operands[2], SImode))" "@ fmov %1,%0 mov %1,%0 @@ -8357,21 +8419,139 @@ label: (const_int 2) (const_int 2) (const_int 0)]) - (set (attr "fp_mode") (if_then_else (eq_attr "fmovd" "yes") - (const_string "single") - (const_string "single")))]) + (set_attr_alternative "fp_mode" + [(if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "single") + (const_string "single") + (const_string "none") + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none")])]) + +(define_insn_and_split "movsf_ie_ra" + [(set (match_operand:SF 0 "general_movdst_operand" + "=f,r,f,f,fy,f,m,r,r,m,f,y,y,rf,r,y,<,y,y") + (match_operand:SF 1 "general_movsrc_operand" + "f,r,G,H,FQ,m,f,FQ,m,r,y,f,>,fr,y,r,y,>,y")) + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SF 2 "=r,r,X,X,&z,r,r,X,r,r,r,r,r,y,r,r,r,r,r")) + (const_int 0)] + "TARGET_SH2E + && (arith_reg_operand (operands[0], SFmode) + || fpul_operand (operands[0], SFmode) + || arith_reg_operand (operands[1], SFmode) + || fpul_operand (operands[1], SFmode))" + "@ + fmov %1,%0 + mov %1,%0 + fldi0 %0 + fldi1 %0 + # + fmov.s %1,%0 + fmov.s %1,%0 + mov.l %1,%0 + mov.l %1,%0 + mov.l %1,%0 + fsts fpul,%0 + flds %1,fpul + lds.l %1,%0 + # + sts %1,%0 + lds %1,%0 + sts.l %1,%0 + lds.l %1,%0 + ! move optimized away" + "reload_completed + && sh_movsf_ie_ra_split_p (operands[0], operands[1], operands[2])" + [(const_int 0)] +{ + if (! rtx_equal_p (operands[0], operands[1])) + { + emit_insn (gen_movsf_ie (operands[2], operands[1])); + emit_insn (gen_movsf_ie (operands[0], operands[2])); + } +} + [(set_attr "type" "fmove,move,fmove,fmove,pcfload,fload,fstore,pcload,load, + store,fmove,fmove,load,*,fpul_gp,gp_fpul,fstore,load,nil") + (set_attr "late_fp_use" "*,*,*,*,*,*,yes,*,*,*,*,*,*,*,yes,*,yes,*,*") + (set_attr_alternative "length" + [(const_int 2) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 4) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (const_int 2) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 4) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 0)]) + (set_attr_alternative "fp_mode" + [(if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "single") + (const_string "single") + (const_string "none") + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none")])]) (define_split [(set (match_operand:SF 0 "register_operand" "") (match_operand:SF 1 "register_operand" "")) - (use (match_operand:PSI 2 "fpscr_operand" "")) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI FPUL_REG))] "TARGET_SH1" [(parallel [(set (reg:SF FPUL_REG) (match_dup 1)) - (use (match_dup 2)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))]) (parallel [(set (match_dup 0) (reg:SF FPUL_REG)) - (use (match_dup 2)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (scratch:SI))])] "") @@ -8391,7 +8571,15 @@ label: } if (TARGET_SH2E) { - emit_sf_insn (gen_movsf_ie (operands[0], operands[1], get_fpscr_rtx ())); + if (lra_in_progress) + { + if (GET_CODE (operands[0]) == SCRATCH) + DONE; + emit_insn (gen_movsf_ie_ra (operands[0], operands[1])); + DONE; + } + + emit_insn (gen_movsf_ie (operands[0], operands[1])); DONE; } }) @@ -8406,7 +8594,7 @@ label: (define_expand "reload_insf__frn" [(parallel [(set (match_operand:SF 0 "register_operand" "=a") (match_operand:SF 1 "immediate_operand" "FQ")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (match_operand:SI 2 "register_operand" "=&z"))])] "TARGET_SH1" "") @@ -8595,7 +8783,7 @@ label: (pc)))] "TARGET_SHMEDIA" { - enum machine_mode mode = GET_MODE (operands[1]); + machine_mode mode = GET_MODE (operands[1]); if (mode == VOIDmode) mode = GET_MODE (operands[2]); if (GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE) @@ -8804,7 +8992,7 @@ label: (define_insn "jump_compact" [(set (pc) (label_ref (match_operand 0 "" "")))] - "TARGET_SH1 && !find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)" + "TARGET_SH1 && !CROSSING_JUMP_P (insn)" { /* The length is 16 if the delay slot is unfilled. */ if (get_attr_length(insn) > 4) @@ -8852,7 +9040,7 @@ label: }) (define_insn "force_mode_for_call" - [(use (reg:PSI FPSCR_REG))] + [(use (reg:SI FPSCR_MODES_REG))] "TARGET_SHCOMPACT" "" [(set_attr "length" "0") @@ -8863,7 +9051,7 @@ label: (define_insn "calli" [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SH1" { @@ -8885,7 +9073,7 @@ label: (define_insn "calli_tbr_rel" [(call (mem (match_operand:SI 0 "symbol_ref_operand" "")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SH2A && sh2a_is_function_vector_call (operands[0])" { @@ -8906,7 +9094,7 @@ label: (define_insn "calli_pcrel" [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (use (match_operand 2 "" "")) (clobber (reg:SI PR_REG))] @@ -8925,7 +9113,7 @@ label: (define_insn_and_split "call_pcrel" [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (clobber (reg:SI PR_REG)) (clobber (match_scratch:SI 2 "=r"))] @@ -8956,7 +9144,7 @@ label: (match_operand 2 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && ! (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))" "jsr @%0%#" @@ -8972,7 +9160,7 @@ label: (match_operand 2 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI R10_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))" @@ -8995,7 +9183,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SH1" { @@ -9018,7 +9206,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SH2A && sh2a_is_function_vector_call (operands[1])" { @@ -9039,7 +9227,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (use (match_operand 3 "" "")) (clobber (reg:SI PR_REG))] @@ -9059,7 +9247,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (clobber (reg:SI PR_REG)) (clobber (match_scratch:SI 3 "=r"))] @@ -9092,7 +9280,7 @@ label: (match_operand 3 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && ! (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))" "jsr @%1%#" @@ -9109,7 +9297,7 @@ label: (match_operand 3 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI R10_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))" @@ -9133,7 +9321,7 @@ label: [(parallel [(call (mem:SI (match_operand 0 "arith_reg_operand" "")) (match_operand 1 "" "")) (match_operand 2 "" "") - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))])] "" { @@ -9232,7 +9420,7 @@ label: (match_operand 3 "immediate_operand" "n"))) (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && ! (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))" "jsr @%0%#" @@ -9250,7 +9438,7 @@ label: (match_operand 3 "immediate_operand" "n"))) (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI R10_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && (INTVAL (operands[2]) & CALL_COOKIE_RET_TRAMP (1))" @@ -9321,7 +9509,7 @@ label: (call (mem:SI (match_operand 1 "arith_reg_operand" "")) (match_operand 2 "" ""))) (match_operand 3 "" "") - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))])] "" { @@ -9416,7 +9604,7 @@ label: (define_insn "sibcalli" [(call (mem:SI (match_operand:SI 0 "register_operand" "k")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)] "TARGET_SH1" "jmp @%0%#" @@ -9430,7 +9618,7 @@ label: [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "k")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)] "TARGET_SH2" { @@ -9448,7 +9636,7 @@ label: [(call (mem:SI (unspec:SI [(match_operand:SI 0 "symbol_ref_operand" "")] UNSPEC_THUNK)) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)] "TARGET_SH1" "bra %O0" @@ -9462,7 +9650,7 @@ label: (define_insn_and_split "sibcall_pcrel" [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "")) (match_operand 1 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (match_scratch:SI 2 "=k")) (return)] "TARGET_SH2" @@ -9491,7 +9679,7 @@ label: (return) (use (match_operand:SI 2 "register_operand" "z,x")) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) ;; We want to make sure the `x' above will only match MACH_REG ;; because sibcall_epilogue may clobber MACL_REG. (clobber (reg:SI MACL_REG))] @@ -9525,7 +9713,7 @@ label: [(call (mem:SI (match_operand 0 "arith_reg_operand" "")) (match_operand 1 "" "")) (match_operand 2 "" "") - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)])] "" { @@ -9622,7 +9810,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "register_operand" "k")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)] "TARGET_SH1" "jmp @%1%#" @@ -9637,7 +9825,7 @@ label: (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "k")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)] "TARGET_SH2" { @@ -9654,7 +9842,7 @@ label: [(set (match_operand 0 "" "=rf") (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "")) (match_operand 2 "" ""))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (match_scratch:SI 3 "=k")) (return)] "TARGET_SH2" @@ -9686,7 +9874,7 @@ label: (return) (use (match_operand:SI 3 "register_operand" "z,x")) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) ;; We want to make sure the `x' above will only match MACH_REG ;; because sibcall_epilogue may clobber MACL_REG. (clobber (reg:SI MACL_REG))] @@ -9722,7 +9910,7 @@ label: (call (mem:SI (match_operand 1 "arith_reg_operand" "")) (match_operand 2 "" ""))) (match_operand 3 "" "") - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (return)])] "" { @@ -9828,7 +10016,7 @@ label: (match_operand 3 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && ! (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))" "jsr @%1%#" @@ -9847,7 +10035,7 @@ label: (match_operand 3 "immediate_operand" "n") (use (reg:SI R0_REG)) (use (reg:SI R1_REG)) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (clobber (reg:SI R10_REG)) (clobber (reg:SI PR_REG))] "TARGET_SHCOMPACT && (INTVAL (operands[3]) & CALL_COOKIE_RET_TRAMP (1))" @@ -9924,7 +10112,8 @@ label: sh_expand_epilogue (true); if (TARGET_SHCOMPACT) { - rtx insn, set; + rtx_insn *insn; + rtx set; /* If epilogue clobbers r0, preserve it in macl. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) @@ -10006,6 +10195,18 @@ label: (match_operand 2 "" "")])] "(TARGET_SH2E || TARGET_SH2A) || TARGET_SHMEDIA" { + if (! TARGET_SHMEDIA) + { + /* RA does not know that the call sets the function value registers. + We avoid problems by claiming that those registers are clobbered + at this point. */ + for (int i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_clobber (SET_SRC (set)); + } + } + emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx)); for (int i = 0; i < XVECLEN (operands[2], 0); i++) @@ -10352,7 +10553,7 @@ label: (call:SI (mem:SI (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_TLSGD)) (const_int 0))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (clobber (reg:SI PR_REG)) (clobber (scratch:SI))] @@ -10379,7 +10580,7 @@ label: (call:SI (mem:SI (unspec:SI [(match_operand:SI 1 "" "")] UNSPEC_TLSLDM)) (const_int 0))) - (use (reg:PSI FPSCR_REG)) + (use (reg:SI FPSCR_MODES_REG)) (use (reg:SI PIC_REG)) (clobber (reg:SI PR_REG)) (clobber (scratch:SI))] @@ -10806,7 +11007,7 @@ label: (clobber (match_scratch:SI 3 "=X,1"))] "TARGET_SH1" { - rtx diff_vec = PATTERN (NEXT_INSN (operands[2])); + rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[2]))); gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); @@ -10840,7 +11041,7 @@ label: (clobber (match_operand:SI 4 "" "=X,1"))] "TARGET_SH2 && reload_completed && flag_pic" { - rtx diff_vec = PATTERN (NEXT_INSN (operands[2])); + rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[2]))); gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); switch (GET_MODE (diff_vec)) @@ -10878,7 +11079,7 @@ label: UNSPEC_CASESI)))] "TARGET_SHMEDIA" { - rtx diff_vec = PATTERN (NEXT_INSN (operands[2])); + rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[2]))); gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); @@ -10905,7 +11106,7 @@ label: (label_ref:DI (match_operand 3 "" ""))] UNSPEC_CASESI)))] "TARGET_SHMEDIA" { - rtx diff_vec = PATTERN (NEXT_INSN (operands[3])); + rtx diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[3]))); gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); @@ -11203,7 +11404,7 @@ label: (match_operand 3 "cmp_operand" "")]))] "TARGET_SHMEDIA" { - enum machine_mode mode = GET_MODE (operands[2]); + machine_mode mode = GET_MODE (operands[2]); enum rtx_code code = GET_CODE (operands[1]); bool invert, swap; if (mode == VOIDmode) @@ -11252,9 +11453,7 @@ label: if (swap) { - rtx tem = operands[2]; - operands[2] = operands[3]; - operands[3] = tem; + std::swap (operands[2], operands[3]); code = swap_condition (code); } @@ -11356,13 +11555,21 @@ label: DONE; }) -(define_insn "movrt_negc" +(define_insn_and_split "movrt_negc" [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1))) + (xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1))) (set (reg:SI T_REG) (const_int 1)) (use (match_operand:SI 2 "arith_reg_operand" "r"))] "TARGET_SH1" "negc %2,%0" + "&& 1" + [(const_int 0)] +{ + if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands)) + DONE; + else + FAIL; +} [(set_attr "type" "arith")]) ;; The -1 constant will not be CSE-ed for the *movrt_negc pattern, but the @@ -11371,17 +11578,25 @@ label: ;; generating a pseudo reg before reload. (define_insn_and_split "*movrt_negc" [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1))) + (xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1))) (clobber (match_scratch:SI 2 "=r")) (clobber (reg:SI T_REG))] "TARGET_SH1 && ! TARGET_SH2A" "#" - "&& reload_completed" - [(set (match_dup 2) (const_int -1)) - (parallel - [(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1))) - (set (reg:SI T_REG) (const_int 1)) - (use (match_dup 2))])]) + "&& 1" + [(const_int 0)] +{ + if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands)) + DONE; + else if (reload_completed) + { + emit_move_insn (operands[2], gen_int_mode (-1, SImode)); + emit_insn (gen_movrt_negc (operands[0], operands[1], operands[2])); + DONE; + } + else + FAIL; +}) ;; Store the negated T bit in a reg using r0 and xor. This one doesn't ;; clobber the T bit, which is useful when storing the T bit and the @@ -11392,48 +11607,15 @@ label: [(set (match_operand:SI 0 "arith_reg_dest" "=z") (xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1))) (use (reg:SI T_REG))] - "TARGET_SH1 && !TARGET_SH2A" + "TARGET_SH1" "#" "&& reload_completed" [(set (match_dup 0) (reg:SI T_REG)) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))]) -;; Store the T bit and the negated T bit in two regs in parallel. There is -;; no real insn to do that, but specifying this pattern will give combine -;; some opportunities. -(define_insn_and_split "*movt_movrt" - [(parallel [(set (match_operand:SI 0 "arith_reg_dest") - (match_operand:SI 1 "negt_reg_operand")) - (set (match_operand:SI 2 "arith_reg_dest") - (match_operand:SI 3 "t_reg_operand"))])] - "TARGET_SH1" - "#" - "&& 1" - [(const_int 0)] -{ - rtx i = TARGET_SH2A - ? gen_movrt (operands[0], get_t_reg_rtx ()) - : gen_movrt_xor (operands[0], get_t_reg_rtx ()); - - emit_insn (i); - emit_insn (gen_movt (operands[2], get_t_reg_rtx ())); - DONE; -}) - -(define_insn_and_split "*movt_movrt" - [(parallel [(set (match_operand:SI 0 "arith_reg_dest") - (match_operand:SI 1 "t_reg_operand")) - (set (match_operand:SI 2 "arith_reg_dest") - (match_operand:SI 3 "negt_reg_operand"))])] - "TARGET_SH1" - "#" - "&& 1" - [(parallel [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (match_dup 1))])]) - ;; Use negc to store the T bit in a MSB of a reg in the following way: -;; T = 1: 0x80000000 -> reg -;; T = 0: 0x7FFFFFFF -> reg +;; T = 0: 0x80000000 -> reg +;; T = 1: 0x7FFFFFFF -> reg ;; This works because 0 - 0x80000000 = 0x80000000. ;; ;; This insn must not match again after it has been split into the constant @@ -11466,27 +11648,27 @@ label: "negc %1,%0" [(set_attr "type" "arith")]) -;; These are essentially the same as above, but with the inverted T bit. -;; Combine recognizes the split patterns, but does not take them sometimes -;; if the T_REG clobber is specified. Instead it tries to split out the -;; T bit negation. Since these splits are supposed to be taken only by -;; combine, it will see the T_REG clobber of the *mov_t_msb_neg insn, so this -;; should be fine. -(define_split +(define_insn_and_split "*mov_t_msb_neg" [(set (match_operand:SI 0 "arith_reg_dest") (plus:SI (match_operand 1 "negt_reg_operand") - (const_int 2147483647)))] ;; 0x7fffffff - "TARGET_SH1 && can_create_pseudo_p ()" + (const_int 2147483647))) ;; 0x7fffffff + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" [(parallel [(set (match_dup 0) (minus:SI (const_int -2147483648) (reg:SI T_REG))) (clobber (reg:SI T_REG))])]) -(define_split +(define_insn_and_split "*mov_t_msb_neg" [(set (match_operand:SI 0 "arith_reg_dest") (if_then_else:SI (match_operand 1 "t_reg_operand") (const_int 2147483647) ;; 0x7fffffff - (const_int -2147483648)))] ;; 0x80000000 - "TARGET_SH1 && can_create_pseudo_p ()" + (const_int -2147483648))) ;; 0x80000000 + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" [(parallel [(set (match_dup 0) (minus:SI (const_int -2147483648) (reg:SI T_REG))) (clobber (reg:SI T_REG))])]) @@ -11568,34 +11750,34 @@ label: ;; Store inverted T bit as MSB in a reg. ;; T = 0: 0x80000000 -> reg ;; T = 1: 0x00000000 -> reg -;; On SH2A we can get away without clobbering the T_REG. +;; On SH2A we can get away without clobbering the T_REG using the movrt insn. +;; On non SH2A we resort to the following sequence: +;; movt Rn +;; tst Rn,Rn +;; rotcr Rn +;; The T bit value will be modified during the sequence, but the rotcr insn +;; will restore its original value. (define_insn_and_split "*negt_msb" [(set (match_operand:SI 0 "arith_reg_dest") (match_operand:SI 1 "negt_reg_shl31_operand"))] - "TARGET_SH2A" + "TARGET_SH1" "#" "&& can_create_pseudo_p ()" [(const_int 0)] { rtx tmp = gen_reg_rtx (SImode); - emit_insn (gen_movrt (tmp, get_t_reg_rtx ())); - emit_insn (gen_rotrsi3 (operands[0], tmp, const1_rtx)); - DONE; -}) -(define_insn_and_split "*negt_msb" - [(set (match_operand:SI 0 "arith_reg_dest") - (match_operand:SI 1 "negt_reg_shl31_operand")) - (clobber (reg:SI T_REG))] - "TARGET_SH1 && !TARGET_SH2A" - "#" - "&& can_create_pseudo_p ()" - [(const_int 0)] -{ - rtx tmp = gen_reg_rtx (SImode); - emit_move_insn (tmp, get_t_reg_rtx ()); - emit_insn (gen_cmpeqsi_t (tmp, const0_rtx)); - emit_insn (gen_rotcr (operands[0], tmp, get_t_reg_rtx ())); + if (TARGET_SH2A) + { + emit_insn (gen_movrt (tmp, get_t_reg_rtx ())); + emit_insn (gen_rotrsi3 (operands[0], tmp, const1_rtx)); + } + else + { + emit_move_insn (tmp, get_t_reg_rtx ()); + emit_insn (gen_cmpeqsi_t (tmp, const0_rtx)); + emit_insn (gen_rotcr (operands[0], tmp, get_t_reg_rtx ())); + } DONE; }) @@ -11624,14 +11806,22 @@ label: (define_insn "*cset_zero" [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (if_then_else:SI (match_operand:SI 1 "t_reg_operand") + (if_then_else:SI (match_operand:SI 1 "cbranch_treg_value") (match_operand:SI 2 "arith_reg_operand" "0") (const_int 0)))] "TARGET_SH1 && TARGET_ZDCBRANCH" { - return "bt 0f" "\n" - " mov #0,%0" "\n" - "0:"; + int tval = sh_eval_treg_value (operands[1]); + if (tval == true) + return "bt 0f" "\n" + " mov #0,%0" "\n" + "0:"; + else if (tval == false) + return "bf 0f" "\n" + " mov #0,%0" "\n" + "0:"; + else + gcc_unreachable (); } [(set_attr "type" "arith") ;; poor approximation (set_attr "length" "4")]) @@ -12089,83 +12279,86 @@ label: FAIL; }) +(define_expand "setmemqi" + [(parallel [(set (match_operand:BLK 0 "memory_operand") + (match_operand 2 "const_int_operand")) + (use (match_operand:QI 1 "const_int_operand")) + (use (match_operand:QI 3 "const_int_operand"))])] + "TARGET_SH1 && optimize" + { + if (optimize_insn_for_size_p ()) + FAIL; + + sh_expand_setmem (operands); + DONE; + }) + ;; ------------------------------------------------------------------------- ;; Floating point instructions. ;; ------------------------------------------------------------------------- -;; ??? All patterns should have a type attribute. - -(define_expand "movpsi" - [(set (match_operand:PSI 0 "register_operand" "") - (match_operand:PSI 1 "general_movsrc_operand" ""))] - "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" - "") - -;; The c / m alternative is a fake to guide reload to load directly into -;; fpscr, since reload doesn't know how to use post-increment. -;; TARGET_LEGITIMATE_ADDRESS_P guards about bogus addresses before reload, -;; SECONDARY_INPUT_RELOAD_CLASS does this during reload, and the insn's -;; predicate after reload. -;; The mac_gp type for r/!c might look a bit odd, but it actually schedules -;; like a mac -> gpr move. -(define_insn "fpu_switch" - [(set (match_operand:PSI 0 "general_movdst_operand" "=c,c,r,c,c,r,m,r,<") - (match_operand:PSI 1 "general_movsrc_operand" "c,>,m,m,r,r,r,!c,c"))] - "TARGET_SH2E - && (! reload_completed - || true_regnum (operands[0]) != FPSCR_REG - || !MEM_P (operands[1]) - || GET_CODE (XEXP (operands[1], 0)) != PLUS)" +;; FIXME: For now we disallow any memory operands for fpscr loads/stores, +;; except for post-inc loads and pre-dec stores for push/pop purposes. +;; This avoids problems with reload. As a consequence, user initiated fpscr +;; stores to memory will always be ferried through a general register. +;; User initiated fpscr loads always have to undergo bit masking to preserve +;; the current fpu mode settings for the compiler generated code. Thus such +;; fpscr loads will always have to go through general registers anyways. +(define_insn "lds_fpscr" + [(set (reg:SI FPSCR_REG) + (match_operand:SI 0 "fpscr_movsrc_operand" "r,>")) + (set (reg:SI FPSCR_STAT_REG) + (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_STAT)) + (set (reg:SI FPSCR_MODES_REG) + (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] + "TARGET_FPU_ANY" + "@ + lds %0,fpscr + lds.l %0,fpscr" + [(set_attr "type" "gp_fpscr,mem_fpscr")]) + +;; A move fpscr -> reg schedules like a move mac -> reg. Thus we use mac_gp +;; type for it. +(define_insn "sts_fpscr" + [(set (match_operand:SI 0 "fpscr_movdst_operand" "=r,<") + (reg:SI FPSCR_REG)) + (use (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_FPU_ANY" "@ - ! precision stays the same - lds.l %1,fpscr - mov.l %1,%0 - # - lds %1,fpscr - mov %1,%0 - mov.l %1,%0 sts fpscr,%0 sts.l fpscr,%0" - [(set_attr "length" "0,2,2,4,2,2,2,2,2") - (set_attr "type" "nil,mem_fpscr,load,mem_fpscr,gp_fpscr,move,store, - mac_gp,fstore")]) + [(set_attr "type" "mac_gp,fstore")]) -(define_peephole2 - [(set (reg:PSI FPSCR_REG) - (mem:PSI (match_operand:SI 0 "register_operand" "")))] - "(TARGET_SH4 || TARGET_SH2A_DOUBLE) && peep2_reg_dead_p (1, operands[0])" - [(const_int 0)] +(define_expand "set_fpscr" + [(parallel [(set (reg:SI FPSCR_REG) + (match_operand:SI 0 "general_operand")) + (set (reg:SI FPSCR_STAT_REG) + (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))])] + "TARGET_FPU_ANY" { - rtx fpscr, mem, new_insn; + /* We have to mask out the FR, SZ and PR bits. To do that, we need to + get the current FPSCR value first. + (a & ~mask) | (b & mask) = a ^ ((a ^ b) & mask) */ - fpscr = SET_DEST (PATTERN (curr_insn)); - mem = SET_SRC (PATTERN (curr_insn)); - mem = replace_equiv_address (mem, gen_rtx_POST_INC (Pmode, operands[0])); + rtx mask = force_reg (SImode, GEN_INT (FPSCR_FR | FPSCR_SZ | FPSCR_PR)); - new_insn = emit_insn (gen_fpu_switch (fpscr, mem)); - add_reg_note (new_insn, REG_INC, operands[0]); - DONE; -}) + rtx a = force_reg (SImode, operands[0]); -(define_split - [(set (reg:PSI FPSCR_REG) - (mem:PSI (match_operand:SI 0 "register_operand" "")))] - "(TARGET_SH4 || TARGET_SH2A_DOUBLE) - && (flag_peephole2 ? epilogue_completed : reload_completed)" - [(const_int 0)] -{ - rtx fpscr, mem, new_insn; + rtx b = gen_reg_rtx (SImode); + emit_insn (gen_sts_fpscr (b)); + + rtx a_xor_b = gen_reg_rtx (SImode); + emit_insn (gen_xorsi3 (a_xor_b, a, b)); - fpscr = SET_DEST (PATTERN (curr_insn)); - mem = SET_SRC (PATTERN (curr_insn)); - mem = replace_equiv_address (mem, gen_rtx_POST_INC (Pmode, operands[0])); + rtx a_xor_b_and_mask = gen_reg_rtx (SImode); + emit_insn (gen_andsi3 (a_xor_b_and_mask, a_xor_b, mask)); - new_insn = emit_insn (gen_fpu_switch (fpscr, mem)); - add_reg_note (new_insn, REG_INC, operands[0]); + rtx r = gen_reg_rtx (SImode); + emit_insn (gen_xorsi3 (r, a_xor_b_and_mask, a)); + emit_insn (gen_lds_fpscr (r)); - if (!find_regno_note (curr_insn, REG_DEAD, true_regnum (operands[0]))) - emit_insn (gen_addsi3 (operands[0], operands[0], GEN_INT (-4))); DONE; }) @@ -12176,21 +12369,22 @@ label: ;; it is probably best to claim no function unit, which matches the ;; current setting. (define_insn "toggle_sz" - [(set (reg:PSI FPSCR_REG) - (xor:PSI (reg:PSI FPSCR_REG) (const_int 1048576)))] + [(set (reg:SI FPSCR_REG) + (xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_SZ))) + (set (reg:SI FPSCR_MODES_REG) + (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fschg" [(set_attr "type" "fpscr_toggle") (set_attr "fp_set" "unknown")]) -;; There's no way we can use it today, since optimize mode switching -;; doesn't enable us to know from which mode we're switching to the -;; mode it requests, to tell whether we can use a relative mode switch -;; (like toggle_pr) or an absolute switch (like loading fpscr from -;; memory). +;; Toggle FPU precision PR mode. + (define_insn "toggle_pr" - [(set (reg:PSI FPSCR_REG) - (xor:PSI (reg:PSI FPSCR_REG) (const_int 524288)))] - "TARGET_SH4A_FP && ! TARGET_FPU_SINGLE" + [(set (reg:SI FPSCR_REG) + (xor:SI (reg:SI FPSCR_REG) (const_int FPSCR_PR))) + (set (reg:SI FPSCR_MODES_REG) + (unspec_volatile:SI [(const_int 0)] UNSPECV_FPSCR_MODES))] + "TARGET_SH4A_FP" "fpchg" [(set_attr "type" "fpscr_toggle")]) @@ -12202,7 +12396,7 @@ label: { if (TARGET_SH2E) { - expand_sf_binop (&gen_addsf3_i, operands); + emit_insn (gen_addsf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12301,7 +12495,8 @@ label: [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (plus:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0") (match_operand:SF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E" "fadd %2,%0" [(set_attr "type" "fp") @@ -12315,7 +12510,7 @@ label: { if (TARGET_SH2E) { - expand_sf_binop (&gen_subsf3_i, operands); + emit_insn (gen_subsf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12332,7 +12527,8 @@ label: [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (minus:SF (match_operand:SF 1 "fp_arith_reg_operand" "0") (match_operand:SF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E" "fsub %2,%0" [(set_attr "type" "fp") @@ -12346,8 +12542,7 @@ label: { if (TARGET_SH2E) { - emit_insn (gen_mulsf3_i (operands[0], operands[1], operands[2], - get_fpscr_rtx ())); + emit_insn (gen_mulsf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12364,7 +12559,8 @@ label: [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%0") (match_operand:SF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E" "fmul %2,%0" [(set_attr "type" "fp") @@ -12380,8 +12576,8 @@ label: { if (TARGET_SH2E) { - emit_sf_insn (gen_fmasf4_i (operands[0], operands[1], operands[2], - operands[3], get_fpscr_rtx ())); + emit_insn (gen_fmasf4_i (operands[0], operands[1], operands[2], + operands[3])); DONE; } }) @@ -12391,7 +12587,8 @@ label: (fma:SF (match_operand:SF 1 "fp_arith_reg_operand" "w") (match_operand:SF 2 "fp_arith_reg_operand" "f") (match_operand:SF 3 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 4 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E" "fmac %1,%2,%0" [(set_attr "type" "fp") @@ -12414,22 +12611,20 @@ label: (plus:SF (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%w") (match_operand:SF 2 "fp_arith_reg_operand" "f")) (match_operand:SF 3 "arith_reg_operand" "0"))) - (use (match_operand:PSI 4 "fpscr_operand"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E && flag_fp_contract_mode != FP_CONTRACT_OFF" "fmac %1,%2,%0" "&& can_create_pseudo_p ()" [(parallel [(set (match_dup 0) (fma:SF (match_dup 1) (match_dup 2) (match_dup 3))) - (use (match_dup 4))])] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))])] { /* Change 'b * a + a' into 'a * b + a'. This is better for register allocation. */ if (REGNO (operands[2]) == REGNO (operands[3])) - { - rtx tmp = operands[1]; - operands[1] = operands[2]; - operands[2] = tmp; - } + std::swap (operands[1], operands[2]); } [(set_attr "type" "fp") (set_attr "fp_mode" "single")]) @@ -12451,7 +12646,7 @@ label: { if (TARGET_SH2E) { - expand_sf_binop (&gen_divsf3_i, operands); + emit_insn (gen_divsf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12468,7 +12663,8 @@ label: [(set (match_operand:SF 0 "fp_arith_reg_dest" "=f") (div:SF (match_operand:SF 1 "fp_arith_reg_operand" "0") (match_operand:SF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH2E" "fdiv %2,%0" [(set_attr "type" "fdiv") @@ -12486,10 +12682,9 @@ label: (float:SF (match_operand:SI 1 "fpul_operand" "")))] "TARGET_SH2E || TARGET_SHMEDIA_FPU" { - if (TARGET_SH4 || TARGET_SH2A_SINGLE) + if (!TARGET_SHMEDIA_FPU) { - emit_sf_insn (gen_floatsisf2_i4 (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_floatsisf2_i4 (operands[0], operands[1])); DONE; } }) @@ -12504,19 +12699,13 @@ label: (define_insn "floatsisf2_i4" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (float:SF (match_operand:SI 1 "fpul_operand" "y"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] - "(TARGET_SH4 || TARGET_SH2A_SINGLE)" + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_SH2E" "float %1,%0" [(set_attr "type" "fp") (set_attr "fp_mode" "single")]) -(define_insn "*floatsisf2_ie" - [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") - (float:SF (match_operand:SI 1 "fpul_operand" "y")))] - "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)" - "float %1,%0" - [(set_attr "type" "fp")]) - (define_insn "fix_truncsfdi2" [(set (match_operand:DI 0 "fp_arith_reg_dest" "=f") (fix:DI (match_operand:SF 1 "fp_arith_reg_operand" "f")))] @@ -12529,10 +12718,9 @@ label: (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f")))] "TARGET_SH2E || TARGET_SHMEDIA_FPU" { - if (TARGET_SH4 || TARGET_SH2A_SINGLE) + if (!TARGET_SHMEDIA_FPU) { - emit_sf_insn (gen_fix_truncsfsi2_i4 (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_fix_truncsfsi2_i4 (operands[0], operands[1])); DONE; } }) @@ -12547,98 +12735,43 @@ label: (define_insn "fix_truncsfsi2_i4" [(set (match_operand:SI 0 "fpul_operand" "=y") (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] - "(TARGET_SH4 || TARGET_SH2A_SINGLE)" + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_SH2E" "ftrc %1,%0" [(set_attr "type" "ftrc_s") (set_attr "fp_mode" "single")]) -;; ??? This pattern is used nowhere. fix_truncsfsi2 always expands to -;; fix_truncsfsi2_i4. -;; (define_insn "fix_truncsfsi2_i4_2" -;; [(set (match_operand:SI 0 "arith_reg_operand" "=r") -;; (fix:SI (match_operand:SF 1 "arith_reg_operand" "f"))) -;; (use (reg:PSI FPSCR_REG)) -;; (clobber (reg:SI FPUL_REG))] -;; "TARGET_SH4" -;; "#" -;; [(set_attr "length" "4") -;; (set_attr "fp_mode" "single")]) - -;;(define_split -;; [(set (match_operand:SI 0 "arith_reg_operand" "=r") -;; (fix:SI (match_operand:SF 1 "arith_reg_operand" "f"))) -;; (use (match_operand:PSI 2 "fpscr_operand" "c")) -;; (clobber (reg:SI FPUL_REG))] -;; "TARGET_SH4" -;; [(parallel [(set (reg:SI FPUL_REG) (fix:SI (match_dup 1))) -;; (use (match_dup 2))]) -;; (set (match_dup 0) (reg:SI FPUL_REG))]) - -(define_insn "*fixsfsi" - [(set (match_operand:SI 0 "fpul_operand" "=y") - (fix:SI (match_operand:SF 1 "fp_arith_reg_operand" "f")))] - "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)" - "ftrc %1,%0" - [(set_attr "type" "fp")]) - (define_insn "cmpgtsf_t" [(set (reg:SI T_REG) (gt:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") - (match_operand:SF 1 "fp_arith_reg_operand" "f")))] - "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)" - "fcmp/gt %1,%0" - [(set_attr "type" "fp_cmp") - (set_attr "fp_mode" "single")]) - -(define_insn "cmpeqsf_t" - [(set (reg:SI T_REG) - (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") - (match_operand:SF 1 "fp_arith_reg_operand" "f")))] - "TARGET_SH2E && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)" - "fcmp/eq %1,%0" - [(set_attr "type" "fp_cmp") - (set_attr "fp_mode" "single")]) - -(define_insn "ieee_ccmpeqsf_t" - [(set (reg:SI T_REG) - (ior:SI (reg:SI T_REG) - (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") - (match_operand:SF 1 "fp_arith_reg_operand" "f"))))] - "TARGET_SH2E && TARGET_IEEE && ! (TARGET_SH4 || TARGET_SH2A_SINGLE)" -{ - return output_ieee_ccmpeq (insn, operands); -} - [(set_attr "length" "4")]) - - -(define_insn "cmpgtsf_t_i4" - [(set (reg:SI T_REG) - (gt:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") (match_operand:SF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] - "(TARGET_SH4 || TARGET_SH2A_SINGLE)" + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_SH2E || TARGET_SH4 || TARGET_SH2A_SINGLE" "fcmp/gt %1,%0" [(set_attr "type" "fp_cmp") (set_attr "fp_mode" "single")]) -(define_insn "cmpeqsf_t_i4" +(define_insn "cmpeqsf_t" [(set (reg:SI T_REG) (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") (match_operand:SF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] - "(TARGET_SH4 || TARGET_SH2A_SINGLE)" + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_SH2E || TARGET_SH4 || TARGET_SH2A_SINGLE" "fcmp/eq %1,%0" [(set_attr "type" "fp_cmp") (set_attr "fp_mode" "single")]) -(define_insn "*ieee_ccmpeqsf_t_4" +(define_insn "ieee_ccmpeqsf_t" [(set (reg:SI T_REG) (ior:SI (reg:SI T_REG) (eq:SI (match_operand:SF 0 "fp_arith_reg_operand" "f") (match_operand:SF 1 "fp_arith_reg_operand" "f")))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] - "TARGET_IEEE && (TARGET_SH4 || TARGET_SH2A_SINGLE)" + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] + "TARGET_IEEE && TARGET_SH2E" { return output_ieee_ccmpeq (insn, operands); } @@ -12695,16 +12828,9 @@ label: }) (define_expand "negsf2" - [(set (match_operand:SF 0 "fp_arith_reg_operand" "") - (neg:SF (match_operand:SF 1 "fp_arith_reg_operand" "")))] - "TARGET_SH2E || TARGET_SHMEDIA_FPU" -{ - if (TARGET_SH2E) - { - expand_sf_unop (&gen_negsf2_i, operands); - DONE; - } -}) + [(set (match_operand:SF 0 "fp_arith_reg_operand") + (neg:SF (match_operand:SF 1 "fp_arith_reg_operand")))] + "TARGET_SH2E || TARGET_SHMEDIA_FPU") (define_insn "*negsf2_media" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") @@ -12713,14 +12839,12 @@ label: "fneg.s %1, %0" [(set_attr "type" "fmove_media")]) -(define_insn "negsf2_i" +(define_insn "*negsf2_i" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") - (neg:SF (match_operand:SF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (neg:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))] "TARGET_SH2E" "fneg %0" - [(set_attr "type" "fmove") - (set_attr "fp_mode" "single")]) + [(set_attr "type" "fmove")]) (define_expand "sqrtsf2" [(set (match_operand:SF 0 "fp_arith_reg_operand" "") @@ -12729,7 +12853,7 @@ label: { if (TARGET_SH3E) { - expand_sf_unop (&gen_sqrtsf2_i, operands); + emit_insn (gen_sqrtsf2_i (operands[0], operands[1])); DONE; } }) @@ -12744,7 +12868,8 @@ label: (define_insn "sqrtsf2_i" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (sqrt:SF (match_operand:SF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_SH3E" "fsqrt %0" [(set_attr "type" "fdiv") @@ -12754,7 +12879,8 @@ label: [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") (div:SF (match_operand:SF 1 "immediate_operand" "i") (sqrt:SF (match_operand:SF 2 "fp_arith_reg_operand" "0")))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_FPU_ANY && TARGET_FSRRA && operands[1] == CONST1_RTX (SFmode)" "fsrra %0" @@ -12776,10 +12902,9 @@ label: rtx fsca = gen_reg_rtx (V2SFmode); rtx scale_reg = force_reg (SFmode, sh_fsca_sf2int ()); - emit_sf_insn (gen_mulsf3 (scaled, operands[2], scale_reg)); - emit_sf_insn (gen_fix_truncsfsi2 (truncated, scaled)); - emit_sf_insn (gen_fsca (fsca, truncated, sh_fsca_int2sf (), - get_fpscr_rtx ())); + emit_insn (gen_mulsf3 (scaled, operands[2], scale_reg)); + emit_insn (gen_fix_truncsfsi2 (truncated, scaled)); + emit_insn (gen_fsca (fsca, truncated, sh_fsca_int2sf ())); emit_move_insn (operands[0], gen_rtx_SUBREG (SFmode, fsca, 4)); emit_move_insn (operands[1], gen_rtx_SUBREG (SFmode, fsca, 0)); @@ -12795,7 +12920,8 @@ label: ] UNSPEC_FSINA) (unspec:SF [(mult:SF (float:SF (match_dup 1)) (match_dup 2)) ] UNSPEC_FCOSA))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_FPU_ANY && TARGET_FSCA" "fsca fpul,%d0" "&& !fpul_operand (operands[1], SImode)" @@ -12810,25 +12936,17 @@ label: gcc_assert (GET_CODE (x) == FIX || GET_CODE (x) == FLOAT); x = XEXP (x, 0); } - gcc_assert (x != NULL_RTX && fpul_operand (x, SImode)); - emit_insn (gen_fsca (operands[0], x, operands[2], operands[3])); + emit_insn (gen_fsca (operands[0], x, operands[2])); DONE; } [(set_attr "type" "fsca") (set_attr "fp_mode" "single")]) (define_expand "abssf2" - [(set (match_operand:SF 0 "fp_arith_reg_operand" "") - (abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "")))] - "TARGET_SH2E || TARGET_SHMEDIA_FPU" -{ - if (TARGET_SH2E) - { - expand_sf_unop (&gen_abssf2_i, operands); - DONE; - } -}) + [(set (match_operand:SF 0 "fp_arith_reg_operand") + (abs:SF (match_operand:SF 1 "fp_arith_reg_operand")))] + "TARGET_SH2E || TARGET_SHMEDIA_FPU") (define_insn "*abssf2_media" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") @@ -12837,14 +12955,12 @@ label: "fabs.s %1, %0" [(set_attr "type" "fmove_media")]) -(define_insn "abssf2_i" +(define_insn "*abssf2_i" [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") - (abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (abs:SF (match_operand:SF 1 "fp_arith_reg_operand" "0")))] "TARGET_SH2E" "fabs %0" - [(set_attr "type" "fmove") - (set_attr "fp_mode" "single")]) + [(set_attr "type" "fmove")]) (define_expand "adddf3" [(set (match_operand:DF 0 "fp_arith_reg_operand" "") @@ -12854,7 +12970,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - expand_df_binop (&gen_adddf3_i, operands); + emit_insn (gen_adddf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12871,7 +12987,8 @@ label: [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (plus:DF (match_operand:DF 1 "fp_arith_reg_operand" "%0") (match_operand:DF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fadd %2,%0" [(set_attr "type" "dfp_arith") @@ -12885,7 +13002,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - expand_df_binop (&gen_subdf3_i, operands); + emit_insn (gen_subdf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12902,7 +13019,8 @@ label: [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (minus:DF (match_operand:DF 1 "fp_arith_reg_operand" "0") (match_operand:DF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fsub %2,%0" [(set_attr "type" "dfp_arith") @@ -12916,7 +13034,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - expand_df_binop (&gen_muldf3_i, operands); + emit_insn (gen_muldf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12933,7 +13051,8 @@ label: [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (mult:DF (match_operand:DF 1 "fp_arith_reg_operand" "%0") (match_operand:DF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fmul %2,%0" [(set_attr "type" "dfp_mul") @@ -12947,7 +13066,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - expand_df_binop (&gen_divdf3_i, operands); + emit_insn (gen_divdf3_i (operands[0], operands[1], operands[2])); DONE; } }) @@ -12964,7 +13083,8 @@ label: [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (div:DF (match_operand:DF 1 "fp_arith_reg_operand" "0") (match_operand:DF 2 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 3 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fdiv %2,%0" [(set_attr "type" "dfdiv") @@ -12984,8 +13104,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - emit_df_insn (gen_floatsidf2_i (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_floatsidf2_i (operands[0], operands[1])); DONE; } }) @@ -13000,7 +13119,8 @@ label: (define_insn "floatsidf2_i" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (float:DF (match_operand:SI 1 "fpul_operand" "y"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "float %1,%0" [(set_attr "type" "dfp_conv") @@ -13020,8 +13140,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - emit_df_insn (gen_fix_truncdfsi2_i (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_fix_truncdfsi2_i (operands[0], operands[1])); DONE; } }) @@ -13036,40 +13155,20 @@ label: (define_insn "fix_truncdfsi2_i" [(set (match_operand:SI 0 "fpul_operand" "=y") (fix:SI (match_operand:DF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "ftrc %1,%0" [(set_attr "type" "dfp_conv") (set_attr "dfp_comp" "no") (set_attr "fp_mode" "double")]) -;; ??? This pattern is used nowhere. fix_truncdfsi2 always expands to -;; fix_truncdfsi2_i. -;; (define_insn "fix_truncdfsi2_i4" -;; [(set (match_operand:SI 0 "arith_reg_operand" "=r") -;; (fix:SI (match_operand:DF 1 "arith_reg_operand" "f"))) -;; (use (match_operand:PSI 2 "fpscr_operand" "c")) -;; (clobber (reg:SI FPUL_REG))] -;; "TARGET_SH4" -;; "#" -;; [(set_attr "length" "4") -;; (set_attr "fp_mode" "double")]) -;; -;; (define_split -;; [(set (match_operand:SI 0 "arith_reg_operand" "=r") -;; (fix:SI (match_operand:DF 1 "arith_reg_operand" "f"))) -;; (use (match_operand:PSI 2 "fpscr_operand" "c")) -;; (clobber (reg:SI FPUL_REG))] -;; "TARGET_SH4" -;; [(parallel [(set (reg:SI FPUL_REG) (fix:SI (match_dup 1))) -;; (use (match_dup 2))]) -;; (set (match_dup 0) (reg:SI FPUL_REG))]) - (define_insn "cmpgtdf_t" [(set (reg:SI T_REG) (gt:SI (match_operand:DF 0 "fp_arith_reg_operand" "f") (match_operand:DF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fcmp/gt %1,%0" [(set_attr "type" "dfp_cmp") @@ -13079,7 +13178,8 @@ label: [(set (reg:SI T_REG) (eq:SI (match_operand:DF 0 "fp_arith_reg_operand" "f") (match_operand:DF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fcmp/eq %1,%0" [(set_attr "type" "dfp_cmp") @@ -13090,7 +13190,8 @@ label: (ior:SI (reg:SI T_REG) (eq:SI (match_operand:DF 0 "fp_arith_reg_operand" "f") (match_operand:DF 1 "fp_arith_reg_operand" "f")))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "TARGET_IEEE && (TARGET_SH4 || TARGET_SH2A_DOUBLE)" { return output_ieee_ccmpeq (insn, operands); @@ -13150,14 +13251,7 @@ label: (define_expand "negdf2" [(set (match_operand:DF 0 "fp_arith_reg_operand") (neg:DF (match_operand:DF 1 "fp_arith_reg_operand")))] - "(TARGET_SH4 || TARGET_SH2A_DOUBLE) || TARGET_SHMEDIA_FPU" -{ - if (TARGET_SH4 || TARGET_SH2A_DOUBLE) - { - expand_df_unop (&gen_negdf2_i, operands); - DONE; - } -}) + "(TARGET_SH4 || TARGET_SH2A_DOUBLE) || TARGET_SHMEDIA_FPU") (define_insn "*negdf2_media" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") @@ -13166,14 +13260,12 @@ label: "fneg.d %1, %0" [(set_attr "type" "fmove_media")]) -(define_insn "negdf2_i" +(define_insn "*negdf2_i" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") - (neg:DF (match_operand:DF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (neg:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fneg %0" - [(set_attr "type" "fmove") - (set_attr "fp_mode" "double")]) + [(set_attr "type" "fmove")]) (define_expand "sqrtdf2" [(set (match_operand:DF 0 "fp_arith_reg_operand") @@ -13182,7 +13274,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - expand_df_unop (&gen_sqrtdf2_i, operands); + emit_insn (gen_sqrtdf2_i (operands[0], operands[1])); DONE; } }) @@ -13197,7 +13289,8 @@ label: (define_insn "sqrtdf2_i" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (sqrt:DF (match_operand:DF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fsqrt %0" [(set_attr "type" "dfdiv") @@ -13206,14 +13299,7 @@ label: (define_expand "absdf2" [(set (match_operand:DF 0 "fp_arith_reg_operand") (abs:DF (match_operand:DF 1 "fp_arith_reg_operand")))] - "(TARGET_SH4 || TARGET_SH2A_DOUBLE) || TARGET_SHMEDIA_FPU" -{ - if (TARGET_SH4 || TARGET_SH2A_DOUBLE) - { - expand_df_unop (&gen_absdf2_i, operands); - DONE; - } -}) + "(TARGET_SH4 || TARGET_SH2A_DOUBLE) || TARGET_SHMEDIA_FPU") (define_insn "*absdf2_media" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") @@ -13222,14 +13308,12 @@ label: "fabs.d %1, %0" [(set_attr "type" "fmove_media")]) -(define_insn "absdf2_i" +(define_insn "*absdf2_i" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") - (abs:DF (match_operand:DF 1 "fp_arith_reg_operand" "0"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (abs:DF (match_operand:DF 1 "fp_arith_reg_operand" "0")))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fabs %0" - [(set_attr "type" "fmove") - (set_attr "fp_mode" "double")]) + [(set_attr "type" "fmove")]) (define_expand "extendsfdf2" [(set (match_operand:DF 0 "fp_arith_reg_operand" "") @@ -13238,8 +13322,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - emit_df_insn (gen_extendsfdf2_i4 (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_extendsfdf2_i4 (operands[0], operands[1])); DONE; } }) @@ -13254,7 +13337,8 @@ label: (define_insn "extendsfdf2_i4" [(set (match_operand:DF 0 "fp_arith_reg_operand" "=f") (float_extend:DF (match_operand:SF 1 "fpul_operand" "y"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fcnvsd %1,%0" [(set_attr "type" "fp") @@ -13267,8 +13351,7 @@ label: { if (TARGET_SH4 || TARGET_SH2A_DOUBLE) { - emit_df_insn (gen_truncdfsf2_i4 (operands[0], operands[1], - get_fpscr_rtx ())); + emit_insn (gen_truncdfsf2_i4 (operands[0], operands[1])); DONE; } }) @@ -13283,7 +13366,8 @@ label: (define_insn "truncdfsf2_i4" [(set (match_operand:SF 0 "fpul_operand" "=y") (float_truncate:SF (match_operand:DF 1 "fp_arith_reg_operand" "f"))) - (use (match_operand:PSI 2 "fpscr_operand" "c"))] + (clobber (reg:SI FPSCR_STAT_REG)) + (use (reg:SI FPSCR_MODES_REG))] "(TARGET_SH4 || TARGET_SH2A_DOUBLE)" "fcnvds %1,%0" [(set_attr "type" "fp") @@ -13390,7 +13474,7 @@ label: [(set (match_operand:SI 0 "register_operand" "=z") (unspec:SI [(match_operand:BLK 1 "unaligned_load_operand" "Sua>")] UNSPEC_MOVUA))] - "TARGET_SH4A_ARCH" + "TARGET_SH4A" "movua.l %1,%0" [(set_attr "type" "movua")]) @@ -13403,7 +13487,7 @@ label: (sign_extract:SI (mem:SI (match_operand:SI 1 "register_operand" "")) (const_int 32) (const_int 0))) (set (match_dup 1) (plus:SI (match_dup 1) (const_int 4)))] - "TARGET_SH4A_ARCH && REGNO (operands[0]) != REGNO (operands[1])" + "TARGET_SH4A && REGNO (operands[0]) != REGNO (operands[1])" [(set (match_operand:SI 0 "register_operand" "") (sign_extract:SI (mem:SI (post_inc:SI (match_operand:SI 1 "register_operand" ""))) @@ -13415,7 +13499,7 @@ label: (sign_extract:SI (match_operand:QI 1 "unaligned_load_operand" "") (match_operand 2 "const_int_operand" "") (match_operand 3 "const_int_operand" "")))] - "TARGET_SH4A_ARCH || TARGET_SH2A" + "TARGET_SH4A || TARGET_SH2A" { if (TARGET_SH2A && TARGET_BITOPS && (satisfies_constraint_Sbw (operands[1]) @@ -13428,7 +13512,7 @@ label: emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG))); DONE; } - if (TARGET_SH4A_ARCH + if (TARGET_SH4A && INTVAL (operands[2]) == 32 && INTVAL (operands[3]) == 0 && MEM_P (operands[1]) && MEM_ALIGN (operands[1]) < 32) @@ -13447,7 +13531,7 @@ label: (zero_extract:SI (match_operand:QI 1 "unaligned_load_operand" "") (match_operand 2 "const_int_operand" "") (match_operand 3 "const_int_operand" "")))] - "TARGET_SH4A_ARCH || TARGET_SH2A" + "TARGET_SH4A || TARGET_SH2A" { if (TARGET_SH2A && TARGET_BITOPS && (satisfies_constraint_Sbw (operands[1]) @@ -13460,7 +13544,7 @@ label: emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG))); DONE; } - if (TARGET_SH4A_ARCH + if (TARGET_SH4A && INTVAL (operands[2]) == 32 && INTVAL (operands[3]) == 0 && MEM_P (operands[1]) && MEM_ALIGN (operands[1]) < 32) @@ -14032,7 +14116,7 @@ label: [(set (match_dup 0) (match_dup 1))] { rtx v = operands[1]; - enum machine_mode new_mode + machine_mode new_mode = mode_for_size (GET_MODE_BITSIZE (GET_MODE (v)), MODE_INT, 0); operands[0] = gen_rtx_REG (new_mode, true_regnum (operands[0])); @@ -15121,7 +15205,7 @@ label: [(set (match_dup 0) (match_dup 3))] { rtx count = operands[2]; - enum machine_mode outer_mode = GET_MODE (operands[2]), inner_mode; + machine_mode outer_mode = GET_MODE (operands[2]), inner_mode; while (GET_CODE (count) == ZERO_EXTEND || GET_CODE (count) == SIGN_EXTEND || (GET_CODE (count) == SUBREG && SUBREG_BYTE (count) == 0) @@ -15801,10 +15885,7 @@ label: "TARGET_SHMEDIA && reload_completed" [(set (match_dup 0) (match_dup 1))] { - int n_changes = 0; - - for_each_rtx (&operands[1], shmedia_cleanup_truncate, &n_changes); - if (!n_changes) + if (!shmedia_cleanup_truncate (operands[1])) FAIL; }) diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt index 1834c6bde97..6e4ab862a4d 100644 --- a/gcc/config/sh/sh.opt +++ b/gcc/config/sh/sh.opt @@ -1,6 +1,6 @@ ; Options for the SH port of the compiler. -; Copyright (C) 2005-2014 Free Software Foundation, Inc. +; Copyright (C) 2005-2015 Free Software Foundation, Inc. ; ; This file is part of GCC. ; @@ -343,7 +343,7 @@ Target RejectNegative Joined UInteger Var(sh_multcost) Init(-1) Cost to assume for a multiply insn musermode -Target Report RejectNegative Var(TARGET_USERMODE) +Target Var(TARGET_USERMODE) Don't generate privileged-mode only code; implies -mno-inline-ic_invalidate if the inline code would not work in user mode. ;; We might want to enable this by default for TARGET_HARD_SH4, because @@ -360,3 +360,6 @@ mfsrra Target Var(TARGET_FSRRA) Enable the use of the fsrra instruction +mlra +Target Report Var(sh_lra_flag) Init(0) Save +Use LRA instead of reload (transitional) diff --git a/gcc/config/sh/sh1.md b/gcc/config/sh/sh1.md index 08b2124474a..64b6cf6e800 100644 --- a/gcc/config/sh/sh1.md +++ b/gcc/config/sh/sh1.md @@ -1,5 +1,5 @@ ;; DFA scheduling description for Renesas / SuperH SH. -;; Copyright (C) 2004-2014 Free Software Foundation, Inc. +;; Copyright (C) 2004-2015 Free Software Foundation, Inc. ;; This file is part of GCC. diff --git a/gcc/config/sh/sh4-300.md b/gcc/config/sh/sh4-300.md index c0c0a5c554b..b41f1cc061a 100644 --- a/gcc/config/sh/sh4-300.md +++ b/gcc/config/sh/sh4-300.md @@ -1,5 +1,5 @@ ;; DFA scheduling description for ST40-300. -;; Copyright (C) 2004-2014 Free Software Foundation, Inc. +;; Copyright (C) 2004-2015 Free Software Foundation, Inc. ;; This file is part of GCC. diff --git a/gcc/config/sh/sh4.md b/gcc/config/sh/sh4.md index 0ff6a0b5711..6009d6d67f0 100644 --- a/gcc/config/sh/sh4.md +++ b/gcc/config/sh/sh4.md @@ -1,5 +1,5 @@ ;; DFA scheduling description for SH4. -;; Copyright (C) 2004-2014 Free Software Foundation, Inc. +;; Copyright (C) 2004-2015 Free Software Foundation, Inc. ;; This file is part of GCC. diff --git a/gcc/config/sh/sh4a.md b/gcc/config/sh/sh4a.md index 694185181f5..1446148ace3 100644 --- a/gcc/config/sh/sh4a.md +++ b/gcc/config/sh/sh4a.md @@ -1,5 +1,5 @@ ;; Scheduling description for Renesas SH4a -;; Copyright (C) 2003-2014 Free Software Foundation, Inc. +;; Copyright (C) 2003-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; diff --git a/gcc/config/sh/sh64.h b/gcc/config/sh/sh64.h index 73d91caa39d..2897d8318db 100644 --- a/gcc/config/sh/sh64.h +++ b/gcc/config/sh/sh64.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler for SuperH SH 5. - Copyright (C) 2000-2014 Free Software Foundation, Inc. + Copyright (C) 2000-2015 Free Software Foundation, Inc. Contributed by Alexandre Oliva <aoliva@redhat.com> This file is part of GCC. diff --git a/gcc/config/sh/sh_optimize_sett_clrt.cc b/gcc/config/sh/sh_optimize_sett_clrt.cc index 313e5b5f4c2..4324506ce79 100644 --- a/gcc/config/sh/sh_optimize_sett_clrt.cc +++ b/gcc/config/sh/sh_optimize_sett_clrt.cc @@ -1,5 +1,5 @@ /* An SH specific RTL pass that tries to optimize clrt and sett insns. - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -21,6 +21,21 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "machmode.h" +#include "predict.h" +#include "vec.h" +#include "hashtab.h" +#include "hash-set.h" +#include "tm.h" +#include "hard-reg-set.h" +#include "input.h" +#include "function.h" +#include "dominance.h" +#include "cfg.h" +#include "cfgrtl.h" +#include "cfganal.h" +#include "lcm.h" +#include "cfgbuild.h" +#include "cfgcleanup.h" #include "basic-block.h" #include "df.h" #include "rtl.h" @@ -79,8 +94,8 @@ class sh_optimize_sett_clrt : public rtl_opt_pass public: sh_optimize_sett_clrt (gcc::context* ctx, const char* name); virtual ~sh_optimize_sett_clrt (void); - virtual bool gate (void); - virtual unsigned int execute (void); + virtual bool gate (function*); + virtual unsigned int execute (function* fun); private: static const pass_data default_pass_data; @@ -88,9 +103,9 @@ private: struct ccreg_value { // The insn at which the ccreg value was determined. - // Might be NULL_RTX if e.g. an unknown value is recorded for an + // Might be NULL if e.g. an unknown value is recorded for an // empty basic block. - rtx insn; + rtx_insn *insn; // The basic block where the insn was discovered. basic_block bb; @@ -111,14 +126,14 @@ private: // Given a start insn and its basic block, recursively determine all // possible ccreg values in all basic block paths that can lead to the // start insn. - void find_last_ccreg_values (rtx start_insn, basic_block bb, + bool find_last_ccreg_values (rtx_insn *start_insn, basic_block bb, std::vector<ccreg_value>& values_out, std::vector<basic_block>& prev_visited_bb) const; // Given a cbranch insn, its basic block and another basic block, determine // the value to which the ccreg will be set after jumping/falling through to // the specified target basic block. - bool sh_cbranch_ccreg_value (rtx cbranch_insn, + bool sh_cbranch_ccreg_value (rtx_insn *cbranch_insn, basic_block cbranch_insn_bb, basic_block branch_target_bb) const; @@ -138,8 +153,6 @@ const pass_data sh_optimize_sett_clrt::default_pass_data = RTL_PASS, // type "", // name (overwritten by the constructor) OPTGROUP_NONE, // optinfo_flags - true, // has_gate - true, // has_execute TV_OPTIMIZE, // tv_id 0, // properties_required 0, // properties_provided @@ -162,13 +175,13 @@ sh_optimize_sett_clrt::~sh_optimize_sett_clrt (void) } bool -sh_optimize_sett_clrt::gate (void) +sh_optimize_sett_clrt::gate (function*) { return optimize > 0; } unsigned int -sh_optimize_sett_clrt::execute (void) +sh_optimize_sett_clrt::execute (function* fun) { unsigned int ccr0 = INVALID_REGNUM; unsigned int ccr1 = INVALID_REGNUM; @@ -206,8 +219,8 @@ sh_optimize_sett_clrt::execute (void) // Look for insns that set the ccreg to a constant value and see if it can // be optimized. basic_block bb; - FOR_EACH_BB_REVERSE_FN (bb, cfun) - for (rtx next_i, i = NEXT_INSN (BB_HEAD (bb)); + FOR_EACH_BB_REVERSE_FN (bb, fun) + for (rtx_insn *next_i, *i = NEXT_INSN (BB_HEAD (bb)); i != NULL_RTX && i != BB_END (bb); i = next_i) { next_i = NEXT_INSN (i); @@ -226,8 +239,8 @@ sh_optimize_sett_clrt::execute (void) ccreg_values.clear (); visited_bbs.clear (); - find_last_ccreg_values (PREV_INSN (i), bb, ccreg_values, - visited_bbs); + bool ok = find_last_ccreg_values (PREV_INSN (i), bb, ccreg_values, + visited_bbs); log_msg ("number of ccreg values collected: %u\n", (unsigned int)ccreg_values.size ()); @@ -235,7 +248,7 @@ sh_optimize_sett_clrt::execute (void) // If all the collected values are equal and are equal to the // constant value of the setcc insn, the setcc insn can be // removed. - if (all_ccreg_values_equal (ccreg_values) + if (ok && all_ccreg_values_equal (ccreg_values) && rtx_equal_p (ccreg_values.front ().value, setcc_val)) { log_msg ("all values are "); @@ -278,7 +291,7 @@ sh_optimize_sett_clrt::const_setcc_value (rtx pat) const bool sh_optimize_sett_clrt -::sh_cbranch_ccreg_value (rtx cbranch_insn, basic_block cbranch_insn_bb, +::sh_cbranch_ccreg_value (rtx_insn *cbranch_insn, basic_block cbranch_insn_bb, basic_block branch_target_bb) const { rtx pc_set_rtx = pc_set (cbranch_insn); @@ -309,9 +322,9 @@ sh_optimize_sett_clrt gcc_unreachable (); } -void +bool sh_optimize_sett_clrt -::find_last_ccreg_values (rtx start_insn, basic_block bb, +::find_last_ccreg_values (rtx_insn *start_insn, basic_block bb, std::vector<ccreg_value>& values_out, std::vector<basic_block>& prev_visited_bb) const { @@ -324,7 +337,7 @@ sh_optimize_sett_clrt log_msg ("(prev visited [bb %d])", prev_visited_bb.back ()->index); log_msg ("\n"); - for (rtx i = start_insn; i != NULL_RTX && i != PREV_INSN (BB_HEAD (bb)); + for (rtx_insn *i = start_insn; i != NULL && i != PREV_INSN (BB_HEAD (bb)); i = PREV_INSN (i)) { if (!INSN_P (i)) @@ -348,7 +361,7 @@ sh_optimize_sett_clrt log_msg ("\n"); values_out.push_back (v); - return; + return true; } if (any_condjump_p (i) && onlyjump_p (i) && !prev_visited_bb.empty ()) @@ -372,7 +385,7 @@ sh_optimize_sett_clrt log_msg ("\n"); values_out.push_back (v); - return; + return true; } } @@ -393,10 +406,14 @@ sh_optimize_sett_clrt for (edge_iterator ei = ei_start (bb->preds); !ei_end_p (ei); ei_next (&ei)) { + if (ei_edge (ei)->flags & EDGE_COMPLEX) + log_return (false, "aborting due to complex edge\n"); + basic_block pred_bb = ei_edge (ei)->src; pred_bb_count += 1; - find_last_ccreg_values (BB_END (pred_bb), pred_bb, values_out, - prev_visited_bb); + if (!find_last_ccreg_values (BB_END (pred_bb), pred_bb, values_out, + prev_visited_bb)) + return false; } prev_visited_bb.pop_back (); @@ -419,6 +436,8 @@ sh_optimize_sett_clrt values_out.push_back (v); } + + return true; } bool diff --git a/gcc/config/sh/sh_treg_combine.cc b/gcc/config/sh/sh_treg_combine.cc index e7360402251..e4f3581099c 100644 --- a/gcc/config/sh/sh_treg_combine.cc +++ b/gcc/config/sh/sh_treg_combine.cc @@ -1,6 +1,6 @@ /* An SH specific RTL pass that tries to combine comparisons and redundant condition code register stores across multiple basic blocks. - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -22,6 +22,21 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "machmode.h" +#include "predict.h" +#include "vec.h" +#include "hashtab.h" +#include "hash-set.h" +#include "tm.h" +#include "hard-reg-set.h" +#include "input.h" +#include "function.h" +#include "dominance.h" +#include "cfg.h" +#include "cfgrtl.h" +#include "cfganal.h" +#include "lcm.h" +#include "cfgbuild.h" +#include "cfgcleanup.h" #include "basic-block.h" #include "df.h" #include "rtl.h" @@ -31,6 +46,23 @@ along with GCC; see the file COPYING3. If not see #include "recog.h" #include "tree-pass.h" #include "target.h" +#include "symtab.h" +#include "inchash.h" +#include "tree.h" +#include "optabs.h" +#include "flags.h" +#include "statistics.h" +#include "double-int.h" +#include "real.h" +#include "fixed-value.h" +#include "alias.h" +#include "wide-int.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "calls.h" +#include "varasm.h" +#include "stmt.h" #include "expr.h" #include <algorithm> @@ -78,14 +110,17 @@ Example 1) In [bb 4] elimination of the comparison would require inversion of the branch condition and compensation of other BBs. -Instead an inverting reg-move can be used: +Instead the comparison in [bb 3] can be replaced with the comparison in [bb 5] +by using a reg-reg move. In [bb 4] a logical not is used to compensate the +inverted condition. [bb 3] (set (reg:SI 167) (reg:SI 173)) -> bb 5 [BB 4] -(set (reg:SI 167) (not:SI (reg:SI 177))) +(set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0))) +(set (reg:SI 167) (reg:SI 147 t)) -> bb 5 [bb 5] @@ -214,9 +249,9 @@ In order to handle cases such as above the RTL pass does the following: and replace the comparisons in the BBs with reg-reg copies to get the operands in place (create new pseudo regs). - - If the cstores differ, try to apply the special case - (eq (reg) (const_int 0)) -> inverted = (not (reg)). - for the subordinate cstore types and eliminate the dominating ones. + - If the cstores differ and the comparison is a test against zero, + use reg-reg copies for the dominating cstores and logical not cstores + for the subordinate cstores. - If the comparison types in the BBs are not the same, or the first approach doesn't work out for some reason, try to eliminate the comparison before the @@ -250,8 +285,8 @@ In order to handle cases such as above the RTL pass does the following: struct set_of_reg { - // The insn where the search stopped or NULL_RTX. - rtx insn; + // The insn where the search stopped or NULL. + rtx_insn *insn; // The set rtx of the specified reg if found, NULL_RTX otherwise. // Notice that the set rtx can also be in a parallel. @@ -281,14 +316,14 @@ struct set_of_reg // Given a reg rtx and a start insn find the insn (in the same basic block) // that sets the reg. static set_of_reg -find_set_of_reg_bb (rtx reg, rtx insn) +find_set_of_reg_bb (rtx reg, rtx_insn *insn) { set_of_reg result = { insn, NULL_RTX }; - if (!REG_P (reg) || insn == NULL_RTX) + if (!REG_P (reg) || insn == NULL) return result; - for (result.insn = insn; result.insn != NULL_RTX; + for (result.insn = insn; result.insn != NULL; result.insn = prev_nonnote_insn_bb (result.insn)) { if (BARRIER_P (result.insn)) @@ -338,7 +373,7 @@ is_adjacent_bb (basic_block a, basic_block b) // Internal function of trace_reg_uses. static void -trace_reg_uses_1 (rtx reg, rtx start_insn, basic_block bb, int& count, +trace_reg_uses_1 (rtx reg, rtx_insn *start_insn, basic_block bb, int& count, std::vector<basic_block>& visited_bb, rtx abort_at_insn) { if (bb == NULL) @@ -360,7 +395,7 @@ trace_reg_uses_1 (rtx reg, rtx start_insn, basic_block bb, int& count, if (end_insn == NULL_RTX) log_return_void ("[bb %d] end_insn is null\n", bb->index); - for (rtx i = NEXT_INSN (start_insn); i != end_insn; i = NEXT_INSN (i)) + for (rtx_insn *i = NEXT_INSN (start_insn); i != end_insn; i = NEXT_INSN (i)) { if (INSN_P (i)) { @@ -396,7 +431,7 @@ trace_reg_uses_1 (rtx reg, rtx start_insn, basic_block bb, int& count, // that insn. If the insn 'abort_at_insn' uses the specified reg, it is also // counted. static int -trace_reg_uses (rtx reg, rtx start_insn, rtx abort_at_insn) +trace_reg_uses (rtx reg, rtx_insn *start_insn, rtx abort_at_insn) { log_msg ("\ntrace_reg_uses\nreg = "); log_rtx (reg); @@ -412,6 +447,16 @@ trace_reg_uses (rtx reg, rtx start_insn, rtx abort_at_insn) return count; } +static bool +is_conditional_insn (rtx_insn* i) +{ + if (! (INSN_P (i) && NONDEBUG_INSN_P (i))) + return false; + + rtx p = PATTERN (i); + return GET_CODE (p) == SET && GET_CODE (XEXP (p, 1)) == IF_THEN_ELSE; +} + // FIXME: Remove dependency on SH predicate function somehow. extern int t_reg_operand (rtx, machine_mode); extern int negt_reg_operand (rtx, machine_mode); @@ -424,8 +469,8 @@ class sh_treg_combine : public rtl_opt_pass public: sh_treg_combine (gcc::context* ctx, bool split_insns, const char* name); virtual ~sh_treg_combine (void); - virtual bool gate (void); - virtual unsigned int execute (void); + virtual bool gate (function *); + virtual unsigned int execute (function *); private: // Type of ccreg store that is supported. @@ -463,7 +508,8 @@ private: // A ccreg trace for a conditional branch. struct cbranch_trace { - rtx cbranch_insn; + rtx_insn *cbranch_insn; + rtx* condition_rtx_in_insn; branch_condition_type_t cbranch_type; // The comparison against zero right before the conditional branch. @@ -473,11 +519,16 @@ private: // the BB of the cbranch itself and might be empty. std::list<bb_entry> bb_entries; - cbranch_trace (rtx insn) + cbranch_trace (rtx_insn *insn) : cbranch_insn (insn), + condition_rtx_in_insn (NULL), cbranch_type (unknown_branch_condition), setcc () { + if (is_conditional_insn (cbranch_insn)) + condition_rtx_in_insn = &XEXP (XEXP (PATTERN (cbranch_insn), 1), 0); + else if (rtx x = pc_set (cbranch_insn)) + condition_rtx_in_insn = &XEXP (XEXP (x, 1), 0); } basic_block bb (void) const { return BLOCK_FOR_INSN (cbranch_insn); } @@ -485,8 +536,16 @@ private: rtx branch_condition_rtx (void) const { - rtx x = pc_set (cbranch_insn); - return x == NULL_RTX ? NULL_RTX : XEXP (XEXP (x, 1), 0); + return condition_rtx_in_insn != NULL ? *condition_rtx_in_insn : NULL; + } + rtx& + branch_condition_rtx_ref (void) const + { + // Before anything gets to invoke this function, there are other checks + // in place to make sure that we have a known branch condition and thus + // the ref to the rtx in the insn. + gcc_assert (condition_rtx_in_insn != NULL); + return *condition_rtx_in_insn; } bool @@ -537,7 +596,8 @@ private: set_not_found, other_set_found }; - record_return_t record_set_of_reg (rtx reg, rtx start_insn, bb_entry& e); + record_return_t record_set_of_reg (rtx reg, rtx_insn *start_insn, + bb_entry& e); // Tells whether the cbranch insn of the specified bb_entry can be removed // safely without triggering any side effects. @@ -558,11 +618,12 @@ private: bool can_extend_ccreg_usage (const bb_entry& e, const cbranch_trace& trace) const; - // Create an insn rtx that is a negating reg move (not operation). + // Create an insn rtx that performs a logical not (test != 0) on the src_reg + // and stores the result in dst_reg. rtx make_not_reg_insn (rtx dst_reg, rtx src_reg) const; // Create an insn rtx that inverts the ccreg. - rtx make_inv_ccreg_insn (void) const; + rtx_insn *make_inv_ccreg_insn (void) const; // Adds the specified insn to the set of modified or newly added insns that // might need splitting at the end of the pass. @@ -584,7 +645,7 @@ private: // Given a branch insn, try to optimize its branch condition. // If any insns are modified or added they are added to 'm_touched_insns'. - void try_optimize_cbranch (rtx i); + void try_optimize_cbranch (rtx_insn *i); }; @@ -593,15 +654,12 @@ const pass_data sh_treg_combine::default_pass_data = RTL_PASS, // type "", // name (overwritten by the constructor) OPTGROUP_NONE, // optinfo_flags - true, // has_gate - true, // has_execute TV_OPTIMIZE, // tv_id 0, // properties_required 0, // properties_provided 0, // properties_destroyed 0, // todo_flags_start TODO_df_finish | TODO_df_verify // todo_flags_finish - | TODO_verify_rtl_sharing }; sh_treg_combine::sh_treg_combine (gcc::context* ctx, bool split_insns, @@ -673,7 +731,7 @@ sh_treg_combine::is_inverted_ccreg (const_rtx x) const } sh_treg_combine::record_return_t -sh_treg_combine::record_set_of_reg (rtx reg, rtx start_insn, +sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn, bb_entry& new_entry) { log_msg ("\n[bb %d]\n", new_entry.bb->index); @@ -683,7 +741,7 @@ sh_treg_combine::record_set_of_reg (rtx reg, rtx start_insn, new_entry.cstore_type = cstore_unknown; - for (rtx i = start_insn; i != NULL_RTX; ) + for (rtx_insn *i = start_insn; i != NULL; ) { new_entry.cstore = find_set_of_reg_bb (reg, i); @@ -794,7 +852,7 @@ sh_treg_combine::can_remove_cstore (const bb_entry& e, // must not be a usage of the copied regs between the reg-reg copies. // Otherwise we assume that the result of the cstore is used in some // other way. - rtx prev_insn = e.cstore.insn; + rtx_insn *prev_insn = e.cstore.insn; for (std::vector<set_of_reg>::const_reverse_iterator i = e.cstore_reg_reg_copies.rbegin (); i != e.cstore_reg_reg_copies.rend (); ++i) @@ -892,22 +950,42 @@ sh_treg_combine::can_remove_comparison (const bb_entry& e, rtx sh_treg_combine::make_not_reg_insn (rtx dst_reg, rtx src_reg) const { - // This will to go through expanders and may output multiple insns - // for multi-word regs. + // On SH we can do only SImode and DImode comparisons. + if (! (GET_MODE (src_reg) == SImode || GET_MODE (src_reg) == DImode)) + return NULL; + + // On SH we can store the ccreg into an SImode or DImode reg only. + if (! (GET_MODE (dst_reg) == SImode || GET_MODE (dst_reg) == DImode)) + return NULL; + start_sequence (); - expand_simple_unop (GET_MODE (dst_reg), NOT, src_reg, dst_reg, 0); + + emit_insn (gen_rtx_SET (VOIDmode, m_ccreg, + gen_rtx_fmt_ee (EQ, SImode, src_reg, const0_rtx))); + + if (GET_MODE (dst_reg) == SImode) + emit_move_insn (dst_reg, m_ccreg); + else if (GET_MODE (dst_reg) == DImode) + { + emit_move_insn (gen_lowpart (SImode, dst_reg), m_ccreg); + emit_move_insn (gen_highpart (SImode, dst_reg), const0_rtx); + } + else + gcc_unreachable (); + rtx i = get_insns (); end_sequence (); + return i; } -rtx +rtx_insn * sh_treg_combine::make_inv_ccreg_insn (void) const { start_sequence (); - rtx i = emit_insn (gen_rtx_SET (VOIDmode, m_ccreg, - gen_rtx_fmt_ee (XOR, GET_MODE (m_ccreg), - m_ccreg, const1_rtx))); + rtx_insn *i = emit_insn (gen_rtx_SET (VOIDmode, m_ccreg, + gen_rtx_fmt_ee (XOR, GET_MODE (m_ccreg), + m_ccreg, const1_rtx))); end_sequence (); return i; } @@ -994,8 +1072,18 @@ sh_treg_combine::try_invert_branch_condition (cbranch_trace& trace) { log_msg ("inverting branch condition\n"); - if (!invert_jump_1 (trace.cbranch_insn, JUMP_LABEL (trace.cbranch_insn))) - log_return (false, "invert_jump_1 failed\n"); + rtx& comp = trace.branch_condition_rtx_ref (); + + rtx_code rev_cmp_code = reversed_comparison_code (comp, trace.cbranch_insn); + + if (rev_cmp_code == UNKNOWN) + log_return (false, "reversed_comparison_code = UNKNOWN\n"); + + validate_change (trace.cbranch_insn, &comp, + gen_rtx_fmt_ee (rev_cmp_code, + GET_MODE (comp), XEXP (comp, 0), + XEXP (comp, 1)), + 1); if (verify_changes (num_validated_changes ())) confirm_change_group (); @@ -1080,7 +1168,12 @@ sh_treg_combine::try_combine_comparisons (cbranch_trace& trace, // There is one special case though, where an integer comparison // (eq (reg) (const_int 0)) // can be inverted with a sequence - // (eq (not (reg)) (const_int 0)) + // (set (t) (eq (reg) (const_int 0)) + // (set (reg) (t)) + // (eq (reg) (const_int 0)) + // + // FIXME: On SH2A it might be better to use the nott insn in this case, + // i.e. do the try_eliminate_cstores approach instead. if (inv_cstore_count != 0 && cstore_count != 0) { if (make_not_reg_insn (comp_op0, comp_op0) == NULL_RTX) @@ -1224,7 +1317,7 @@ sh_treg_combine::try_eliminate_cstores (cbranch_trace& trace, // invert the ccreg as a replacement for one of them. if (cstore_count != 0 && inv_cstore_count != 0) { - rtx i = make_inv_ccreg_insn (); + rtx_insn *i = make_inv_ccreg_insn (); if (recog_memoized (i) < 0) { log_msg ("failed to match ccreg inversion insn:\n"); @@ -1265,7 +1358,7 @@ sh_treg_combine::try_eliminate_cstores (cbranch_trace& trace, } void -sh_treg_combine::try_optimize_cbranch (rtx insn) +sh_treg_combine::try_optimize_cbranch (rtx_insn *insn) { cbranch_trace trace (insn); @@ -1295,9 +1388,17 @@ sh_treg_combine::try_optimize_cbranch (rtx insn) // for now we limit the search to the current basic block. trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn)); - if (!is_cmp_eq_zero (trace.setcc.set_src ())) + if (trace.setcc.set_src () == NULL_RTX) log_return_void ("could not find set of ccreg in current BB\n"); + if (!is_cmp_eq_zero (trace.setcc.set_src ()) + && !is_inverted_ccreg (trace.setcc.set_src ())) + { + log_msg ("unsupported set of ccreg in current BB: "); + log_rtx (trace.setcc.set_src ()); + log_return_void ("\n"); + } + rtx trace_reg = XEXP (trace.setcc.set_src (), 0); log_msg ("set of ccreg:\n"); @@ -1314,6 +1415,19 @@ sh_treg_combine::try_optimize_cbranch (rtx insn) log_return_void ("\nbecause it's volatile\n"); } + // If the ccreg is inverted before cbranch try inverting the branch + // condition. + if (is_inverted_ccreg (trace.setcc.set_src ())) + { + if (!trace.can_invert_condition ()) + log_return_void ("branch condition can't be inverted - aborting\n"); + + if (try_invert_branch_condition (trace)) + delete_insn (trace.setcc.insn); + + return; + } + // Now that we have an insn which tests some reg and sets the condition // reg before the conditional branch, try to figure out how that tested // reg was formed, i.e. find all the insns that set the tested reg in @@ -1436,13 +1550,13 @@ sh_treg_combine::try_optimize_cbranch (rtx insn) } bool -sh_treg_combine::gate (void) +sh_treg_combine::gate (function *) { return optimize > 0; } unsigned int -sh_treg_combine::execute (void) +sh_treg_combine::execute (function *fun) { unsigned int ccr0 = INVALID_REGNUM; unsigned int ccr1 = INVALID_REGNUM; @@ -1466,14 +1580,26 @@ sh_treg_combine::execute (void) log_rtx (m_ccreg); log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE); - // Look for basic blocks that end with a conditional branch and try to - // optimize them. + // Look for basic blocks that end with a conditional branch or for + // conditional insns and try to optimize them. basic_block bb; - FOR_EACH_BB_FN (bb, cfun) + FOR_EACH_BB_FN (bb, fun) { - rtx i = BB_END (bb); + rtx_insn* i = BB_END (bb); + if (i == NULL || i == PREV_INSN (BB_HEAD (bb))) + continue; + + // A conditional branch is always the last insn of a basic block. if (any_condjump_p (i) && onlyjump_p (i)) - try_optimize_cbranch (i); + { + try_optimize_cbranch (i); + i = PREV_INSN (i); + } + + // Check all insns in block for conditional insns. + for (; i != NULL && i != PREV_INSN (BB_HEAD (bb)); i = PREV_INSN (i)) + if (is_conditional_insn (i)) + try_optimize_cbranch (i); } log_msg ("\n\n"); diff --git a/gcc/config/sh/shmedia.h b/gcc/config/sh/shmedia.h index 3df9962745f..10ab894a520 100644 --- a/gcc/config/sh/shmedia.h +++ b/gcc/config/sh/shmedia.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2014 Free Software Foundation, Inc. +/* Copyright (C) 2000-2015 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/config/sh/shmedia.md b/gcc/config/sh/shmedia.md index 9ca829d2deb..21d00348394 100644 --- a/gcc/config/sh/shmedia.md +++ b/gcc/config/sh/shmedia.md @@ -1,5 +1,5 @@ ;; DFA scheduling description for SH-5 SHmedia instructions. -;; Copyright (C) 2004-2014 Free Software Foundation, Inc. +;; Copyright (C) 2004-2015 Free Software Foundation, Inc. ;; This file is part of GCC. diff --git a/gcc/config/sh/sshmedia.h b/gcc/config/sh/sshmedia.h index 5cf16473346..4403428dc0c 100644 --- a/gcc/config/sh/sshmedia.h +++ b/gcc/config/sh/sshmedia.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2014 Free Software Foundation, Inc. +/* Copyright (C) 2000-2015 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/config/sh/superh.h b/gcc/config/sh/superh.h index 98bc197a869..fd39efd35a1 100644 --- a/gcc/config/sh/superh.h +++ b/gcc/config/sh/superh.h @@ -1,5 +1,5 @@ /* Definitions of target machine for gcc for Super-H using sh-superh-elf. - Copyright (C) 2001-2014 Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. This file is part of GNU CC. diff --git a/gcc/config/sh/sync.md b/gcc/config/sh/sync.md index a0a22a1f5b7..b9f23cba58b 100644 --- a/gcc/config/sh/sync.md +++ b/gcc/config/sh/sync.md @@ -1,5 +1,5 @@ ;; GCC machine description for SH synchronization instructions. -;; Copyright (C) 2011-2014 Free Software Foundation, Inc. +;; Copyright (C) 2011-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -224,7 +224,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, addr, exp_val, new_val); else if (TARGET_ATOMIC_SOFT_GUSA) @@ -264,7 +264,7 @@ (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3)) (clobber (reg:SI R0_REG))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,r0" "\n" " cmp/eq %2,r0" "\n" @@ -437,7 +437,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], addr, val); else if (TARGET_ATOMIC_SOFT_GUSA) atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], addr, val); @@ -466,9 +466,10 @@ (set (mem:SI (match_dup 1)) (unspec:SI [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,r0" "\n" " mov r0,%0" "\n" @@ -484,6 +485,7 @@ (set (mem:QIHI (match_dup 1)) (unspec:QIHI [(match_operand:QIHI 2 "register_operand" "r")] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG)) (clobber (match_scratch:SI 3 "=&r")) (clobber (match_scratch:SI 4 "=1"))] @@ -583,7 +585,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], addr, operands[2]); else if (TARGET_ATOMIC_SOFT_GUSA) @@ -617,9 +619,10 @@ [(FETCHOP:SI (mem:SI (match_dup 1)) (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>"))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,r0" "\n" " mov r0,%0" "\n" @@ -637,6 +640,7 @@ [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>"))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG)) (clobber (match_scratch:SI 3 "=&r")) (clobber (match_scratch:SI 4 "=1"))] @@ -750,7 +754,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], addr, operands[2]); else if (TARGET_ATOMIC_SOFT_GUSA) @@ -784,9 +788,10 @@ [(not:SI (and:SI (mem:SI (match_dup 1)) (match_operand:SI 2 "logical_operand" "rK08")))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,r0" "\n" " mov r0,%0" "\n" @@ -805,6 +810,7 @@ [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_operand:QIHI 2 "logical_operand" "rK08")))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG)) (clobber (match_scratch:SI 3 "=&r")) (clobber (match_scratch:SI 4 "=1"))] @@ -903,7 +909,7 @@ " and %0,%3" "\n" " not %3,%3" "\n" " mov.<bwl> %3,@%1" "\n" - " stc %4,sr"; + " ldc %4,sr"; } [(set_attr "length" "20")]) @@ -926,7 +932,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], addr, operands[2]); else if (TARGET_ATOMIC_SOFT_GUSA) @@ -960,9 +966,10 @@ (set (mem:SI (match_dup 1)) (unspec:SI [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))] - UNSPEC_ATOMIC))] + UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,%0" "\n" " <fetchop_name> %2,%0" "\n" @@ -980,6 +987,7 @@ (unspec:QIHI [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG)) (clobber (match_scratch:SI 3 "=&r")) (clobber (match_scratch:SI 4 "=1"))] @@ -1091,7 +1099,7 @@ rtx atomic_insn; if (TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) + || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], addr, operands[2]); else if (TARGET_ATOMIC_SOFT_GUSA) @@ -1124,9 +1132,10 @@ (set (mem:SI (match_dup 1)) (unspec:SI [(not:SI (and:SI (mem:SI (match_dup 1)) (match_dup 2)))] - UNSPEC_ATOMIC))] + UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1))] "TARGET_ATOMIC_HARD_LLCS - || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" + || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" { return "\r0: movli.l @%1,%0" "\n" " and %2,%0" "\n" @@ -1145,6 +1154,7 @@ (unspec:QIHI [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))] UNSPEC_ATOMIC)) + (set (reg:SI T_REG) (const_int 1)) (clobber (reg:SI R0_REG)) (clobber (match_scratch:SI 3 "=&r")) (clobber (match_scratch:SI 4 "=1"))] @@ -1353,7 +1363,7 @@ " ldc r0,sr" "\n" " mov.b @%0,r0" "\n" " mov.b %1,@%0" "\n" - " stc %2,sr" "\n" + " ldc %2,sr" "\n" " tst r0,r0"; } [(set_attr "length" "16")]) diff --git a/gcc/config/sh/t-sh b/gcc/config/sh/t-sh index d9f2b3d9394..19e0e4a7df7 100644 --- a/gcc/config/sh/t-sh +++ b/gcc/config/sh/t-sh @@ -1,4 +1,4 @@ -# Copyright (C) 1993-2014 Free Software Foundation, Inc. +# Copyright (C) 1993-2015 Free Software Foundation, Inc. # # This file is part of GCC. # diff --git a/gcc/config/sh/t-sh64 b/gcc/config/sh/t-sh64 index 3222099b8a7..fb09f3fbbbf 100644 --- a/gcc/config/sh/t-sh64 +++ b/gcc/config/sh/t-sh64 @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# Copyright (C) 2002-2015 Free Software Foundation, Inc. # # This file is part of GCC. # diff --git a/gcc/config/sh/ushmedia.h b/gcc/config/sh/ushmedia.h index 03064e964d5..09755ba6fb1 100644 --- a/gcc/config/sh/ushmedia.h +++ b/gcc/config/sh/ushmedia.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2014 Free Software Foundation, Inc. +/* Copyright (C) 2000-2015 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/config/sh/vxworks.h b/gcc/config/sh/vxworks.h index 15dae73c725..d2f31b9b5bc 100644 --- a/gcc/config/sh/vxworks.h +++ b/gcc/config/sh/vxworks.h @@ -1,6 +1,6 @@ /* Definitions of target machine for GCC, for SuperH with targeting the VXWorks run time environment. - Copyright (C) 2003-2014 Free Software Foundation, Inc. + Copyright (C) 2003-2015 Free Software Foundation, Inc. Contributed by CodeSourcery, LLC. This file is part of GCC. |