aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/v850
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/config/v850
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/config/v850')
-rw-r--r--gcc-4.9/gcc/config/v850/constraints.md108
-rw-r--r--gcc-4.9/gcc/config/v850/predicates.md584
-rw-r--r--gcc-4.9/gcc/config/v850/rtems.h36
-rw-r--r--gcc-4.9/gcc/config/v850/t-rtems7
-rw-r--r--gcc-4.9/gcc/config/v850/t-v85035
-rw-r--r--gcc-4.9/gcc/config/v850/v850-c.c274
-rw-r--r--gcc-4.9/gcc/config/v850/v850-modes.def27
-rw-r--r--gcc-4.9/gcc/config/v850/v850-opts.h33
-rw-r--r--gcc-4.9/gcc/config/v850/v850-protos.h69
-rw-r--r--gcc-4.9/gcc/config/v850/v850.c3281
-rw-r--r--gcc-4.9/gcc/config/v850/v850.h979
-rw-r--r--gcc-4.9/gcc/config/v850/v850.md3115
-rw-r--r--gcc-4.9/gcc/config/v850/v850.opt159
13 files changed, 8707 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/v850/constraints.md b/gcc-4.9/gcc/config/v850/constraints.md
new file mode 100644
index 000000000..3b40afa93
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/constraints.md
@@ -0,0 +1,108 @@
+;; Constraint definitions for V850.
+;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_register_constraint "e" "EVEN_REGS"
+ "@internal")
+
+;; Integer constraints.
+(define_constraint "I"
+ "Integer constant 0."
+ (and (match_code "const_int")
+ (match_test "ival == 0")))
+
+(define_constraint "J"
+ "A signed 5-bit immediate."
+ (and (match_code "const_int")
+ (match_test "ival >= -16 && ival <= 15")))
+
+(define_constraint "K"
+ "A signed 16-bit immediate."
+ (and (match_code "const_int")
+ (match_test "ival >= -32768 && ival <= 32767")))
+
+(define_constraint "L"
+ "A valid constant for a movhi instruction."
+ (and (match_code "const_int")
+ (ior (match_test "(ival | 0x7fff0000) == 0x7fff0000")
+ (match_test "(ival | 0x7fff0000) + 0x10000 == 0"))))
+
+(define_constraint "M"
+ "An unsigned 16-bit immediate."
+ (and (match_code "const_int")
+ (match_test "ival >= 0 && ival <= 65535")))
+
+(define_constraint "N"
+ "An unsigned 5-bit immediate in shift instructions."
+ (and (match_code "const_int")
+ (match_test "ival >= 0 && ival <= 31")))
+
+(define_constraint "O"
+ "A signed 9-bit immediate for word multiply instructions."
+ (and (match_code "const_int")
+ (match_test "ival >= -255 && ival <= 255")))
+
+(define_constraint "P"
+ "@internal"
+ (and (match_code "const_int")
+ (match_test "0")))
+
+;; Floating-point constraints.
+(define_constraint "G"
+ "A zero of some form."
+ (and (match_code "const_double")
+ (ior (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT")
+ (match_test "GET_MODE_CLASS (mode) == MODE_INT"))
+ (match_test "op == CONST0_RTX (mode)")))
+
+(define_constraint "H"
+ "@internal"
+ (and (match_code "const_double")
+ (match_test "0")))
+
+;;; Extra constraints.
+(define_memory_constraint "Q"
+ "A memory address that does not contain a symbol address."
+ (and (match_code "mem")
+ (match_test "ep_memory_operand (op, mode, FALSE)")))
+
+(define_constraint "R"
+ "@internal"
+ (match_test "special_symbolref_operand (op, VOIDmode)"))
+
+(define_constraint "S"
+ "@internal"
+ (and (match_code "symbol_ref")
+ (match_test "!SYMBOL_REF_ZDA_P (op)")))
+
+(define_constraint "T"
+ "@internal"
+ (match_test "ep_memory_operand (op, mode, TRUE)"))
+
+(define_constraint "U"
+ "@internal"
+ (ior (and (match_code "symbol_ref")
+ (match_test "SYMBOL_REF_ZDA_P (op)"))
+ (and (match_code "const")
+ (match_test "GET_CODE (XEXP (op, 0)) == PLUS")
+ (match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF")
+ (match_test "SYMBOL_REF_ZDA_P (XEXP (XEXP (op, 0), 0))"))))
+
+(define_constraint "W"
+ "@internal"
+ (match_test "disp23_operand (op, VOIDmode)"))
diff --git a/gcc-4.9/gcc/config/v850/predicates.md b/gcc-4.9/gcc/config/v850/predicates.md
new file mode 100644
index 000000000..1e16c1cae
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/predicates.md
@@ -0,0 +1,584 @@
+;; Predicate definitions for NEC V850.
+;; Copyright (C) 2005-2014 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; Return true if OP is either a register or 0.
+
+(define_predicate "reg_or_0_operand"
+ (match_code "reg,subreg,const_int,const_double")
+{
+ if (GET_CODE (op) == CONST_INT)
+ return INTVAL (op) == 0;
+
+ else if (GET_CODE (op) == CONST_DOUBLE)
+ return satisfies_constraint_G (op);
+
+ else
+ return register_operand (op, mode);
+})
+
+;; Return true if OP is either a register or a signed five bit
+;; integer.
+
+(define_predicate "reg_or_int5_operand"
+ (match_code "reg,subreg,const_int")
+{
+ if (GET_CODE (op) == CONST_INT)
+ return CONST_OK_FOR_J (INTVAL (op));
+
+ else
+ return register_operand (op, mode);
+})
+
+;; Return true if OP is either a register or a signed nine bit
+;; integer.
+
+(define_predicate "reg_or_int9_operand"
+ (match_code "reg,subreg,const_int")
+{
+ if (GET_CODE (op) == CONST_INT)
+ return CONST_OK_FOR_O (INTVAL (op));
+
+ return register_operand (op, mode);
+})
+
+;; Return true if OP is either a register or a const integer.
+
+(define_predicate "reg_or_const_operand"
+ (match_code "reg,const_int")
+{
+ if (GET_CODE (op) == CONST_INT)
+ return TRUE;
+
+ return register_operand (op, mode);
+})
+
+;; Return true if OP is a even number register.
+
+(define_predicate "even_reg_operand"
+ (match_code "reg")
+{
+ return (GET_CODE (op) == REG
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || ((REGNO (op) > 0) && (REGNO (op) < 32)
+ && ((REGNO (op) & 1)==0))));
+})
+
+;; Return true if OP is a valid call operand.
+
+(define_predicate "call_address_operand"
+ (match_code "reg,symbol_ref")
+{
+ /* Only registers are valid call operands if TARGET_LONG_CALLS. */
+ if (TARGET_LONG_CALLS)
+ return GET_CODE (op) == REG;
+ return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
+})
+
+;; Return true if OP is a valid source operand for SImode move.
+
+(define_predicate "movsi_source_operand"
+ (match_code "label_ref,symbol_ref,const_int,const_double,const,high,mem,reg,subreg")
+{
+ /* Some constants, as well as symbolic operands
+ must be done with HIGH & LO_SUM patterns. */
+ if (CONSTANT_P (op)
+ && GET_CODE (op) != HIGH
+ && !(GET_CODE (op) == CONST_INT
+ && (CONST_OK_FOR_J (INTVAL (op))
+ || CONST_OK_FOR_K (INTVAL (op))
+ || CONST_OK_FOR_L (INTVAL (op)))))
+ return special_symbolref_operand (op, mode);
+ else
+ return general_operand (op, mode);
+})
+
+;; Return true if OP is a valid operand for 23 bit displacement
+;; operations.
+
+(define_predicate "disp23_operand"
+ (match_code "const_int")
+{
+ if (GET_CODE (op) == CONST_INT
+ && ((unsigned)(INTVAL (op)) >= 0x8000)
+ && ((unsigned)(INTVAL (op)) < 0x400000))
+ return 1;
+ else
+ return 0;
+})
+
+;; Return true if OP is a symbol ref with 16-bit signed value.
+
+(define_predicate "special_symbolref_operand"
+ (match_code "symbol_ref")
+{
+ if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && satisfies_constraint_K (XEXP (XEXP (op, 0), 1)))
+ op = XEXP (XEXP (op, 0), 0);
+
+ if (GET_CODE (op) == SYMBOL_REF)
+ return (SYMBOL_REF_FLAGS (op)
+ & (SYMBOL_FLAG_ZDA | SYMBOL_FLAG_TDA | SYMBOL_FLAG_SDA)) != 0;
+
+ return FALSE;
+})
+
+;; Return true if OP is a valid operand for bit related operations
+;; containing only single 1 in its binary representation.
+
+(define_predicate "power_of_two_operand"
+ (match_code "const_int")
+{
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+
+ if (exact_log2 (INTVAL (op)) == -1)
+ return 0;
+ return 1;
+})
+
+;; Return nonzero if the given RTX is suitable for collapsing into a
+;; jump to a function prologue.
+
+(define_predicate "pattern_is_ok_for_prologue"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int i;
+ rtx vector_element;
+
+ /* If there are no registers to save then the function prologue
+ is not suitable. */
+ if (count <= (TARGET_LONG_CALLS ? 3 : 2))
+ return 0;
+
+ /* The pattern matching has already established that we are adjusting the
+ stack and pushing at least one register. We must now check that the
+ remaining entries in the vector to make sure that they are also register
+ pushes, except for the last entry which should be a CLOBBER of r10.
+
+ The test below performs the C equivalent of this machine description
+ pattern match:
+
+ (set (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 2 "immediate_operand" "i")))
+ (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
+
+ */
+
+ for (i = 2; i < count - (TARGET_LONG_CALLS ? 2: 1); i++)
+ {
+ rtx dest;
+ rtx src;
+ rtx plus;
+
+ vector_element = XVECEXP (op, 0, i);
+
+ if (GET_CODE (vector_element) != SET)
+ return 0;
+
+ dest = SET_DEST (vector_element);
+ src = SET_SRC (vector_element);
+
+ if (GET_CODE (dest) != MEM
+ || GET_MODE (dest) != SImode
+ || GET_CODE (src) != REG
+ || GET_MODE (src) != SImode
+ || ! register_is_ok_for_epilogue (src, SImode))
+ return 0;
+
+ plus = XEXP (dest, 0);
+
+ if ( GET_CODE (plus) != PLUS
+ || GET_CODE (XEXP (plus, 0)) != REG
+ || GET_MODE (XEXP (plus, 0)) != SImode
+ || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
+ || GET_CODE (XEXP (plus, 1)) != CONST_INT)
+ return 0;
+
+ /* If the register is being pushed somewhere other than the stack
+ space just acquired by the first operand then abandon this quest.
+ Note: the test is <= because both values are negative. */
+ if (INTVAL (XEXP (plus, 1))
+ <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
+ {
+ return 0;
+ }
+ }
+
+ /* Make sure that the last entries in the vector are clobbers. */
+ vector_element = XVECEXP (op, 0, i++);
+
+ if (GET_CODE (vector_element) != CLOBBER
+ || GET_CODE (XEXP (vector_element, 0)) != REG
+ || REGNO (XEXP (vector_element, 0)) != 10)
+ return 0;
+
+ if (TARGET_LONG_CALLS)
+ {
+ vector_element = XVECEXP (op, 0, i++);
+
+ if (GET_CODE (vector_element) != CLOBBER
+ || GET_CODE (XEXP (vector_element, 0)) != REG
+ || REGNO (XEXP (vector_element, 0)) != 11)
+ return 0;
+ }
+
+ return i == count;
+})
+
+;; Return nonzero if the given RTX is suitable for collapsing into
+;; jump to a function epilogue.
+
+(define_predicate "pattern_is_ok_for_epilogue"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int i;
+
+ /* If there are no registers to restore then the function epilogue
+ is not suitable. */
+ if (count <= 2)
+ return 0;
+
+ /* The pattern matching has already established that we are performing a
+ function epilogue and that we are popping at least one register. We must
+ now check the remaining entries in the vector to make sure that they are
+ also register pops. There is no good reason why there should ever be
+ anything else in this vector, but being paranoid always helps...
+
+ The test below performs the C equivalent of this machine description
+ pattern match:
+
+ (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
+ (mem:SI (plus:SI (reg:SI 3) (match_operand:SI n "immediate_operand" "i"))))
+ */
+
+ for (i = 2; i < count; i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+ rtx dest;
+ rtx src;
+ rtx plus;
+
+ if (GET_CODE (vector_element) != SET)
+ return 0;
+
+ dest = SET_DEST (vector_element);
+ src = SET_SRC (vector_element);
+
+ if (GET_CODE (dest) != REG
+ || GET_MODE (dest) != SImode
+ || ! register_is_ok_for_epilogue (dest, SImode)
+ || GET_CODE (src) != MEM
+ || GET_MODE (src) != SImode)
+ return 0;
+
+ plus = XEXP (src, 0);
+
+ if (GET_CODE (plus) != PLUS
+ || GET_CODE (XEXP (plus, 0)) != REG
+ || GET_MODE (XEXP (plus, 0)) != SImode
+ || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
+ || GET_CODE (XEXP (plus, 1)) != CONST_INT)
+ return 0;
+ }
+
+ return 1;
+})
+
+;; Return true if the given RTX is a register which can be restored by
+;; a function epilogue.
+
+(define_predicate "register_is_ok_for_epilogue"
+ (match_code "reg")
+{
+ /* The save/restore routines can only cope with registers 20 - 31. */
+ return ((GET_CODE (op) == REG)
+ && (((REGNO (op) >= 20) && REGNO (op) <= 31)));
+})
+
+;; Return nonzero if the given RTX is suitable for collapsing into a
+;; DISPOSE instruction.
+
+(define_predicate "pattern_is_ok_for_dispose"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int i;
+
+ /* If there are no registers to restore then
+ the dispose instruction is not suitable. */
+ if (count <= 2)
+ return 0;
+
+ /* The pattern matching has already established that we are performing a
+ function epilogue and that we are popping at least one register. We must
+ now check the remaining entries in the vector to make sure that they are
+ also register pops. There is no good reason why there should ever be
+ anything else in this vector, but being paranoid always helps...
+
+ The test below performs the C equivalent of this machine description
+ pattern match:
+
+ (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
+ (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI n "immediate_operand" "i"))))
+ */
+
+ for (i = 3; i < count; i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+ rtx dest;
+ rtx src;
+ rtx plus;
+
+ if (GET_CODE (vector_element) != SET)
+ return 0;
+
+ dest = SET_DEST (vector_element);
+ src = SET_SRC (vector_element);
+
+ if ( GET_CODE (dest) != REG
+ || GET_MODE (dest) != SImode
+ || ! register_is_ok_for_epilogue (dest, SImode)
+ || GET_CODE (src) != MEM
+ || GET_MODE (src) != SImode)
+ return 0;
+
+ plus = XEXP (src, 0);
+
+ if ( GET_CODE (plus) != PLUS
+ || GET_CODE (XEXP (plus, 0)) != REG
+ || GET_MODE (XEXP (plus, 0)) != SImode
+ || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
+ || GET_CODE (XEXP (plus, 1)) != CONST_INT)
+ return 0;
+ }
+
+ return 1;
+})
+
+;; Return nonzero if the given RTX is suitable for collapsing into a
+;; PREPARE instruction.
+
+(define_predicate "pattern_is_ok_for_prepare"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ int i;
+
+ /* If there are no registers to restore then the prepare instruction
+ is not suitable. */
+ if (count <= 1)
+ return 0;
+
+ /* The pattern matching has already established that we are adjusting the
+ stack and pushing at least one register. We must now check that the
+ remaining entries in the vector to make sure that they are also register
+ pushes.
+
+ The test below performs the C equivalent of this machine description
+ pattern match:
+
+ (set (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 2 "immediate_operand" "i")))
+ (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
+
+ */
+
+ for (i = 1; i < count; i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+ rtx dest;
+ rtx src;
+ rtx plus;
+
+ if (GET_CODE (vector_element) == CLOBBER)
+ continue;
+
+ if (GET_CODE (vector_element) != SET)
+ return 0;
+
+ dest = SET_DEST (vector_element);
+ src = SET_SRC (vector_element);
+
+ if ( GET_CODE (dest) != MEM
+ || GET_MODE (dest) != SImode
+ || GET_CODE (src) != REG
+ || GET_MODE (src) != SImode
+ || ! register_is_ok_for_epilogue (src, SImode)
+ )
+ return 0;
+
+ plus = XEXP (dest, 0);
+
+ if ( GET_CODE (plus) != PLUS
+ || GET_CODE (XEXP (plus, 0)) != REG
+ || GET_MODE (XEXP (plus, 0)) != SImode
+ || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
+ || GET_CODE (XEXP (plus, 1)) != CONST_INT)
+ return 0;
+
+ /* If the register is being pushed somewhere other than the stack
+ space just acquired by the first operand then abandon this quest.
+ Note: the test is <= because both values are negative. */
+ if (INTVAL (XEXP (plus, 1))
+ < INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
+ return 0;
+ }
+
+ return 1;
+})
+
+;; Return true if OP is a valid operand for bit related operations
+;; containing only single 0 in its binary representation.
+
+(define_predicate "not_power_of_two_operand"
+ (match_code "const_int")
+{
+ unsigned int mask;
+
+ if (mode == QImode)
+ mask = 0xff;
+ else if (mode == HImode)
+ mask = 0xffff;
+ else if (mode == SImode)
+ mask = 0xffffffff;
+ else
+ return 0;
+
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+
+ if (exact_log2 (~INTVAL (op) & mask) == -1)
+ return 0;
+ return 1;
+})
+
+;; Return true if OP is a float value operand with value as 1.
+
+(define_predicate "const_float_1_operand"
+ (match_code "const_int")
+{
+ if (GET_CODE (op) != CONST_DOUBLE
+ || mode != GET_MODE (op)
+ || (mode != DFmode && mode != SFmode))
+ return 0;
+
+ return op == CONST1_RTX(mode);
+})
+
+;; Return true if OP is a float value operand with value as 0.
+
+(define_predicate "const_float_0_operand"
+ (match_code "const_int")
+{
+ if (GET_CODE (op) != CONST_DOUBLE
+ || mode != GET_MODE (op)
+ || (mode != DFmode && mode != SFmode))
+ return 0;
+
+ return op == CONST0_RTX(mode);
+})
+
+(define_predicate "label_ref_operand"
+ (match_code "label_ref")
+)
+
+
+(define_predicate "e3v5_shift_operand"
+ (match_code "const_int,reg")
+ {
+ if (CONST_INT_P (op))
+ return IN_RANGE (INTVAL (op), 0, 31);
+ return true;
+ }
+)
+
+(define_predicate "ior_operator"
+ (match_code "ior")
+{
+ return (GET_CODE (op) == IOR);
+})
+
+;; Return true if the floating point comparison operation
+;; given produces a canonical answer.
+(define_predicate "v850_float_z_comparison_operator"
+ (match_code "lt,le,eq,gt,ge")
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (GET_RTX_CLASS (code) != RTX_COMPARE
+ && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
+ return 0;
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ if ((GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM)
+ || XEXP (op, 1) != const0_rtx)
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_LTmode)
+ return code == LT;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_LEmode)
+ return code == LE;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_EQmode)
+ return code == EQ;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_GTmode)
+ return code == GT;
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_GEmode)
+ return code == GE;
+
+ /* Note we do not accept CC_FPU_NEmode here. See
+ v850_float_nz_comparison for the reason why. */
+ return 0;
+})
+
+;; Return true if the floating point comparison operation
+;; given produces an inverted answer.
+(define_predicate "v850_float_nz_comparison_operator"
+ (match_code "ne")
+{
+ enum rtx_code code = GET_CODE (op);
+
+ /* The V850E2V3 does not have a floating point NZ comparison operator.
+ Instead it is implemented as an EQ comparison and this function ensures
+ that the branch_nz_normal and set_nz_insn patterns are used to examine
+ (and invert) the result of the floating point comparison. */
+
+ if (GET_RTX_CLASS (code) != RTX_COMPARE
+ && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
+ return 0;
+
+ if (mode != GET_MODE (op) && mode != VOIDmode)
+ return 0;
+
+ if ((GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM)
+ || XEXP (op, 1) != const0_rtx)
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CC_FPU_NEmode)
+ return code == NE;
+
+ return 0;
+})
diff --git a/gcc-4.9/gcc/config/v850/rtems.h b/gcc-4.9/gcc/config/v850/rtems.h
new file mode 100644
index 000000000..01dff3e52
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/rtems.h
@@ -0,0 +1,36 @@
+/* Definitions for rtems targeting a v850 using ELF.
+ Copyright (C) 2012-2014 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* Specify predefined symbols in preprocessor. */
+
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define( "__rtems__" ); \
+ builtin_assert( "system=rtems" ); \
+ } \
+ while (0)
+
+/* Map mv850e1 and mv850es to mv850e to match MULTILIB_MATCHES */
+#undef ASM_SPEC
+#define ASM_SPEC "%{mv850es:-mv850e} \
+%{mv850e1:-mv850e} \
+%{!mv850es:%{!mv850e1:%{mv*:-mv%*}} \
+%{m8byte-align:-m8byte-align} \
+%{mgcc-abi:-mgcc-abi}}"
diff --git a/gcc-4.9/gcc/config/v850/t-rtems b/gcc-4.9/gcc/config/v850/t-rtems
new file mode 100644
index 000000000..c0427e5fd
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/t-rtems
@@ -0,0 +1,7 @@
+# Custom multilibs for RTEMS
+
+MULTILIB_OPTIONS = mv850/mv850e/mv850e2/mv850e2v3
+MULTILIB_DIRNAMES = v850 v850e v850e2 v850e2v3
+MULTILIB_MATCHES = mv850e=mv850e1
+
+MULTILIB_MATCHES += mv850e=mv850es
diff --git a/gcc-4.9/gcc/config/v850/t-v850 b/gcc-4.9/gcc/config/v850/t-v850
new file mode 100644
index 000000000..44346f07d
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/t-v850
@@ -0,0 +1,35 @@
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Create target-specific versions of the libraries
+MULTILIB_OPTIONS = m8byte-align mgcc-abi msoft-float
+MULTILIB_DIRNAMES = 8byte gcc-abi soft-float
+
+MULTILIB_OPTIONS += mv850e3v5
+MULTILIB_DIRNAMES += v850e3v5
+
+TCFLAGS = -mno-app-regs -msmall-sld -Wa,-mwarn-signed-overflow -Wa,-mwarn-unsigned-overflow
+
+v850-c.o: $(srcdir)/config/v850/v850-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(TM_H) $(CPPLIB_H) $(TREE_H) $(C_PRAGMA_H) $(GGC_H) $(TM_P_H)
+ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(srcdir)/config/v850/v850-c.c
+
+# Local Variables:
+# mode: Makefile
+# End:
diff --git a/gcc-4.9/gcc/config/v850/v850-c.c b/gcc-4.9/gcc/config/v850/v850-c.c
new file mode 100644
index 000000000..4c2e052cf
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850-c.c
@@ -0,0 +1,274 @@
+/* v850 specific, C compiler specific functions.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "c-family/c-pragma.h"
+#include "diagnostic-core.h"
+#include "ggc.h"
+#include "tm_p.h"
+
+#ifndef streq
+#define streq(a,b) (strcmp (a, b) == 0)
+#endif
+
+static int pop_data_area (v850_data_area);
+static int push_data_area (v850_data_area);
+static void mark_current_function_as_interrupt (void);
+
+/* Push a data area onto the stack. */
+
+static int
+push_data_area (v850_data_area data_area)
+{
+ data_area_stack_element * elem;
+
+ elem = (data_area_stack_element *) xmalloc (sizeof (* elem));
+
+ if (elem == NULL)
+ return 0;
+
+ elem->prev = data_area_stack;
+ elem->data_area = data_area;
+
+ data_area_stack = elem;
+
+ return 1;
+}
+
+/* Remove a data area from the stack. */
+
+static int
+pop_data_area (v850_data_area data_area)
+{
+ if (data_area_stack == NULL)
+ warning (OPT_Wpragmas, "#pragma GHS endXXXX found without "
+ "previous startXXX");
+ else if (data_area != data_area_stack->data_area)
+ warning (OPT_Wpragmas, "#pragma GHS endXXX does not match "
+ "previous startXXX");
+ else
+ {
+ data_area_stack_element * elem;
+
+ elem = data_area_stack;
+ data_area_stack = data_area_stack->prev;
+
+ free (elem);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Set the machine specific 'interrupt' attribute on the current function. */
+
+static void
+mark_current_function_as_interrupt (void)
+{
+ tree name;
+
+ if (current_function_decl == NULL_TREE)
+ {
+ warning (0, "cannot set interrupt attribute: no current function");
+ return;
+ }
+
+ name = get_identifier ("interrupt");
+
+ if (name == NULL_TREE || TREE_CODE (name) != IDENTIFIER_NODE)
+ {
+ warning (0, "cannot set interrupt attribute: no such identifier");
+ return;
+ }
+
+ decl_attributes (&current_function_decl,
+ tree_cons (name, NULL_TREE, NULL_TREE), 0);
+}
+
+
+/* Support for GHS pragmata. */
+
+void
+ghs_pragma_section (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ int repeat = 0;
+
+ /* #pragma ghs section [name = alias [, name = alias [, ...]]] */
+ do
+ {
+ tree x;
+ enum cpp_ttype type;
+ tree sect_ident;
+ const char *sect, *alias;
+ enum GHS_section_kind kind;
+
+ type = pragma_lex (&x);
+
+ if (type == CPP_EOF && !repeat)
+ goto reset;
+ else if (type == CPP_NAME)
+ {
+ sect_ident = x;
+ sect = IDENTIFIER_POINTER (sect_ident);
+ }
+ else
+ goto bad;
+ repeat = 0;
+
+ if (pragma_lex (&x) != CPP_EQ)
+ goto bad;
+ if (pragma_lex (&x) != CPP_NAME)
+ goto bad;
+
+ alias = IDENTIFIER_POINTER (x);
+
+ type = pragma_lex (&x);
+ if (type == CPP_COMMA)
+ repeat = 1;
+ else if (type != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs section");
+
+ if (streq (sect, "data")) kind = GHS_SECTION_KIND_DATA;
+ else if (streq (sect, "text")) kind = GHS_SECTION_KIND_TEXT;
+ else if (streq (sect, "rodata")) kind = GHS_SECTION_KIND_RODATA;
+ else if (streq (sect, "const")) kind = GHS_SECTION_KIND_RODATA;
+ else if (streq (sect, "rosdata")) kind = GHS_SECTION_KIND_ROSDATA;
+ else if (streq (sect, "rozdata")) kind = GHS_SECTION_KIND_ROZDATA;
+ else if (streq (sect, "sdata")) kind = GHS_SECTION_KIND_SDATA;
+ else if (streq (sect, "tdata")) kind = GHS_SECTION_KIND_TDATA;
+ else if (streq (sect, "zdata")) kind = GHS_SECTION_KIND_ZDATA;
+ /* According to GHS beta documentation, the following should not be
+ allowed! */
+ else if (streq (sect, "bss")) kind = GHS_SECTION_KIND_BSS;
+ else if (streq (sect, "zbss")) kind = GHS_SECTION_KIND_ZDATA;
+ else
+ {
+ warning (0, "unrecognized section name %qE", sect_ident);
+ return;
+ }
+
+ if (streq (alias, "default"))
+ GHS_current_section_names [kind] = NULL;
+ else
+ GHS_current_section_names [kind] =
+ build_string (strlen (alias) + 1, alias);
+ }
+ while (repeat);
+
+ return;
+
+ bad:
+ warning (OPT_Wpragmas, "malformed #pragma ghs section");
+ return;
+
+ reset:
+ /* #pragma ghs section \n: Reset all section names back to their defaults. */
+ {
+ int i;
+
+ for (i = COUNT_OF_GHS_SECTION_KINDS; i--;)
+ GHS_current_section_names [i] = NULL;
+ }
+}
+
+void
+ghs_pragma_interrupt (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs interrupt");
+
+ mark_current_function_as_interrupt ();
+}
+
+void
+ghs_pragma_starttda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs starttda");
+
+ push_data_area (DATA_AREA_TDA);
+}
+
+void
+ghs_pragma_startsda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs startsda");
+
+ push_data_area (DATA_AREA_SDA);
+}
+
+void
+ghs_pragma_startzda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs startzda");
+
+ push_data_area (DATA_AREA_ZDA);
+}
+
+void
+ghs_pragma_endtda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs endtda");
+
+ pop_data_area (DATA_AREA_TDA);
+}
+
+void
+ghs_pragma_endsda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs endsda");
+
+ pop_data_area (DATA_AREA_SDA);
+}
+
+void
+ghs_pragma_endzda (cpp_reader * pfile ATTRIBUTE_UNUSED)
+{
+ tree x;
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of #pragma ghs endzda");
+
+ pop_data_area (DATA_AREA_ZDA);
+}
diff --git a/gcc-4.9/gcc/config/v850/v850-modes.def b/gcc-4.9/gcc/config/v850/v850-modes.def
new file mode 100644
index 000000000..d5729cb36
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850-modes.def
@@ -0,0 +1,27 @@
+/* Definitions of target machine for GNU compiler. NEC V850 series
+ Copyright (C) 2005-2014 Free Software Foundation, Inc.
+ Contributed by NEC EL
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+CC_MODE (CC_FPU_LT);
+CC_MODE (CC_FPU_LE);
+CC_MODE (CC_FPU_GT);
+CC_MODE (CC_FPU_GE);
+CC_MODE (CC_FPU_EQ);
+CC_MODE (CC_FPU_NE);
+
diff --git a/gcc-4.9/gcc/config/v850/v850-opts.h b/gcc-4.9/gcc/config/v850/v850-opts.h
new file mode 100644
index 000000000..a91b1b059
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850-opts.h
@@ -0,0 +1,33 @@
+/* Definitions for option handling for NEC V850 series.
+ Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef V850_OPTS_H
+#define V850_OPTS_H
+
+enum small_memory_type {
+ /* tiny data area, using EP as base register */
+ SMALL_MEMORY_TDA = 0,
+ /* small data area using dp as base register */
+ SMALL_MEMORY_SDA,
+ /* zero data area using r0 as base register */
+ SMALL_MEMORY_ZDA,
+ SMALL_MEMORY_max
+};
+
+#endif
diff --git a/gcc-4.9/gcc/config/v850/v850-protos.h b/gcc-4.9/gcc/config/v850/v850-protos.h
new file mode 100644
index 000000000..ba504cb6b
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850-protos.h
@@ -0,0 +1,69 @@
+/* Prototypes for v850.c functions used in the md file & elsewhere.
+ Copyright (C) 1999-2014 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* Function prototypes that cannot exist in v850.h due to dependency
+ complications. */
+#ifndef GCC_V850_PROTOS_H
+#define GCC_V850_PROTOS_H
+
+extern void expand_prologue (void);
+extern void expand_epilogue (void);
+extern int v850_handle_pragma (int (*)(void), void (*)(int), char *);
+extern int compute_register_save_size (long *);
+extern int compute_frame_size (int, long *);
+extern void v850_init_expanders (void);
+
+#ifdef RTX_CODE
+extern rtx v850_return_addr (int);
+extern const char *output_move_single (rtx *);
+extern void notice_update_cc (rtx, rtx);
+extern char * construct_save_jarl (rtx);
+extern char * construct_restore_jr (rtx);
+#ifdef HAVE_MACHINE_MODES
+extern char * construct_dispose_instruction (rtx);
+extern char * construct_prepare_instruction (rtx);
+extern int ep_memory_operand (rtx, enum machine_mode, int);
+extern int v850_adjust_insn_length (rtx, int);
+extern const char * v850_gen_movdi (rtx *);
+extern rtx v850_gen_compare (enum rtx_code, enum machine_mode,
+ rtx, rtx);
+extern enum machine_mode v850_gen_float_compare (enum rtx_code,
+ enum machine_mode, rtx, rtx);
+extern enum machine_mode v850_select_cc_mode (RTX_CODE, rtx, rtx);
+#endif
+#endif /* RTX_CODE */
+
+#ifdef TREE_CODE
+extern int v850_interrupt_function_p (tree);
+extern void v850_output_aligned_bss (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int);
+extern void v850_output_common (FILE *, tree, const char *, int, int);
+extern void v850_output_local (FILE *, tree, const char *, int, int);
+extern v850_data_area v850_get_data_area (tree);
+#endif
+
+extern void ghs_pragma_section (struct cpp_reader *);
+extern void ghs_pragma_interrupt (struct cpp_reader *);
+extern void ghs_pragma_starttda (struct cpp_reader *);
+extern void ghs_pragma_startsda (struct cpp_reader *);
+extern void ghs_pragma_startzda (struct cpp_reader *);
+extern void ghs_pragma_endtda (struct cpp_reader *);
+extern void ghs_pragma_endsda (struct cpp_reader *);
+extern void ghs_pragma_endzda (struct cpp_reader *);
+
+#endif /* ! GCC_V850_PROTOS_H */
diff --git a/gcc-4.9/gcc/config/v850/v850.c b/gcc-4.9/gcc/config/v850/v850.c
new file mode 100644
index 000000000..eb1932657
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850.c
@@ -0,0 +1,3281 @@
+/* Subroutines for insn-output.c for NEC V850 series
+ Copyright (C) 1996-2014 Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "expr.h"
+#include "function.h"
+#include "diagnostic-core.h"
+#include "ggc.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+#include "df.h"
+#include "opts.h"
+
+#ifndef streq
+#define streq(a,b) (strcmp (a, b) == 0)
+#endif
+
+static void v850_print_operand_address (FILE *, rtx);
+
+/* Names of the various data areas used on the v850. */
+tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+
+/* Track the current data area set by the data area pragma (which
+ can be nested). Tested by check_default_data_area. */
+data_area_stack_element * data_area_stack = NULL;
+
+/* True if we don't need to check any more if the current
+ function is an interrupt handler. */
+static int v850_interrupt_cache_p = FALSE;
+
+rtx v850_compare_op0, v850_compare_op1;
+
+/* Whether current function is an interrupt handler. */
+static int v850_interrupt_p = FALSE;
+
+static GTY(()) section * rosdata_section;
+static GTY(()) section * rozdata_section;
+static GTY(()) section * tdata_section;
+static GTY(()) section * zdata_section;
+static GTY(()) section * zbss_section;
+
+/* We use this to wrap all emitted insns in the prologue. */
+static rtx
+F (rtx x)
+{
+ if (GET_CODE (x) != CLOBBER)
+ RTX_FRAME_RELATED_P (x) = 1;
+ return x;
+}
+
+/* Mark all the subexpressions of the PARALLEL rtx PAR as
+ frame-related. Return PAR.
+
+ dwarf2out.c:dwarf2out_frame_debug_expr ignores sub-expressions of a
+ PARALLEL rtx other than the first if they do not have the
+ FRAME_RELATED flag set on them. */
+
+static rtx
+v850_all_frame_related (rtx par)
+{
+ int len = XVECLEN (par, 0);
+ int i;
+
+ gcc_assert (GET_CODE (par) == PARALLEL);
+ for (i = 0; i < len; i++)
+ F (XVECEXP (par, 0, i));
+
+ return par;
+}
+
+/* Handle the TARGET_PASS_BY_REFERENCE target hook.
+ Specify whether to pass the argument by reference. */
+
+static bool
+v850_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode, const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ unsigned HOST_WIDE_INT size;
+
+ if (!TARGET_GCC_ABI)
+ return 0;
+
+ if (type)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ return size > 8;
+}
+
+/* Return an RTX to represent where an argument with mode MODE
+ and type TYPE will be passed to a function. If the result
+ is NULL_RTX, the argument will be pushed. */
+
+static rtx
+v850_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
+ const_tree type, bool named)
+{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+ rtx result = NULL_RTX;
+ int size, align;
+
+ if (!named)
+ return NULL_RTX;
+
+ if (mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ size = (size + UNITS_PER_WORD -1) & ~(UNITS_PER_WORD -1);
+
+ if (size < 1)
+ {
+ /* Once we have stopped using argument registers, do not start up again. */
+ cum->nbytes = 4 * UNITS_PER_WORD;
+ return NULL_RTX;
+ }
+
+ if (!TARGET_GCC_ABI)
+ align = UNITS_PER_WORD;
+ else if (size <= UNITS_PER_WORD && type)
+ align = TYPE_ALIGN (type) / BITS_PER_UNIT;
+ else
+ align = size;
+
+ cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
+
+ if (cum->nbytes > 4 * UNITS_PER_WORD)
+ return NULL_RTX;
+
+ if (type == NULL_TREE
+ && cum->nbytes + size > 4 * UNITS_PER_WORD)
+ return NULL_RTX;
+
+ switch (cum->nbytes / UNITS_PER_WORD)
+ {
+ case 0:
+ result = gen_rtx_REG (mode, 6);
+ break;
+ case 1:
+ result = gen_rtx_REG (mode, 7);
+ break;
+ case 2:
+ result = gen_rtx_REG (mode, 8);
+ break;
+ case 3:
+ result = gen_rtx_REG (mode, 9);
+ break;
+ default:
+ result = NULL_RTX;
+ }
+
+ return result;
+}
+
+/* Return the number of bytes which must be put into registers
+ for values which are part in registers and part in memory. */
+static int
+v850_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
+ tree type, bool named)
+{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+ int size, align;
+
+ if (!named)
+ return 0;
+
+ if (mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ if (size < 1)
+ size = 1;
+
+ if (!TARGET_GCC_ABI)
+ align = UNITS_PER_WORD;
+ else if (type)
+ align = TYPE_ALIGN (type) / BITS_PER_UNIT;
+ else
+ align = size;
+
+ cum->nbytes = (cum->nbytes + align - 1) & ~ (align - 1);
+
+ if (cum->nbytes > 4 * UNITS_PER_WORD)
+ return 0;
+
+ if (cum->nbytes + size <= 4 * UNITS_PER_WORD)
+ return 0;
+
+ if (type == NULL_TREE
+ && cum->nbytes + size > 4 * UNITS_PER_WORD)
+ return 0;
+
+ return 4 * UNITS_PER_WORD - cum->nbytes;
+}
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+static void
+v850_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
+ if (!TARGET_GCC_ABI)
+ cum->nbytes += (((mode != BLKmode
+ ? GET_MODE_SIZE (mode)
+ : int_size_in_bytes (type)) + UNITS_PER_WORD - 1)
+ & -UNITS_PER_WORD);
+ else
+ cum->nbytes += (((type && int_size_in_bytes (type) > 8
+ ? GET_MODE_SIZE (Pmode)
+ : (mode != BLKmode
+ ? GET_MODE_SIZE (mode)
+ : int_size_in_bytes (type))) + UNITS_PER_WORD - 1)
+ & -UNITS_PER_WORD);
+}
+
+/* Return the high and low words of a CONST_DOUBLE */
+
+static void
+const_double_split (rtx x, HOST_WIDE_INT * p_high, HOST_WIDE_INT * p_low)
+{
+ if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ long t[2];
+ REAL_VALUE_TYPE rv;
+
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, t);
+ *p_high = t[1]; /* since v850 is little endian */
+ *p_low = t[0]; /* high is second word */
+ return;
+
+ case SFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, *p_high);
+ *p_low = 0;
+ return;
+
+ case VOIDmode:
+ case DImode:
+ *p_high = CONST_DOUBLE_HIGH (x);
+ *p_low = CONST_DOUBLE_LOW (x);
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ fatal_insn ("const_double_split got a bad insn:", x);
+}
+
+
+/* Return the cost of the rtx R with code CODE. */
+
+static int
+const_costs_int (HOST_WIDE_INT value, int zero_cost)
+{
+ if (CONST_OK_FOR_I (value))
+ return zero_cost;
+ else if (CONST_OK_FOR_J (value))
+ return 1;
+ else if (CONST_OK_FOR_K (value))
+ return 2;
+ else
+ return 4;
+}
+
+static int
+const_costs (rtx r, enum rtx_code c)
+{
+ HOST_WIDE_INT high, low;
+
+ switch (c)
+ {
+ case CONST_INT:
+ return const_costs_int (INTVAL (r), 0);
+
+ case CONST_DOUBLE:
+ const_double_split (r, &high, &low);
+ if (GET_MODE (r) == SFmode)
+ return const_costs_int (high, 1);
+ else
+ return const_costs_int (high, 1) + const_costs_int (low, 1);
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST:
+ return 2;
+
+ case HIGH:
+ return 1;
+
+ default:
+ return 4;
+ }
+}
+
+static bool
+v850_rtx_costs (rtx x,
+ int codearg,
+ int outer_code ATTRIBUTE_UNUSED,
+ int opno ATTRIBUTE_UNUSED,
+ int * total, bool speed)
+{
+ enum rtx_code code = (enum rtx_code) codearg;
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ *total = COSTS_N_INSNS (const_costs (x, code));
+ return true;
+
+ case MOD:
+ case DIV:
+ case UMOD:
+ case UDIV:
+ if (TARGET_V850E && !speed)
+ *total = 6;
+ else
+ *total = 60;
+ return true;
+
+ case MULT:
+ if (TARGET_V850E
+ && ( GET_MODE (x) == SImode
+ || GET_MODE (x) == HImode
+ || GET_MODE (x) == QImode))
+ {
+ if (GET_CODE (XEXP (x, 1)) == REG)
+ *total = 4;
+ else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ if (CONST_OK_FOR_O (INTVAL (XEXP (x, 1))))
+ *total = 6;
+ else if (CONST_OK_FOR_K (INTVAL (XEXP (x, 1))))
+ *total = 10;
+ }
+ }
+ else
+ *total = 20;
+ return true;
+
+ case ZERO_EXTRACT:
+ if (outer_code == COMPARE)
+ *total = 0;
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+/* Print operand X using operand code CODE to assembly language output file
+ FILE. */
+
+static void
+v850_print_operand (FILE * file, rtx x, int code)
+{
+ HOST_WIDE_INT high, low;
+
+ switch (code)
+ {
+ case 'c':
+ /* We use 'c' operands with symbols for .vtinherit. */
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ output_addr_const(file, x);
+ break;
+ }
+ /* Fall through. */
+ case 'b':
+ case 'B':
+ case 'C':
+ switch ((code == 'B' || code == 'C')
+ ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
+ {
+ case NE:
+ if (code == 'c' || code == 'C')
+ fprintf (file, "nz");
+ else
+ fprintf (file, "ne");
+ break;
+ case EQ:
+ if (code == 'c' || code == 'C')
+ fprintf (file, "z");
+ else
+ fprintf (file, "e");
+ break;
+ case GE:
+ fprintf (file, "ge");
+ break;
+ case GT:
+ fprintf (file, "gt");
+ break;
+ case LE:
+ fprintf (file, "le");
+ break;
+ case LT:
+ fprintf (file, "lt");
+ break;
+ case GEU:
+ fprintf (file, "nl");
+ break;
+ case GTU:
+ fprintf (file, "h");
+ break;
+ case LEU:
+ fprintf (file, "nh");
+ break;
+ case LTU:
+ fprintf (file, "l");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case 'F': /* High word of CONST_DOUBLE. */
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
+ break;
+
+ case CONST_DOUBLE:
+ const_double_split (x, &high, &low);
+ fprintf (file, "%ld", (long) high);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case 'G': /* Low word of CONST_DOUBLE. */
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ fprintf (file, "%ld", (long) INTVAL (x));
+ break;
+
+ case CONST_DOUBLE:
+ const_double_split (x, &high, &low);
+ fprintf (file, "%ld", (long) low);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case 'L':
+ fprintf (file, "%d\n", (int)(INTVAL (x) & 0xffff));
+ break;
+ case 'M':
+ fprintf (file, "%d", exact_log2 (INTVAL (x)));
+ break;
+ case 'O':
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (XEXP (x, 0), 0);
+ else
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ if (SYMBOL_REF_ZDA_P (x))
+ fprintf (file, "zdaoff");
+ else if (SYMBOL_REF_SDA_P (x))
+ fprintf (file, "sdaoff");
+ else if (SYMBOL_REF_TDA_P (x))
+ fprintf (file, "tdaoff");
+ else
+ gcc_unreachable ();
+ break;
+ case 'P':
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+ output_addr_const (file, x);
+ break;
+ case 'Q':
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (XEXP (x, 0), 0);
+ else
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ if (SYMBOL_REF_ZDA_P (x))
+ fprintf (file, "r0");
+ else if (SYMBOL_REF_SDA_P (x))
+ fprintf (file, "gp");
+ else if (SYMBOL_REF_TDA_P (x))
+ fprintf (file, "ep");
+ else
+ gcc_unreachable ();
+ break;
+ case 'R': /* 2nd word of a double. */
+ switch (GET_CODE (x))
+ {
+ case REG:
+ fprintf (file, reg_names[REGNO (x) + 1]);
+ break;
+ case MEM:
+ x = XEXP (adjust_address (x, SImode, 4), 0);
+ v850_print_operand_address (file, x);
+ if (GET_CODE (x) == CONST_INT)
+ fprintf (file, "[r0]");
+ break;
+
+ case CONST_INT:
+ {
+ unsigned HOST_WIDE_INT v = INTVAL (x);
+
+ /* Trickery to avoid problems with shifting
+ 32-bits at a time on a 32-bit host. */
+ v = v >> 16;
+ v = v >> 16;
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, v);
+ break;
+ }
+
+ case CONST_DOUBLE:
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_HIGH (x));
+ break;
+
+ default:
+ debug_rtx (x);
+ gcc_unreachable ();
+ }
+ break;
+ case 'S':
+ {
+ /* If it's a reference to a TDA variable, use sst/sld vs. st/ld. */
+ if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
+ fputs ("s", file);
+
+ break;
+ }
+ case 'T':
+ {
+ /* Like an 'S' operand above, but for unsigned loads only. */
+ if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), TRUE))
+ fputs ("s", file);
+
+ break;
+ }
+ case 'W': /* Print the instruction suffix. */
+ switch (GET_MODE (x))
+ {
+ default:
+ gcc_unreachable ();
+
+ case QImode: fputs (".b", file); break;
+ case HImode: fputs (".h", file); break;
+ case SImode: fputs (".w", file); break;
+ case SFmode: fputs (".w", file); break;
+ }
+ break;
+ case '.': /* Register r0. */
+ fputs (reg_names[0], file);
+ break;
+ case 'z': /* Reg or zero. */
+ if (REG_P (x))
+ fputs (reg_names[REGNO (x)], file);
+ else if ((GET_MODE(x) == SImode
+ || GET_MODE(x) == DFmode
+ || GET_MODE(x) == SFmode)
+ && x == CONST0_RTX(GET_MODE(x)))
+ fputs (reg_names[0], file);
+ else
+ {
+ gcc_assert (x == const0_rtx);
+ fputs (reg_names[0], file);
+ }
+ break;
+ default:
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ output_address (gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, 0),
+ XEXP (x, 0)));
+ else
+ output_address (XEXP (x, 0));
+ break;
+
+ case REG:
+ fputs (reg_names[REGNO (x)], file);
+ break;
+ case SUBREG:
+ fputs (reg_names[subreg_regno (x)], file);
+ break;
+ case CONST_DOUBLE:
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+ break;
+
+ case CONST_INT:
+ case SYMBOL_REF:
+ case CONST:
+ case LABEL_REF:
+ case CODE_LABEL:
+ v850_print_operand_address (file, x);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ }
+}
+
+
+/* Output assembly language output for the address ADDR to FILE. */
+
+static void
+v850_print_operand_address (FILE * file, rtx addr)
+{
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ fprintf (file, "0[");
+ v850_print_operand (file, addr, 0);
+ fprintf (file, "]");
+ break;
+ case LO_SUM:
+ if (GET_CODE (XEXP (addr, 0)) == REG)
+ {
+ /* reg,foo */
+ fprintf (file, "lo(");
+ v850_print_operand (file, XEXP (addr, 1), 0);
+ fprintf (file, ")[");
+ v850_print_operand (file, XEXP (addr, 0), 0);
+ fprintf (file, "]");
+ }
+ break;
+ case PLUS:
+ if (GET_CODE (XEXP (addr, 0)) == REG
+ || GET_CODE (XEXP (addr, 0)) == SUBREG)
+ {
+ /* reg,foo */
+ v850_print_operand (file, XEXP (addr, 1), 0);
+ fprintf (file, "[");
+ v850_print_operand (file, XEXP (addr, 0), 0);
+ fprintf (file, "]");
+ }
+ else
+ {
+ v850_print_operand (file, XEXP (addr, 0), 0);
+ fprintf (file, "+");
+ v850_print_operand (file, XEXP (addr, 1), 0);
+ }
+ break;
+ case SYMBOL_REF:
+ {
+ const char *off_name = NULL;
+ const char *reg_name = NULL;
+
+ if (SYMBOL_REF_ZDA_P (addr))
+ {
+ off_name = "zdaoff";
+ reg_name = "r0";
+ }
+ else if (SYMBOL_REF_SDA_P (addr))
+ {
+ off_name = "sdaoff";
+ reg_name = "gp";
+ }
+ else if (SYMBOL_REF_TDA_P (addr))
+ {
+ off_name = "tdaoff";
+ reg_name = "ep";
+ }
+
+ if (off_name)
+ fprintf (file, "%s(", off_name);
+ output_addr_const (file, addr);
+ if (reg_name)
+ fprintf (file, ")[%s]", reg_name);
+ }
+ break;
+ case CONST:
+ if (special_symbolref_operand (addr, VOIDmode))
+ {
+ rtx x = XEXP (XEXP (addr, 0), 0);
+ const char *off_name;
+ const char *reg_name;
+
+ if (SYMBOL_REF_ZDA_P (x))
+ {
+ off_name = "zdaoff";
+ reg_name = "r0";
+ }
+ else if (SYMBOL_REF_SDA_P (x))
+ {
+ off_name = "sdaoff";
+ reg_name = "gp";
+ }
+ else if (SYMBOL_REF_TDA_P (x))
+ {
+ off_name = "tdaoff";
+ reg_name = "ep";
+ }
+ else
+ gcc_unreachable ();
+
+ fprintf (file, "%s(", off_name);
+ output_addr_const (file, addr);
+ fprintf (file, ")[%s]", reg_name);
+ }
+ else
+ output_addr_const (file, addr);
+ break;
+ default:
+ output_addr_const (file, addr);
+ break;
+ }
+}
+
+static bool
+v850_print_operand_punct_valid_p (unsigned char code)
+{
+ return code == '.';
+}
+
+/* When assemble_integer is used to emit the offsets for a switch
+ table it can encounter (TRUNCATE:HI (MINUS:SI (LABEL_REF:SI) (LABEL_REF:SI))).
+ output_addr_const will normally barf at this, but it is OK to omit
+ the truncate and just emit the difference of the two labels. The
+ .hword directive will automatically handle the truncation for us.
+
+ Returns true if rtx was handled, false otherwise. */
+
+static bool
+v850_output_addr_const_extra (FILE * file, rtx x)
+{
+ if (GET_CODE (x) != TRUNCATE)
+ return false;
+
+ x = XEXP (x, 0);
+
+ /* We must also handle the case where the switch table was passed a
+ constant value and so has been collapsed. In this case the first
+ label will have been deleted. In such a case it is OK to emit
+ nothing, since the table will not be used.
+ (cf gcc.c-torture/compile/990801-1.c). */
+ if (GET_CODE (x) == MINUS
+ && GET_CODE (XEXP (x, 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == CODE_LABEL
+ && INSN_DELETED_P (XEXP (XEXP (x, 0), 0)))
+ return true;
+
+ output_addr_const (file, x);
+ return true;
+}
+
+/* Return appropriate code to load up a 1, 2, or 4 integer/floating
+ point value. */
+
+const char *
+output_move_single (rtx * operands)
+{
+ rtx dst = operands[0];
+ rtx src = operands[1];
+
+ if (REG_P (dst))
+ {
+ if (REG_P (src))
+ return "mov %1,%0";
+
+ else if (GET_CODE (src) == CONST_INT)
+ {
+ HOST_WIDE_INT value = INTVAL (src);
+
+ if (CONST_OK_FOR_J (value)) /* Signed 5-bit immediate. */
+ return "mov %1,%0";
+
+ else if (CONST_OK_FOR_K (value)) /* Signed 16-bit immediate. */
+ return "movea %1,%.,%0";
+
+ else if (CONST_OK_FOR_L (value)) /* Upper 16 bits were set. */
+ return "movhi hi0(%1),%.,%0";
+
+ /* A random constant. */
+ else if (TARGET_V850E_UP)
+ return "mov %1,%0";
+ else
+ return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
+ }
+
+ else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
+ {
+ HOST_WIDE_INT high, low;
+
+ const_double_split (src, &high, &low);
+
+ if (CONST_OK_FOR_J (high)) /* Signed 5-bit immediate. */
+ return "mov %F1,%0";
+
+ else if (CONST_OK_FOR_K (high)) /* Signed 16-bit immediate. */
+ return "movea %F1,%.,%0";
+
+ else if (CONST_OK_FOR_L (high)) /* Upper 16 bits were set. */
+ return "movhi hi0(%F1),%.,%0";
+
+ /* A random constant. */
+ else if (TARGET_V850E_UP)
+ return "mov %F1,%0";
+
+ else
+ return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0";
+ }
+
+ else if (GET_CODE (src) == MEM)
+ return "%S1ld%W1 %1,%0";
+
+ else if (special_symbolref_operand (src, VOIDmode))
+ return "movea %O1(%P1),%Q1,%0";
+
+ else if (GET_CODE (src) == LABEL_REF
+ || GET_CODE (src) == SYMBOL_REF
+ || GET_CODE (src) == CONST)
+ {
+ if (TARGET_V850E_UP)
+ return "mov hilo(%1),%0";
+ else
+ return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
+ }
+
+ else if (GET_CODE (src) == HIGH)
+ return "movhi hi(%1),%.,%0";
+
+ else if (GET_CODE (src) == LO_SUM)
+ {
+ operands[2] = XEXP (src, 0);
+ operands[3] = XEXP (src, 1);
+ return "movea lo(%3),%2,%0";
+ }
+ }
+
+ else if (GET_CODE (dst) == MEM)
+ {
+ if (REG_P (src))
+ return "%S0st%W0 %1,%0";
+
+ else if (GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
+ return "%S0st%W0 %.,%0";
+
+ else if (GET_CODE (src) == CONST_DOUBLE
+ && CONST0_RTX (GET_MODE (dst)) == src)
+ return "%S0st%W0 %.,%0";
+ }
+
+ fatal_insn ("output_move_single:", gen_rtx_SET (VOIDmode, dst, src));
+ return "";
+}
+
+enum machine_mode
+v850_select_cc_mode (enum rtx_code cond, rtx op0, rtx op1 ATTRIBUTE_UNUSED)
+{
+ if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+ {
+ switch (cond)
+ {
+ case LE:
+ return CC_FPU_LEmode;
+ case GE:
+ return CC_FPU_GEmode;
+ case LT:
+ return CC_FPU_LTmode;
+ case GT:
+ return CC_FPU_GTmode;
+ case EQ:
+ return CC_FPU_EQmode;
+ case NE:
+ return CC_FPU_NEmode;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ return CCmode;
+}
+
+enum machine_mode
+v850_gen_float_compare (enum rtx_code cond, enum machine_mode mode ATTRIBUTE_UNUSED, rtx op0, rtx op1)
+{
+ if (GET_MODE (op0) == DFmode)
+ {
+ switch (cond)
+ {
+ case LE:
+ emit_insn (gen_cmpdf_le_insn (op0, op1));
+ break;
+ case GE:
+ emit_insn (gen_cmpdf_ge_insn (op0, op1));
+ break;
+ case LT:
+ emit_insn (gen_cmpdf_lt_insn (op0, op1));
+ break;
+ case GT:
+ emit_insn (gen_cmpdf_gt_insn (op0, op1));
+ break;
+ case NE:
+ /* Note: There is no NE comparison operator. So we
+ perform an EQ comparison and invert the branch.
+ See v850_float_nz_comparison for how this is done. */
+ case EQ:
+ emit_insn (gen_cmpdf_eq_insn (op0, op1));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else if (GET_MODE (v850_compare_op0) == SFmode)
+ {
+ switch (cond)
+ {
+ case LE:
+ emit_insn (gen_cmpsf_le_insn(op0, op1));
+ break;
+ case GE:
+ emit_insn (gen_cmpsf_ge_insn(op0, op1));
+ break;
+ case LT:
+ emit_insn (gen_cmpsf_lt_insn(op0, op1));
+ break;
+ case GT:
+ emit_insn (gen_cmpsf_gt_insn(op0, op1));
+ break;
+ case NE:
+ /* Note: There is no NE comparison operator. So we
+ perform an EQ comparison and invert the branch.
+ See v850_float_nz_comparison for how this is done. */
+ case EQ:
+ emit_insn (gen_cmpsf_eq_insn(op0, op1));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ gcc_unreachable ();
+
+ return v850_select_cc_mode (cond, op0, op1);
+}
+
+rtx
+v850_gen_compare (enum rtx_code cond, enum machine_mode mode, rtx op0, rtx op1)
+{
+ if (GET_MODE_CLASS(GET_MODE (op0)) != MODE_FLOAT)
+ {
+ emit_insn (gen_cmpsi_insn (op0, op1));
+ return gen_rtx_fmt_ee (cond, mode, gen_rtx_REG(CCmode, CC_REGNUM), const0_rtx);
+ }
+ else
+ {
+ rtx cc_reg;
+ mode = v850_gen_float_compare (cond, mode, op0, op1);
+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn (gen_rtx_SET(mode, cc_reg, gen_rtx_REG (mode, FCC_REGNUM)));
+
+ return gen_rtx_fmt_ee (cond, mode, cc_reg, const0_rtx);
+ }
+}
+
+/* Return maximum offset supported for a short EP memory reference of mode
+ MODE and signedness UNSIGNEDP. */
+
+static int
+ep_memory_offset (enum machine_mode mode, int unsignedp ATTRIBUTE_UNUSED)
+{
+ int max_offset = 0;
+
+ switch (mode)
+ {
+ case QImode:
+ if (TARGET_SMALL_SLD)
+ max_offset = (1 << 4);
+ else if ((TARGET_V850E_UP)
+ && unsignedp)
+ max_offset = (1 << 4);
+ else
+ max_offset = (1 << 7);
+ break;
+
+ case HImode:
+ if (TARGET_SMALL_SLD)
+ max_offset = (1 << 5);
+ else if ((TARGET_V850E_UP)
+ && unsignedp)
+ max_offset = (1 << 5);
+ else
+ max_offset = (1 << 8);
+ break;
+
+ case SImode:
+ case SFmode:
+ max_offset = (1 << 8);
+ break;
+
+ default:
+ break;
+ }
+
+ return max_offset;
+}
+
+/* Return true if OP is a valid short EP memory reference */
+
+int
+ep_memory_operand (rtx op, enum machine_mode mode, int unsigned_load)
+{
+ rtx addr, op0, op1;
+ int max_offset;
+ int mask;
+
+ /* If we are not using the EP register on a per-function basis
+ then do not allow this optimization at all. This is to
+ prevent the use of the SLD/SST instructions which cannot be
+ guaranteed to work properly due to a hardware bug. */
+ if (!TARGET_EP)
+ return FALSE;
+
+ if (GET_CODE (op) != MEM)
+ return FALSE;
+
+ max_offset = ep_memory_offset (mode, unsigned_load);
+
+ mask = GET_MODE_SIZE (mode) - 1;
+
+ addr = XEXP (op, 0);
+ if (GET_CODE (addr) == CONST)
+ addr = XEXP (addr, 0);
+
+ switch (GET_CODE (addr))
+ {
+ default:
+ break;
+
+ case SYMBOL_REF:
+ return SYMBOL_REF_TDA_P (addr);
+
+ case REG:
+ return REGNO (addr) == EP_REGNUM;
+
+ case PLUS:
+ op0 = XEXP (addr, 0);
+ op1 = XEXP (addr, 1);
+ if (GET_CODE (op1) == CONST_INT
+ && INTVAL (op1) < max_offset
+ && INTVAL (op1) >= 0
+ && (INTVAL (op1) & mask) == 0)
+ {
+ if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM)
+ return TRUE;
+
+ if (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_TDA_P (op0))
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/* Substitute memory references involving a pointer, to use the ep pointer,
+ taking care to save and preserve the ep. */
+
+static void
+substitute_ep_register (rtx first_insn,
+ rtx last_insn,
+ int uses,
+ int regno,
+ rtx * p_r1,
+ rtx * p_ep)
+{
+ rtx reg = gen_rtx_REG (Pmode, regno);
+ rtx insn;
+
+ if (!*p_r1)
+ {
+ df_set_regs_ever_live (1, true);
+ *p_r1 = gen_rtx_REG (Pmode, 1);
+ *p_ep = gen_rtx_REG (Pmode, 30);
+ }
+
+ if (TARGET_DEBUG)
+ fprintf (stderr, "\
+Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
+ 2 * (uses - 3), uses, reg_names[regno],
+ IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+ INSN_UID (first_insn), INSN_UID (last_insn));
+
+ if (NOTE_P (first_insn))
+ first_insn = next_nonnote_insn (first_insn);
+
+ last_insn = next_nonnote_insn (last_insn);
+ for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn))
+ {
+ if (NONJUMP_INSN_P (insn))
+ {
+ rtx pattern = single_set (insn);
+
+ /* Replace the memory references. */
+ if (pattern)
+ {
+ rtx *p_mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
+
+ if (GET_CODE (SET_DEST (pattern)) == MEM
+ && GET_CODE (SET_SRC (pattern)) == MEM)
+ p_mem = (rtx *)0;
+
+ else if (GET_CODE (SET_DEST (pattern)) == MEM)
+ p_mem = &SET_DEST (pattern);
+
+ else if (GET_CODE (SET_SRC (pattern)) == MEM)
+ p_mem = &SET_SRC (pattern);
+
+ else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND
+ && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
+ p_mem = &XEXP (SET_SRC (pattern), 0);
+
+ else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND
+ && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
+ {
+ p_mem = &XEXP (SET_SRC (pattern), 0);
+ unsignedp = TRUE;
+ }
+ else
+ p_mem = (rtx *)0;
+
+ if (p_mem)
+ {
+ rtx addr = XEXP (*p_mem, 0);
+
+ if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno)
+ *p_mem = change_address (*p_mem, VOIDmode, *p_ep);
+
+ else if (GET_CODE (addr) == PLUS
+ && GET_CODE (XEXP (addr, 0)) == REG
+ && REGNO (XEXP (addr, 0)) == (unsigned) regno
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT
+ && ((INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (*p_mem),
+ unsignedp))
+ && ((INTVAL (XEXP (addr, 1))) >= 0))
+ *p_mem = change_address (*p_mem, VOIDmode,
+ gen_rtx_PLUS (Pmode,
+ *p_ep,
+ XEXP (addr, 1)));
+ }
+ }
+ }
+ }
+
+ /* Optimize back to back cases of ep <- r1 & r1 <- ep. */
+ insn = prev_nonnote_insn (first_insn);
+ if (insn && NONJUMP_INSN_P (insn)
+ && GET_CODE (PATTERN (insn)) == SET
+ && SET_DEST (PATTERN (insn)) == *p_ep
+ && SET_SRC (PATTERN (insn)) == *p_r1)
+ delete_insn (insn);
+ else
+ emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn);
+
+ emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn);
+ emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);
+}
+
+
+/* TARGET_MACHINE_DEPENDENT_REORG. On the 850, we use it to implement
+ the -mep mode to copy heavily used pointers to ep to use the implicit
+ addressing. */
+
+static void
+v850_reorg (void)
+{
+ struct
+ {
+ int uses;
+ rtx first_insn;
+ rtx last_insn;
+ }
+ regs[FIRST_PSEUDO_REGISTER];
+
+ int i;
+ int use_ep = FALSE;
+ rtx r1 = NULL_RTX;
+ rtx ep = NULL_RTX;
+ rtx insn;
+ rtx pattern;
+
+ /* If not ep mode, just return now. */
+ if (!TARGET_EP)
+ return;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ regs[i].uses = 0;
+ regs[i].first_insn = NULL_RTX;
+ regs[i].last_insn = NULL_RTX;
+ }
+
+ for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ {
+ switch (GET_CODE (insn))
+ {
+ /* End of basic block */
+ default:
+ if (!use_ep)
+ {
+ int max_uses = -1;
+ int max_regno = -1;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (max_uses < regs[i].uses)
+ {
+ max_uses = regs[i].uses;
+ max_regno = i;
+ }
+ }
+
+ if (max_uses > 3)
+ substitute_ep_register (regs[max_regno].first_insn,
+ regs[max_regno].last_insn,
+ max_uses, max_regno, &r1, &ep);
+ }
+
+ use_ep = FALSE;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ regs[i].uses = 0;
+ regs[i].first_insn = NULL_RTX;
+ regs[i].last_insn = NULL_RTX;
+ }
+ break;
+
+ case NOTE:
+ break;
+
+ case INSN:
+ pattern = single_set (insn);
+
+ /* See if there are any memory references we can shorten. */
+ if (pattern)
+ {
+ rtx src = SET_SRC (pattern);
+ rtx dest = SET_DEST (pattern);
+ rtx mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
+
+ /* We might have (SUBREG (MEM)) here, so just get rid of the
+ subregs to make this code simpler. */
+ if (GET_CODE (dest) == SUBREG
+ && (GET_CODE (SUBREG_REG (dest)) == MEM
+ || GET_CODE (SUBREG_REG (dest)) == REG))
+ alter_subreg (&dest, false);
+ if (GET_CODE (src) == SUBREG
+ && (GET_CODE (SUBREG_REG (src)) == MEM
+ || GET_CODE (SUBREG_REG (src)) == REG))
+ alter_subreg (&src, false);
+
+ if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
+ mem = NULL_RTX;
+
+ else if (GET_CODE (dest) == MEM)
+ mem = dest;
+
+ else if (GET_CODE (src) == MEM)
+ mem = src;
+
+ else if (GET_CODE (src) == SIGN_EXTEND
+ && GET_CODE (XEXP (src, 0)) == MEM)
+ mem = XEXP (src, 0);
+
+ else if (GET_CODE (src) == ZERO_EXTEND
+ && GET_CODE (XEXP (src, 0)) == MEM)
+ {
+ mem = XEXP (src, 0);
+ unsignedp = TRUE;
+ }
+ else
+ mem = NULL_RTX;
+
+ if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
+ use_ep = TRUE;
+
+ else if (!use_ep && mem
+ && GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD)
+ {
+ rtx addr = XEXP (mem, 0);
+ int regno = -1;
+ int short_p;
+
+ if (GET_CODE (addr) == REG)
+ {
+ short_p = TRUE;
+ regno = REGNO (addr);
+ }
+
+ else if (GET_CODE (addr) == PLUS
+ && GET_CODE (XEXP (addr, 0)) == REG
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT
+ && ((INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (mem), unsignedp))
+ && ((INTVAL (XEXP (addr, 1))) >= 0))
+ {
+ short_p = TRUE;
+ regno = REGNO (XEXP (addr, 0));
+ }
+
+ else
+ short_p = FALSE;
+
+ if (short_p)
+ {
+ regs[regno].uses++;
+ regs[regno].last_insn = insn;
+ if (!regs[regno].first_insn)
+ regs[regno].first_insn = insn;
+ }
+ }
+
+ /* Loading up a register in the basic block zaps any savings
+ for the register */
+ if (GET_CODE (dest) == REG)
+ {
+ enum machine_mode mode = GET_MODE (dest);
+ int regno;
+ int endregno;
+
+ regno = REGNO (dest);
+ endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+ if (!use_ep)
+ {
+ /* See if we can use the pointer before this
+ modification. */
+ int max_uses = -1;
+ int max_regno = -1;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (max_uses < regs[i].uses)
+ {
+ max_uses = regs[i].uses;
+ max_regno = i;
+ }
+ }
+
+ if (max_uses > 3
+ && max_regno >= regno
+ && max_regno < endregno)
+ {
+ substitute_ep_register (regs[max_regno].first_insn,
+ regs[max_regno].last_insn,
+ max_uses, max_regno, &r1,
+ &ep);
+
+ /* Since we made a substitution, zap all remembered
+ registers. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ regs[i].uses = 0;
+ regs[i].first_insn = NULL_RTX;
+ regs[i].last_insn = NULL_RTX;
+ }
+ }
+ }
+
+ for (i = regno; i < endregno; i++)
+ {
+ regs[i].uses = 0;
+ regs[i].first_insn = NULL_RTX;
+ regs[i].last_insn = NULL_RTX;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* # of registers saved by the interrupt handler. */
+#define INTERRUPT_FIXED_NUM 5
+
+/* # of bytes for registers saved by the interrupt handler. */
+#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)
+
+/* # of words saved for other registers. */
+#define INTERRUPT_ALL_SAVE_NUM \
+ (30 - INTERRUPT_FIXED_NUM)
+
+#define INTERRUPT_ALL_SAVE_SIZE (4 * INTERRUPT_ALL_SAVE_NUM)
+
+int
+compute_register_save_size (long * p_reg_saved)
+{
+ int size = 0;
+ int i;
+ int interrupt_handler = v850_interrupt_function_p (current_function_decl);
+ int call_p = df_regs_ever_live_p (LINK_POINTER_REGNUM);
+ long reg_saved = 0;
+
+ /* Count space for the register saves. */
+ if (interrupt_handler)
+ {
+ for (i = 0; i <= 31; i++)
+ switch (i)
+ {
+ default:
+ if (df_regs_ever_live_p (i) || call_p)
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+ }
+ break;
+
+ /* We don't save/restore r0 or the stack pointer */
+ case 0:
+ case STACK_POINTER_REGNUM:
+ break;
+
+ /* For registers with fixed use, we save them, set them to the
+ appropriate value, and then restore them.
+ These registers are handled specially, so don't list them
+ on the list of registers to save in the prologue. */
+ case 1: /* temp used to hold ep */
+ case 4: /* gp */
+ case 10: /* temp used to call interrupt save/restore */
+ case 11: /* temp used to call interrupt save/restore (long call) */
+ case EP_REGNUM: /* ep */
+ size += 4;
+ break;
+ }
+ }
+ else
+ {
+ /* Find the first register that needs to be saved. */
+ for (i = 0; i <= 31; i++)
+ if (df_regs_ever_live_p (i) && ((! call_used_regs[i])
+ || i == LINK_POINTER_REGNUM))
+ break;
+
+ /* If it is possible that an out-of-line helper function might be
+ used to generate the prologue for the current function, then we
+ need to cover the possibility that such a helper function will
+ be used, despite the fact that there might be gaps in the list of
+ registers that need to be saved. To detect this we note that the
+ helper functions always push at least register r29 (provided
+ that the function is not an interrupt handler). */
+
+ if (TARGET_PROLOG_FUNCTION
+ && (i == 2 || ((i >= 20) && (i < 30))))
+ {
+ if (i == 2)
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+
+ i = 20;
+ }
+
+ /* Helper functions save all registers between the starting
+ register and the last register, regardless of whether they
+ are actually used by the function or not. */
+ for (; i <= 29; i++)
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+ }
+
+ if (df_regs_ever_live_p (LINK_POINTER_REGNUM))
+ {
+ size += 4;
+ reg_saved |= 1L << LINK_POINTER_REGNUM;
+ }
+ }
+ else
+ {
+ for (; i <= 31; i++)
+ if (df_regs_ever_live_p (i) && ((! call_used_regs[i])
+ || i == LINK_POINTER_REGNUM))
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+ }
+ }
+ }
+
+ if (p_reg_saved)
+ *p_reg_saved = reg_saved;
+
+ return size;
+}
+
+/* Typical stack layout should looks like this after the function's prologue:
+
+ | |
+ -- ^
+ | | \ |
+ | | arguments saved | Increasing
+ | | on the stack | addresses
+ PARENT arg pointer -> | | /
+ -------------------------- ---- -------------------
+ | | - space for argument split between regs & stack
+ --
+ CHILD | | \ <-- (return address here)
+ | | other call
+ | | saved registers
+ | | /
+ --
+ frame pointer -> | | \ ___
+ | | local |
+ | | variables |f
+ | | / |r
+ -- |a
+ | | \ |m
+ | | outgoing |e
+ | | arguments | | Decreasing
+ (hard) frame pointer | | / | | addresses
+ and stack pointer -> | | / _|_ |
+ -------------------------- ---- ------------------ V */
+
+int
+compute_frame_size (int size, long * p_reg_saved)
+{
+ return (size
+ + compute_register_save_size (p_reg_saved)
+ + crtl->outgoing_args_size);
+}
+
+static int
+use_prolog_function (int num_save, int frame_size)
+{
+ int alloc_stack = (4 * num_save);
+ int unalloc_stack = frame_size - alloc_stack;
+ int save_func_len, restore_func_len;
+ int save_normal_len, restore_normal_len;
+
+ if (! TARGET_DISABLE_CALLT)
+ save_func_len = restore_func_len = 2;
+ else
+ save_func_len = restore_func_len = TARGET_LONG_CALLS ? (4+4+4+2+2) : 4;
+
+ if (unalloc_stack)
+ {
+ save_func_len += CONST_OK_FOR_J (-unalloc_stack) ? 2 : 4;
+ restore_func_len += CONST_OK_FOR_J (-unalloc_stack) ? 2 : 4;
+ }
+
+ /* See if we would have used ep to save the stack. */
+ if (TARGET_EP && num_save > 3 && (unsigned)frame_size < 255)
+ save_normal_len = restore_normal_len = (3 * 2) + (2 * num_save);
+ else
+ save_normal_len = restore_normal_len = 4 * num_save;
+
+ save_normal_len += CONST_OK_FOR_J (-frame_size) ? 2 : 4;
+ restore_normal_len += (CONST_OK_FOR_J (frame_size) ? 2 : 4) + 2;
+
+ /* Don't bother checking if we don't actually save any space.
+ This happens for instance if one register is saved and additional
+ stack space is allocated. */
+ return ((save_func_len + restore_func_len) < (save_normal_len + restore_normal_len));
+}
+
+static void
+increment_stack (signed int amount, bool in_prologue)
+{
+ rtx inc;
+
+ if (amount == 0)
+ return;
+
+ inc = GEN_INT (amount);
+
+ if (! CONST_OK_FOR_K (amount))
+ {
+ rtx reg = gen_rtx_REG (Pmode, 12);
+
+ inc = emit_move_insn (reg, inc);
+ if (in_prologue)
+ F (inc);
+ inc = reg;
+ }
+
+ inc = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, inc));
+ if (in_prologue)
+ F (inc);
+}
+
+void
+expand_prologue (void)
+{
+ unsigned int i;
+ unsigned int size = get_frame_size ();
+ unsigned int actual_fsize;
+ unsigned int init_stack_alloc = 0;
+ rtx save_regs[32];
+ rtx save_all;
+ unsigned int num_save;
+ int code;
+ int interrupt_handler = v850_interrupt_function_p (current_function_decl);
+ long reg_saved = 0;
+
+ actual_fsize = compute_frame_size (size, &reg_saved);
+
+ if (flag_stack_usage_info)
+ current_function_static_stack_size = actual_fsize;
+
+ /* Save/setup global registers for interrupt functions right now. */
+ if (interrupt_handler)
+ {
+ if (! TARGET_DISABLE_CALLT && (TARGET_V850E_UP))
+ emit_insn (gen_callt_save_interrupt ());
+ else
+ emit_insn (gen_save_interrupt ());
+
+ actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
+
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
+
+ /* Interrupt functions are not passed arguments, so no need to
+ allocate space for split structure arguments. */
+ gcc_assert (crtl->args.pretend_args_size == 0);
+ }
+
+ /* Identify all of the saved registers. */
+ num_save = 0;
+ for (i = 1; i < 32; i++)
+ {
+ if (((1L << i) & reg_saved) != 0)
+ save_regs[num_save++] = gen_rtx_REG (Pmode, i);
+ }
+
+ if (crtl->args.pretend_args_size)
+ {
+ if (num_save == 0)
+ {
+ increment_stack (- (actual_fsize + crtl->args.pretend_args_size), true);
+ actual_fsize = 0;
+ }
+ else
+ increment_stack (- crtl->args.pretend_args_size, true);
+ }
+
+ /* See if we have an insn that allocates stack space and saves the particular
+ registers we want to. Note that the helpers won't
+ allocate additional space for registers GCC saves to complete a
+ "split" structure argument. */
+ save_all = NULL_RTX;
+ if (TARGET_PROLOG_FUNCTION
+ && !crtl->args.pretend_args_size
+ && num_save > 0)
+ {
+ if (use_prolog_function (num_save, actual_fsize))
+ {
+ int alloc_stack = 4 * num_save;
+ int offset = 0;
+
+ save_all = gen_rtx_PARALLEL
+ (VOIDmode,
+ rtvec_alloc (num_save + 1
+ + (TARGET_DISABLE_CALLT ? (TARGET_LONG_CALLS ? 2 : 1) : 0)));
+
+ XVECEXP (save_all, 0, 0)
+ = gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT(-alloc_stack)));
+ for (i = 0; i < num_save; i++)
+ {
+ offset -= 4;
+ XVECEXP (save_all, 0, i+1)
+ = gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT(offset))),
+ save_regs[i]);
+ }
+
+ if (TARGET_DISABLE_CALLT)
+ {
+ XVECEXP (save_all, 0, num_save + 1)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));
+
+ if (TARGET_LONG_CALLS)
+ XVECEXP (save_all, 0, num_save + 2)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
+ }
+
+ v850_all_frame_related (save_all);
+
+ code = recog (save_all, NULL_RTX, NULL);
+ if (code >= 0)
+ {
+ rtx insn = emit_insn (save_all);
+ INSN_CODE (insn) = code;
+ actual_fsize -= alloc_stack;
+
+ }
+ else
+ save_all = NULL_RTX;
+ }
+ }
+
+ /* If no prolog save function is available, store the registers the old
+ fashioned way (one by one). */
+ if (!save_all)
+ {
+ /* Special case interrupt functions that save all registers for a call. */
+ if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ {
+ if (! TARGET_DISABLE_CALLT && (TARGET_V850E_UP))
+ emit_insn (gen_callt_save_all_interrupt ());
+ else
+ emit_insn (gen_save_all_interrupt ());
+ }
+ else
+ {
+ int offset;
+ /* If the stack is too big, allocate it in chunks so we can do the
+ register saves. We use the register save size so we use the ep
+ register. */
+ if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
+ init_stack_alloc = compute_register_save_size (NULL);
+ else
+ init_stack_alloc = actual_fsize;
+
+ /* Save registers at the beginning of the stack frame. */
+ offset = init_stack_alloc - 4;
+
+ if (init_stack_alloc)
+ increment_stack (- (signed) init_stack_alloc, true);
+
+ /* Save the return pointer first. */
+ if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
+ {
+ F (emit_move_insn (gen_rtx_MEM (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset)),
+ save_regs[--num_save]));
+ offset -= 4;
+ }
+
+ for (i = 0; i < num_save; i++)
+ {
+ F (emit_move_insn (gen_rtx_MEM (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset)),
+ save_regs[i]));
+ offset -= 4;
+ }
+ }
+ }
+
+ /* Allocate the rest of the stack that was not allocated above (either it is
+ > 32K or we just called a function to save the registers and needed more
+ stack. */
+ if (actual_fsize > init_stack_alloc)
+ increment_stack (init_stack_alloc - actual_fsize, true);
+
+ /* If we need a frame pointer, set it up now. */
+ if (frame_pointer_needed)
+ F (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
+}
+
+
+void
+expand_epilogue (void)
+{
+ unsigned int i;
+ unsigned int size = get_frame_size ();
+ long reg_saved = 0;
+ int actual_fsize = compute_frame_size (size, &reg_saved);
+ rtx restore_regs[32];
+ rtx restore_all;
+ unsigned int num_restore;
+ int code;
+ int interrupt_handler = v850_interrupt_function_p (current_function_decl);
+
+ /* Eliminate the initial stack stored by interrupt functions. */
+ if (interrupt_handler)
+ {
+ actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
+ }
+
+ /* Cut off any dynamic stack created. */
+ if (frame_pointer_needed)
+ emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
+
+ /* Identify all of the saved registers. */
+ num_restore = 0;
+ for (i = 1; i < 32; i++)
+ {
+ if (((1L << i) & reg_saved) != 0)
+ restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);
+ }
+
+ /* See if we have an insn that restores the particular registers we
+ want to. */
+ restore_all = NULL_RTX;
+
+ if (TARGET_PROLOG_FUNCTION
+ && num_restore > 0
+ && !crtl->args.pretend_args_size
+ && !interrupt_handler)
+ {
+ int alloc_stack = (4 * num_restore);
+
+ /* Don't bother checking if we don't actually save any space. */
+ if (use_prolog_function (num_restore, actual_fsize))
+ {
+ int offset;
+ restore_all = gen_rtx_PARALLEL (VOIDmode,
+ rtvec_alloc (num_restore + 2));
+ XVECEXP (restore_all, 0, 0) = ret_rtx;
+ XVECEXP (restore_all, 0, 1)
+ = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (alloc_stack)));
+
+ offset = alloc_stack - 4;
+ for (i = 0; i < num_restore; i++)
+ {
+ XVECEXP (restore_all, 0, i+2)
+ = gen_rtx_SET (VOIDmode,
+ restore_regs[i],
+ gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT(offset))));
+ offset -= 4;
+ }
+
+ code = recog (restore_all, NULL_RTX, NULL);
+
+ if (code >= 0)
+ {
+ rtx insn;
+
+ actual_fsize -= alloc_stack;
+ increment_stack (actual_fsize, false);
+
+ insn = emit_jump_insn (restore_all);
+ INSN_CODE (insn) = code;
+ }
+ else
+ restore_all = NULL_RTX;
+ }
+ }
+
+ /* If no epilogue save function is available, restore the registers the
+ old fashioned way (one by one). */
+ if (!restore_all)
+ {
+ unsigned int init_stack_free;
+
+ /* If the stack is large, we need to cut it down in 2 pieces. */
+ if (interrupt_handler)
+ init_stack_free = 0;
+ else if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
+ init_stack_free = 4 * num_restore;
+ else
+ init_stack_free = (signed) actual_fsize;
+
+ /* Deallocate the rest of the stack if it is > 32K. */
+ if ((unsigned int) actual_fsize > init_stack_free)
+ increment_stack (actual_fsize - init_stack_free, false);
+
+ /* Special case interrupt functions that save all registers
+ for a call. */
+ if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ {
+ if (! TARGET_DISABLE_CALLT)
+ emit_insn (gen_callt_restore_all_interrupt ());
+ else
+ emit_insn (gen_restore_all_interrupt ());
+ }
+ else
+ {
+ /* Restore registers from the beginning of the stack frame. */
+ int offset = init_stack_free - 4;
+
+ /* Restore the return pointer first. */
+ if (num_restore > 0
+ && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)
+ {
+ emit_move_insn (restore_regs[--num_restore],
+ gen_rtx_MEM (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset)));
+ offset -= 4;
+ }
+
+ for (i = 0; i < num_restore; i++)
+ {
+ emit_move_insn (restore_regs[i],
+ gen_rtx_MEM (SImode,
+ plus_constant (Pmode,
+ stack_pointer_rtx,
+ offset)));
+
+ emit_use (restore_regs[i]);
+ offset -= 4;
+ }
+
+ /* Cut back the remainder of the stack. */
+ increment_stack (init_stack_free + crtl->args.pretend_args_size,
+ false);
+ }
+
+ /* And return or use reti for interrupt handlers. */
+ if (interrupt_handler)
+ {
+ if (! TARGET_DISABLE_CALLT && (TARGET_V850E_UP))
+ emit_insn (gen_callt_return_interrupt ());
+ else
+ emit_jump_insn (gen_return_interrupt ());
+ }
+ else if (actual_fsize)
+ emit_jump_insn (gen_return_internal ());
+ else
+ emit_jump_insn (gen_return_simple ());
+ }
+
+ v850_interrupt_cache_p = FALSE;
+ v850_interrupt_p = FALSE;
+}
+
+/* Update the condition code from the insn. */
+void
+notice_update_cc (rtx body, rtx insn)
+{
+ switch (get_attr_cc (insn))
+ {
+ case CC_NONE:
+ /* Insn does not affect CC at all. */
+ break;
+
+ case CC_NONE_0HIT:
+ /* Insn does not change CC, but the 0'th operand has been changed. */
+ if (cc_status.value1 != 0
+ && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
+ cc_status.value1 = 0;
+ break;
+
+ case CC_SET_ZN:
+ /* Insn sets the Z,N flags of CC to recog_data.operand[0].
+ V,C is in an unusable state. */
+ CC_STATUS_INIT;
+ cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
+ cc_status.value1 = recog_data.operand[0];
+ break;
+
+ case CC_SET_ZNV:
+ /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].
+ C is in an unusable state. */
+ CC_STATUS_INIT;
+ cc_status.flags |= CC_NO_CARRY;
+ cc_status.value1 = recog_data.operand[0];
+ break;
+
+ case CC_COMPARE:
+ /* The insn is a compare instruction. */
+ CC_STATUS_INIT;
+ cc_status.value1 = SET_SRC (body);
+ break;
+
+ case CC_CLOBBER:
+ /* Insn doesn't leave CC in a usable state. */
+ CC_STATUS_INIT;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Retrieve the data area that has been chosen for the given decl. */
+
+v850_data_area
+v850_get_data_area (tree decl)
+{
+ if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_SDA;
+
+ if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_TDA;
+
+ if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_ZDA;
+
+ return DATA_AREA_NORMAL;
+}
+
+/* Store the indicated data area in the decl's attributes. */
+
+static void
+v850_set_data_area (tree decl, v850_data_area data_area)
+{
+ tree name;
+
+ switch (data_area)
+ {
+ case DATA_AREA_SDA: name = get_identifier ("sda"); break;
+ case DATA_AREA_TDA: name = get_identifier ("tda"); break;
+ case DATA_AREA_ZDA: name = get_identifier ("zda"); break;
+ default:
+ return;
+ }
+
+ DECL_ATTRIBUTES (decl) = tree_cons
+ (name, NULL, DECL_ATTRIBUTES (decl));
+}
+
+/* Handle an "interrupt" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_interrupt_attribute (tree * node,
+ tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "sda", "tda" or "zda" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_data_area_attribute (tree* node,
+ tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ v850_data_area data_area;
+ v850_data_area area;
+ tree decl = *node;
+
+ /* Implement data area attribute. */
+ if (is_attribute_p ("sda", name))
+ data_area = DATA_AREA_SDA;
+ else if (is_attribute_p ("tda", name))
+ data_area = DATA_AREA_TDA;
+ else if (is_attribute_p ("zda", name))
+ data_area = DATA_AREA_ZDA;
+ else
+ gcc_unreachable ();
+
+ switch (TREE_CODE (decl))
+ {
+ case VAR_DECL:
+ if (current_function_decl != NULL_TREE)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "data area attributes cannot be specified for "
+ "local variables");
+ *no_add_attrs = true;
+ }
+
+ /* Drop through. */
+
+ case FUNCTION_DECL:
+ area = v850_get_data_area (decl);
+ if (area != DATA_AREA_NORMAL && data_area != area)
+ {
+ error ("data area of %q+D conflicts with previous declaration",
+ decl);
+ *no_add_attrs = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+
+/* Return nonzero if FUNC is an interrupt function as specified
+ by the "interrupt" attribute. */
+
+int
+v850_interrupt_function_p (tree func)
+{
+ tree a;
+ int ret = 0;
+
+ if (v850_interrupt_cache_p)
+ return v850_interrupt_p;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
+ if (a != NULL_TREE)
+ ret = 1;
+
+ else
+ {
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
+ ret = a != NULL_TREE;
+ }
+
+ /* Its not safe to trust global variables until after function inlining has
+ been done. */
+ if (reload_completed | reload_in_progress)
+ v850_interrupt_p = ret;
+
+ return ret;
+}
+
+
+static void
+v850_encode_data_area (tree decl, rtx symbol)
+{
+ int flags;
+
+ /* Map explicit sections into the appropriate attribute */
+ if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ {
+ if (DECL_SECTION_NAME (decl))
+ {
+ const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
+ if (streq (name, ".zdata") || streq (name, ".zbss"))
+ v850_set_data_area (decl, DATA_AREA_ZDA);
+
+ else if (streq (name, ".sdata") || streq (name, ".sbss"))
+ v850_set_data_area (decl, DATA_AREA_SDA);
+
+ else if (streq (name, ".tdata"))
+ v850_set_data_area (decl, DATA_AREA_TDA);
+ }
+
+ /* If no attribute, support -m{zda,sda,tda}=n */
+ else
+ {
+ int size = int_size_in_bytes (TREE_TYPE (decl));
+ if (size <= 0)
+ ;
+
+ else if (size <= small_memory_max [(int) SMALL_MEMORY_TDA])
+ v850_set_data_area (decl, DATA_AREA_TDA);
+
+ else if (size <= small_memory_max [(int) SMALL_MEMORY_SDA])
+ v850_set_data_area (decl, DATA_AREA_SDA);
+
+ else if (size <= small_memory_max [(int) SMALL_MEMORY_ZDA])
+ v850_set_data_area (decl, DATA_AREA_ZDA);
+ }
+
+ if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ return;
+ }
+
+ flags = SYMBOL_REF_FLAGS (symbol);
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break;
+ case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break;
+ case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break;
+ default: gcc_unreachable ();
+ }
+ SYMBOL_REF_FLAGS (symbol) = flags;
+}
+
+static void
+v850_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ v850_encode_data_area (decl, XEXP (rtl, 0));
+}
+
+/* Construct a JR instruction to a routine that will perform the equivalent of
+ the RTL passed in as an argument. This RTL is a function epilogue that
+ pops registers off the stack and possibly releases some extra stack space
+ as well. The code has already verified that the RTL matches these
+ requirements. */
+
+char *
+construct_restore_jr (rtx op)
+{
+ int count = XVECLEN (op, 0);
+ int stack_bytes;
+ unsigned long int mask;
+ unsigned long int first;
+ unsigned long int last;
+ int i;
+ static char buff [100]; /* XXX */
+
+ if (count <= 2)
+ {
+ error ("bogus JR construction: %d", count);
+ return NULL;
+ }
+
+ /* Work out how many bytes to pop off the stack before retrieving
+ registers. */
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
+ gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
+ gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
+
+ stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
+
+ /* Each pop will remove 4 bytes from the stack.... */
+ stack_bytes -= (count - 2) * 4;
+
+ /* Make sure that the amount we are popping either 0 or 16 bytes. */
+ if (stack_bytes != 0)
+ {
+ error ("bad amount of stack space removal: %d", stack_bytes);
+ return NULL;
+ }
+
+ /* Now compute the bit mask of registers to push. */
+ mask = 0;
+ for (i = 2; i < count; i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
+ SImode));
+
+ mask |= 1 << REGNO (SET_DEST (vector_element));
+ }
+
+ /* Scan for the first register to pop. */
+ for (first = 0; first < 32; first++)
+ {
+ if (mask & (1 << first))
+ break;
+ }
+
+ gcc_assert (first < 32);
+
+ /* Discover the last register to pop. */
+ if (mask & (1 << LINK_POINTER_REGNUM))
+ {
+ last = LINK_POINTER_REGNUM;
+ }
+ else
+ {
+ gcc_assert (!stack_bytes);
+ gcc_assert (mask & (1 << 29));
+
+ last = 29;
+ }
+
+ /* Note, it is possible to have gaps in the register mask.
+ We ignore this here, and generate a JR anyway. We will
+ be popping more registers than is strictly necessary, but
+ it does save code space. */
+
+ if (TARGET_LONG_CALLS)
+ {
+ char name[40];
+
+ if (first == last)
+ sprintf (name, "__return_%s", reg_names [first]);
+ else
+ sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);
+
+ sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",
+ name, name);
+ }
+ else
+ {
+ if (first == last)
+ sprintf (buff, "jr __return_%s", reg_names [first]);
+ else
+ sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
+ }
+
+ return buff;
+}
+
+
+/* Construct a JARL instruction to a routine that will perform the equivalent
+ of the RTL passed as a parameter. This RTL is a function prologue that
+ saves some of the registers r20 - r31 onto the stack, and possibly acquires
+ some stack space as well. The code has already verified that the RTL
+ matches these requirements. */
+char *
+construct_save_jarl (rtx op)
+{
+ int count = XVECLEN (op, 0);
+ int stack_bytes;
+ unsigned long int mask;
+ unsigned long int first;
+ unsigned long int last;
+ int i;
+ static char buff [100]; /* XXX */
+
+ if (count <= (TARGET_LONG_CALLS ? 3 : 2))
+ {
+ error ("bogus JARL construction: %d", count);
+ return NULL;
+ }
+
+ /* Paranoia. */
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
+ gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
+ gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) == REG);
+ gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
+
+ /* Work out how many bytes to push onto the stack after storing the
+ registers. */
+ stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
+
+ /* Each push will put 4 bytes from the stack.... */
+ stack_bytes += (count - (TARGET_LONG_CALLS ? 3 : 2)) * 4;
+
+ /* Make sure that the amount we are popping either 0 or 16 bytes. */
+ if (stack_bytes != 0)
+ {
+ error ("bad amount of stack space removal: %d", stack_bytes);
+ return NULL;
+ }
+
+ /* Now compute the bit mask of registers to push. */
+ mask = 0;
+ for (i = 1; i < count - (TARGET_LONG_CALLS ? 2 : 1); i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
+ SImode));
+
+ mask |= 1 << REGNO (SET_SRC (vector_element));
+ }
+
+ /* Scan for the first register to push. */
+ for (first = 0; first < 32; first++)
+ {
+ if (mask & (1 << first))
+ break;
+ }
+
+ gcc_assert (first < 32);
+
+ /* Discover the last register to push. */
+ if (mask & (1 << LINK_POINTER_REGNUM))
+ {
+ last = LINK_POINTER_REGNUM;
+ }
+ else
+ {
+ gcc_assert (!stack_bytes);
+ gcc_assert (mask & (1 << 29));
+
+ last = 29;
+ }
+
+ /* Note, it is possible to have gaps in the register mask.
+ We ignore this here, and generate a JARL anyway. We will
+ be pushing more registers than is strictly necessary, but
+ it does save code space. */
+
+ if (TARGET_LONG_CALLS)
+ {
+ char name[40];
+
+ if (first == last)
+ sprintf (name, "__save_%s", reg_names [first]);
+ else
+ sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]);
+
+ if (TARGET_V850E3V5_UP)
+ sprintf (buff, "mov hilo(%s), r11\n\tjarl [r11], r10", name);
+ else
+ sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11",
+ name, name);
+ }
+ else
+ {
+ if (first == last)
+ sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
+ else
+ sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
+ reg_names [last]);
+ }
+
+ return buff;
+}
+
+/* A version of asm_output_aligned_bss() that copes with the special
+ data areas of the v850. */
+void
+v850_output_aligned_bss (FILE * file,
+ tree decl,
+ const char * name,
+ unsigned HOST_WIDE_INT size,
+ int align)
+{
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ switch_to_section (zbss_section);
+ break;
+
+ case DATA_AREA_SDA:
+ switch_to_section (sbss_section);
+ break;
+
+ case DATA_AREA_TDA:
+ switch_to_section (tdata_section);
+
+ default:
+ switch_to_section (bss_section);
+ break;
+ }
+
+ ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+ ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_COMMON */
+void
+v850_output_common (FILE * file,
+ tree decl,
+ const char * name,
+ int size,
+ int align)
+{
+ if (decl == NULL_TREE)
+ {
+ fprintf (file, "%s", COMMON_ASM_OP);
+ }
+ else
+ {
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ fprintf (file, "%s", ZCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_SDA:
+ fprintf (file, "%s", SCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_TDA:
+ fprintf (file, "%s", TCOMMON_ASM_OP);
+ break;
+
+ default:
+ fprintf (file, "%s", COMMON_ASM_OP);
+ break;
+ }
+ }
+
+ assemble_name (file, name);
+ fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
+void
+v850_output_local (FILE * file,
+ tree decl,
+ const char * name,
+ int size,
+ int align)
+{
+ fprintf (file, "%s", LOCAL_ASM_OP);
+ assemble_name (file, name);
+ fprintf (file, "\n");
+
+ ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
+}
+
+/* Add data area to the given declaration if a ghs data area pragma is
+ currently in effect (#pragma ghs startXXX/endXXX). */
+static void
+v850_insert_attributes (tree decl, tree * attr_ptr ATTRIBUTE_UNUSED )
+{
+ if (data_area_stack
+ && data_area_stack->data_area
+ && current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
+ && v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ v850_set_data_area (decl, data_area_stack->data_area);
+
+ /* Initialize the default names of the v850 specific sections,
+ if this has not been done before. */
+
+ if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
+ {
+ GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
+ = build_string (sizeof (".sdata")-1, ".sdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
+ = build_string (sizeof (".rosdata")-1, ".rosdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
+ = build_string (sizeof (".tdata")-1, ".tdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
+ = build_string (sizeof (".zdata")-1, ".zdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
+ = build_string (sizeof (".rozdata")-1, ".rozdata");
+ }
+
+ if (current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == CONST_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
+ && !DECL_SECTION_NAME (decl))
+ {
+ enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
+ tree chosen_section;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ kind = GHS_SECTION_KIND_TEXT;
+ else
+ {
+ /* First choose a section kind based on the data area of the decl. */
+ switch (v850_get_data_area (decl))
+ {
+ default:
+ gcc_unreachable ();
+
+ case DATA_AREA_SDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROSDATA
+ : GHS_SECTION_KIND_SDATA);
+ break;
+
+ case DATA_AREA_TDA:
+ kind = GHS_SECTION_KIND_TDATA;
+ break;
+
+ case DATA_AREA_ZDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROZDATA
+ : GHS_SECTION_KIND_ZDATA);
+ break;
+
+ case DATA_AREA_NORMAL: /* default data area */
+ if (TREE_READONLY (decl))
+ kind = GHS_SECTION_KIND_RODATA;
+ else if (DECL_INITIAL (decl))
+ kind = GHS_SECTION_KIND_DATA;
+ else
+ kind = GHS_SECTION_KIND_BSS;
+ }
+ }
+
+ /* Now, if the section kind has been explicitly renamed,
+ then attach a section attribute. */
+ chosen_section = GHS_current_section_names [(int) kind];
+
+ /* Otherwise, if this kind of section needs an explicit section
+ attribute, then also attach one. */
+ if (chosen_section == NULL)
+ chosen_section = GHS_default_section_names [(int) kind];
+
+ if (chosen_section)
+ {
+ /* Only set the section name if specified by a pragma, because
+ otherwise it will force those variables to get allocated storage
+ in this module, rather than by the linker. */
+ DECL_SECTION_NAME (decl) = chosen_section;
+ }
+ }
+}
+
+/* Construct a DISPOSE instruction that is the equivalent of
+ the given RTX. We have already verified that this should
+ be possible. */
+
+char *
+construct_dispose_instruction (rtx op)
+{
+ int count = XVECLEN (op, 0);
+ int stack_bytes;
+ unsigned long int mask;
+ int i;
+ static char buff[ 100 ]; /* XXX */
+ int use_callt = 0;
+
+ if (count <= 2)
+ {
+ error ("bogus DISPOSE construction: %d", count);
+ return NULL;
+ }
+
+ /* Work out how many bytes to pop off the
+ stack before retrieving registers. */
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
+ gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
+ gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
+
+ stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
+
+ /* Each pop will remove 4 bytes from the stack.... */
+ stack_bytes -= (count - 2) * 4;
+
+ /* Make sure that the amount we are popping
+ will fit into the DISPOSE instruction. */
+ if (stack_bytes > 128)
+ {
+ error ("too much stack space to dispose of: %d", stack_bytes);
+ return NULL;
+ }
+
+ /* Now compute the bit mask of registers to push. */
+ mask = 0;
+
+ for (i = 2; i < count; i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
+ SImode));
+
+ if (REGNO (SET_DEST (vector_element)) == 2)
+ use_callt = 1;
+ else
+ mask |= 1 << REGNO (SET_DEST (vector_element));
+ }
+
+ if (! TARGET_DISABLE_CALLT
+ && (use_callt || stack_bytes == 0))
+ {
+ if (use_callt)
+ {
+ sprintf (buff, "callt ctoff(__callt_return_r2_r%d)", (mask & (1 << 31)) ? 31 : 29);
+ return buff;
+ }
+ else
+ {
+ for (i = 20; i < 32; i++)
+ if (mask & (1 << i))
+ break;
+
+ if (i == 31)
+ sprintf (buff, "callt ctoff(__callt_return_r31c)");
+ else
+ sprintf (buff, "callt ctoff(__callt_return_r%d_r%s)",
+ i, (mask & (1 << 31)) ? "31c" : "29");
+ }
+ }
+ else
+ {
+ static char regs [100]; /* XXX */
+ int done_one;
+
+ /* Generate the DISPOSE instruction. Note we could just issue the
+ bit mask as a number as the assembler can cope with this, but for
+ the sake of our readers we turn it into a textual description. */
+ regs[0] = 0;
+ done_one = 0;
+
+ for (i = 20; i < 32; i++)
+ {
+ if (mask & (1 << i))
+ {
+ int first;
+
+ if (done_one)
+ strcat (regs, ", ");
+ else
+ done_one = 1;
+
+ first = i;
+ strcat (regs, reg_names[ first ]);
+
+ for (i++; i < 32; i++)
+ if ((mask & (1 << i)) == 0)
+ break;
+
+ if (i > first + 1)
+ {
+ strcat (regs, " - ");
+ strcat (regs, reg_names[ i - 1 ] );
+ }
+ }
+ }
+
+ sprintf (buff, "dispose %d {%s}, r31", stack_bytes / 4, regs);
+ }
+
+ return buff;
+}
+
+/* Construct a PREPARE instruction that is the equivalent of
+ the given RTL. We have already verified that this should
+ be possible. */
+
+char *
+construct_prepare_instruction (rtx op)
+{
+ int count;
+ int stack_bytes;
+ unsigned long int mask;
+ int i;
+ static char buff[ 100 ]; /* XXX */
+ int use_callt = 0;
+
+ if (XVECLEN (op, 0) <= 1)
+ {
+ error ("bogus PREPEARE construction: %d", XVECLEN (op, 0));
+ return NULL;
+ }
+
+ /* Work out how many bytes to push onto
+ the stack after storing the registers. */
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
+ gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
+ gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
+
+ stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
+
+
+ /* Make sure that the amount we are popping
+ will fit into the DISPOSE instruction. */
+ if (stack_bytes < -128)
+ {
+ error ("too much stack space to prepare: %d", stack_bytes);
+ return NULL;
+ }
+
+ /* Now compute the bit mask of registers to push. */
+ count = 0;
+ mask = 0;
+ for (i = 1; i < XVECLEN (op, 0); i++)
+ {
+ rtx vector_element = XVECEXP (op, 0, i);
+
+ if (GET_CODE (vector_element) == CLOBBER)
+ continue;
+
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
+ SImode));
+
+ if (REGNO (SET_SRC (vector_element)) == 2)
+ use_callt = 1;
+ else
+ mask |= 1 << REGNO (SET_SRC (vector_element));
+ count++;
+ }
+
+ stack_bytes += count * 4;
+
+ if ((! TARGET_DISABLE_CALLT)
+ && (use_callt || stack_bytes == 0))
+ {
+ if (use_callt)
+ {
+ sprintf (buff, "callt ctoff(__callt_save_r2_r%d)", (mask & (1 << 31)) ? 31 : 29 );
+ return buff;
+ }
+
+ for (i = 20; i < 32; i++)
+ if (mask & (1 << i))
+ break;
+
+ if (i == 31)
+ sprintf (buff, "callt ctoff(__callt_save_r31c)");
+ else
+ sprintf (buff, "callt ctoff(__callt_save_r%d_r%s)",
+ i, (mask & (1 << 31)) ? "31c" : "29");
+ }
+ else
+ {
+ static char regs [100]; /* XXX */
+ int done_one;
+
+
+ /* Generate the PREPARE instruction. Note we could just issue the
+ bit mask as a number as the assembler can cope with this, but for
+ the sake of our readers we turn it into a textual description. */
+ regs[0] = 0;
+ done_one = 0;
+
+ for (i = 20; i < 32; i++)
+ {
+ if (mask & (1 << i))
+ {
+ int first;
+
+ if (done_one)
+ strcat (regs, ", ");
+ else
+ done_one = 1;
+
+ first = i;
+ strcat (regs, reg_names[ first ]);
+
+ for (i++; i < 32; i++)
+ if ((mask & (1 << i)) == 0)
+ break;
+
+ if (i > first + 1)
+ {
+ strcat (regs, " - ");
+ strcat (regs, reg_names[ i - 1 ] );
+ }
+ }
+ }
+
+ sprintf (buff, "prepare {%s}, %d", regs, (- stack_bytes) / 4);
+ }
+
+ return buff;
+}
+
+/* Return an RTX indicating where the return address to the
+ calling function can be found. */
+
+rtx
+v850_return_addr (int count)
+{
+ if (count != 0)
+ return const0_rtx;
+
+ return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
+}
+
+/* Implement TARGET_ASM_INIT_SECTIONS. */
+
+static void
+v850_asm_init_sections (void)
+{
+ rosdata_section
+ = get_unnamed_section (0, output_section_asm_op,
+ "\t.section .rosdata,\"a\"");
+
+ rozdata_section
+ = get_unnamed_section (0, output_section_asm_op,
+ "\t.section .rozdata,\"a\"");
+
+ tdata_section
+ = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ "\t.section .tdata,\"aw\"");
+
+ zdata_section
+ = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ "\t.section .zdata,\"aw\"");
+
+ zbss_section
+ = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+ output_section_asm_op,
+ "\t.section .zbss,\"aw\"");
+}
+
+static section *
+v850_select_section (tree exp,
+ int reloc ATTRIBUTE_UNUSED,
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+{
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ int is_const;
+ if (!TREE_READONLY (exp)
+ || TREE_SIDE_EFFECTS (exp)
+ || !DECL_INITIAL (exp)
+ || (DECL_INITIAL (exp) != error_mark_node
+ && !TREE_CONSTANT (DECL_INITIAL (exp))))
+ is_const = FALSE;
+ else
+ is_const = TRUE;
+
+ switch (v850_get_data_area (exp))
+ {
+ case DATA_AREA_ZDA:
+ return is_const ? rozdata_section : zdata_section;
+
+ case DATA_AREA_TDA:
+ return tdata_section;
+
+ case DATA_AREA_SDA:
+ return is_const ? rosdata_section : sdata_section;
+
+ default:
+ return is_const ? readonly_data_section : data_section;
+ }
+ }
+ return readonly_data_section;
+}
+
+/* Worker function for TARGET_FUNCTION_VALUE_REGNO_P. */
+
+static bool
+v850_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == 10);
+}
+
+/* Worker function for TARGET_RETURN_IN_MEMORY. */
+
+static bool
+v850_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ /* Return values > 8 bytes in length in memory. */
+ return int_size_in_bytes (type) > 8
+ || TYPE_MODE (type) == BLKmode
+ /* With the rh850 ABI return all aggregates in memory. */
+ || ((! TARGET_GCC_ABI) && AGGREGATE_TYPE_P (type))
+ ;
+}
+
+/* Worker function for TARGET_FUNCTION_VALUE. */
+
+static rtx
+v850_function_value (const_tree valtype,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (TYPE_MODE (valtype), 10);
+}
+
+
+/* Worker function for TARGET_CAN_ELIMINATE. */
+
+static bool
+v850_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true);
+}
+
+/* Worker function for TARGET_CONDITIONAL_REGISTER_USAGE.
+
+ If TARGET_APP_REGS is not defined then add r2 and r5 to
+ the pool of fixed registers. See PR 14505. */
+
+static void
+v850_conditional_register_usage (void)
+{
+ if (TARGET_APP_REGS)
+ {
+ fixed_regs[2] = 0; call_used_regs[2] = 0;
+ fixed_regs[5] = 0; call_used_regs[5] = 1;
+ }
+}
+
+/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE. */
+
+static void
+v850_asm_trampoline_template (FILE *f)
+{
+ fprintf (f, "\tjarl .+4,r12\n");
+ fprintf (f, "\tld.w 12[r12],r20\n");
+ fprintf (f, "\tld.w 16[r12],r12\n");
+ fprintf (f, "\tjmp [r12]\n");
+ fprintf (f, "\tnop\n");
+ fprintf (f, "\t.long 0\n");
+ fprintf (f, "\t.long 0\n");
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT. */
+
+static void
+v850_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0);
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, SImode, 16);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, 20);
+ emit_move_insn (mem, fnaddr);
+}
+
+static int
+v850_issue_rate (void)
+{
+ return (TARGET_V850E2_UP ? 2 : 1);
+}
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
+
+static bool
+v850_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+ return (GET_CODE (x) == CONST_DOUBLE
+ || !(GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && !CONST_OK_FOR_K (INTVAL (XEXP (XEXP (x, 0), 1)))));
+}
+
+static int
+v850_memory_move_cost (enum machine_mode mode,
+ reg_class_t reg_class ATTRIBUTE_UNUSED,
+ bool in)
+{
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 0:
+ return in ? 24 : 8;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return in ? 6 : 2;
+ default:
+ return (GET_MODE_SIZE (mode) / 2) * (in ? 3 : 1);
+ }
+}
+
+int
+v850_adjust_insn_length (rtx insn, int length)
+{
+ if (TARGET_V850E3V5_UP)
+ {
+ if (CALL_P (insn))
+ {
+ if (TARGET_LONG_CALLS)
+ {
+ /* call_internal_long, call_value_internal_long. */
+ if (length == 8)
+ length = 4;
+ if (length == 16)
+ length = 10;
+ }
+ else
+ {
+ /* call_internal_short, call_value_internal_short. */
+ if (length == 8)
+ length = 4;
+ }
+ }
+ }
+ return length;
+}
+
+/* V850 specific attributes. */
+
+static const struct attribute_spec v850_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
+ { "interrupt_handler", 0, 0, true, false, false,
+ v850_handle_interrupt_attribute, false },
+ { "interrupt", 0, 0, true, false, false,
+ v850_handle_interrupt_attribute, false },
+ { "sda", 0, 0, true, false, false,
+ v850_handle_data_area_attribute, false },
+ { "tda", 0, 0, true, false, false,
+ v850_handle_data_area_attribute, false },
+ { "zda", 0, 0, true, false, false,
+ v850_handle_data_area_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
+static void
+v850_option_override (void)
+{
+ if (flag_exceptions || flag_non_call_exceptions)
+ flag_omit_frame_pointer = 0;
+
+ /* The RH850 ABI does not (currently) support the use of the CALLT instruction. */
+ if (! TARGET_GCC_ABI)
+ target_flags |= MASK_DISABLE_CALLT;
+}
+
+const char *
+v850_gen_movdi (rtx * operands)
+{
+ if (REG_P (operands[0]))
+ {
+ if (REG_P (operands[1]))
+ {
+ if (REGNO (operands[0]) == (REGNO (operands[1]) - 1))
+ return "mov %1, %0; mov %R1, %R0";
+
+ return "mov %R1, %R0; mov %1, %0";
+ }
+
+ if (MEM_P (operands[1]))
+ {
+ if (REGNO (operands[0]) & 1)
+ /* Use two load word instructions to synthesise a load double. */
+ return "ld.w %1, %0 ; ld.w %R1, %R0" ;
+
+ return "ld.dw %1, %0";
+ }
+
+ return "mov %1, %0; mov %R1, %R0";
+ }
+
+ gcc_assert (REG_P (operands[1]));
+
+ if (REGNO (operands[1]) & 1)
+ /* Use two store word instructions to synthesise a store double. */
+ return "st.w %1, %0 ; st.w %R1, %R0 ";
+
+ return "st.dw %1, %0";
+}
+
+/* Initialize the GCC target structure. */
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE v850_option_override
+
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST v850_memory_move_cost
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND v850_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS v850_print_operand_address
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P v850_print_operand_punct_valid_p
+
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA v850_output_addr_const_extra
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
+
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
+
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION v850_select_section
+
+/* The assembler supports switchable .bss sections, but
+ v850_select_section doesn't yet make use of them. */
+#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
+
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS v850_rtx_costs
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG v850_reorg
+
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE v850_issue_rate
+
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P v850_function_value_regno_p
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE v850_function_value
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY v850_return_in_memory
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE v850_pass_by_reference
+
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES v850_arg_partial_bytes
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG v850_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE v850_function_arg_advance
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE v850_can_eliminate
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE v850_conditional_register_usage
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE v850_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT v850_trampoline_init
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P v850_legitimate_constant_p
+
+#undef TARGET_CAN_USE_DOLOOP_P
+#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-v850.h"
diff --git a/gcc-4.9/gcc/config/v850/v850.h b/gcc-4.9/gcc/config/v850/v850.h
new file mode 100644
index 000000000..92db20a44
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850.h
@@ -0,0 +1,979 @@
+/* Definitions of target machine for GNU compiler. NEC V850 series
+ Copyright (C) 1996-2014 Free Software Foundation, Inc.
+ Contributed by Jeff Law (law@cygnus.com).
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_V850_H
+#define GCC_V850_H
+
+extern GTY(()) rtx v850_compare_op0;
+extern GTY(()) rtx v850_compare_op1;
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{!shared:%{!symbolic:--start-group -lc -lgcc --end-group}}"
+
+#undef ENDFILE_SPEC
+#undef LINK_SPEC
+#undef STARTFILE_SPEC
+#undef ASM_SPEC
+
+#define TARGET_CPU_generic 1
+#define TARGET_CPU_v850e 2
+#define TARGET_CPU_v850e1 3
+#define TARGET_CPU_v850e2 4
+#define TARGET_CPU_v850e2v3 5
+#define TARGET_CPU_v850e3v5 6
+
+#ifndef TARGET_CPU_DEFAULT
+#define TARGET_CPU_DEFAULT TARGET_CPU_generic
+#endif
+
+#define MASK_DEFAULT MASK_V850
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850}"
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850__}"
+
+/* Choose which processor will be the default.
+ We must pass a -mv850xx option to the assembler if no explicit -mv* option
+ is given, because the assembler's processor default may not be correct. */
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e
+#undef MASK_DEFAULT
+#define MASK_DEFAULT MASK_V850E
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e}"
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e__}"
+#endif
+
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e1
+#undef MASK_DEFAULT
+#define MASK_DEFAULT MASK_V850E /* No practical difference. */
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e1}"
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e1__} %{mv850e1:-D__v850e1__}"
+#endif
+
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e2
+#undef MASK_DEFAULT
+#define MASK_DEFAULT MASK_V850E2
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e2}"
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e2__} %{mv850e2:-D__v850e2__}"
+#endif
+
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e2v3
+#undef MASK_DEFAULT
+#define MASK_DEFAULT MASK_V850E2V3
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e2v3}"
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e2v3__} %{mv850e2v3:-D__v850e2v3__}"
+#endif
+
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v850e3v5
+#undef MASK_DEFAULT
+#define MASK_DEFAULT MASK_V850E3V5
+#undef SUBTARGET_ASM_SPEC
+#define SUBTARGET_ASM_SPEC "%{!mv*:-mv850e3v5}"
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "%{!mv*:-D__v850e3v5__} %{mv850e3v5:-D__v850e3v5__}"
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (Renesas V850E3V5)");
+#endif
+
+#define TARGET_V850E3V5_UP ((TARGET_V850E3V5))
+#define TARGET_V850E2V3_UP ((TARGET_V850E2V3) || TARGET_V850E3V5_UP)
+#define TARGET_V850E2_UP ((TARGET_V850E2) || TARGET_V850E2V3_UP)
+#define TARGET_V850E_UP ((TARGET_V850E) || TARGET_V850E2_UP)
+#define TARGET_ALL ((TARGET_V850) || TARGET_V850E_UP)
+
+#define ASM_SPEC "%{m850es:-mv850e1}%{!mv850es:%{mv*:-mv%*}} \
+%{mrelax:-mrelax} \
+%{m8byte-align:-m8byte-align} \
+%{mgcc-abi:-mgcc-abi}"
+
+#define LINK_SPEC "%{mgcc-abi:-m v850}"
+
+#define CPP_SPEC "\
+ %{mv850e3v5:-D__v850e3v5__} \
+ %{mv850e2v3:-D__v850e2v3__} \
+ %{mv850e2:-D__v850e2__} \
+ %{mv850es:-D__v850e1__} \
+ %{mv850e1:-D__v850e1__} \
+ %{mv850e:-D__v850e__} \
+ %{mv850:-D__v850__} \
+ %(subtarget_cpp_spec) \
+ %{mep:-D__EP__}"
+
+#define EXTRA_SPECS \
+ { "subtarget_asm_spec", SUBTARGET_ASM_SPEC }, \
+ { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }
+
+
+/* Macro to decide when FPU instructions can be used. */
+#define TARGET_USE_FPU (TARGET_V850E2V3_UP && ! TARGET_SOFT_FLOAT)
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define( "__v851__" ); \
+ builtin_define( "__v850" ); \
+ builtin_define( "__v850__" ); \
+ builtin_assert( "machine=v850" ); \
+ builtin_assert( "cpu=v850" ); \
+ if (TARGET_EP) \
+ builtin_define ("__EP__"); \
+ if (TARGET_GCC_ABI) \
+ builtin_define ("__V850_GCC_ABI__"); \
+ else \
+ builtin_define ("__V850_RH850_ABI__"); \
+ if (! TARGET_DISABLE_CALLT) \
+ builtin_define ("__V850_CALLT__"); \
+ if (TARGET_8BYTE_ALIGN) \
+ builtin_define ("__V850_8BYTE_ALIGN__");\
+ builtin_define (TARGET_USE_FPU ? \
+ "__FPU_OK__" : "__NO_FPU__");\
+ } \
+ while(0)
+
+#define MASK_CPU (MASK_V850 | MASK_V850E | MASK_V850E1 | MASK_V850E2 | MASK_V850E2V3 | MASK_V850E3V5)
+
+/* Target machine storage layout */
+
+/* Define this if most significant bit is lowest numbered
+ in instructions that operate on numbered bit-fields.
+ This is not true on the NEC V850. */
+#define BITS_BIG_ENDIAN 0
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+/* This is not true on the NEC V850. */
+#define BYTES_BIG_ENDIAN 0
+
+/* Define this if most significant word of a multiword number is lowest
+ numbered.
+ This is not true on the NEC V850. */
+#define WORDS_BIG_ENDIAN 0
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 4
+
+/* Define this macro if it is advisable to hold scalars in registers
+ in a wider mode than that declared by the program. In such cases,
+ the value is constrained to be within the bounds of the declared
+ type, but kept valid in the wider mode. The signedness of the
+ extension may differ from that of the type.
+
+ Some simple experiments have shown that leaving UNSIGNEDP alone
+ generates the best overall code. */
+
+#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < 4) \
+ { (MODE) = SImode; }
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY 32
+
+/* The stack goes in 32-bit lumps. */
+#define STACK_BOUNDARY BIGGEST_ALIGNMENT
+
+/* Allocation boundary (in *bits*) for the code of a function.
+ 16 is the minimum boundary; 32 would give better performance. */
+#define FUNCTION_BOUNDARY (((! TARGET_GCC_ABI) || optimize_size) ? 16 : 32)
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT (TARGET_8BYTE_ALIGN ? 64 : 32)
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* No structure field wants to be aligned rounder than this. */
+#define BIGGEST_FIELD_ALIGNMENT BIGGEST_ALIGNMENT
+
+/* Define this if move instructions will actually fail to work
+ when given unaligned data. */
+#define STRICT_ALIGNMENT (!TARGET_NO_STRICT_ALIGN)
+
+/* Define this as 1 if `char' should by default be signed; else as 0.
+
+ On the NEC V850, loads do sign extension, so make this default. */
+#define DEFAULT_SIGNED_CHAR 1
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/* Standard register usage. */
+
+/* Number of actual hardware registers.
+ The hardware registers are assigned numbers for the compiler
+ from 0 to just below FIRST_PSEUDO_REGISTER.
+
+ All registers that the compiler knows about must be given numbers,
+ even those that are not normally considered general registers. */
+
+#define FIRST_PSEUDO_REGISTER 36
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator. */
+
+#define FIXED_REGISTERS \
+ { 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, 1, 0, \
+ 1, 1, \
+ 1, 1}
+
+/* 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you
+ like. */
+
+#define CALL_USED_REGISTERS \
+ { 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, 1, 1, \
+ 1, 1, \
+ 1, 1}
+
+/* List the order in which to allocate registers. Each register must be
+ listed once, even those in FIXED_REGISTERS.
+
+ On the 850, we make the return registers first, then all of the volatile
+ registers, then the saved registers in reverse order to better save the
+ registers with an out of line function, and finally the fixed
+ registers. */
+
+#define REG_ALLOC_ORDER \
+{ \
+ 10, 11, /* return registers */ \
+ 12, 13, 14, 15, 16, 17, 18, 19, /* scratch registers */ \
+ 6, 7, 8, 9, 31, /* argument registers */ \
+ 29, 28, 27, 26, 25, 24, 23, 22, /* saved registers */ \
+ 21, 20, 2, \
+ 0, 1, 3, 4, 5, 30, 32, 33, /* fixed registers */ \
+ 34, 35 \
+}
+
+/* Return number of consecutive hard regs needed starting at reg REGNO
+ to hold something of mode MODE.
+
+ This is ordinarily the length in words of a value of mode MODE
+ but can be less for certain modes in special long registers. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode
+ MODE. */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) <= 4) || (((REGNO) & 1) == 0 && (REGNO) != 0))
+
+/* Value is 1 if it is a good idea to tie two pseudo registers
+ when one has mode MODE1 and one has mode MODE2.
+ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+ for any hard reg, then this must be 0 for correct output. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ (MODE1 == MODE2 || (GET_MODE_SIZE (MODE1) <= 4 && GET_MODE_SIZE (MODE2) <= 4))
+
+
+/* Define the classes of registers for register constraints in the
+ machine description. Also define ranges of constants.
+
+ One of the classes must always be named ALL_REGS and include all hard regs.
+ If there is more than one class, another class must be named NO_REGS
+ and contain no registers.
+
+ The name GENERAL_REGS must be the name of a class (or an alias for
+ another name such as ALL_REGS). This is the class of registers
+ that is allowed by "g" or "r" in a register constraint.
+ Also, registers outside this class are allocated only when
+ instructions express preferences for them.
+
+ The classes must be numbered in nondecreasing order; that is,
+ a larger-numbered class must never be contained completely
+ in a smaller-numbered class.
+
+ For any two classes, it is very desirable that there be another
+ class that represents their union. */
+
+enum reg_class
+{
+ NO_REGS, EVEN_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file. */
+
+#define REG_CLASS_NAMES \
+{ "NO_REGS", "EVEN_REGS", "GENERAL_REGS", "ALL_REGS", "LIM_REGS" }
+
+/* Define which registers fit in which classes.
+ This is an initializer for a vector of HARD_REG_SET
+ of length N_REG_CLASSES. */
+
+#define REG_CLASS_CONTENTS \
+{ \
+ { 0x00000000,0x0 }, /* NO_REGS */ \
+ { 0x55555554,0x0 }, /* EVEN_REGS */ \
+ { 0xfffffffe,0x0 }, /* GENERAL_REGS */ \
+ { 0xffffffff,0x0 }, /* ALL_REGS */ \
+}
+
+/* The same information, inverted:
+ Return the class number of the smallest class containing
+ reg number REGNO. This could be a conditional expression
+ or could index an array. */
+
+#define REGNO_REG_CLASS(REGNO) ((REGNO == CC_REGNUM || REGNO == FCC_REGNUM) ? NO_REGS : GENERAL_REGS)
+
+/* The class value for index registers, and the one for base regs. */
+
+#define INDEX_REG_CLASS NO_REGS
+#define BASE_REG_CLASS GENERAL_REGS
+
+/* Macros to check register numbers against specific register classes. */
+
+/* These assume that REGNO is a hard or pseudo reg number.
+ They give nonzero only if REGNO is a hard reg of the suitable class
+ or a pseudo reg currently allocated to a suitable hard reg.
+ Since they use reg_renumber, they are safe only once reg_renumber
+ has been allocated, which happens in reginfo.c during register
+ allocation. */
+
+#define REGNO_OK_FOR_BASE_P(regno) \
+ (((regno) < FIRST_PSEUDO_REGISTER \
+ && (regno) != CC_REGNUM \
+ && (regno) != FCC_REGNUM) \
+ || reg_renumber[regno] >= 0)
+
+#define REGNO_OK_FOR_INDEX_P(regno) 0
+
+/* Convenience wrappers around insn_const_int_ok_for_constraint. */
+
+#define CONST_OK_FOR_I(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_I)
+#define CONST_OK_FOR_J(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_J)
+#define CONST_OK_FOR_K(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_K)
+#define CONST_OK_FOR_L(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_L)
+#define CONST_OK_FOR_M(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_M)
+#define CONST_OK_FOR_N(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_N)
+#define CONST_OK_FOR_O(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_O)
+#define CONST_OK_FOR_W(VALUE) \
+ insn_const_int_ok_for_constraint (VALUE, CONSTRAINT_W)
+
+/* Stack layout; function entry, exit and calling. */
+
+/* Define this if pushing a word on the stack
+ makes the stack pointer a smaller address. */
+
+#define STACK_GROWS_DOWNWARD
+
+/* Define this to nonzero if the nominal address of the stack frame
+ is at the high-address end of the local variables;
+ that is, each additional local variable allocated
+ goes at a more negative offset in the frame. */
+
+#define FRAME_GROWS_DOWNWARD 1
+
+/* Offset within stack frame to start allocating local variables at.
+ If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
+ first local allocated. Otherwise, it is the offset to the BEGINNING
+ of the first local allocated. */
+
+#define STARTING_FRAME_OFFSET 0
+
+/* Offset of first parameter from the argument pointer register value. */
+/* Is equal to the size of the saved fp + pc, even if an fp isn't
+ saved since the value is used before we know. */
+
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+/* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM SP_REGNUM
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 34
+
+/* Register containing return address from latest function call. */
+#define LINK_POINTER_REGNUM LP_REGNUM
+
+/* On some machines the offset between the frame pointer and starting
+ offset of the automatic variables is not known until after register
+ allocation has been done (for example, because the saved registers
+ are between these two locations). On those machines, define
+ `FRAME_POINTER_REGNUM' the number of a special, fixed register to
+ be used internally until the offset is known, and define
+ `HARD_FRAME_POINTER_REGNUM' to be actual the hard register number
+ used for the frame pointer.
+
+ You should define this macro only in the very rare circumstances
+ when it is not possible to calculate the offset between the frame
+ pointer and the automatic variables until after register
+ allocation has been completed. When this macro is defined, you
+ must also indicate in your definition of `ELIMINABLE_REGS' how to
+ eliminate `FRAME_POINTER_REGNUM' into either
+ `HARD_FRAME_POINTER_REGNUM' or `STACK_POINTER_REGNUM'.
+
+ Do not define this macro if it would be the same as
+ `FRAME_POINTER_REGNUM'. */
+#undef HARD_FRAME_POINTER_REGNUM
+#define HARD_FRAME_POINTER_REGNUM 29
+
+/* Base register for access to arguments of the function. */
+#define ARG_POINTER_REGNUM 35
+
+/* Register in which static-chain is passed to a function. */
+#define STATIC_CHAIN_REGNUM 20
+
+/* If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. If
+ it is not defined, the only elimination attempted by the compiler
+ is to replace references to the frame pointer with references to
+ the stack pointer.
+
+ The definition of this macro is a list of structure
+ initializations, each of which specifies an original and
+ replacement register.
+
+ On some machines, the position of the argument pointer is not
+ known until the compilation is completed. In such a case, a
+ separate hard register must be used for the argument pointer.
+ This register can be eliminated by replacing it with either the
+ frame pointer or the argument pointer, depending on whether or not
+ the frame pointer has been eliminated.
+
+ In this case, you might specify:
+ #define ELIMINABLE_REGS \
+ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+ Note that the elimination of the argument pointer with the stack
+ pointer is specified first since that is the preferred elimination. */
+
+#define ELIMINABLE_REGS \
+{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \
+ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} \
+
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It
+ specifies the initial difference between the specified pair of
+ registers. This macro must be defined if `ELIMINABLE_REGS' is
+ defined. */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+{ \
+ if ((FROM) == FRAME_POINTER_REGNUM) \
+ (OFFSET) = get_frame_size () + crtl->outgoing_args_size; \
+ else if ((FROM) == ARG_POINTER_REGNUM) \
+ (OFFSET) = compute_frame_size (get_frame_size (), (long *)0); \
+ else \
+ gcc_unreachable (); \
+}
+
+/* Keep the stack pointer constant throughout the function. */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#define RETURN_ADDR_RTX(COUNT, FP) v850_return_addr (COUNT)
+
+/* Define a data type for recording info about an argument list
+ during the scan of that argument list. This data type should
+ hold all necessary information about the function itself
+ and about the args processed so far, enough to enable macros
+ such as FUNCTION_ARG to determine where the next arg should go. */
+
+#define CUMULATIVE_ARGS struct cum_arg
+struct cum_arg { int nbytes; };
+
+/* 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. */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+ do { (CUM).nbytes = 0; } while (0)
+
+/* When a parameter is passed in a register, stack space is still
+ allocated for it. */
+#define REG_PARM_STACK_SPACE(DECL) 0
+
+/* 1 if N is a possible register number for function argument passing. */
+
+#define FUNCTION_ARG_REGNO_P(N) (N >= 6 && N <= 9)
+
+/* Define how to find the value returned by a library function
+ assuming the value has mode MODE. */
+
+#define LIBCALL_VALUE(MODE) \
+ gen_rtx_REG (MODE, 10)
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+ the stack pointer does not matter. The value is tested only in
+ functions that have frame pointers.
+ No definition is equivalent to always zero. */
+
+#define EXIT_IGNORE_STACK 1
+
+/* Define this macro as a C expression that is nonzero for registers
+ used by the epilogue or the `return' pattern. */
+
+#define EPILOGUE_USES(REGNO) \
+ (reload_completed && (REGNO) == LINK_POINTER_REGNUM)
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) ;
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#define TRAMPOLINE_SIZE 24
+
+/* Addressing modes, and classification of registers for them. */
+
+
+/* 1 if X is an rtx for a constant that is a valid address. */
+
+/* ??? This seems too exclusive. May get better code by accepting more
+ possibilities here, in particular, should accept ZDA_NAME SYMBOL_REFs. */
+
+#define CONSTANT_ADDRESS_P(X) constraint_satisfied_p (X, CONSTRAINT_K)
+
+/* Maximum number of registers that can appear in a valid memory address. */
+
+#define MAX_REGS_PER_ADDRESS 1
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+ and check its validity for a certain class.
+ We have two alternate definitions for each of them.
+ The usual definition accepts all pseudo regs; the other rejects
+ them unless they have been allocated suitable hard regs.
+ The symbol REG_OK_STRICT causes the latter definition to be used.
+
+ Most source files want to accept pseudo regs in the hope that
+ they will get allocated to the class that the insn wants them to be in.
+ Source files for reload pass need to be strict.
+ After reload, it makes no difference, since pseudo regs have
+ been eliminated by then. */
+
+#ifndef REG_OK_STRICT
+
+/* Nonzero if X is a hard reg that can be used as an index
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_INDEX_P(X) 0
+/* Nonzero if X is a hard reg that can be used as a base reg
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_BASE_P(X) 1
+#define REG_OK_FOR_INDEX_P_STRICT(X) 0
+#define REG_OK_FOR_BASE_P_STRICT(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#define STRICT 0
+
+#else
+
+/* Nonzero if X is a hard reg that can be used as an index. */
+#define REG_OK_FOR_INDEX_P(X) 0
+/* Nonzero if X is a hard reg that can be used as a base reg. */
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#define STRICT 1
+
+#endif
+
+
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
+ that is a valid memory address for an instruction.
+ The MODE argument is the machine mode for the MEM expression
+ that wants to use this address.
+
+ The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
+ except for CONSTANT_ADDRESS_P which is actually
+ machine-independent. */
+
+/* Accept either REG or SUBREG where a register is valid. */
+
+#define RTX_OK_FOR_BASE_P(X) \
+ ((REG_P (X) && REG_OK_FOR_BASE_P (X)) \
+ || (GET_CODE (X) == SUBREG && REG_P (SUBREG_REG (X)) \
+ && REG_OK_FOR_BASE_P (SUBREG_REG (X))))
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+do { \
+ if (RTX_OK_FOR_BASE_P (X)) \
+ goto ADDR; \
+ if (CONSTANT_ADDRESS_P (X) \
+ && (MODE == QImode || INTVAL (X) % 2 == 0) \
+ && (GET_MODE_SIZE (MODE) <= 4 || INTVAL (X) % 4 == 0)) \
+ goto ADDR; \
+ if (GET_CODE (X) == LO_SUM \
+ && REG_P (XEXP (X, 0)) \
+ && REG_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && CONSTANT_P (XEXP (X, 1)) \
+ && (GET_CODE (XEXP (X, 1)) != CONST_INT \
+ || ((MODE == QImode || INTVAL (XEXP (X, 1)) % 2 == 0) \
+ && CONST_OK_FOR_K (INTVAL (XEXP (X, 1))))) \
+ && GET_MODE_SIZE (MODE) <= GET_MODE_SIZE (word_mode)) \
+ goto ADDR; \
+ if (special_symbolref_operand (X, MODE) \
+ && (GET_MODE_SIZE (MODE) <= GET_MODE_SIZE (word_mode))) \
+ goto ADDR; \
+ if (GET_CODE (X) == PLUS \
+ && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && constraint_satisfied_p (XEXP (X,1), CONSTRAINT_K) \
+ && ((MODE == QImode || INTVAL (XEXP (X, 1)) % 2 == 0) \
+ && CONST_OK_FOR_K (INTVAL (XEXP (X, 1)) \
+ + (GET_MODE_NUNITS (MODE) * UNITS_PER_WORD)))) \
+ goto ADDR; \
+} while (0)
+
+
+/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
+ return the mode to be used for the comparison.
+
+ For floating-point equality comparisons, CCFPEQmode should be used.
+ VOIDmode should be used in all other cases.
+
+ For integer comparisons against zero, reduce to CCNOmode or CCZmode if
+ possible, to allow for more combinations. */
+
+#define SELECT_CC_MODE(OP, X, Y) v850_select_cc_mode (OP, X, Y)
+
+/* Tell final.c how to eliminate redundant test instructions. */
+
+/* Here we define machine-dependent flags and fields in cc_status
+ (see `conditions.h'). No extra ones are needed for the VAX. */
+
+/* Store in cc_status the expressions
+ that the condition codes will describe
+ after execution of an instruction whose pattern is EXP.
+ Do not alter them if the instruction would not alter the cc's. */
+
+#define CC_OVERFLOW_UNUSABLE 0x200
+#define CC_NO_CARRY CC_NO_OVERFLOW
+#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN)
+
+/* Nonzero if access to memory by bytes or half words is no faster
+ than accessing full words. */
+#define SLOW_BYTE_ACCESS 1
+
+/* According expr.c, a value of around 6 should minimize code size, and
+ for the V850 series, that's our primary concern. */
+#define MOVE_RATIO(speed) 6
+
+/* Indirect calls are expensive, never turn a direct call
+ into an indirect call. */
+#define NO_FUNCTION_CSE
+
+/* The four different data regions on the v850. */
+typedef enum
+{
+ DATA_AREA_NORMAL,
+ DATA_AREA_SDA,
+ DATA_AREA_TDA,
+ DATA_AREA_ZDA
+} v850_data_area;
+
+#define TEXT_SECTION_ASM_OP "\t.section .text"
+#define DATA_SECTION_ASM_OP "\t.section .data"
+#define BSS_SECTION_ASM_OP "\t.section .bss"
+#define SDATA_SECTION_ASM_OP "\t.section .sdata,\"aw\""
+#define SBSS_SECTION_ASM_OP "\t.section .sbss,\"aw\""
+
+#define SCOMMON_ASM_OP "\t.scomm\t"
+#define ZCOMMON_ASM_OP "\t.zcomm\t"
+#define TCOMMON_ASM_OP "\t.tcomm\t"
+
+#define ASM_COMMENT_START "#"
+
+/* Output to assembler file text saying following lines
+ may contain character constants, extra white space, comments, etc. */
+
+#define ASM_APP_ON "#APP\n"
+
+/* Output to assembler file text saying following lines
+ no longer contain unusual constructs. */
+
+#define ASM_APP_OFF "#NO_APP\n"
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
+/* This says how to output the assembler to define a global
+ uninitialized but not common symbol. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
+
+#undef ASM_OUTPUT_ALIGNED_BSS
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ v850_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
+
+/* This says how to output the assembler to define a global
+ uninitialized, common symbol. */
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \
+ v850_output_common (FILE, DECL, NAME, SIZE, ALIGN)
+
+/* This says how to output the assembler to define a local
+ uninitialized symbol. */
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#undef ASM_OUTPUT_LOCAL
+#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+ v850_output_local (FILE, DECL, NAME, SIZE, ALIGN)
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.global "
+
+#define ASM_PN_FORMAT "%s___%lu"
+
+/* This is how we tell the assembler that two symbols have the same value. */
+
+#define ASM_OUTPUT_DEF(FILE,NAME1,NAME2) \
+ do { assemble_name(FILE, NAME1); \
+ fputs(" = ", FILE); \
+ assemble_name(FILE, NAME2); \
+ fputc('\n', FILE); } while (0)
+
+
+/* How to refer to registers in assembler output.
+ This sequence is indexed by compiler's hard-register-number (see above). */
+
+#define REGISTER_NAMES \
+{ "r0", "r1", "r2", "sp", "gp", "r5", "r6" , "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
+ "r24", "r25", "r26", "r27", "r28", "r29", "ep", "r31", \
+ "psw", "fcc", \
+ ".fp", ".ap"}
+
+/* Register numbers */
+
+#define ADDITIONAL_REGISTER_NAMES \
+{ { "zero", ZERO_REGNUM }, \
+ { "hp", 2 }, \
+ { "r3", 3 }, \
+ { "r4", 4 }, \
+ { "tp", 5 }, \
+ { "fp", 29 }, \
+ { "r30", 30 }, \
+ { "lp", LP_REGNUM} }
+
+/* This is how to output an element of a case-vector that is absolute. */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t%s .L%d\n", \
+ (TARGET_BIG_SWITCH ? ".long" : ".short"), VALUE)
+
+/* This is how to output an element of a case-vector that is relative. */
+
+/* Disable the shift, which is for the currently disabled "switch"
+ opcode. Se casesi in v850.md. */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t%s %s.L%d-.L%d%s\n", \
+ (TARGET_BIG_SWITCH ? ".long" : ".short"), \
+ (0 && ! TARGET_BIG_SWITCH && (TARGET_V850E_UP) ? "(" : ""), \
+ VALUE, REL, \
+ (0 && ! TARGET_BIG_SWITCH && (TARGET_V850E_UP) ? ")>>1" : ""))
+
+#define ASM_OUTPUT_ALIGN(FILE, LOG) \
+ if ((LOG) != 0) \
+ fprintf (FILE, "\t.align %d\n", (LOG))
+
+/* We don't have to worry about dbx compatibility for the v850. */
+#define DEFAULT_GDB_EXTENSIONS 1
+
+/* Use dwarf2 debugging info by default. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#define DWARF2_FRAME_INFO 1
+#define DWARF2_UNWIND_INFO 0
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_POINTER_REGNUM)
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_POINTER_REGNUM)
+
+#ifndef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \
+ sprintf (STRING, "*.%s%u", PREFIX, (unsigned int)(NUM))
+#endif
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE (TARGET_BIG_SWITCH ? SImode : HImode)
+
+/* Define as C expression which evaluates to nonzero if the tablejump
+ instruction expects the table to contain offsets from the address of the
+ table.
+ Do not define this if the table should contain absolute addresses. */
+#define CASE_VECTOR_PC_RELATIVE 1
+
+/* The switch instruction requires that the jump table immediately follow
+ it. */
+#define JUMP_TABLES_IN_TEXT_SECTION (!TARGET_JUMP_TABLES_IN_DATA_SECTION)
+
+#undef ASM_OUTPUT_BEFORE_CASE_LABEL
+#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \
+ ASM_OUTPUT_ALIGN ((FILE), (TARGET_BIG_SWITCH ? 2 : 1));
+
+#define WORD_REGISTER_OPERATIONS
+
+/* Byte and short loads sign extend the value to a word. */
+#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX 4
+
+/* Define if shifts truncate the shift count
+ which implies one can omit a sign-extension or zero-extension
+ of a shift count. */
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode SImode
+
+/* A function address in a call instruction
+ is a byte address (for indexing purposes)
+ so give the MEM rtx a byte's mode. */
+#define FUNCTION_MODE QImode
+
+/* Tell compiler we want to support GHS pragmas */
+#define REGISTER_TARGET_PRAGMAS() do { \
+ c_register_pragma ("ghs", "interrupt", ghs_pragma_interrupt); \
+ c_register_pragma ("ghs", "section", ghs_pragma_section); \
+ c_register_pragma ("ghs", "starttda", ghs_pragma_starttda); \
+ c_register_pragma ("ghs", "startsda", ghs_pragma_startsda); \
+ c_register_pragma ("ghs", "startzda", ghs_pragma_startzda); \
+ c_register_pragma ("ghs", "endtda", ghs_pragma_endtda); \
+ c_register_pragma ("ghs", "endsda", ghs_pragma_endsda); \
+ c_register_pragma ("ghs", "endzda", ghs_pragma_endzda); \
+} while (0)
+
+/* enum GHS_SECTION_KIND is an enumeration of the kinds of sections that
+ can appear in the "ghs section" pragma. These names are used to index
+ into the GHS_default_section_names[] and GHS_current_section_names[]
+ that are defined in v850.c, and so the ordering of each must remain
+ consistent.
+
+ These arrays give the default and current names for each kind of
+ section defined by the GHS pragmas. The current names can be changed
+ by the "ghs section" pragma. If the current names are null, use
+ the default names. Note that the two arrays have different types.
+
+ For the *normal* section kinds (like .data, .text, etc.) we do not
+ want to explicitly force the name of these sections, but would rather
+ let the linker (or at least the back end) choose the name of the
+ section, UNLESS the user has force a specific name for these section
+ kinds. To accomplish this set the name in ghs_default_section_names
+ to null. */
+
+enum GHS_section_kind
+{
+ GHS_SECTION_KIND_DEFAULT,
+
+ GHS_SECTION_KIND_TEXT,
+ GHS_SECTION_KIND_DATA,
+ GHS_SECTION_KIND_RODATA,
+ GHS_SECTION_KIND_BSS,
+ GHS_SECTION_KIND_SDATA,
+ GHS_SECTION_KIND_ROSDATA,
+ GHS_SECTION_KIND_TDATA,
+ GHS_SECTION_KIND_ZDATA,
+ GHS_SECTION_KIND_ROZDATA,
+
+ COUNT_OF_GHS_SECTION_KINDS /* must be last */
+};
+
+/* The following code is for handling pragmas supported by the
+ v850 compiler produced by Green Hills Software. This is at
+ the specific request of a customer. */
+
+typedef struct data_area_stack_element
+{
+ struct data_area_stack_element * prev;
+ v850_data_area data_area; /* Current default data area. */
+} data_area_stack_element;
+
+/* Track the current data area set by the
+ data area pragma (which can be nested). */
+extern data_area_stack_element * data_area_stack;
+
+/* Names of the various data areas used on the v850. */
+extern tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+extern tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+
+/* The assembler op to start the file. */
+
+#define FILE_ASM_OP "\t.file\n"
+
+/* Implement ZDA, TDA, and SDA */
+
+#define EP_REGNUM 30 /* ep register number */
+
+#define SYMBOL_FLAG_ZDA (SYMBOL_FLAG_MACH_DEP << 0)
+#define SYMBOL_FLAG_TDA (SYMBOL_FLAG_MACH_DEP << 1)
+#define SYMBOL_FLAG_SDA (SYMBOL_FLAG_MACH_DEP << 2)
+#define SYMBOL_REF_ZDA_P(X) ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_ZDA) != 0)
+#define SYMBOL_REF_TDA_P(X) ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_TDA) != 0)
+#define SYMBOL_REF_SDA_P(X) ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_SDA) != 0)
+
+#define TARGET_ASM_INIT_SECTIONS v850_asm_init_sections
+
+/* Define this so that the cc1plus will not think that system header files
+ need an implicit 'extern "C" { ... }' assumed. This breaks testing C++
+ in a build directory where the libstdc++ header files are found via a
+ -isystem <path-to-build-dir>. */
+#define NO_IMPLICIT_EXTERN_C
+
+#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
+ ((LENGTH) = v850_adjust_insn_length ((INSN), (LENGTH)))
+
+#endif /* ! GCC_V850_H */
diff --git a/gcc-4.9/gcc/config/v850/v850.md b/gcc-4.9/gcc/config/v850/v850.md
new file mode 100644
index 000000000..341aae45d
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850.md
@@ -0,0 +1,3115 @@
+;; GCC machine description for NEC V850
+;; Copyright (C) 1996-2014 Free Software Foundation, Inc.
+;; Contributed by Jeff Law (law@cygnus.com).
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; The original PO technology requires these to be ordered by speed,
+;; so that assigner will pick the fastest.
+
+;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; The V851 manual states that the instruction address space is 16M;
+;; the various branch/call instructions only have a 22bit offset (4M range).
+;;
+;; One day we'll probably need to handle calls to targets more than 4M
+;; away.
+
+;; The size of instructions in bytes.
+
+;;---------------------------------------------------------------------------
+;; Constants
+
+;;
+(define_constants
+ [(ZERO_REGNUM 0) ; constant zero
+ (SP_REGNUM 3) ; Stack Pointer
+ (GP_REGNUM 4) ; GP Pointer
+ (EP_REGNUM 30) ; EP pointer
+ (LP_REGNUM 31) ; Return address register
+ (CC_REGNUM 32) ; Condition code pseudo register
+ (FCC_REGNUM 33) ; Floating Condition code pseudo register
+ (UNSPEC_LOOP 200) ; loop counter
+ ]
+)
+
+(define_attr "length" ""
+ (const_int 4))
+
+(define_attr "long_calls" "yes,no"
+ (const (if_then_else (symbol_ref "TARGET_LONG_CALLS")
+ (const_string "yes")
+ (const_string "no"))))
+
+;; Types of instructions (for scheduling purposes).
+
+(define_attr "type" "load,store,bit1,mult,macc,div,fpu,single,other"
+ (const_string "other"))
+
+(define_attr "cpu" "none,v850,v850e,v850e1,v850e2,v850e2v3,v850e3v5"
+ (cond [(match_test "TARGET_V850")
+ (const_string "v850")
+ (match_test "TARGET_V850E")
+ (const_string "v850e")
+ (match_test "TARGET_V850E1")
+ (const_string "v850e1")
+ (match_test "TARGET_V850E2")
+ (const_string "v850e2")
+ (match_test "TARGET_V850E2V3")
+ (const_string "v850e2v3")
+ (match_test "TARGET_V850E3V5")
+ (const_string "v850e3v5")]
+ (const_string "none")))
+
+;; Condition code settings.
+;; none - insn does not affect cc
+;; none_0hit - insn does not affect cc but it does modify operand 0
+;; This attribute is used to keep track of when operand 0 changes.
+;; See the description of NOTICE_UPDATE_CC for more info.
+;; set_znv - sets z,n,v to usable values; c is unknown.
+;; set_zn - sets z,n to usable values; v,c is unknown.
+;; compare - compare instruction
+;; clobber - value of cc is unknown
+(define_attr "cc" "none,none_0hit,set_z,set_zn,set_znv,compare,clobber"
+ (const_string "clobber"))
+
+;; Function units for the V850. As best as I can tell, there's
+;; a traditional memory load/use stall as well as a stall if
+;; the result of a multiply is used too early.
+
+(define_insn_reservation "v850_other" 1
+ (eq_attr "type" "other")
+ "nothing")
+(define_insn_reservation "v850_mult" 2
+ (eq_attr "type" "mult")
+ "nothing")
+(define_insn_reservation "v850_memory" 2
+ (eq_attr "type" "load")
+ "nothing")
+
+(include "predicates.md")
+(include "constraints.md")
+
+;; ----------------------------------------------------------------------
+;; MOVE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+(define_insn "sign23byte_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI
+ (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "disp23_operand" "W")))))]
+ "TARGET_V850E2V3_UP"
+ "ld.b %2[%1],%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "unsign23byte_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI
+ (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "disp23_operand" "W")))))]
+ "TARGET_V850E2V3_UP"
+ "ld.bu %2[%1],%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "sign23hword_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "disp23_operand" "W")))))]
+ "TARGET_V850E2V3_UP"
+ "ld.h %2[%1],%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "unsign23hword_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "disp23_operand" "W")))))]
+ "TARGET_V850E2V3_UP"
+ "ld.hu %2[%1],%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "23word_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "disp23_operand" "W"))))]
+ "TARGET_V850E2V3_UP"
+ "ld.w %2[%1],%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "23byte_store"
+ [(set (mem:QI (plus:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "disp23_operand" "W")))
+ (match_operand:QI 2 "register_operand" "r"))]
+ "TARGET_V850E2V3_UP"
+ "st.b %2,%1[%0]"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "23hword_store"
+ [(set (mem:HI (plus:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "disp23_operand" "W")))
+ (match_operand:HI 2 "register_operand" "r"))]
+ "TARGET_V850E2V3_UP"
+ "st.h %2,%1[%0]"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "23word_store"
+ [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand 1 "disp23_operand" "W")))
+ (match_operand:SI 2 "register_operand" "r"))]
+ "TARGET_V850E2V3_UP"
+ "st.w %2,%1[%0]"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+;; movdi
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand")
+ (match_operand:DI 1 "general_operand"))]
+ "TARGET_V850E3V5_UP"
+ {
+ /* One of the ops has to be in a register or 0. */
+ if (!register_operand (operand0, DImode)
+ && !register_operand (operand1, DImode))
+ operands[1] = copy_to_mode_reg (DImode, operand1);
+
+ if (register_operand (operand0, DImode)
+ && (CONST_INT_P (operands[1]) || CONST_DOUBLE_P (operands[1])))
+ {
+ int i;
+
+ for (i = 0; i < UNITS_PER_WORD * 2; i += UNITS_PER_WORD)
+ emit_move_insn (simplify_gen_subreg (SImode, operands[0], DImode, i),
+ simplify_gen_subreg (SImode, operands[1], DImode, i));
+ DONE;
+ }
+ }
+)
+
+(define_insn "*movdi_internal"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,e!r,m")
+ (match_operand:DI 1 "nonimmediate_operand" "r,m,e!r"))]
+ "TARGET_V850E3V5_UP
+ || (register_operand (operands[0], DImode) && register_operand (operands[1], DImode))"
+ { return v850_gen_movdi (operands); }
+ [(set_attr "length" "4,12,12")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "other,load,store")]
+)
+
+;; movqi
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ {
+ /* One of the ops has to be in a register or 0 */
+ if (!register_operand (operand0, QImode)
+ && !reg_or_0_operand (operand1, QImode))
+ operands[1] = copy_to_mode_reg (QImode, operand1);
+ })
+
+(define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,Q,r,m,m")
+ (match_operand:QI 1 "general_operand" "Jr,n,Q,Ir,m,r,I"))]
+ "register_operand (operands[0], QImode)
+ || reg_or_0_operand (operands[1], QImode)"
+{
+ return output_move_single (operands);
+}
+ [(set_attr "length" "2,4,2,2,4,4,4")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+ (set_attr "type" "other,other,load,other,load,store,store")])
+
+;; movhi
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+{
+ /* One of the ops has to be in a register or 0 */
+ if (!register_operand (operand0, HImode)
+ && !reg_or_0_operand (operand1, HImode))
+ operands[1] = copy_to_mode_reg (HImode, operand1);
+})
+
+(define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,Q,r,m,m")
+ (match_operand:HI 1 "general_operand" "Jr,n,Q,Ir,m,r,I"))]
+ "register_operand (operands[0], HImode)
+ || reg_or_0_operand (operands[1], HImode)"
+{
+ return output_move_single (operands);
+}
+ [(set_attr "length" "2,4,2,2,4,4,4")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+ (set_attr "type" "other,other,load,other,load,store,store")])
+
+;; movsi and helpers
+
+(define_insn "*movsi_high"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (match_operand 1 "immediate_operand" "i")))]
+ ""
+ "movhi hi(%1),%.,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "other")])
+
+(define_insn "*movsi_lo"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "immediate_operand" "i")))]
+ ""
+ "movea lo(%2),%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "other")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ {
+ /* One of the ops has to be in a register or 0 */
+ if (!register_operand (operand0, SImode)
+ && !reg_or_0_operand (operand1, SImode))
+ operands[1] = copy_to_mode_reg (SImode, operand1);
+
+ /* Some constants, as well as symbolic operands
+ must be done with HIGH & LO_SUM patterns. */
+ if (CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != HIGH
+ && ! (TARGET_V850E_UP)
+ && !special_symbolref_operand (operands[1], VOIDmode)
+ && !(GET_CODE (operands[1]) == CONST_INT
+ && (CONST_OK_FOR_J (INTVAL (operands[1]))
+ || CONST_OK_FOR_K (INTVAL (operands[1]))
+ || CONST_OK_FOR_L (INTVAL (operands[1])))))
+ {
+ rtx temp;
+
+ if (reload_in_progress || reload_completed)
+ temp = operands[0];
+ else
+ temp = gen_reg_rtx (SImode);
+
+ emit_insn (gen_rtx_SET (SImode, temp,
+ gen_rtx_HIGH (SImode, operand1)));
+ emit_insn (gen_rtx_SET (SImode, operand0,
+ gen_rtx_LO_SUM (SImode, temp, operand1)));
+ DONE;
+ }
+ })
+
+;; This is the same as the following pattern, except that it includes
+;; support for arbitrary 32-bit immediates.
+
+;; ??? This always loads addresses using hilo. If the only use of this address
+;; was in a load/store, then we would get smaller code if we only loaded the
+;; upper part with hi, and then put the lower part in the load/store insn.
+
+(define_insn "*movsi_internal_v850e"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,Q,r,r,m,m,r")
+ (match_operand:SI 1 "general_operand" "Jr,K,L,Q,Ir,m,R,r,I,i"))]
+ "(TARGET_V850E_UP)
+ && (register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))"
+{
+ return output_move_single (operands);
+}
+ [(set_attr "length" "2,4,4,2,2,4,4,4,4,6")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+ (set_attr "type" "other,other,other,load,other,load,other,store,store,other")])
+
+(define_insn "*movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,Q,r,r,m,m")
+ (match_operand:SI 1 "movsi_source_operand" "Jr,K,L,Q,Ir,m,R,r,I"))]
+ "register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode)"
+{
+ return output_move_single (operands);
+}
+ [(set_attr "length" "2,4,4,2,2,4,4,4,4")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+ (set_attr "type" "other,other,other,load,other,load,store,store,other")])
+
+(define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,r,r,Q,r,m,m,r")
+ (match_operand:SF 1 "general_operand" "Jr,K,L,n,Q,Ir,m,r,IG,iF"))]
+ "register_operand (operands[0], SFmode)
+ || reg_or_0_operand (operands[1], SFmode)"
+{
+ return output_move_single (operands);
+}
+ [(set_attr "length" "2,4,4,8,2,2,4,4,4,8")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+ (set_attr "type" "other,other,other,other,load,other,load,store,store,other")])
+
+;; ----------------------------------------------------------------------
+;; TEST INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "*v850_tst1"
+ [(set (cc0)
+ (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "m")
+ (const_int 1)
+ (match_operand:QI 1 "const_int_operand" "n"))
+ (const_int 0)))]
+ ""
+ "tst1 %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+;; This replaces ld.b;sar;andi with tst1;setf nz.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (compare (zero_extract:SI (match_operand:QI 1 "memory_operand" "")
+ (const_int 1)
+ (match_operand 2 "const_int_operand" ""))
+ (const_int 0)))]
+ ""
+ [(set (cc0) (compare (zero_extract:SI (match_dup 1)
+ (const_int 1)
+ (match_dup 2))
+ (const_int 0)))
+ (set (match_dup 0) (ne:SI (cc0) (const_int 0)))])
+
+(define_expand "cbranchsi4"
+ [(set (cc0)
+ (compare (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "reg_or_int5_operand" "")))
+ (set (pc)
+ (if_then_else
+ (match_operator 0 "ordered_comparison_operator" [(cc0)
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "")
+
+(define_expand "cstoresi4"
+ [(set (cc0)
+ (compare (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "reg_or_int5_operand" "")))
+ (set (match_operand:SI 0 "register_operand")
+ (match_operator:SI 1 "ordered_comparison_operator" [(cc0)
+ (const_int 0)]))]
+ "")
+
+(define_expand "cmpsi"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "register_operand" "r,r")
+ (match_operand:SI 1 "reg_or_int5_operand" "r,J")))]
+ ""
+ {
+ v850_compare_op0 = operands[0];
+ v850_compare_op1 = operands[1];
+ DONE;
+ })
+
+(define_insn "cmpsi_insn"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "register_operand" "r,r")
+ (match_operand:SI 1 "reg_or_int5_operand" "r,J")))]
+ ""
+ "@
+ cmp %1,%0
+ cmp %1,%0"
+ [(set_attr "length" "2,2")
+ (set_attr "cc" "compare")])
+
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "register_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))
+ (clobber (cc0))]
+ "TARGET_USE_FPU"
+{
+ enum rtx_code cond = GET_CODE (operands[0]);
+ enum machine_mode mode;
+ rtx fcc_reg;
+ rtx cc_reg;
+ rtx tmp;
+
+ v850_compare_op0 = operands[1];
+ v850_compare_op1 = operands[2];
+
+ if (GET_MODE_CLASS (GET_MODE (v850_compare_op0)) != MODE_FLOAT)
+ FAIL;
+
+ mode = v850_gen_float_compare (cond, VOIDmode, v850_compare_op0, v850_compare_op1);
+ fcc_reg = gen_rtx_REG (mode, FCC_REGNUM);
+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn(gen_rtx_SET (mode, cc_reg, fcc_reg));
+ tmp = gen_rtx_fmt_ee (cond, mode, cc_reg, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, operands[3]), pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ DONE;
+})
+
+(define_insn "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")]))]
+ "TARGET_USE_FPU"
+{
+ if (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE)
+ return "cmpf.s %c1, %z2, %z3 ; trfsr ; setf nz, %0";
+ if (GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE)
+ return "cmpf.s %c1, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == EQ)
+ return "cmpf.s eq, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == NE)
+ return "cmpf.s neq, %z2, %z3 ; trfsr ; setf nz, %0";
+ gcc_unreachable ();
+}
+ [(set_attr "length" "12")
+ (set_attr "type" "fpu")]
+)
+
+(define_expand "cbranchdf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:DF 1 "even_reg_operand")
+ (match_operand:DF 2 "even_reg_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))
+ (clobber (cc0))]
+ "TARGET_USE_FPU"
+{
+ enum rtx_code cond = GET_CODE (operands[0]);
+ enum machine_mode mode;
+ rtx fcc_reg;
+ rtx cc_reg;
+ rtx tmp;
+
+ v850_compare_op0 = operands[1];
+ v850_compare_op1 = operands[2];
+
+ if (GET_MODE_CLASS (GET_MODE (v850_compare_op0)) != MODE_FLOAT)
+ FAIL;
+
+ mode = v850_gen_float_compare (cond, VOIDmode, v850_compare_op0, v850_compare_op1);
+ fcc_reg = gen_rtx_REG (mode, FCC_REGNUM);
+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
+ emit_insn(gen_rtx_SET (mode, cc_reg, fcc_reg));
+ tmp = gen_rtx_fmt_ee (cond, mode, cc_reg, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, operands[3]), pc_rtx);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+ DONE;
+})
+
+(define_insn "cstoredf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:DF 2 "even_reg_operand" "r")
+ (match_operand:DF 3 "even_reg_operand" "r")]))]
+ "TARGET_USE_FPU"
+{
+ if (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE)
+ return "cmpf.d %c1, %z2, %z3 ; trfsr ; setf nz, %0";
+ if (GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE)
+ return "cmpf.d %c1, %z2, %z3 ; trfsr ; setf z, %0";
+ if (GET_CODE (operands[1]) == EQ)
+ return "cmpf.d eq, %z2, %z3 ; trfsr ; setf z ,%0";
+ if (GET_CODE (operands[1]) == NE)
+ return "cmpf.d neq, %z2, %z3 ; trfsr ; setf nz, %0";
+ gcc_unreachable ();
+}
+ [(set_attr "length" "12")
+ (set_attr "type" "fpu")]
+)
+
+(define_expand "cmpsf"
+ [(set (reg:CC CC_REGNUM)
+ (compare (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ {
+ v850_compare_op0 = operands[0];
+ v850_compare_op1 = operands[1];
+ DONE;
+ })
+
+(define_expand "cmpdf"
+ [(set (reg:CC CC_REGNUM)
+ (compare (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ {
+ v850_compare_op0 = operands[0];
+ v850_compare_op1 = operands[1];
+ DONE;
+ })
+
+;; ----------------------------------------------------------------------
+;; ADD INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,r,r")
+ (match_operand:SI 2 "nonmemory_operand" "rJ,K,U")))
+ (clobber (reg:CC CC_REGNUM))]
+
+ ""
+ "@
+ add %2,%0
+ addi %2,%1,%0
+ addi %O2(%P2),%1,%0"
+ [(set_attr "length" "2,4,4")
+ (set_attr "cc" "set_zn,set_zn,set_zn")])
+
+;; ----------------------------------------------------------------------
+;; SUBTRACT INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,r")
+ (match_operand:SI 2 "register_operand" "r,0")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ sub %2,%0
+ subr %1,%0"
+ [(set_attr "length" "2,2")
+ (set_attr "cc" "set_zn,set_zn")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "0")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "subr %.,%0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_zn")])
+
+;; ----------------------------------------------------------------------
+;; MULTIPLY INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_expand "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mult:SI
+ (sign_extend:SI (match_operand:HI 1 "register_operand" ""))
+ (sign_extend:SI (match_operand:HI 2 "nonmemory_operand" ""))))]
+ ""
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ emit_insn (gen_mulhisi3_internal2 (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ })
+
+(define_insn "*mulhisi3_internal1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+ (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
+ ""
+ "mulh %2,%0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "mult")])
+
+(define_insn "mulhisi3_internal2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mult:SI
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,r"))
+ (match_operand:HI 2 "const_int_operand" "J,K")))]
+ ""
+ "@
+ mulh %2,%0
+ mulhi %2,%1,%0"
+ [(set_attr "length" "2,4")
+ (set_attr "cc" "none_0hit,none_0hit")
+ (set_attr "type" "mult")])
+
+;; ??? The scheduling info is probably wrong.
+
+;; ??? This instruction can also generate the 32-bit highpart, but using it
+;; may increase code size counter to the desired result.
+
+;; ??? This instructions can also give a DImode result.
+
+;; ??? There is unsigned version, but it matters only for the DImode/highpart
+;; results.
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "reg_or_int9_operand" "rO")))]
+ "(TARGET_V850E_UP)"
+ "mul %2,%1,%."
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "mult")])
+
+;; ----------------------------------------------------------------------
+;; DIVIDE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; ??? These insns do set the Z/N condition codes, except that they are based
+;; on only one of the two results, so it doesn't seem to make sense to use
+;; them.
+
+;; ??? The scheduling info is probably wrong.
+
+(define_insn "divmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (mod:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E_UP"
+{
+ if (TARGET_V850E2_UP)
+ return "divq %2,%0,%3";
+ else
+ return "div %2,%0,%3";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "div")])
+
+(define_insn "udivmodsi4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))
+ (set (match_operand:SI 3 "register_operand" "=r")
+ (umod:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E_UP"
+{
+ if (TARGET_V850E2_UP)
+ return "divqu %2,%0,%3";
+ else
+ return "divu %2,%0,%3";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "div")])
+
+;; ??? There is a 2 byte instruction for generating only the quotient.
+;; However, it isn't clear how to compute the length field correctly.
+
+(define_insn "divmodhi4"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (div:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "register_operand" "r")))
+ (set (match_operand:HI 3 "register_operand" "=r")
+ (mod:HI (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E_UP"
+ "divh %2,%0,%3"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "div")])
+
+;; Half-words are sign-extended by default, so we must zero extend to a word
+;; here before doing the divide.
+
+(define_insn "udivmodhi4"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (udiv:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:HI 2 "register_operand" "r")))
+ (set (match_operand:HI 3 "register_operand" "=r")
+ (umod:HI (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E_UP"
+ "zxh %0 ; divhu %2,%0,%3"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "div")])
+
+;; ----------------------------------------------------------------------
+;; AND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "*v850_clr1_1"
+ [(set (match_operand:QI 0 "memory_operand" "=m")
+ (subreg:QI
+ (and:SI (subreg:SI (match_dup 0) 0)
+ (match_operand:QI 1 "not_power_of_two_operand" "")) 0))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+{
+ rtx xoperands[2];
+ xoperands[0] = operands[0];
+ xoperands[1] = GEN_INT (~INTVAL (operands[1]) & 0xff);
+ output_asm_insn ("clr1 %M1,%0", xoperands);
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_clr1_2"
+ [(set (match_operand:HI 0 "indirect_operand" "=m")
+ (subreg:HI
+ (and:SI (subreg:SI (match_dup 0) 0)
+ (match_operand:HI 1 "not_power_of_two_operand" "")) 0))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+{
+ int log2 = exact_log2 (~INTVAL (operands[1]) & 0xffff);
+
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("clr1 %1,%0", xoperands);
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_clr1_3"
+ [(set (match_operand:SI 0 "indirect_operand" "=m")
+ (and:SI (match_dup 0)
+ (match_operand:SI 1 "not_power_of_two_operand" "")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+{
+ int log2 = exact_log2 (~INTVAL (operands[1]) & 0xffffffff);
+
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("clr1 %1,%0", xoperands);
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,M")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ and %2,%0
+ and %.,%0
+ andi %2,%1,%0"
+ [(set_attr "length" "2,2,4")
+ (set_attr "cc" "set_zn")])
+
+;; ----------------------------------------------------------------------
+;; OR INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "*v850_set1_1"
+ [(set (match_operand:QI 0 "memory_operand" "=m")
+ (subreg:QI (ior:SI (subreg:SI (match_dup 0) 0)
+ (match_operand 1 "power_of_two_operand" "")) 0))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "set1 %M1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_set1_2"
+ [(set (match_operand:HI 0 "indirect_operand" "=m")
+ (subreg:HI (ior:SI (subreg:SI (match_dup 0) 0)
+ (match_operand 1 "power_of_two_operand" "")) 0))]
+ ""
+{
+ int log2 = exact_log2 (INTVAL (operands[1]));
+
+ if (log2 < 8)
+ return "set1 %M1,%0";
+ else
+ {
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("set1 %1,%0", xoperands);
+ }
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_set1_3"
+ [(set (match_operand:SI 0 "indirect_operand" "=m")
+ (ior:SI (match_dup 0)
+ (match_operand 1 "power_of_two_operand" "")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+{
+ int log2 = exact_log2 (INTVAL (operands[1]));
+
+ if (log2 < 8)
+ return "set1 %M1,%0";
+ else
+ {
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("set1 %1,%0", xoperands);
+ }
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,M")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ or %2,%0
+ or %.,%0
+ ori %2,%1,%0"
+ [(set_attr "length" "2,2,4")
+ (set_attr "cc" "set_zn")])
+
+;; ----------------------------------------------------------------------
+;; XOR INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "*v850_not1_1"
+ [(set (match_operand:QI 0 "memory_operand" "=m")
+ (subreg:QI (xor:SI (subreg:SI (match_dup 0) 0)
+ (match_operand 1 "power_of_two_operand" "")) 0))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "not1 %M1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_not1_2"
+ [(set (match_operand:HI 0 "indirect_operand" "=m")
+ (subreg:HI (xor:SI (subreg:SI (match_dup 0) 0)
+ (match_operand 1 "power_of_two_operand" "")) 0))]
+ ""
+{
+ int log2 = exact_log2 (INTVAL (operands[1]));
+
+ if (log2 < 8)
+ return "not1 %M1,%0";
+ else
+ {
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("not1 %1,%0", xoperands);
+ }
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "*v850_not1_3"
+ [(set (match_operand:SI 0 "indirect_operand" "=m")
+ (xor:SI (match_dup 0)
+ (match_operand 1 "power_of_two_operand" "")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+{
+ int log2 = exact_log2 (INTVAL (operands[1]));
+
+ if (log2 < 8)
+ return "not1 %M1,%0";
+ else
+ {
+ rtx xoperands[2];
+ xoperands[0] = gen_rtx_MEM (QImode,
+ plus_constant (Pmode, XEXP (operands[0], 0),
+ log2 / 8));
+ xoperands[1] = GEN_INT (log2 % 8);
+ output_asm_insn ("not1 %1,%0", xoperands);
+ }
+ return "";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")
+ (set_attr "type" "bit1")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,M")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ xor %2,%0
+ xor %.,%0
+ xori %2,%1,%0"
+ [(set_attr "length" "2,2,4")
+ (set_attr "cc" "set_zn")])
+
+;; ----------------------------------------------------------------------
+;; NOT INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "not %1,%0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "set_zn")])
+
+;; -----------------------------------------------------------------
+;; BIT FIELDS
+;; -----------------------------------------------------------------
+
+;; ??? Is it worth defining insv and extv for the V850 series?!?
+
+;; An insv pattern would be useful, but does not get used because
+;; store_bit_field never calls insv when storing a constant value into a
+;; single-bit bitfield.
+
+;; extv/extzv patterns would be useful, but do not get used because
+;; optimize_bitfield_compare in fold-const usually converts single
+;; bit extracts into an AND with a mask.
+
+(define_insn "insv"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "immediate_operand" "n")
+ (match_operand:SI 2 "immediate_operand" "n"))
+ (match_operand:SI 3 "register_operand" "r"))]
+ "TARGET_V850E3V5_UP"
+ "bins %3, %2, %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")]
+)
+
+;; -----------------------------------------------------------------
+;; Scc INSTRUCTIONS
+;; -----------------------------------------------------------------
+
+(define_insn "*setcc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "comparison_operator"
+ [(cc0) (const_int 0)]))]
+ ""
+{
+ if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
+ && (GET_CODE (operands[1]) == GT
+ || GET_CODE (operands[1]) == GE
+ || GET_CODE (operands[1]) == LE
+ || GET_CODE (operands[1]) == LT))
+ return 0;
+
+ return "setf %c1,%0";
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "setf_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "comparison_operator"
+ [(reg:CC CC_REGNUM) (const_int 0)]))]
+ ""
+ "setf %b1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "set_z_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand 1 "v850_float_z_comparison_operator" ""))]
+ "TARGET_V850E2V3_UP"
+ "setf z,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+(define_insn "set_nz_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand 1 "v850_float_nz_comparison_operator" ""))]
+ "TARGET_V850E2V3_UP"
+ "setf nz,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")])
+
+;; ----------------------------------------------------------------------
+;; CONDITIONAL MOVE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; Instructions using cc0 aren't allowed to have input reloads, so we must
+;; hide the fact that this instruction uses cc0. We do so by including the
+;; compare instruction inside it.
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operand 1 "comparison_operator")
+ (match_operand:SI 2 "reg_or_const_operand" "rJ")
+ (match_operand:SI 3 "reg_or_const_operand" "rI")))]
+ "(TARGET_V850E_UP)"
+ {
+ /* Make sure that we have an integer comparison... */
+ if (GET_MODE (XEXP (operands[1], 0)) != CCmode
+ && GET_MODE (XEXP (operands[1], 0)) != SImode)
+ FAIL;
+
+ if ((GET_CODE (operands[2]) == CONST_INT
+ && GET_CODE (operands[3]) == CONST_INT))
+ {
+ int o2 = INTVAL (operands[2]);
+ int o3 = INTVAL (operands[3]);
+
+ if (o2 == 1 && o3 == 0)
+ FAIL; /* setf */
+ if (o3 == 1 && o2 == 0)
+ FAIL; /* setf */
+ if (o2 == 0 && (o3 < -16 || o3 > 15) && exact_log2 (o3) >= 0)
+ FAIL; /* setf + shift */
+ if (o3 == 0 && (o2 < -16 || o2 > 15) && exact_log2 (o2) >=0)
+ FAIL; /* setf + shift */
+ if (o2 != 0)
+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
+ if (o3 !=0 )
+ operands[3] = copy_to_mode_reg (SImode, operands[3]);
+ }
+ else
+ {
+ if (GET_CODE (operands[2]) != REG)
+ operands[2] = copy_to_mode_reg (SImode,operands[2]);
+ if (GET_CODE (operands[3]) != REG)
+ operands[3] = copy_to_mode_reg (SImode, operands[3]);
+ }
+ })
+
+;; ??? Clobbering the condition codes is overkill.
+
+;; ??? We sometimes emit an unnecessary compare instruction because the
+;; condition codes may have already been set by an earlier instruction,
+;; but we have no code here to avoid the compare if it is unnecessary.
+
+(define_insn "movsicc_normal_cc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(reg:CC CC_REGNUM) (const_int 0)])
+ (match_operand:SI 2 "reg_or_int5_operand" "rJ")
+ (match_operand:SI 3 "reg_or_0_operand" "rI")))]
+ "(TARGET_V850E_UP)"
+ "cmov %c1,%2,%z3,%0";
+ [(set_attr "length" "6")
+ (set_attr "cc" "compare")])
+
+(define_insn "movsicc_reversed_cc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(reg:CC CC_REGNUM) (const_int 0)])
+ (match_operand:SI 2 "reg_or_0_operand" "rI")
+ (match_operand:SI 3 "reg_or_int5_operand" "rJ")))]
+ "(TARGET_V850E_UP)"
+ "cmov %C1,%3,%z2,%0"
+ [(set_attr "length" "6")
+ (set_attr "cc" "compare")])
+
+(define_insn "*movsicc_normal"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(match_operand:SI 4 "register_operand" "r")
+ (match_operand:SI 5 "reg_or_int5_operand" "rJ")])
+ (match_operand:SI 2 "reg_or_int5_operand" "rJ")
+ (match_operand:SI 3 "reg_or_0_operand" "rI")))]
+ "(TARGET_V850E_UP)"
+ "cmp %5,%4 ; cmov %c1,%2,%z3,%0"
+ [(set_attr "length" "6")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_reversed"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(match_operand:SI 4 "register_operand" "r")
+ (match_operand:SI 5 "reg_or_int5_operand" "rJ")])
+ (match_operand:SI 2 "reg_or_0_operand" "rI")
+ (match_operand:SI 3 "reg_or_int5_operand" "rJ")))]
+ "(TARGET_V850E_UP)"
+ "cmp %5,%4 ; cmov %C1,%3,%z2,%0"
+ [(set_attr "length" "6")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_tst1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(zero_extract:SI
+ (match_operand:QI 2 "memory_operand" "m")
+ (const_int 1)
+ (match_operand 3 "const_int_operand" "n"))
+ (const_int 0)])
+ (match_operand:SI 4 "reg_or_int5_operand" "rJ")
+ (match_operand:SI 5 "reg_or_0_operand" "rI")))]
+ "(TARGET_V850E_UP)"
+ "tst1 %3,%2 ; cmov %c1,%4,%z5,%0"
+ [(set_attr "length" "8")
+ (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_tst1_reversed"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(zero_extract:SI
+ (match_operand:QI 2 "memory_operand" "m")
+ (const_int 1)
+ (match_operand 3 "const_int_operand" "n"))
+ (const_int 0)])
+ (match_operand:SI 4 "reg_or_0_operand" "rI")
+ (match_operand:SI 5 "reg_or_int5_operand" "rJ")))]
+ "(TARGET_V850E_UP)"
+ "tst1 %3,%2 ; cmov %C1,%5,%z4,%0"
+ [(set_attr "length" "8")
+ (set_attr "cc" "clobber")])
+
+;; Matching for sasf requires combining 4 instructions, so we provide a
+;; dummy pattern to match the first 3, which will always be turned into the
+;; second pattern by subsequent combining. As above, we must include the
+;; comparison to avoid input reloads in an insn using cc0.
+
+(define_insn "*sasf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI
+ (match_operator 1 "comparison_operator"
+ [(match_operand:SI 3 "register_operand" "r")
+ (match_operand:SI 4 "reg_or_int5_operand" "rJ")])
+ (ashift:SI (match_operand:SI 2 "register_operand" "0")
+ (const_int 1))))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "cmp %4,%3 ; sasf %c1,%0"
+ [(set_attr "length" "6")
+ (set_attr "cc" "clobber")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI
+ (match_operator 1 "comparison_operator"
+ [(match_operand:SI 4 "register_operand" "")
+ (match_operand:SI 5 "reg_or_int5_operand" "")])
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" "")))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)
+ && ((INTVAL (operands[2]) ^ INTVAL (operands[3])) == 1)
+ && ((INTVAL (operands[2]) + INTVAL (operands[3])) != 1)
+ && (GET_CODE (operands[5]) == CONST_INT
+ || REGNO (operands[0]) != REGNO (operands[5]))
+ && REGNO (operands[0]) != REGNO (operands[4])"
+ [(set (match_dup 0) (match_dup 6))
+ (parallel [(set (match_dup 0)
+ (ior:SI (match_op_dup 7 [(match_dup 4) (match_dup 5)])
+ (ashift:SI (match_dup 0) (const_int 1))))
+ (clobber (reg:CC CC_REGNUM))])]
+ {
+ operands[6] = GEN_INT (INTVAL (operands[2]) >> 1);
+ if (INTVAL (operands[2]) & 0x1)
+ operands[7] = operands[1];
+ else
+ operands[7] = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
+ GET_MODE (operands[1]),
+ XEXP (operands[1], 0), XEXP (operands[1], 1));
+ })
+
+;; ---------------------------------------------------------------------
+;; BYTE SWAP INSTRUCTIONS
+;; ---------------------------------------------------------------------
+(define_expand "rotlhi3"
+ [(parallel [(set (match_operand:HI 0 "register_operand" "")
+ (rotate:HI (match_operand:HI 1 "register_operand" "")
+ (match_operand:HI 2 "const_int_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])]
+ "(TARGET_V850E_UP)"
+ {
+ if (INTVAL (operands[2]) != 8)
+ FAIL;
+ })
+
+(define_insn "*rotlhi3_8"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (rotate:HI (match_operand:HI 1 "register_operand" "r")
+ (const_int 8)))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "bsh %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+(define_expand "rotlsi3"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (rotate:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (reg:CC CC_REGNUM))])]
+ "(TARGET_V850E_UP)"
+ {
+ if (INTVAL (operands[2]) != 16)
+ FAIL;
+ })
+
+(define_insn "rotlsi3_a"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 4 "ior_operator"
+ [(ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n"))
+ (lshiftrt:SI (match_dup 1)
+ (match_operand:SI 3 "const_int_operand" "n"))]))]
+ "TARGET_V850E3V5_UP && (INTVAL (operands[2]) + INTVAL (operands[3]) == 32)"
+ "rotl %2, %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")]
+)
+
+(define_insn "rotlsi3_b"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 4 "ior_operator"
+ [(lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 3 "const_int_operand" "n"))
+ (ashift:SI (match_dup 1)
+ (match_operand:SI 2 "const_int_operand" "n"))]))]
+ "TARGET_V850E3V5_UP && (INTVAL (operands[2]) + INTVAL (operands[3]) == 32)"
+ "rotl %2, %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")]
+)
+
+(define_insn "rotlsi3_v850e3v5"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "e3v5_shift_operand" "rn")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E3V5_UP"
+ "rotl %2, %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")]
+)
+
+(define_insn "*rotlsi3_16"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 16)))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "hsw %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+;; ----------------------------------------------------------------------
+;; JUMP INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; Doloop
+
+(define_expand "doloop_begin"
+ [(use (match_operand 0 "" "")) ; loop pseudo
+ (use (match_operand 1 "" ""))] ; doloop_end pattern
+ "TARGET_V850E3V5_UP && TARGET_LOOP"
+ {
+ rtx loop_cnt = operands[0];
+ gcc_assert (GET_MODE (loop_cnt) == SImode);
+ emit_insn (gen_fix_loop_counter (loop_cnt));
+ DONE;
+ }
+)
+
+(define_insn "fix_loop_counter"
+ [(unspec:SI [(match_operand:SI 0 "register_operand" "+r,!m")
+ (clobber (match_scratch:SI 1 "=X,r"))] UNSPEC_LOOP)]
+ "TARGET_V850E3V5_UP && TARGET_LOOP"
+ {
+ switch (which_alternative)
+ {
+ case 0: return "add 1, %0 # LOOP_BEGIN";
+ case 1: return "ld.w %0, %1; add 1, %1; st.w %1, %0 # LOOP_BEGIN";
+ default: gcc_unreachable ();
+ }
+ }
+ [(set_attr "length" "2,6")
+ (set_attr "cc" "none")]
+)
+
+(define_expand "doloop_end"
+ [(use (match_operand 0 "" "")) ; loop pseudo
+ (use (match_operand 1 "" ""))] ; label
+ "TARGET_V850E3V5_UP && TARGET_LOOP"
+ {
+ rtx loop_cnt = operands[0];
+ rtx label = operands[1];
+
+ if (GET_MODE (loop_cnt) != SImode)
+ FAIL;
+
+ emit_jump_insn (gen_doloop_end_internal_loop (label, loop_cnt));
+ DONE;
+ }
+)
+
+(define_insn "doloop_end_internal_loop"
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "+r,!m")
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_dup 1) (plus:SI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:SI 2 "=X,r"))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E3V5_UP && TARGET_LOOP"
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ if (get_attr_length (insn) == 4)
+ return "loop %1, %0 # LOOP.1.0";
+
+ return "add -1, %1; bne %l0 # LOOP.1.1";
+ case 1:
+ return "ld.w %1, %2; add -1, %2; st.w %2, %1; bne %l0 # LOOP.2.1";
+ default:
+ gcc_unreachable ();
+ }
+ }
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65534))
+ (const_int 4)
+ (const_int 14)))
+ (set_attr "cc" "none")])
+
+;; Conditional jump instructions
+
+(define_insn "*branch_normal"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
+ && (GET_CODE (operands[1]) == GT
+ || GET_CODE (operands[1]) == GE
+ || GET_CODE (operands[1]) == LE
+ || GET_CODE (operands[1]) == LT))
+ return 0;
+
+ if (get_attr_length (insn) == 2)
+ return "b%b1 %l0";
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "b%b1 %l0";
+ return "b%B1 .+6 ; jr %l0";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+(define_insn "*branch_invert"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+{
+ if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
+ && (GET_CODE (operands[1]) == GT
+ || GET_CODE (operands[1]) == GE
+ || GET_CODE (operands[1]) == LE
+ || GET_CODE (operands[1]) == LT))
+ return NULL;
+
+ if (get_attr_length (insn) == 2)
+ return "b%B1 %l0";
+
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "b%B1 %l0";
+
+ return "b%b1 .+6 ; jr %l0";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+(define_insn "branch_z_normal"
+ [(set (pc)
+ (if_then_else (match_operand 1 "v850_float_z_comparison_operator" "")
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "TARGET_V850E2V3_UP"
+{
+ if (get_attr_length (insn) == 2)
+ return "bz %l0";
+
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "bz %l0";
+
+ return "bnz 1f ; jr %l0 ; 1:";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+(define_insn "*branch_z_invert"
+ [(set (pc)
+ (if_then_else (match_operand 1 "v850_float_z_comparison_operator" "")
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "TARGET_V850E2V3_UP"
+{
+ if (get_attr_length (insn) == 2)
+ return "bnz %l0";
+
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "bnz %l0";
+
+ return "bz 1f ; jr %l0 ; 1:";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+(define_insn "branch_nz_normal"
+ [(set (pc)
+ (if_then_else (match_operand 1 "v850_float_nz_comparison_operator" "")
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "TARGET_V850E2V3_UP"
+{
+ if (get_attr_length (insn) == 2)
+ return "bnz %l0";
+
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "bnz %l0";
+
+ return "bz 1f ; jr %l0 ; 1:";
+}
+[(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+(define_insn "*branch_nz_invert"
+ [(set (pc)
+ (if_then_else (match_operand 1 "v850_float_nz_comparison_operator" "")
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "TARGET_V850E2V3_UP"
+{
+ if (get_attr_length (insn) == 2)
+ return "bz %l0";
+
+ if (TARGET_V850E3V5_UP && get_attr_length (insn) == 4)
+ return "bz %l0";
+
+ return "bnz 1f ; jr %l0 ; 1:";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 65536))
+ (const_int 4)
+ (const_int 6))))
+ (set_attr "cc" "none")])
+
+;; Unconditional and other jump instructions.
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+{
+ if (get_attr_length (insn) == 2)
+ return "br %0";
+ else
+ return "jr %0";
+}
+ [(set (attr "length")
+ (if_then_else (lt (abs (minus (match_dup 0) (pc)))
+ (const_int 256))
+ (const_int 2)
+ (const_int 4)))
+ (set_attr "cc" "none")])
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "jmp %0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_insn "tablejump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jmp %0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_insn "switch"
+ [(set (pc)
+ (plus:SI
+ (sign_extend:SI
+ (mem:HI
+ (plus:SI (ashift:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1))
+ (label_ref (match_operand 1 "" "")))))
+ (label_ref (match_dup 1))))]
+ "(TARGET_V850E_UP)"
+ "switch %0"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")
+ (match_operand 3 "" "") (match_operand 4 "" "")]
+ ""
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ rtx tableaddress = gen_reg_rtx (SImode);
+ rtx test;
+ rtx mem;
+
+ /* Subtract the lower bound from the index. */
+ emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
+
+ /* Compare the result against the number of table entries;
+ branch to the default label if out of range of the table. */
+ test = gen_rtx_fmt_ee (GTU, VOIDmode, reg, operands[2]);
+ emit_jump_insn (gen_cbranchsi4 (test, reg, operands[2], operands[4]));
+
+ /* Shift index for the table array access. */
+ emit_insn (gen_ashlsi3 (reg, reg, GEN_INT (TARGET_BIG_SWITCH ? 2 : 1)));
+ /* Load the table address into a pseudo. */
+ emit_insn (gen_movsi (tableaddress,
+ gen_rtx_LABEL_REF (Pmode, operands[3])));
+ /* Add the table address to the index. */
+ emit_insn (gen_addsi3 (reg, reg, tableaddress));
+ /* Load the table entry. */
+ mem = gen_const_mem (CASE_VECTOR_MODE, reg);
+ if (! TARGET_BIG_SWITCH)
+ {
+ rtx reg2 = gen_reg_rtx (HImode);
+ emit_insn (gen_movhi (reg2, mem));
+ emit_insn (gen_extendhisi2 (reg, reg2));
+ }
+ else
+ emit_insn (gen_movsi (reg, mem));
+ /* Add the table address. */
+ emit_insn (gen_addsi3 (reg, reg, tableaddress));
+ /* Branch to the switch label. */
+ emit_jump_insn (gen_tablejump (reg, operands[3]));
+ DONE;
+ })
+
+;; Call subroutine with no return value.
+
+(define_expand "call"
+ [(call (match_operand:QI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ {
+ if (! call_address_operand (XEXP (operands[0], 0), QImode)
+ || TARGET_LONG_CALLS)
+ XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
+ if (TARGET_LONG_CALLS)
+ emit_call_insn (gen_call_internal_long (XEXP (operands[0], 0), operands[1]));
+ else
+ emit_call_insn (gen_call_internal_short (XEXP (operands[0], 0), operands[1]));
+
+ DONE;
+ })
+
+(define_insn "call_internal_short"
+ [(call (mem:QI (match_operand:SI 0 "call_address_operand" "S,r"))
+ (match_operand:SI 1 "general_operand" "g,g"))
+ (clobber (reg:SI 31))]
+ "! TARGET_LONG_CALLS"
+ {
+ if (which_alternative == 1)
+ {
+ if (TARGET_V850E3V5_UP)
+ return "jarl [%0], r31";
+
+ return "jarl .+4, r31 ; add 4, r31 ; jmp %0";
+ }
+
+ return "jarl %0, r31";
+ }
+ [(set_attr "length" "4,8")
+ (set_attr "cc" "clobber,clobber")]
+)
+
+(define_insn "call_internal_long"
+ [(call (mem:QI (match_operand:SI 0 "call_address_operand" "S,r"))
+ (match_operand:SI 1 "general_operand" "g,g"))
+ (clobber (reg:SI 31))]
+ "TARGET_LONG_CALLS"
+{
+ if (which_alternative == 0)
+ {
+ if (GET_CODE (operands[0]) == REG)
+ return "jarl %0,r31";
+
+ if (TARGET_V850E3V5_UP)
+ return "mov hilo(%0), r11 ; jarl [r11], r31";
+
+ return "movhi hi(%0), r0, r11 ; movea lo(%0), r11, r11 ; jarl .+4,r31 ; add 4, r31 ; jmp r11";
+ }
+
+ if (TARGET_V850E3V5_UP)
+ return "jarl [%0], r31";
+
+ return "jarl .+4,r31 ; add 4,r31 ; jmp %0";
+}
+ [(set_attr "length" "16,8")
+ (set_attr "cc" "clobber,clobber")]
+)
+
+;; Call subroutine, returning value in operand 0
+;; (which must be a hard register).
+
+(define_expand "call_value"
+ [(set (match_operand 0 "" "")
+ (call (match_operand:QI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
+ ""
+ {
+ if (! call_address_operand (XEXP (operands[1], 0), QImode)
+ || TARGET_LONG_CALLS)
+ XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
+ if (TARGET_LONG_CALLS)
+ emit_call_insn (gen_call_value_internal_long (operands[0],
+ XEXP (operands[1], 0),
+ operands[2]));
+ else
+ emit_call_insn (gen_call_value_internal_short (operands[0],
+ XEXP (operands[1], 0),
+ operands[2]));
+ DONE;
+ })
+
+(define_insn "call_value_internal_short"
+ [(set (match_operand 0 "" "=r,r")
+ (call (mem:QI (match_operand:SI 1 "call_address_operand" "S,r"))
+ (match_operand:SI 2 "general_operand" "g,g")))
+ (clobber (reg:SI 31))]
+ "! TARGET_LONG_CALLS"
+ {
+ if (which_alternative == 1)
+ {
+ if (TARGET_V850E3V5_UP)
+ return "jarl [%1], r31";
+
+ return "jarl .+4, r31 ; add 4, r31 ; jmp %1";
+ }
+
+ return "jarl %1, r31";
+ }
+ [(set_attr "length" "4,8")
+ (set_attr "cc" "clobber,clobber")]
+)
+
+(define_insn "call_value_internal_long"
+ [(set (match_operand 0 "" "=r,r")
+ (call (mem:QI (match_operand:SI 1 "call_address_operand" "S,r"))
+ (match_operand:SI 2 "general_operand" "g,g")))
+ (clobber (reg:SI 31))]
+ "TARGET_LONG_CALLS"
+{
+ if (which_alternative == 0)
+ {
+ if (GET_CODE (operands[1]) == REG)
+ return "jarl %1, r31";
+
+ /* Reload can generate this pattern.... */
+ if (TARGET_V850E3V5_UP)
+ return "mov hilo(%1), r11 ; jarl [r11], r31";
+
+ return "movhi hi(%1), r0, r11 ; movea lo(%1), r11, r11 ; jarl .+4, r31 ; add 4, r31 ; jmp r11";
+ }
+
+ if (TARGET_V850E3V5_UP)
+ return "jarl [%1], r31";
+
+ return "jarl .+4, r31 ; add 4, r31 ; jmp %1";
+}
+ [(set_attr "length" "16,8")
+ (set_attr "cc" "clobber,clobber")]
+)
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+;; ----------------------------------------------------------------------
+;; EXTEND INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+(define_insn "*zero_extendhisi2_v850e"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (zero_extend:SI
+ (match_operand:HI 1 "nonimmediate_operand" "0,r,T,m")))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "@
+ zxh %0
+ andi 65535,%1,%0
+ sld.hu %1,%0
+ ld.hu %1,%0"
+ [(set_attr "length" "2,4,2,4")
+ (set_attr "cc" "none_0hit,set_zn,none_0hit,none_0hit")])
+
+(define_insn "*zero_extendhisi2_v850"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI
+ (match_operand:HI 1 "register_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))] ;; A lie, but we have to match the expander
+ ""
+ "andi 65535,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")])
+
+(define_expand "zero_extendhisi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (zero_extend:SI
+ (match_operand:HI 1 "nonimmediate_operand")))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
+ {
+ if (! (TARGET_V850E_UP))
+ operands[1] = force_reg (HImode, operands[1]);
+ })
+
+(define_insn "*zero_extendqisi2_v850e"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (zero_extend:SI
+ (match_operand:QI 1 "nonimmediate_operand" "0,r,T,m")))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "@
+ zxb %0
+ andi 255,%1,%0
+ sld.bu %1,%0
+ ld.bu %1,%0"
+ [(set_attr "length" "2,4,2,4")
+ (set_attr "cc" "none_0hit,set_zn,none_0hit,none_0hit")])
+
+(define_insn "*zero_extendqisi2_v850"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI
+ (match_operand:QI 1 "register_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))] ;; A lie, but we have to match the expander
+ ""
+ "andi 255,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")])
+
+(define_expand "zero_extendqisi2"
+ [(parallel [(set (match_operand:SI 0 "register_operand")
+ (zero_extend:SI
+ (match_operand:QI 1 "nonimmediate_operand")))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
+ {
+ if (! (TARGET_V850E_UP))
+ operands[1] = force_reg (QImode, operands[1]);
+ })
+
+;;- sign extension instructions
+
+;; ??? The extendhisi2 pattern should not emit shifts for v850e?
+
+(define_insn "*extendhisi_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,Q,m")))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "@
+ sxh %0
+ sld.h %1,%0
+ ld.h %1,%0"
+ [(set_attr "length" "2,2,4")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit")])
+
+;; ??? This is missing a sign extend from memory pattern to match the ld.h
+;; instruction.
+
+(define_expand "extendhisi2"
+ [(parallel [(set (match_dup 2)
+ (ashift:SI (match_operand:HI 1 "register_operand" "")
+ (const_int 16)))
+ (clobber (reg:CC CC_REGNUM))])
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 16)))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
+ {
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+ })
+
+;; ??? The extendqisi2 pattern should not emit shifts for v850e?
+
+(define_insn "*extendqisi_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,Q,m")))
+ (clobber (reg:CC CC_REGNUM))]
+ "(TARGET_V850E_UP)"
+ "@
+ sxb %0
+ sld.b %1,%0
+ ld.b %1,%0"
+ [(set_attr "length" "2,2,4")
+ (set_attr "cc" "none_0hit,none_0hit,none_0hit")])
+
+;; ??? This is missing a sign extend from memory pattern to match the ld.b
+;; instruction.
+
+(define_expand "extendqisi2"
+ [(parallel [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "register_operand" "")
+ (const_int 24)))
+ (clobber (reg:CC CC_REGNUM))])
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
+ {
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+ })
+
+;; ----------------------------------------------------------------------
+;; SHIFTS
+;; ----------------------------------------------------------------------
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI
+ (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,N")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ shl %2,%0
+ shl %2,%0"
+ [(set_attr "length" "4,2")
+ (set_attr "cc" "set_zn")])
+
+(define_insn "ashlsi3_v850e2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E2_UP"
+ "shl %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_znv")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (lshiftrt:SI
+ (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,N")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ shr %2,%0
+ shr %2,%0"
+ [(set_attr "length" "4,2")
+ (set_attr "cc" "set_zn")])
+
+(define_insn "lshrsi3_v850e2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E2_UP"
+ "shr %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")])
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashiftrt:SI
+ (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,N")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ sar %2,%0
+ sar %2,%0"
+ [(set_attr "length" "4,2")
+ (set_attr "cc" "set_zn, set_zn")])
+
+(define_insn "ashrsi3_v850e2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "nonmemory_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E2_UP"
+ "sar %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_zn")])
+
+;; ----------------------------------------------------------------------
+;; FIND FIRST BIT INSTRUCTION
+;; ----------------------------------------------------------------------
+
+(define_insn "ffssi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ffs:SI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_V850E2_UP"
+ "sch1r %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+;; ----------------------------------------------------------------------
+;; PROLOGUE/EPILOGUE
+;; ----------------------------------------------------------------------
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+ {
+ expand_prologue ();
+ DONE;
+ })
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+ {
+ expand_epilogue ();
+ DONE;
+ })
+
+(define_insn "return_simple"
+ [(return)]
+ "reload_completed"
+ "jmp [r31]"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_insn "return_internal"
+ [(return)
+ (use (reg:SI 31))]
+ ""
+ "jmp [r31]"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+;; ----------------------------------------------------------------------
+;; v850e2V3 floating-point hardware support
+;; ----------------------------------------------------------------------
+
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (plus:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "addf.s %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (plus:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "addf.d %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (minus:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "subf.s %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (minus:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "subf.d %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (mult:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "mulf.s %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (mult:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "mulf.d %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (div:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "divf.s %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (div:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "divf.d %2,%1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "minsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (smin:SF (match_operand:SF 1 "reg_or_0_operand" "r")
+ (match_operand:SF 2 "reg_or_0_operand" "r")))]
+ "TARGET_USE_FPU"
+ "minf.s %z1,%z2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "mindf3"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (smin:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "minf.d %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "maxsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (smax:SF (match_operand:SF 1 "reg_or_0_operand" "r")
+ (match_operand:SF 2 "reg_or_0_operand" "r")))]
+ "TARGET_USE_FPU"
+ "maxf.s %z1,%z2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "maxdf3"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (smax:DF (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "maxf.d %1,%2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (abs:SF (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "absf.s %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (abs:DF (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "absf.d %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (neg:SF (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "negf.s %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (neg:DF (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "negf.d %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; square-root
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "sqrtf.s %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (sqrt:DF (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "sqrtf.d %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; float -> int
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.sw %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "fixuns_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unsigned_fix:SI (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.suw %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")]
+)
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.dw %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "fixuns_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unsigned_fix:SI (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.duw %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")]
+)
+
+(define_insn "fix_truncsfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (fix:DI (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.sl %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "fixuns_truncsfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unsigned_fix:DI (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.sul %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")]
+)
+
+(define_insn "fix_truncdfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (fix:DI (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.dl %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "fixuns_truncdfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unsigned_fix:DI (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "trncf.dul %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")]
+)
+
+;; int -> float
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (float:SF (match_operand:SI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.ws %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "unsfloatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unsigned_float:SF (match_operand:SI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.uws %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (float:DF (match_operand:SI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.wd %z1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "unsfloatsidf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (unsigned_float:DF (match_operand:SI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.uwd %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "floatdisf2"
+ [(set (match_operand:SF 0 "even_reg_operand" "=r")
+ (float:SF (match_operand:DI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.ls %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "unsfloatdisf2"
+ [(set (match_operand:SF 0 "even_reg_operand" "=r")
+ (unsigned_float:SF (match_operand:DI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.uls %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "floatdidf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (float:DF (match_operand:DI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.ld %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "unsfloatdidf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (unsigned_float:DF (match_operand:DI 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.uld %z1, %0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; single-float -> double-float
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (float_extend:DF
+ (match_operand:SF 1 "reg_or_0_operand" "rI")))]
+ "TARGET_USE_FPU"
+ "cvtf.sd %z1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; double-float -> single-float
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (float_truncate:SF
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cvtf.ds %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;;
+;; ---------------- special insns
+;;
+
+;;; reciprocal
+(define_insn "recipsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "recipf.s %2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "recipdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (div:DF (match_operand:DF 1 "const_float_1_operand" "")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "recipf.d %2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;;; reciprocal of square-root
+(define_insn "rsqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (div:SF (match_operand:SF 1 "const_float_1_operand" "")
+ (sqrt:SF (match_operand:SF 2 "register_operand" "r"))))]
+ "TARGET_USE_FPU"
+ "rsqrtf.s %2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "rsqrtdf2"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (div:DF (match_operand:DF 1 "const_float_1_operand" "")
+ (sqrt:DF (match_operand:DF 2 "even_reg_operand" "r"))))]
+ "TARGET_USE_FPU"
+ "rsqrtf.d %2,%0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; Note: The FPU-2.0 (ie pre e3v5) versions of these routines do not actually
+;; need operand 4 to be the same as operand 0. But the FPU-2.0 versions are
+;; also deprecated so the loss of flexibility is unimportant.
+
+;;; multiply-add
+(define_insn "fmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (fma:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "0")))]
+ "TARGET_USE_FPU"
+ { return TARGET_V850E3V5_UP ? "fmaf.s %1, %2, %0" : "maddf.s %2, %1, %3, %0"; }
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;;; multiply-subtract
+(define_insn "fmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (fma:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")
+ (neg:SF (match_operand:SF 3 "register_operand" "0"))))]
+ "TARGET_USE_FPU"
+ { return TARGET_V850E3V5_UP ? "fmsf.s %1, %2, %0" : "msubf.s %2, %1, %3, %0"; }
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;;; negative-multiply-add
+(define_insn "fnmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (neg:SF (fma:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "0"))))]
+ "TARGET_USE_FPU"
+ { return TARGET_V850E3V5_UP ? "fnmaf.s %1, %2, %0" : "nmaddf.s %2, %1, %3, %0"; }
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;; negative-multiply-subtract
+(define_insn "fnmssf4"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (neg:SF (fma:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")
+ (neg:SF (match_operand:SF 3 "register_operand" "0")))))]
+ "TARGET_USE_FPU"
+ { return TARGET_V850E3V5_UP ? "fnmsf.s %1, %2, %0" : "nmsubf.s %2, %1, %3, %0"; }
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+;
+; ---------------- comparison/conditionals
+;
+; SF
+
+(define_insn "cmpsf_le_insn"
+ [(set (reg:CC_FPU_LE FCC_REGNUM)
+ (compare:CC_FPU_LE (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.s le, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpsf_lt_insn"
+ [(set (reg:CC_FPU_LT FCC_REGNUM)
+ (compare:CC_FPU_LT (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.s lt, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpsf_ge_insn"
+ [(set (reg:CC_FPU_GE FCC_REGNUM)
+ (compare:CC_FPU_GE (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.s le, %z1, %z0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpsf_gt_insn"
+ [(set (reg:CC_FPU_GT FCC_REGNUM)
+ (compare:CC_FPU_GT (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.s lt, %z1, %z0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpsf_eq_insn"
+ [(set (reg:CC_FPU_EQ FCC_REGNUM)
+ (compare:CC_FPU_EQ (match_operand:SF 0 "register_operand" "r")
+ (match_operand:SF 1 "register_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.s eq, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+; DF
+
+(define_insn "cmpdf_le_insn"
+ [(set (reg:CC_FPU_LE FCC_REGNUM)
+ (compare:CC_FPU_LE (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.d le, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpdf_lt_insn"
+ [(set (reg:CC_FPU_LT FCC_REGNUM)
+ (compare:CC_FPU_LT (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.d lt, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpdf_ge_insn"
+ [(set (reg:CC_FPU_GE FCC_REGNUM)
+ (compare:CC_FPU_GE (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.d le, %z1, %z0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpdf_gt_insn"
+ [(set (reg:CC_FPU_GT FCC_REGNUM)
+ (compare:CC_FPU_GT (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.d lt, %z1, %z0"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+(define_insn "cmpdf_eq_insn"
+ [(set (reg:CC_FPU_EQ FCC_REGNUM)
+ (compare:CC_FPU_EQ (match_operand:DF 0 "even_reg_operand" "r")
+ (match_operand:DF 1 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmpf.d eq, %z0, %z1"
+ [(set_attr "length" "4")
+ (set_attr "cc" "none_0hit")
+ (set_attr "type" "fpu")])
+
+;;
+;; Transfer a v850e2v3 fcc to the Z bit of CC0 (this is necessary to do a
+;; conditional branch based on a floating-point compare)
+;;
+
+(define_insn "trfsr"
+ [(set (match_operand 0 "" "") (match_operand 1 "" ""))]
+ "TARGET_USE_FPU
+ && GET_MODE(operands[0]) == GET_MODE(operands[1])
+ && GET_CODE(operands[0]) == REG && REGNO (operands[0]) == CC_REGNUM
+ && GET_CODE(operands[1]) == REG && REGNO (operands[1]) == FCC_REGNUM
+ && (GET_MODE(operands[0]) == CC_FPU_LEmode
+ || GET_MODE(operands[0]) == CC_FPU_GEmode
+ || GET_MODE(operands[0]) == CC_FPU_LTmode
+ || GET_MODE(operands[0]) == CC_FPU_GTmode
+ || GET_MODE(operands[0]) == CC_FPU_EQmode
+ || GET_MODE(operands[0]) == CC_FPU_NEmode)"
+ "trfsr"
+ [(set_attr "length" "4")
+ (set_attr "cc" "set_z")
+ (set_attr "type" "fpu")])
+
+;;
+;; Floating-point conditional moves for the v850e2v3.
+;;
+
+;; The actual v850e2v3 conditional move instructions
+;;
+(define_insn "movsfcc_z_insn"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (if_then_else:SF
+ (match_operand 3 "v850_float_z_comparison_operator" "")
+ (match_operand:SF 1 "reg_or_0_operand" "rIG")
+ (match_operand:SF 2 "reg_or_0_operand" "rIG")))]
+ "TARGET_USE_FPU"
+ "cmovf.s 0,%z1,%z2,%0"
+ [(set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+(define_insn "movsfcc_nz_insn"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (if_then_else:SF
+ (match_operand 3 "v850_float_nz_comparison_operator" "")
+ (match_operand:SF 1 "reg_or_0_operand" "rIG")
+ (match_operand:SF 2 "reg_or_0_operand" "rIG")))]
+ "TARGET_USE_FPU"
+ "cmovf.s 0,%z2,%z1,%0"
+ [(set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+(define_insn "movdfcc_z_insn"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (if_then_else:DF
+ (match_operand 3 "v850_float_z_comparison_operator" "")
+ (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmovf.d 0,%z1,%z2,%0"
+ [(set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+(define_insn "movdfcc_nz_insn"
+ [(set (match_operand:DF 0 "even_reg_operand" "=r")
+ (if_then_else:DF
+ (match_operand 3 "v850_float_nz_comparison_operator" "")
+ (match_operand:DF 1 "even_reg_operand" "r")
+ (match_operand:DF 2 "even_reg_operand" "r")))]
+ "TARGET_USE_FPU"
+ "cmovf.d 0,%z2,%z1,%0"
+ [(set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+(define_insn "movedfcc_z_zero"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (if_then_else:DF
+ (match_operand 3 "v850_float_z_comparison_operator" "")
+ (match_operand:DF 1 "reg_or_0_operand" "rIG")
+ (match_operand:DF 2 "reg_or_0_operand" "rIG")))]
+ "TARGET_USE_FPU"
+ "cmovf.s 0,%z1,%z2,%0 ; cmovf.s 0,%Z1,%Z2,%R0"
+ [(set_attr "length" "8")
+ (set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+(define_insn "movedfcc_nz_zero"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (if_then_else:DF
+ (match_operand 3 "v850_float_nz_comparison_operator" "")
+ (match_operand:DF 1 "reg_or_0_operand" "rIG")
+ (match_operand:DF 2 "reg_or_0_operand" "rIG")))]
+ "TARGET_USE_FPU"
+ "cmovf.s 0,%z2,%z1,%0 ; cmovf.s 0,%Z2,%Z1,%R0"
+ [(set_attr "length" "8")
+ (set_attr "cc" "clobber")]) ;; ??? or none_0hit
+
+
+;; ----------------------------------------------------------------------
+;; HELPER INSTRUCTIONS for saving the prologue and epilogue registers
+;; ----------------------------------------------------------------------
+
+;; This pattern will match a stack adjust RTX followed by any number of push
+;; RTXs. These RTXs will then be turned into a suitable call to a worker
+;; function.
+
+;;
+;; Actually, convert the RTXs into a PREPARE instruction.
+;;
+
+(define_insn ""
+ [(match_parallel 0 "pattern_is_ok_for_prepare"
+ [(set (reg:SI 3)
+ (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+ (set (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 2 "immediate_operand" "i")))
+ (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))])]
+ "TARGET_PROLOG_FUNCTION && (TARGET_V850E_UP)"
+{
+ return construct_prepare_instruction (operands[0]);
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+(define_insn ""
+ [(match_parallel 0 "pattern_is_ok_for_prologue"
+ [(set (reg:SI 3)
+ (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+ (set (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 2 "immediate_operand" "i")))
+ (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))])]
+ "TARGET_PROLOG_FUNCTION"
+{
+ return construct_save_jarl (operands[0]);
+}
+ [(set (attr "length") (if_then_else (eq_attr "long_calls" "yes")
+ (const_string "16")
+ (const_string "4")))
+ (set_attr "cc" "clobber")])
+
+;;
+;; Actually, turn the RTXs into a DISPOSE instruction.
+;;
+(define_insn ""
+ [(match_parallel 0 "pattern_is_ok_for_dispose"
+ [(return)
+ (set (reg:SI 3)
+ (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+ (set (match_operand:SI 2 "register_is_ok_for_epilogue" "=r")
+ (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 3 "immediate_operand" "i"))))])]
+ "TARGET_PROLOG_FUNCTION && (TARGET_V850E_UP)"
+{
+ return construct_dispose_instruction (operands[0]);
+}
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+;; This pattern will match a return RTX followed by any number of pop RTXs
+;; and possible a stack adjustment as well. These RTXs will be turned into
+;; a suitable call to a worker function.
+
+(define_insn ""
+[(match_parallel 0 "pattern_is_ok_for_epilogue"
+ [(return)
+ (set (reg:SI 3)
+ (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+ (set (match_operand:SI 2 "register_is_ok_for_epilogue" "=r")
+ (mem:SI (plus:SI (reg:SI 3)
+ (match_operand:SI 3 "immediate_operand" "i"))))])]
+ "TARGET_PROLOG_FUNCTION"
+{
+ return construct_restore_jr (operands[0]);
+}
+ [(set (attr "length") (if_then_else (eq_attr "long_calls" "yes")
+ (const_string "12")
+ (const_string "4")))
+ (set_attr "cc" "clobber")])
+
+;; Initialize an interrupt function. Do not depend on TARGET_PROLOG_FUNCTION.
+(define_insn "callt_save_interrupt"
+ [(unspec_volatile [(const_int 0)] 2)]
+ "(TARGET_V850E_UP) && !TARGET_DISABLE_CALLT"
+ ;; The CALLT instruction stores the next address of CALLT to CTPC register
+ ;; without saving its previous value. So if the interrupt handler
+ ;; or its caller could possibly execute the CALLT insn, save_interrupt
+ ;; MUST NOT be called via CALLT.
+{
+ output_asm_insn ("addi -28, sp, sp", operands);
+ output_asm_insn ("st.w r1, 24[sp]", operands);
+ output_asm_insn ("st.w r10, 12[sp]", operands);
+ output_asm_insn ("st.w r11, 16[sp]", operands);
+ output_asm_insn ("stsr ctpc, r10", operands);
+ output_asm_insn ("st.w r10, 20[sp]", operands);
+ output_asm_insn ("stsr ctpsw, r10", operands);
+ output_asm_insn ("st.w r10, 24[sp]", operands);
+ output_asm_insn ("callt ctoff(__callt_save_interrupt)", operands);
+ return "";
+}
+ [(set_attr "length" "26")
+ (set_attr "cc" "clobber")])
+
+(define_insn "callt_return_interrupt"
+ [(unspec_volatile [(const_int 0)] 3)]
+ "(TARGET_V850E_UP) && !TARGET_DISABLE_CALLT"
+ "callt ctoff(__callt_return_interrupt)"
+ [(set_attr "length" "2")
+ (set_attr "cc" "clobber")])
+
+(define_insn "save_interrupt"
+ [(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int -20)))
+ (set (mem:SI (plus:SI (reg:SI 3) (const_int -20))) (reg:SI 30))
+ (set (mem:SI (plus:SI (reg:SI 3) (const_int -16))) (reg:SI 4))
+ (set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 1))
+ (set (mem:SI (plus:SI (reg:SI 3) (const_int -8))) (reg:SI 10))
+ (set (mem:SI (plus:SI (reg:SI 3) (const_int -4))) (reg:SI 11))]
+ ""
+{
+ if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+ return "addi -20,sp,sp \; st.w r11,16[sp] \; st.w r10,12[sp] \; jarl __save_interrupt,r10";
+ else
+ {
+ output_asm_insn ("addi -20, sp, sp", operands);
+ output_asm_insn ("st.w r11, 16[sp]", operands);
+ output_asm_insn ("st.w r10, 12[sp]", operands);
+ output_asm_insn ("st.w ep, 0[sp]", operands);
+ output_asm_insn ("st.w gp, 4[sp]", operands);
+ output_asm_insn ("st.w r1, 8[sp]", operands);
+ output_asm_insn ("movhi hi(__ep), r0, ep", operands);
+ output_asm_insn ("movea lo(__ep), ep, ep", operands);
+ output_asm_insn ("movhi hi(__gp), r0, gp", operands);
+ output_asm_insn ("movea lo(__gp), gp, gp", operands);
+ return "";
+ }
+}
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_LONG_CALLS")
+ (const_int 10)
+ (const_int 34)))
+ (set_attr "cc" "clobber")])
+
+;; Restore r1, r4, r10, and return from the interrupt
+(define_insn "return_interrupt"
+ [(return)
+ (set (reg:SI 3) (plus:SI (reg:SI 3) (const_int 20)))
+ (set (reg:SI 11) (mem:SI (plus:SI (reg:SI 3) (const_int 16))))
+ (set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
+ (set (reg:SI 1) (mem:SI (plus:SI (reg:SI 3) (const_int 8))))
+ (set (reg:SI 4) (mem:SI (plus:SI (reg:SI 3) (const_int 4))))
+ (set (reg:SI 30) (mem:SI (reg:SI 3)))]
+ ""
+{
+ if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+ return "jr __return_interrupt";
+ else
+ {
+ output_asm_insn ("ld.w 0[sp], ep", operands);
+ output_asm_insn ("ld.w 4[sp], gp", operands);
+ output_asm_insn ("ld.w 8[sp], r1", operands);
+ output_asm_insn ("ld.w 12[sp], r10", operands);
+ output_asm_insn ("ld.w 16[sp], r11", operands);
+ output_asm_insn ("addi 20, sp, sp", operands);
+ output_asm_insn ("reti", operands);
+ return "";
+ }
+}
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_LONG_CALLS")
+ (const_int 4)
+ (const_int 24)))
+ (set_attr "cc" "clobber")])
+
+;; Save all registers except for the registers saved in save_interrupt when
+;; an interrupt function makes a call.
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+;; This is needed because the rest of the compiler is not ready to handle
+;; insns this complicated.
+
+(define_insn "callt_save_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 0)]
+ "(TARGET_V850E_UP) && !TARGET_DISABLE_CALLT"
+ "callt ctoff(__callt_save_all_interrupt)"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_insn "save_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+{
+ if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+ return "jarl __save_all_interrupt,r10";
+
+ output_asm_insn ("addi -120, sp, sp", operands);
+
+ if (TARGET_EP)
+ {
+ output_asm_insn ("mov ep, r1", operands);
+ output_asm_insn ("mov sp, ep", operands);
+ output_asm_insn ("sst.w r31, 116[ep]", operands);
+ output_asm_insn ("sst.w r2, 112[ep]", operands);
+ output_asm_insn ("sst.w gp, 108[ep]", operands);
+ output_asm_insn ("sst.w r6, 104[ep]", operands);
+ output_asm_insn ("sst.w r7, 100[ep]", operands);
+ output_asm_insn ("sst.w r8, 96[ep]", operands);
+ output_asm_insn ("sst.w r9, 92[ep]", operands);
+ output_asm_insn ("sst.w r11, 88[ep]", operands);
+ output_asm_insn ("sst.w r12, 84[ep]", operands);
+ output_asm_insn ("sst.w r13, 80[ep]", operands);
+ output_asm_insn ("sst.w r14, 76[ep]", operands);
+ output_asm_insn ("sst.w r15, 72[ep]", operands);
+ output_asm_insn ("sst.w r16, 68[ep]", operands);
+ output_asm_insn ("sst.w r17, 64[ep]", operands);
+ output_asm_insn ("sst.w r18, 60[ep]", operands);
+ output_asm_insn ("sst.w r19, 56[ep]", operands);
+ output_asm_insn ("sst.w r20, 52[ep]", operands);
+ output_asm_insn ("sst.w r21, 48[ep]", operands);
+ output_asm_insn ("sst.w r22, 44[ep]", operands);
+ output_asm_insn ("sst.w r23, 40[ep]", operands);
+ output_asm_insn ("sst.w r24, 36[ep]", operands);
+ output_asm_insn ("sst.w r25, 32[ep]", operands);
+ output_asm_insn ("sst.w r26, 28[ep]", operands);
+ output_asm_insn ("sst.w r27, 24[ep]", operands);
+ output_asm_insn ("sst.w r28, 20[ep]", operands);
+ output_asm_insn ("sst.w r29, 16[ep]", operands);
+ output_asm_insn ("mov r1, ep", operands);
+ }
+ else
+ {
+ output_asm_insn ("st.w r31, 116[sp]", operands);
+ output_asm_insn ("st.w r2, 112[sp]", operands);
+ output_asm_insn ("st.w gp, 108[sp]", operands);
+ output_asm_insn ("st.w r6, 104[sp]", operands);
+ output_asm_insn ("st.w r7, 100[sp]", operands);
+ output_asm_insn ("st.w r8, 96[sp]", operands);
+ output_asm_insn ("st.w r9, 92[sp]", operands);
+ output_asm_insn ("st.w r11, 88[sp]", operands);
+ output_asm_insn ("st.w r12, 84[sp]", operands);
+ output_asm_insn ("st.w r13, 80[sp]", operands);
+ output_asm_insn ("st.w r14, 76[sp]", operands);
+ output_asm_insn ("st.w r15, 72[sp]", operands);
+ output_asm_insn ("st.w r16, 68[sp]", operands);
+ output_asm_insn ("st.w r17, 64[sp]", operands);
+ output_asm_insn ("st.w r18, 60[sp]", operands);
+ output_asm_insn ("st.w r19, 56[sp]", operands);
+ output_asm_insn ("st.w r20, 52[sp]", operands);
+ output_asm_insn ("st.w r21, 48[sp]", operands);
+ output_asm_insn ("st.w r22, 44[sp]", operands);
+ output_asm_insn ("st.w r23, 40[sp]", operands);
+ output_asm_insn ("st.w r24, 36[sp]", operands);
+ output_asm_insn ("st.w r25, 32[sp]", operands);
+ output_asm_insn ("st.w r26, 28[sp]", operands);
+ output_asm_insn ("st.w r27, 24[sp]", operands);
+ output_asm_insn ("st.w r28, 20[sp]", operands);
+ output_asm_insn ("st.w r29, 16[sp]", operands);
+ }
+
+ return "";
+}
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_LONG_CALLS")
+ (const_int 4)
+ (const_int 62)
+ ))
+ (set_attr "cc" "clobber")])
+
+(define_insn "_save_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 0)]
+ "TARGET_V850 && ! TARGET_LONG_CALLS"
+ "jarl __save_all_interrupt,r10"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
+
+;; Restore all registers saved when an interrupt function makes a call.
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+;; This is needed because the rest of the compiler is not ready to handle
+;; insns this complicated.
+
+(define_insn "callt_restore_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 1)]
+ "(TARGET_V850E_UP) && !TARGET_DISABLE_CALLT"
+ "callt ctoff(__callt_restore_all_interrupt)"
+ [(set_attr "length" "2")
+ (set_attr "cc" "none")])
+
+(define_insn "restore_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 1)]
+ ""
+{
+ if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+ return "jarl __restore_all_interrupt,r10";
+
+ if (TARGET_EP)
+ {
+ output_asm_insn ("mov ep, r1", operands);
+ output_asm_insn ("mov sp, ep", operands);
+ output_asm_insn ("sld.w 116[ep], r31", operands);
+ output_asm_insn ("sld.w 112[ep], r2", operands);
+ output_asm_insn ("sld.w 108[ep], gp", operands);
+ output_asm_insn ("sld.w 104[ep], r6", operands);
+ output_asm_insn ("sld.w 100[ep], r7", operands);
+ output_asm_insn ("sld.w 96[ep], r8", operands);
+ output_asm_insn ("sld.w 92[ep], r9", operands);
+ output_asm_insn ("sld.w 88[ep], r11", operands);
+ output_asm_insn ("sld.w 84[ep], r12", operands);
+ output_asm_insn ("sld.w 80[ep], r13", operands);
+ output_asm_insn ("sld.w 76[ep], r14", operands);
+ output_asm_insn ("sld.w 72[ep], r15", operands);
+ output_asm_insn ("sld.w 68[ep], r16", operands);
+ output_asm_insn ("sld.w 64[ep], r17", operands);
+ output_asm_insn ("sld.w 60[ep], r18", operands);
+ output_asm_insn ("sld.w 56[ep], r19", operands);
+ output_asm_insn ("sld.w 52[ep], r20", operands);
+ output_asm_insn ("sld.w 48[ep], r21", operands);
+ output_asm_insn ("sld.w 44[ep], r22", operands);
+ output_asm_insn ("sld.w 40[ep], r23", operands);
+ output_asm_insn ("sld.w 36[ep], r24", operands);
+ output_asm_insn ("sld.w 32[ep], r25", operands);
+ output_asm_insn ("sld.w 28[ep], r26", operands);
+ output_asm_insn ("sld.w 24[ep], r27", operands);
+ output_asm_insn ("sld.w 20[ep], r28", operands);
+ output_asm_insn ("sld.w 16[ep], r29", operands);
+ output_asm_insn ("mov r1, ep", operands);
+ }
+ else
+ {
+ output_asm_insn ("ld.w 116[sp], r31", operands);
+ output_asm_insn ("ld.w 112[sp], r2", operands);
+ output_asm_insn ("ld.w 108[sp], gp", operands);
+ output_asm_insn ("ld.w 104[sp], r6", operands);
+ output_asm_insn ("ld.w 100[sp], r7", operands);
+ output_asm_insn ("ld.w 96[sp], r8", operands);
+ output_asm_insn ("ld.w 92[sp], r9", operands);
+ output_asm_insn ("ld.w 88[sp], r11", operands);
+ output_asm_insn ("ld.w 84[sp], r12", operands);
+ output_asm_insn ("ld.w 80[sp], r13", operands);
+ output_asm_insn ("ld.w 76[sp], r14", operands);
+ output_asm_insn ("ld.w 72[sp], r15", operands);
+ output_asm_insn ("ld.w 68[sp], r16", operands);
+ output_asm_insn ("ld.w 64[sp], r17", operands);
+ output_asm_insn ("ld.w 60[sp], r18", operands);
+ output_asm_insn ("ld.w 56[sp], r19", operands);
+ output_asm_insn ("ld.w 52[sp], r20", operands);
+ output_asm_insn ("ld.w 48[sp], r21", operands);
+ output_asm_insn ("ld.w 44[sp], r22", operands);
+ output_asm_insn ("ld.w 40[sp], r23", operands);
+ output_asm_insn ("ld.w 36[sp], r24", operands);
+ output_asm_insn ("ld.w 32[sp], r25", operands);
+ output_asm_insn ("ld.w 28[sp], r26", operands);
+ output_asm_insn ("ld.w 24[sp], r27", operands);
+ output_asm_insn ("ld.w 20[sp], r28", operands);
+ output_asm_insn ("ld.w 16[sp], r29", operands);
+ }
+ output_asm_insn ("addi 120, sp, sp", operands);
+ return "";
+}
+ [(set (attr "length")
+ (if_then_else (match_test "TARGET_LONG_CALLS")
+ (const_int 4)
+ (const_int 62)
+ ))
+ (set_attr "cc" "clobber")])
+
+(define_insn "_restore_all_interrupt"
+ [(unspec_volatile [(const_int 0)] 1)]
+ "TARGET_V850 && ! TARGET_LONG_CALLS"
+ "jarl __restore_all_interrupt,r10"
+ [(set_attr "length" "4")
+ (set_attr "cc" "clobber")])
diff --git a/gcc-4.9/gcc/config/v850/v850.opt b/gcc-4.9/gcc/config/v850/v850.opt
new file mode 100644
index 000000000..c02750796
--- /dev/null
+++ b/gcc-4.9/gcc/config/v850/v850.opt
@@ -0,0 +1,159 @@
+; Options for the NEC V850 port of the compiler.
+
+; Copyright (C) 2005-2014 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>.
+
+HeaderInclude
+config/v850/v850-opts.h
+
+Variable
+int small_memory_max[(int)SMALL_MEMORY_max] = { 0, 0, 0 }
+
+mapp-regs
+Target Report Mask(APP_REGS)
+Use registers r2 and r5
+
+mbig-switch
+Target Report Mask(BIG_SWITCH)
+Use 4 byte entries in switch tables
+
+mdebug
+Target Report Mask(DEBUG)
+Enable backend debugging
+
+mdisable-callt
+Target Report Mask(DISABLE_CALLT)
+Do not use the callt instruction (default)
+
+mep
+Target Report Mask(EP)
+Reuse r30 on a per function basis
+
+mghs
+Target RejectNegative InverseMask(GCC_ABI) MaskExists
+
+mlong-calls
+Target Report Mask(LONG_CALLS)
+Prohibit PC relative function calls
+
+mprolog-function
+Target Report Mask(PROLOG_FUNCTION)
+Use stubs for function prologues
+
+msda=
+Target RejectNegative Joined UInteger
+Set the max size of data eligible for the SDA area
+
+msda-
+Target RejectNegative Joined Undocumented Alias(msda=)
+
+msmall-sld
+Target Report Mask(SMALL_SLD)
+Enable the use of the short load instructions
+
+mspace
+Target RejectNegative
+Same as: -mep -mprolog-function
+
+mtda=
+Target RejectNegative Joined UInteger
+Set the max size of data eligible for the TDA area
+
+mtda-
+Target RejectNegative Joined Undocumented Alias(mtda=)
+
+mno-strict-align
+Target Report Mask(NO_STRICT_ALIGN)
+Do not enforce strict alignment
+
+mjump-tables-in-data-section
+Target Report Mask(JUMP_TABLES_IN_DATA_SECTION)
+Put jump tables for switch statements into the .data section rather than the .code section
+
+mUS-bit-set
+Target Report Mask(US_BIT_SET)
+
+mv850
+Target Report RejectNegative Mask(V850)
+Compile for the v850 processor
+
+mv850e
+Target Report RejectNegative Mask(V850E)
+Compile for the v850e processor
+
+mv850e1
+Target RejectNegative Mask(V850E1)
+Compile for the v850e1 processor
+
+mv850es
+Target RejectNegative Mask(V850E1)
+Compile for the v850es variant of the v850e1
+
+mv850e2
+Target Report RejectNegative Mask(V850E2)
+Compile for the v850e2 processor
+
+mv850e2v3
+Target Report RejectNegative Mask(V850E2V3)
+Compile for the v850e2v3 processor
+
+mv850e3v5
+Target Report RejectNegative Mask(V850E3V5)
+Compile for the v850e3v5 processor
+
+mv850e2v4
+Target RejectNegative Mask(V850E3V5) MaskExists
+
+mloop
+Target Report Mask(LOOP)
+Enable v850e3v5 loop instructions
+
+mzda=
+Target RejectNegative Joined UInteger
+Set the max size of data eligible for the ZDA area
+
+mzda-
+Target RejectNegative Joined Undocumented Alias(mzda=)
+
+mrelax
+Target Report Mask(RELAX)
+Enable relaxing in the assembler
+
+mlong-jumps
+Target Report Mask(BIG_SWITCH) MaskExists
+Prohibit PC relative jumps
+
+msoft-float
+Target Report RejectNegative Mask(SOFT_FLOAT)
+Inhibit the use of hardware floating point instructions
+
+mhard-float
+Target Report RejectNegative InverseMask(SOFT_FLOAT) MaskExists
+Allow the use of hardware floating point instructions for V850E2V3 and up
+
+mrh850-abi
+Target RejectNegative Report InverseMask(GCC_ABI) MaskExists
+Enable support for the RH850 ABI. This is the default
+
+mgcc-abi
+Target RejectNegative Report Mask(GCC_ABI)
+Enable support for the old GCC ABI
+
+m8byte-align
+Target Report Mask(8BYTE_ALIGN)
+Support alignments of up to 64-bits