mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			9369 lines
		
	
	
		
			296 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			9369 lines
		
	
	
		
			296 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/configure
 | ||
| +++ b/configure
 | ||
| @@ -3730,6 +3730,9 @@ case "${target}" in
 | ||
|    ip2k-*-*)
 | ||
|      noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj}"
 | ||
|      ;;
 | ||
| +  ubicom32-*-*)
 | ||
| +    noconfigdirs="$noconfigdirs target-libffi"
 | ||
| +    ;;
 | ||
|    *-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
 | ||
|      noconfigdirs="$noconfigdirs target-newlib target-libgloss"
 | ||
|      ;;
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/constraints.md
 | ||
| @@ -0,0 +1,149 @@
 | ||
| +; Constraint definitions for Ubicom32
 | ||
| +
 | ||
| +; Copyright (C) 2009 Free Software Foundation, Inc.
 | ||
| +; Contributed by Ubicom, 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 "a" "ALL_ADDRESS_REGS"
 | ||
| +  "An An register.")
 | ||
| +
 | ||
| +(define_register_constraint "d" "DATA_REGS"
 | ||
| +  "A Dn register.")
 | ||
| +
 | ||
| +(define_register_constraint "h" "ACC_REGS"
 | ||
| +  "An accumulator register.")
 | ||
| +
 | ||
| +(define_register_constraint "l" "ACC_LO_REGS"
 | ||
| +  "An accn_lo register.")
 | ||
| +
 | ||
| +(define_register_constraint "Z" "FDPIC_REG"
 | ||
| +  "The FD-PIC GOT pointer: A0.")
 | ||
| +
 | ||
| +(define_constraint "I"
 | ||
| +  "An 8-bit signed constant value."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= -128) && (ival <= 127)")))
 | ||
| +
 | ||
| +(define_constraint "Q"
 | ||
| +  "An 8-bit signed constant value represented as unsigned."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= 0x00) && (ival <= 0xff)")))
 | ||
| +
 | ||
| +(define_constraint "R"
 | ||
| +  "An 8-bit signed constant value represented as unsigned."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "((ival >= 0x0000) && (ival <= 0x007f)) || ((ival >= 0xff80) && (ival <= 0xffff))")))
 | ||
| +
 | ||
| +(define_constraint "J"
 | ||
| +  "A 7-bit unsigned constant value."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= 0) && (ival <= 127)")))
 | ||
| +
 | ||
| +(define_constraint "K"
 | ||
| +  "A 7-bit unsigned constant value shifted << 1."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= 0) && (ival <= 254) && ((ival & 1) == 0)")))
 | ||
| +
 | ||
| +(define_constraint "L"
 | ||
| +  "A 7-bit unsigned constant value shifted << 2."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= 0) && (ival <= 508) && ((ival & 3) == 0)")))
 | ||
| +
 | ||
| +(define_constraint "M"
 | ||
| +  "A 5-bit unsigned constant value."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= 0) && (ival <= 31)")))
 | ||
| +
 | ||
| +(define_constraint "N"
 | ||
| +  "A signed 16 bit constant value."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= -32768) && (ival <= 32767)")))
 | ||
| +
 | ||
| +(define_constraint "O"
 | ||
| +  "An exact bitmask of contiguous 1 bits starting at bit 0."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "exact_log2 (ival + 1) != -1")))
 | ||
| +
 | ||
| +(define_constraint "P"
 | ||
| +  "A 7-bit negative constant value shifted << 2."
 | ||
| +  (and (match_code "const_int")
 | ||
| +       (match_test "(ival >= -504) && (ival <= 0) && ((ival & 3) == 0)")))
 | ||
| +
 | ||
| +(define_constraint "S"
 | ||
| +  "A symbolic reference."
 | ||
| +  (match_code "symbol_ref"))
 | ||
| +
 | ||
| +(define_constraint "Y"
 | ||
| +  "An FD-PIC symbolic reference."
 | ||
| +  (and (match_test "TARGET_FDPIC")
 | ||
| +       (match_test "GET_CODE (op) == UNSPEC")
 | ||
| +       (ior (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT")
 | ||
| +	    (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT_FUNCDESC"))))
 | ||
| +
 | ||
| +(define_memory_constraint "T1"
 | ||
| +  "A memory operand that can be used for .1 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (match_test "GET_MODE (op) == QImode")))
 | ||
| +
 | ||
| +(define_memory_constraint "T2"
 | ||
| +  "A memory operand that can be used for .2 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (match_test "GET_MODE (op) == HImode")))
 | ||
| +
 | ||
| +(define_memory_constraint "T4"
 | ||
| +  "A memory operand that can be used for .4 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (ior (match_test "GET_MODE (op) == SImode")
 | ||
| +	    (match_test "GET_MODE (op) == DImode")
 | ||
| +	    (match_test "GET_MODE (op) == SFmode"))))
 | ||
| +
 | ||
| +(define_memory_constraint "U1"
 | ||
| +  "An offsettable memory operand that can be used for .1 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (match_test "GET_MODE (op) == QImode")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
 | ||
| +
 | ||
| +(define_memory_constraint "U2"
 | ||
| +  "An offsettable memory operand that can be used for .2 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (match_test "GET_MODE (op) == HImode")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
 | ||
| +
 | ||
| +(define_memory_constraint "U4"
 | ||
| +  "An offsettable memory operand that can be used for .4 instruction."
 | ||
| +  (and (match_test "memory_operand (op, GET_MODE(op))")
 | ||
| +       (ior (match_test "GET_MODE (op) == SImode")
 | ||
| +	    (match_test "GET_MODE (op) == DImode")
 | ||
| +	    (match_test "GET_MODE (op) == SFmode"))
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
 | ||
| +       (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/crti.S
 | ||
| @@ -0,0 +1,54 @@
 | ||
| +/* Specialized code needed to support construction and destruction of
 | ||
| +   file-scope objects in C++ and Java code, and to support exception handling.
 | ||
| +   Copyright (C) 1999 Free Software Foundation, Inc.
 | ||
| +   Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
 | ||
| +
 | ||
| +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 2, 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 COPYING.  If not, write to
 | ||
| +the Free Software Foundation, 59 Temple Place - Suite 330,
 | ||
| +Boston, MA 02111-1307, USA.  */
 | ||
| +
 | ||
| +/* As a special exception, if you link this library with files
 | ||
| +   compiled with GCC to produce an executable, this does not cause
 | ||
| +   the resulting executable to be covered by the GNU General Public License.
 | ||
| +   This exception does not however invalidate any other reasons why
 | ||
| +   the executable file might be covered by the GNU General Public License.  */
 | ||
| +
 | ||
| +/*
 | ||
| + * This file just supplies function prologues for the .init and .fini
 | ||
| + * sections.  It is linked in before crtbegin.o.
 | ||
| + */
 | ||
| +	.file   "crti.o"
 | ||
| +	.ident  "GNU C crti.o"
 | ||
| +
 | ||
| +	.section .init
 | ||
| +	.align	2
 | ||
| +	.globl	_init
 | ||
| +	.type	_init, @function
 | ||
| +_init:
 | ||
| +	move.4 -4(sp)++, a5
 | ||
| +#ifdef __UBICOM32_FDPIC__
 | ||
| +	move.4 -4(sp)++, a0
 | ||
| +#endif
 | ||
| +
 | ||
| +	.section .fini
 | ||
| +	.align	2
 | ||
| +	.globl	_fini
 | ||
| +	.type	_fini, @function
 | ||
| +_fini:
 | ||
| +	move.4 -4(sp)++, a5
 | ||
| +#ifdef __UBICOM32_FDPIC__
 | ||
| +	move.4 -4(sp)++, a0
 | ||
| +#endif
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/crtn.S
 | ||
| @@ -0,0 +1,47 @@
 | ||
| +/* Specialized code needed to support construction and destruction of
 | ||
| +   file-scope objects in C++ and Java code, and to support exception handling.
 | ||
| +   Copyright (C) 1999 Free Software Foundation, Inc.
 | ||
| +   Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
 | ||
| +
 | ||
| +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 2, 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 COPYING.  If not, write to
 | ||
| +the Free Software Foundation, 59 Temple Place - Suite 330,
 | ||
| +Boston, MA 02111-1307, USA.  */
 | ||
| +
 | ||
| +/* As a special exception, if you link this library with files
 | ||
| +   compiled with GCC to produce an executable, this does not cause
 | ||
| +   the resulting executable to be covered by the GNU General Public License.
 | ||
| +   This exception does not however invalidate any other reasons why
 | ||
| +   the executable file might be covered by the GNU General Public License.  */
 | ||
| +
 | ||
| +/*
 | ||
| + * This file supplies function epilogues for the .init and .fini sections.
 | ||
| + * It is linked in after all other files.
 | ||
| + */
 | ||
| +
 | ||
| +	.file   "crtn.o"
 | ||
| +	.ident  "GNU C crtn.o"
 | ||
| +
 | ||
| +	.section .init
 | ||
| +#ifdef __UBICOM32_FDPIC__
 | ||
| +	move.4	a0, (sp)4++
 | ||
| +#endif
 | ||
| +	ret	(sp)4++
 | ||
| +
 | ||
| +	.section .fini
 | ||
| +#ifdef __UBICOM32_FDPIC__
 | ||
| +	move.4	a0, (sp)4++
 | ||
| +#endif
 | ||
| +	ret	(sp)4++
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/elf.h
 | ||
| @@ -0,0 +1,29 @@
 | ||
| +#undef  STARTFILE_SPEC
 | ||
| +#define STARTFILE_SPEC "\
 | ||
| +%{msim:%{!shared:crt0%O%s}} \
 | ||
| +crti%O%s crtbegin%O%s"
 | ||
| +
 | ||
| +#undef  ENDFILE_SPEC
 | ||
| +#define ENDFILE_SPEC	"crtend%O%s crtn%O%s"
 | ||
| +
 | ||
| +#ifdef __UBICOM32_FDPIC__
 | ||
| +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)			\
 | ||
| +  asm (SECTION_OP);							\
 | ||
| +  asm ("move.4 a0, 0(sp);\n\t"						\
 | ||
| +       "call a5," USER_LABEL_PREFIX #FUNC ";");				\
 | ||
| +  asm (TEXT_SECTION_ASM_OP);
 | ||
| +#endif
 | ||
| +
 | ||
| +#undef SUBTARGET_DRIVER_SELF_SPECS
 | ||
| +#define SUBTARGET_DRIVER_SELF_SPECS \
 | ||
| +     "%{mfdpic:-msim} "
 | ||
| +
 | ||
| +#define NO_IMPLICIT_EXTERN_C
 | ||
| +
 | ||
| +/*
 | ||
| + * We need this to compile crtbegin/crtend. This should really be picked
 | ||
| + * up from elfos.h but at the moment including elfos.h causes other more
 | ||
| + * serous linker issues.
 | ||
| + */
 | ||
| +#define INIT_SECTION_ASM_OP	"\t.section\t.init"
 | ||
| +#define FINI_SECTION_ASM_OP	"\t.section\t.fini"
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/linux.h
 | ||
| @@ -0,0 +1,80 @@
 | ||
| +/* Definitions of target machine for Ubicom32-uclinux
 | ||
| +
 | ||
| +   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 | ||
| +   2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, 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/>.  */
 | ||
| +
 | ||
| +/* Don't assume anything about the header files.  */
 | ||
| +#define NO_IMPLICIT_EXTERN_C
 | ||
| +
 | ||
| +#undef  LIB_SPEC
 | ||
| +#define LIB_SPEC  \
 | ||
| +	"%{pthread:-lpthread} " \
 | ||
| +	"-lc"
 | ||
| +
 | ||
| +#undef LINK_GCC_C_SEQUENCE_SPEC
 | ||
| +#define LINK_GCC_C_SEQUENCE_SPEC \
 | ||
| +  "%{static:--start-group} %G %L %{static:--end-group} " \
 | ||
| +  "%{!static: %G}"
 | ||
| +
 | ||
| +#undef STARTFILE_SPEC
 | ||
| +#define STARTFILE_SPEC \
 | ||
| +  "%{!shared: %{pg|p|profile:gcrt1%O%s;pie:Scrt1%O%s;:crt1%O%s}} " \
 | ||
| +  "crtreloc%O%s crti%O%s %{shared|pie:crtbeginS%O%s;:crtbegin%O%s}"
 | ||
| +
 | ||
| +#undef ENDFILE_SPEC
 | ||
| +#define ENDFILE_SPEC \
 | ||
| +  "%{shared|pie:crtendS%O%s;:crtend%O%s} crtn%O%s"
 | ||
| +
 | ||
| +/* taken from linux.h */
 | ||
| +/* The GNU C++ standard library requires that these macros be defined.  */
 | ||
| +#undef CPLUSPLUS_CPP_SPEC
 | ||
| +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
 | ||
| +
 | ||
| +#define TARGET_OS_CPP_BUILTINS()				\
 | ||
| +    do {							\
 | ||
| +	builtin_define_std ("__UBICOM32__");			\
 | ||
| +	builtin_define_std ("__ubicom32__");			\
 | ||
| +	builtin_define ("__gnu_linux__");			\
 | ||
| +	builtin_define_std ("linux");				\
 | ||
| +	builtin_define_std ("unix");				\
 | ||
| +	builtin_assert ("system=linux");			\
 | ||
| +	builtin_assert ("system=unix");				\
 | ||
| +	builtin_assert ("system=posix");			\
 | ||
| +    } while (0)
 | ||
| +
 | ||
| +#define OBJECT_FORMAT_ELF
 | ||
| +
 | ||
| +
 | ||
| +#undef DRIVER_SELF_SPECS
 | ||
| +#define DRIVER_SELF_SPECS \
 | ||
| +  "%{!mno-fdpic:-mfdpic}"
 | ||
| +
 | ||
| +#undef LINK_SPEC
 | ||
| +#define LINK_SPEC "%{mfdpic: -m elf32ubicom32fdpic -z text } %{shared} %{pie} \
 | ||
| +  %{static:-dn -Bstatic} \
 | ||
| +  %{shared:-G -Bdynamic} \
 | ||
| +  %{!shared: %{!static: \
 | ||
| +   %{rdynamic:-export-dynamic} \
 | ||
| +   %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} \
 | ||
| +   %{static}} "
 | ||
| +
 | ||
| +/*
 | ||
| +#define MD_UNWIND_SUPPORT "config/bfin/linux-unwind.h"
 | ||
| +*/
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/predicates.md
 | ||
| @@ -0,0 +1,327 @@
 | ||
| +; Predicate definitions for Ubicom32.
 | ||
| +
 | ||
| +; Copyright (C) 2009 Free Software Foundation, Inc.
 | ||
| +; Contributed by Ubicom, 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_predicate "ubicom32_move_operand"
 | ||
| +  (match_code "const_int, const_double, const, mem, subreg, reg, lo_sum")
 | ||
| +{
 | ||
| +  if (CONST_INT_P (op))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  if (GET_CODE (op) == CONST_DOUBLE)
 | ||
| +    return true;
 | ||
| +  
 | ||
| +  if (GET_CODE (op) == CONST)
 | ||
| +    return memory_address_p (mode, op);
 | ||
| +
 | ||
| +  if (GET_MODE (op) != mode)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (MEM_P (op))
 | ||
| +    return memory_address_p (mode, XEXP (op, 0));
 | ||
| +  
 | ||
| +  if (GET_CODE (op) == SUBREG) {
 | ||
| +      op = SUBREG_REG (op);
 | ||
| +
 | ||
| +      if (REG_P (op))
 | ||
| +	return true;
 | ||
| +  
 | ||
| +      if (! MEM_P (op))
 | ||
| +	return false;
 | ||
| +
 | ||
| +      /* Paradoxical SUBREG.  */
 | ||
| +      if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (op)))
 | ||
| +	return false;
 | ||
| +
 | ||
| +      return memory_address_p (GET_MODE (op), XEXP (op, 0));
 | ||
| +    }
 | ||
| +
 | ||
| +  return register_operand (op, mode);
 | ||
| +})
 | ||
| +
 | ||
| +;; Returns true if OP is either a symbol reference or a sum of a
 | ||
| +;; symbol reference and a constant.
 | ||
| +
 | ||
| +(define_predicate "ubicom32_symbolic_address_operand"
 | ||
| +  (match_code "symbol_ref, label_ref, const")
 | ||
| +{
 | ||
| +  switch (GET_CODE (op))
 | ||
| +    {
 | ||
| +    case SYMBOL_REF:
 | ||
| +    case LABEL_REF:
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case CONST:
 | ||
| +      op = XEXP (op, 0);
 | ||
| +      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
 | ||
| +	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
 | ||
| +	      && CONST_INT_P (XEXP (op, 1)));
 | ||
| +
 | ||
| +    default:
 | ||
| +      return false;
 | ||
| +    }
 | ||
| +})
 | ||
| +
 | ||
| +;; Return true if operand is the uClinux FD-PIC register.
 | ||
| +
 | ||
| +(define_predicate "ubicom32_fdpic_operand"
 | ||
| +  (match_code "reg")
 | ||
| +{
 | ||
| +  if (! TARGET_FDPIC)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (!REG_P (op))
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (GET_MODE (op) != mode && mode != VOIDmode)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (REGNO (op) != FDPIC_REGNUM && REGNO (op) < FIRST_PSEUDO_REGISTER)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return true;
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_fdpic_got_offset_operand"
 | ||
| +  (match_code "unspec")
 | ||
| +{
 | ||
| +  if (! TARGET_FDPIC)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (GET_CODE (op) != UNSPEC)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (XINT (op, 1) != UNSPEC_FDPIC_GOT
 | ||
| +      && XINT (op, 1) != UNSPEC_FDPIC_GOT_FUNCDESC)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return true;
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_arith_operand"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| +  return (ubicom32_move_operand (op, mode)
 | ||
| +	  && ! ubicom32_symbolic_address_operand (op, mode)
 | ||
| +	  && (! CONST_INT_P (op)
 | ||
| +	      || satisfies_constraint_I (op)));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_arith_operand_dot1"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| +  return (ubicom32_move_operand (op, mode)
 | ||
| +	  && ! ubicom32_symbolic_address_operand (op, mode)
 | ||
| +	  && (! CONST_INT_P (op)
 | ||
| +	      || satisfies_constraint_Q (op)));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_arith_operand_dot2"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| +  return (ubicom32_move_operand (op, mode)
 | ||
| +	  && ! ubicom32_symbolic_address_operand (op, mode)
 | ||
| +	  && (! CONST_INT_P (op)
 | ||
| +	      || satisfies_constraint_R (op)));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_compare_operand"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| + return (ubicom32_move_operand (op, mode)
 | ||
| +	  && ! ubicom32_symbolic_address_operand (op, mode)
 | ||
| +	  && (! CONST_INT_P (op)
 | ||
| +	      || satisfies_constraint_N (op)));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_compare_operator"
 | ||
| +  (match_code "compare"))
 | ||
| +
 | ||
| +(define_predicate "ubicom32_and_or_si3_operand"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| +  return (ubicom32_arith_operand (op, mode)
 | ||
| +	  || (CONST_INT_P (op)
 | ||
| +	      && ((exact_log2 (INTVAL (op) + 1) != -1
 | ||
| +		   && exact_log2 (INTVAL (op) + 1) <= 31)
 | ||
| +		  || (exact_log2 (INTVAL (op)) != -1
 | ||
| +		      && exact_log2 (INTVAL (op)) <= 31)
 | ||
| +		  || (exact_log2 (~INTVAL (op)) != -1
 | ||
| +		      && exact_log2 (~INTVAL (op)) <= 31))));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_and_or_hi3_operand"
 | ||
| +  (match_code "subreg, reg, const_int, lo_sum, mem")
 | ||
| +{
 | ||
| +  return (ubicom32_arith_operand (op, mode)
 | ||
| +	  || (CONST_INT_P (op)
 | ||
| +	      && exact_log2 (INTVAL (op) + 1) != -1
 | ||
| +	      && exact_log2 (INTVAL (op) + 1) <= 15));
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_mem_or_address_register_operand"
 | ||
| +  (match_code "subreg, reg, mem")
 | ||
| +{
 | ||
| +  unsigned int regno;
 | ||
| +
 | ||
| +  if (MEM_P (op)
 | ||
| +      && memory_operand (op, mode))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  if (REG_P (op))
 | ||
| +    regno = REGNO (op);
 | ||
| +  else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
 | ||
| +    {
 | ||
| +      int offset;
 | ||
| +      if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
 | ||
| +	offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
 | ||
| +      else
 | ||
| +	offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
 | ||
| +				      GET_MODE (SUBREG_REG (op)),
 | ||
| +				      SUBREG_BYTE (op),
 | ||
| +				      GET_MODE (op));
 | ||
| +      regno = REGNO (SUBREG_REG (op)) + offset;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return (regno >= FIRST_PSEUDO_REGISTER 
 | ||
| +	  || REGNO_REG_CLASS (regno) == FDPIC_REG
 | ||
| +	  || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_data_register_operand"
 | ||
| +  (match_code "subreg, reg")
 | ||
| +{
 | ||
| +  unsigned int regno;
 | ||
| +
 | ||
| +  if (REG_P (op))
 | ||
| +    regno = REGNO (op);
 | ||
| +  else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
 | ||
| +    {
 | ||
| +      int offset;
 | ||
| +      if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
 | ||
| +	offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
 | ||
| +      else
 | ||
| +	offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
 | ||
| +				      GET_MODE (SUBREG_REG (op)),
 | ||
| +				      SUBREG_BYTE (op),
 | ||
| +				      GET_MODE (op));
 | ||
| +      regno = REGNO (SUBREG_REG (op)) + offset;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return ((regno >= FIRST_PSEUDO_REGISTER 
 | ||
| +	   && regno != REGNO (virtual_stack_vars_rtx))
 | ||
| +	  || REGNO_REG_CLASS (regno) == DATA_REGS);
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_address_register_operand"
 | ||
| +  (match_code "subreg, reg")
 | ||
| +{
 | ||
| +  unsigned int regno;
 | ||
| +
 | ||
| +  if (REG_P (op))
 | ||
| +    regno = REGNO (op);
 | ||
| +  else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
 | ||
| +    {
 | ||
| +      int offset;
 | ||
| +      if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
 | ||
| +	offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
 | ||
| +      else
 | ||
| +	offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
 | ||
| +				      GET_MODE (SUBREG_REG (op)),
 | ||
| +				      SUBREG_BYTE (op),
 | ||
| +				      GET_MODE (op));
 | ||
| +      regno = REGNO (SUBREG_REG (op)) + offset;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return (regno >= FIRST_PSEUDO_REGISTER 
 | ||
| +	  || REGNO_REG_CLASS (regno) == FDPIC_REG
 | ||
| +	  || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_acc_lo_register_operand"
 | ||
| +  (match_code "subreg, reg")
 | ||
| +{
 | ||
| +  unsigned int regno;
 | ||
| +
 | ||
| +  if (REG_P (op))
 | ||
| +    regno = REGNO (op);
 | ||
| +  else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
 | ||
| +    {
 | ||
| +      int offset;
 | ||
| +      if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
 | ||
| +	offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
 | ||
| +      else
 | ||
| +	offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
 | ||
| +				      GET_MODE (SUBREG_REG (op)),
 | ||
| +				      SUBREG_BYTE (op),
 | ||
| +				      GET_MODE (op));
 | ||
| +      regno = REGNO (SUBREG_REG (op)) + offset;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return ((regno >= FIRST_PSEUDO_REGISTER 
 | ||
| +	   && regno != REGNO (virtual_stack_vars_rtx))
 | ||
| +	  || REGNO_REG_CLASS (regno) == ACC_LO_REGS);
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_acc_hi_register_operand"
 | ||
| +  (match_code "subreg, reg")
 | ||
| +{
 | ||
| +  unsigned int regno;
 | ||
| +
 | ||
| +  if (REG_P (op))
 | ||
| +    regno = REGNO (op);
 | ||
| +  else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
 | ||
| +    {
 | ||
| +      int offset;
 | ||
| +      if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
 | ||
| +	offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
 | ||
| +      else
 | ||
| +	offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
 | ||
| +				      GET_MODE (SUBREG_REG (op)),
 | ||
| +				      SUBREG_BYTE (op),
 | ||
| +				      GET_MODE (op));
 | ||
| +      regno = REGNO (SUBREG_REG (op)) + offset;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    return false;
 | ||
| +
 | ||
| +  return ((regno >= FIRST_PSEUDO_REGISTER 
 | ||
| +	   && regno != REGNO (virtual_stack_vars_rtx))
 | ||
| +	  || REGNO_REG_CLASS (regno) == ACC_REGS);
 | ||
| +})
 | ||
| +
 | ||
| +(define_predicate "ubicom32_call_address_operand"
 | ||
| +  (match_code "symbol_ref, subreg, reg")
 | ||
| +{
 | ||
| +  return (GET_CODE (op) == SYMBOL_REF || REG_P (op));
 | ||
| +})
 | ||
| +
 | ||
| +(define_special_predicate "ubicom32_cc_register_operand"
 | ||
| +  (and (match_code "reg")
 | ||
| +       (match_test "REGNO (op) == CC_REGNUM")))
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/t-ubicom32
 | ||
| @@ -0,0 +1,52 @@
 | ||
| +# Name of assembly file containing libgcc1 functions.
 | ||
| +# This entry must be present, but it can be empty if the target does
 | ||
| +# not need any assembler functions to support its code generation.
 | ||
| +CROSS_LIBGCC1 =
 | ||
| +
 | ||
| +# Alternatively if assembler functions *are* needed then define the
 | ||
| +# entries below:
 | ||
| +# CROSS_LIBGCC1 = libgcc1-asm.a
 | ||
| +
 | ||
| +LIB2FUNCS_EXTRA = \
 | ||
| +	$(srcdir)/config/udivmodsi4.c \
 | ||
| +	$(srcdir)/config/divmod.c \
 | ||
| +	$(srcdir)/config/udivmod.c
 | ||
| +
 | ||
| +# If any special flags are necessary when building libgcc2 put them here.
 | ||
| +#
 | ||
| +# TARGET_LIBGCC2_CFLAGS = 
 | ||
| +
 | ||
| +# We want fine grained libraries, so use the new code to build the
 | ||
| +# floating point emulation libraries.
 | ||
| +FPBIT = fp-bit.c
 | ||
| +DPBIT = dp-bit.c
 | ||
| +
 | ||
| +fp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	echo '#define FLOAT'				> fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c			>> fp-bit.c
 | ||
| +
 | ||
| +dp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c > dp-bit.c
 | ||
| +
 | ||
| +# Commented out to speed up compiler development!
 | ||
| +#
 | ||
| +# MULTILIB_OPTIONS = march=ubicom32v1/march=ubicom32v2/march=ubicom32v3/march=ubicom32v4
 | ||
| +# MULTILIB_DIRNAMES = ubicom32v1 ubicom32v2 ubicom32v3 ubicom32v4
 | ||
| +
 | ||
| +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
 | ||
| +MULTILIB_OPTIONS += mfdpic
 | ||
| +MULTILIB_OPTIONS += mno-ipos-abi/mipos-abi
 | ||
| +MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore
 | ||
| +
 | ||
| +# Assemble startup files.
 | ||
| +$(T)crti.o: $(srcdir)/config/ubicom32/crti.S $(GCC_PASSES)
 | ||
| +	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
 | ||
| +	-c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crti.S
 | ||
| +
 | ||
| +$(T)crtn.o: $(srcdir)/config/ubicom32/crtn.S $(GCC_PASSES)
 | ||
| +	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
 | ||
| +	-c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crtn.S
 | ||
| +
 | ||
| +# these parts are required because uClibc ldso needs them to link.
 | ||
| +# they are not in the specfile so they will not be included automatically.
 | ||
| +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crti.o crtn.o
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/t-ubicom32-linux
 | ||
| @@ -0,0 +1,35 @@
 | ||
| +# Name of assembly file containing libgcc1 functions.
 | ||
| +# This entry must be present, but it can be empty if the target does
 | ||
| +# not need any assembler functions to support its code generation.
 | ||
| +CROSS_LIBGCC1 =
 | ||
| +
 | ||
| +# Alternatively if assembler functions *are* needed then define the
 | ||
| +# entries below:
 | ||
| +# CROSS_LIBGCC1 = libgcc1-asm.a
 | ||
| +
 | ||
| +LIB2FUNCS_EXTRA = \
 | ||
| +	$(srcdir)/config/udivmodsi4.c \
 | ||
| +	$(srcdir)/config/divmod.c \
 | ||
| +	$(srcdir)/config/udivmod.c
 | ||
| +
 | ||
| +# If any special flags are necessary when building libgcc2 put them here.
 | ||
| +#
 | ||
| +# TARGET_LIBGCC2_CFLAGS =
 | ||
| +
 | ||
| +# We want fine grained libraries, so use the new code to build the
 | ||
| +# floating point emulation libraries.
 | ||
| +FPBIT = fp-bit.c
 | ||
| +DPBIT = dp-bit.c
 | ||
| +
 | ||
| +fp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	echo '#define FLOAT'				> fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c			>> fp-bit.c
 | ||
| +
 | ||
| +dp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c > dp-bit.c
 | ||
| +
 | ||
| +# We only support v3 and v4 ISAs for uClinux.
 | ||
| +
 | ||
| +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
 | ||
| +
 | ||
| +#EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/t-ubicom32-uclinux
 | ||
| @@ -0,0 +1,35 @@
 | ||
| +# Name of assembly file containing libgcc1 functions.
 | ||
| +# This entry must be present, but it can be empty if the target does
 | ||
| +# not need any assembler functions to support its code generation.
 | ||
| +CROSS_LIBGCC1 =
 | ||
| +
 | ||
| +# Alternatively if assembler functions *are* needed then define the
 | ||
| +# entries below:
 | ||
| +# CROSS_LIBGCC1 = libgcc1-asm.a
 | ||
| +
 | ||
| +LIB2FUNCS_EXTRA = \
 | ||
| +	$(srcdir)/config/udivmodsi4.c \
 | ||
| +	$(srcdir)/config/divmod.c \
 | ||
| +	$(srcdir)/config/udivmod.c
 | ||
| +
 | ||
| +# If any special flags are necessary when building libgcc2 put them here.
 | ||
| +#
 | ||
| +# TARGET_LIBGCC2_CFLAGS = 
 | ||
| +
 | ||
| +# We want fine grained libraries, so use the new code to build the
 | ||
| +# floating point emulation libraries.
 | ||
| +FPBIT = fp-bit.c
 | ||
| +DPBIT = dp-bit.c
 | ||
| +
 | ||
| +fp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	echo '#define FLOAT'				> fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c			>> fp-bit.c
 | ||
| +
 | ||
| +dp-bit.c: $(srcdir)/config/fp-bit.c
 | ||
| +	cat $(srcdir)/config/fp-bit.c > dp-bit.c
 | ||
| +
 | ||
| +# We only support v3 and v4 ISAs for uClinux.
 | ||
| +
 | ||
| +MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
 | ||
| +
 | ||
| +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o # crtbeginS.o crtendS.o
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32-modes.def
 | ||
| @@ -0,0 +1,30 @@
 | ||
| +/* Definitions of target machine for GNU compiler, Ubicom32 architecture.
 | ||
| +   Copyright (C) 2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, 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/>.  */
 | ||
| +
 | ||
| +/* Some insns set all condition code flags, some only set the Z and N flags, and
 | ||
| +   some only set the Z flag.  */
 | ||
| +
 | ||
| +CC_MODE (CCW);
 | ||
| +CC_MODE (CCWZN);
 | ||
| +CC_MODE (CCWZ);
 | ||
| +CC_MODE (CCS);
 | ||
| +CC_MODE (CCSZN);
 | ||
| +CC_MODE (CCSZ);
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32-protos.h
 | ||
| @@ -0,0 +1,84 @@
 | ||
| +/* Function prototypes for Ubicom IP3000.
 | ||
| +
 | ||
| +   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 | ||
| +   2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, Inc.
 | ||
| +
 | ||
| +   This file is part of GNU CC.
 | ||
| +
 | ||
| +   GNU CC is free software; you can redistribute it and/or modify it under
 | ||
| +   the terms of the GNU General Public License as published by the Free
 | ||
| +   Software Foundation; either version 2, or (at your option) any later
 | ||
| +   version.
 | ||
| +
 | ||
| +   GNU CC is distributed in the hope that it will be useful, but WITHOUT
 | ||
| +   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | ||
| +   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 | ||
| +   for more details.
 | ||
| +
 | ||
| +   You should have received a copy of the GNU General Public License along
 | ||
| +   with GNU CC; see the file COPYING.  If not, write to the Free Software
 | ||
| +   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 | ||
| +
 | ||
| +#ifdef RTX_CODE
 | ||
| +
 | ||
| +#ifdef TREE_CODE
 | ||
| +extern void ubicom32_va_start (tree, rtx);
 | ||
| +#endif /* TREE_CODE */
 | ||
| +
 | ||
| +extern void ubicom32_print_operand (FILE *, rtx, int);
 | ||
| +extern void ubicom32_print_operand_address (FILE *, rtx);
 | ||
| +
 | ||
| +extern void ubicom32_conditional_register_usage (void);
 | ||
| +extern enum reg_class ubicom32_preferred_reload_class (rtx, enum reg_class);
 | ||
| +extern int ubicom32_regno_ok_for_index_p (int, int);
 | ||
| +extern void ubicom32_expand_movsi (rtx *);
 | ||
| +extern void ubicom32_expand_addsi3 (rtx *);
 | ||
| +extern int ubicom32_emit_mult_sequence (rtx *);
 | ||
| +extern void ubicom32_emit_move_const_int (rtx, rtx);
 | ||
| +extern bool ubicom32_legitimate_constant_p (rtx);
 | ||
| +extern bool ubicom32_legitimate_address_p (enum machine_mode, rtx, int);
 | ||
| +extern rtx ubicom32_legitimize_address (rtx, rtx, enum machine_mode);
 | ||
| +extern rtx ubicom32_legitimize_reload_address (rtx, enum machine_mode, int, int);
 | ||
| +extern void ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1);
 | ||
| +extern int ubicom32_mode_dependent_address_p (rtx);
 | ||
| +extern void ubicom32_output_cond_jump (rtx, rtx, rtx);
 | ||
| +extern void ubicom32_expand_eh_return (rtx *);
 | ||
| +extern void ubicom32_expand_call_fdpic (rtx *);
 | ||
| +extern void ubicom32_expand_call_value_fdpic (rtx *);
 | ||
| +extern enum machine_mode ubicom32_select_cc_mode (RTX_CODE, rtx, rtx);
 | ||
| +extern rtx ubicom32_gen_compare_reg (RTX_CODE, rtx, rtx);
 | ||
| +extern int ubicom32_shiftable_const_int (int);
 | ||
| +#endif /* RTX_CODE */
 | ||
| +
 | ||
| +#ifdef TREE_CODE
 | ||
| +extern void init_cumulative_args (CUMULATIVE_ARGS *cum,
 | ||
| +				  tree fntype,
 | ||
| +				  struct rtx_def *libname,
 | ||
| +				  int indirect);
 | ||
| +extern struct rtx_def *function_arg (CUMULATIVE_ARGS *,
 | ||
| +				     enum machine_mode, tree, int);
 | ||
| +extern struct rtx_def *function_incoming_arg (CUMULATIVE_ARGS *,
 | ||
| +					      enum machine_mode,
 | ||
| +					      tree, int);
 | ||
| +extern int function_arg_partial_nregs (CUMULATIVE_ARGS *,
 | ||
| +				       enum machine_mode, tree, int);
 | ||
| +extern struct rtx_def *ubicom32_va_arg (tree, tree);
 | ||
| +extern int ubicom32_reg_parm_stack_space (tree);
 | ||
| +#endif /* TREE_CODE */
 | ||
| +
 | ||
| +extern struct rtx_def * ubicom32_builtin_saveregs (void);
 | ||
| +extern void asm_file_start (FILE *);
 | ||
| +extern void ubicom32_expand_prologue (void);
 | ||
| +extern void ubicom32_expand_epilogue (void);
 | ||
| +extern int ubicom32_initial_elimination_offset (int, int);
 | ||
| +extern int ubicom32_regno_ok_for_base_p (int, int);
 | ||
| +extern bool ubicom32_hard_regno_mode_ok (unsigned int, enum machine_mode);
 | ||
| +extern int ubicom32_can_use_return_insn_p (void);
 | ||
| +extern rtx ubicom32_return_addr_rtx (int, rtx);
 | ||
| +extern void ubicom32_optimization_options (int, int);
 | ||
| +extern void ubicom32_override_options (void);
 | ||
| +extern bool ubicom32_match_cc_mode (rtx, enum machine_mode);
 | ||
| +
 | ||
| +extern int ubicom32_reorg_completed;
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32.c
 | ||
| @@ -0,0 +1,2881 @@
 | ||
| +/* Subroutines for insn-output.c for Ubicom32
 | ||
| +
 | ||
| +   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 | ||
| +   2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, Inc.
 | ||
| +
 | ||
| +   This file is part of GCC.
 | ||
| +
 | ||
| +   GCC is free software; you can redistribute it and/or modify it
 | ||
| +   under the terms of the GNU General Public License as published
 | ||
| +   by the Free Software Foundation; either version 3, or (at your
 | ||
| +   option) any later version.
 | ||
| +
 | ||
| +   GCC is distributed in the hope that it will be useful, but WITHOUT
 | ||
| +   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 | ||
| +   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 | ||
| +   License for more details.
 | ||
| +
 | ||
| +   You should have received a copy of the GNU General Public License
 | ||
| +   along with GCC; see the file COPYING3.  If not see
 | ||
| +   <http://www.gnu.org/licenses/>.  */
 | ||
| +
 | ||
| +#include "config.h"
 | ||
| +#include "system.h"
 | ||
| +#include "coretypes.h"
 | ||
| +#include "tm.h"
 | ||
| +#include "rtl.h"
 | ||
| +#include "tree.h"
 | ||
| +#include "regs.h"
 | ||
| +#include "hard-reg-set.h"
 | ||
| +#include "real.h"
 | ||
| +#include "insn-config.h"
 | ||
| +#include "conditions.h"
 | ||
| +#include "insn-flags.h"
 | ||
| +#include "output.h"
 | ||
| +#include "insn-attr.h"
 | ||
| +#include "insn-codes.h"
 | ||
| +#include "flags.h"
 | ||
| +#include "recog.h"
 | ||
| +#include "expr.h"
 | ||
| +#include "function.h"
 | ||
| +#include "obstack.h"
 | ||
| +#include "toplev.h"
 | ||
| +#include "tm_p.h"
 | ||
| +#include "tm-constrs.h"
 | ||
| +#include "basic-block.h"
 | ||
| +#include "integrate.h"
 | ||
| +#include "target.h"
 | ||
| +#include "target-def.h"
 | ||
| +#include "reload.h"
 | ||
| +#include "df.h"
 | ||
| +#include "langhooks.h"
 | ||
| +#include "optabs.h"
 | ||
| +
 | ||
| +static tree ubicom32_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
 | ||
| +static void ubicom32_layout_frame (void);
 | ||
| +static void ubicom32_function_prologue (FILE *, HOST_WIDE_INT);
 | ||
| +static void ubicom32_function_epilogue (FILE *, HOST_WIDE_INT);
 | ||
| +static bool ubicom32_rtx_costs (rtx, int, int, int *, bool speed);
 | ||
| +static bool ubicom32_fixed_condition_code_regs (unsigned int *,
 | ||
| +						unsigned int *);
 | ||
| +static enum machine_mode ubicom32_cc_modes_compatible (enum machine_mode,
 | ||
| +						       enum machine_mode);
 | ||
| +static int ubicom32_naked_function_p (void);
 | ||
| +static void ubicom32_machine_dependent_reorg (void);
 | ||
| +static bool ubicom32_assemble_integer (rtx, unsigned int, int);
 | ||
| +static void ubicom32_asm_init_sections (void);
 | ||
| +static int ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,tree, 
 | ||
| +				       bool);
 | ||
| +static bool ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 | ||
| +					enum machine_mode mode, const_tree type,
 | ||
| +					bool named ATTRIBUTE_UNUSED);
 | ||
| +static bool ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 | ||
| +				    enum machine_mode mode, const_tree type,
 | ||
| +				    bool named ATTRIBUTE_UNUSED);
 | ||
| +
 | ||
| +static bool ubicom32_return_in_memory (const_tree type, 
 | ||
| +				       const_tree fntype ATTRIBUTE_UNUSED);
 | ||
| +static bool ubicom32_is_base_reg (rtx, int);
 | ||
| +static void ubicom32_init_builtins (void);
 | ||
| +static rtx ubicom32_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 | ||
| +static tree ubicom32_fold_builtin (tree, tree, bool);
 | ||
| +static int ubicom32_get_valid_offset_mask (enum machine_mode);
 | ||
| +static bool ubicom32_cannot_force_const_mem (rtx);
 | ||
| +
 | ||
| +/* Case values threshold */
 | ||
| +int ubicom32_case_values_threshold = 6;
 | ||
| +
 | ||
| +/* Nonzero if this chip supports the Ubicom32 v3 ISA.  */
 | ||
| +int ubicom32_v3 = 1;
 | ||
| +
 | ||
| +/* Nonzero if this chip supports the Ubicom32 v4 ISA.  */
 | ||
| +int ubicom32_v4 = 1;
 | ||
| +
 | ||
| +/* Valid attributes:
 | ||
| +   naked - don't generate function prologue/epilogue and `ret' command.  */
 | ||
| +const struct attribute_spec ubicom32_attribute_table[] =
 | ||
| +{
 | ||
| +  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
 | ||
| +  { "naked", 0, 0, true,  false, false, ubicom32_handle_fndecl_attribute },
 | ||
| +  { NULL,    0, 0, false, false, false, NULL }
 | ||
| +};
 | ||
| +
 | ||
| +#undef TARGET_ASM_FUNCTION_PROLOGUE
 | ||
| +#define TARGET_ASM_FUNCTION_PROLOGUE ubicom32_function_prologue
 | ||
| +
 | ||
| +#undef TARGET_ASM_FUNCTION_EPILOGUE
 | ||
| +#define TARGET_ASM_FUNCTION_EPILOGUE ubicom32_function_epilogue
 | ||
| +
 | ||
| +#undef TARGET_ATTRIBUTE_TABLE
 | ||
| +#define TARGET_ATTRIBUTE_TABLE ubicom32_attribute_table
 | ||
| +
 | ||
| +/* All addresses cost the same amount.  */
 | ||
| +#undef TARGET_ADDRESS_COST
 | ||
| +#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
 | ||
| +
 | ||
| +#undef TARGET_RTX_COSTS
 | ||
| +#define TARGET_RTX_COSTS ubicom32_rtx_costs
 | ||
| +
 | ||
| +#undef TARGET_FIXED_CONDITION_CODE_REGS
 | ||
| +#define TARGET_FIXED_CONDITION_CODE_REGS ubicom32_fixed_condition_code_regs
 | ||
| +
 | ||
| +#undef TARGET_CC_MODES_COMPATIBLE
 | ||
| +#define TARGET_CC_MODES_COMPATIBLE ubicom32_cc_modes_compatible
 | ||
| +
 | ||
| +#undef TARGET_MACHINE_DEPENDENT_REORG
 | ||
| +#define TARGET_MACHINE_DEPENDENT_REORG ubicom32_machine_dependent_reorg
 | ||
| +
 | ||
| +#undef  TARGET_ASM_INTEGER
 | ||
| +#define TARGET_ASM_INTEGER ubicom32_assemble_integer
 | ||
| +
 | ||
| +#undef TARGET_ASM_INIT_SECTIONS
 | ||
| +#define TARGET_ASM_INIT_SECTIONS ubicom32_asm_init_sections
 | ||
| +
 | ||
| +#undef TARGET_ARG_PARTIAL_BYTES
 | ||
| +#define TARGET_ARG_PARTIAL_BYTES ubicom32_arg_partial_bytes
 | ||
| +
 | ||
| +#undef TARGET_PASS_BY_REFERENCE
 | ||
| +#define TARGET_PASS_BY_REFERENCE ubicom32_pass_by_reference
 | ||
| +
 | ||
| +#undef TARGET_CALLEE_COPIES
 | ||
| +#define TARGET_CALLEE_COPIES ubicom32_callee_copies
 | ||
| +
 | ||
| +#undef TARGET_RETURN_IN_MEMORY
 | ||
| +#define TARGET_RETURN_IN_MEMORY ubicom32_return_in_memory
 | ||
| +
 | ||
| +#undef TARGET_INIT_BUILTINS
 | ||
| +#define TARGET_INIT_BUILTINS ubicom32_init_builtins
 | ||
| +
 | ||
| +#undef TARGET_EXPAND_BUILTIN
 | ||
| +#define TARGET_EXPAND_BUILTIN ubicom32_expand_builtin
 | ||
| +
 | ||
| +#undef TARGET_FOLD_BUILTIN
 | ||
| +#define TARGET_FOLD_BUILTIN ubicom32_fold_builtin
 | ||
| +
 | ||
| +#undef TARGET_CANNOT_FORCE_CONST_MEM
 | ||
| +#define TARGET_CANNOT_FORCE_CONST_MEM ubicom32_cannot_force_const_mem
 | ||
| +
 | ||
| +struct gcc_target targetm = TARGET_INITIALIZER;
 | ||
| +
 | ||
| +static char save_regs[FIRST_PSEUDO_REGISTER];
 | ||
| +static int nregs;
 | ||
| +static int frame_size;
 | ||
| +int ubicom32_stack_size = 0;	/* size of allocated stack (including frame) */
 | ||
| +int ubicom32_can_use_calli_to_ret;
 | ||
| +
 | ||
| +#define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
 | ||
| +#define ROUND_CALL_BLOCK_SIZE(BYTES) \
 | ||
| +  (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
 | ||
| +
 | ||
| +/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
 | ||
| +   must report the mode of the memory reference from PRINT_OPERAND to
 | ||
| +   PRINT_OPERAND_ADDRESS.  */
 | ||
| +enum machine_mode output_memory_reference_mode;
 | ||
| +
 | ||
| +/* Flag for some split insns from the ubicom32.md.  */
 | ||
| +int ubicom32_reorg_completed;
 | ||
| +
 | ||
| +enum reg_class const ubicom32_regclass_map[FIRST_PSEUDO_REGISTER] =
 | ||
| +{
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  DATA_REGS, 
 | ||
| +  FDPIC_REG, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ADDRESS_REGS, 
 | ||
| +  ACC_REGS,
 | ||
| +  ACC_LO_REGS,
 | ||
| +  ACC_REGS,
 | ||
| +  ACC_LO_REGS,
 | ||
| +  SOURCE3_REG,
 | ||
| +  ADDRESS_REGS,
 | ||
| +  NO_REGS,			/* CC_REG must be NO_REGS */
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  SPECIAL_REGS
 | ||
| +};
 | ||
| +
 | ||
| +rtx ubicom32_compare_op0;
 | ||
| +rtx ubicom32_compare_op1;
 | ||
| +
 | ||
| +/* Handle command line option overrides.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_override_options (void)
 | ||
| +{
 | ||
| +  flag_pic = 0;
 | ||
| +
 | ||
| +  if (strcmp (ubicom32_arch_name, "ubicom32v1") == 0) {
 | ||
| +    /* If we have a version 1 architecture then we want to avoid using jump
 | ||
| +       tables.  */
 | ||
| +    ubicom32_case_values_threshold = 30000;
 | ||
| +    ubicom32_v3 = 0;
 | ||
| +    ubicom32_v4 = 0;
 | ||
| +  } else if (strcmp (ubicom32_arch_name, "ubicom32v2") == 0) {
 | ||
| +    ubicom32_v3 = 0;
 | ||
| +    ubicom32_v4 = 0;
 | ||
| +  } else if (strcmp (ubicom32_arch_name, "ubicom32v3") == 0) {
 | ||
| +    ubicom32_v3 = 1;
 | ||
| +    ubicom32_v4 = 0;
 | ||
| +  } else if (strcmp (ubicom32_arch_name, "ubicom32v4") == 0) {
 | ||
| +    ubicom32_v3 = 1;
 | ||
| +    ubicom32_v4 = 1;
 | ||
| +  }
 | ||
| +
 | ||
| +  /* There is no single unaligned SI op for PIC code.  Sometimes we
 | ||
| +     need to use ".4byte" and sometimes we need to use ".picptr".
 | ||
| +     See ubicom32_assemble_integer for details.  */
 | ||
| +  if (TARGET_FDPIC)
 | ||
| +    targetm.asm_out.unaligned_op.si = 0;
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_conditional_register_usage (void)
 | ||
| +{
 | ||
| +  /* If we're using the old ipOS ABI we need to make D10 through D13
 | ||
| +     caller-clobbered.  */
 | ||
| +  if (TARGET_IPOS_ABI)
 | ||
| +    {
 | ||
| +      call_used_regs[D10_REGNUM] = 1;
 | ||
| +      call_used_regs[D11_REGNUM] = 1;
 | ||
| +      call_used_regs[D12_REGNUM] = 1;
 | ||
| +      call_used_regs[D13_REGNUM] = 1;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* We have some number of optimizations that don't really work for the Ubicom32
 | ||
| +   architecture so we deal with them here.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_optimization_options (int level ATTRIBUTE_UNUSED,
 | ||
| +			       int size ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  /* The tree IVOPTs pass seems to do really bad things for the Ubicom32
 | ||
| +     architecture - it tends to turn things that would happily use pre/post
 | ||
| +     increment/decrement into operations involving unecessary loop
 | ||
| +     indicies.  */
 | ||
| +  flag_ivopts = 0;
 | ||
| +
 | ||
| +  /* We have problems where DSE at the RTL level misses partial stores
 | ||
| +     to the stack.  For now we disable it to avoid this.  */
 | ||
| +  flag_dse = 0;
 | ||
| +}
 | ||
| +
 | ||
| +/* Print operand X using operand code CODE to assembly language output file
 | ||
| +   FILE.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_print_operand (FILE *file, rtx x, int code)
 | ||
| +{
 | ||
| +  switch (code)
 | ||
| +    {
 | ||
| +    case 'A':
 | ||
| +      /* Identify the correct accumulator to use.  */
 | ||
| +      if (REGNO (x) == ACC0_HI_REGNUM || REGNO (x) == ACC0_LO_REGNUM)
 | ||
| +	fprintf (file, "acc0");
 | ||
| +      else if (REGNO (x) == ACC1_HI_REGNUM || REGNO (x) == ACC1_LO_REGNUM)
 | ||
| +	fprintf (file, "acc1");
 | ||
| +      else
 | ||
| +	abort ();
 | ||
| +      break;
 | ||
| +
 | ||
| +    case 'b':
 | ||
| +    case 'B':
 | ||
| +      {
 | ||
| +	enum machine_mode mode;
 | ||
| +
 | ||
| +	mode = GET_MODE (XEXP (x, 0));
 | ||
| +
 | ||
| +	/* These are normal and reversed branches.  */
 | ||
| +	switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
 | ||
| +	  {
 | ||
| +	  case NE:
 | ||
| +	    fprintf (file, "ne");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case EQ:
 | ||
| +	    fprintf (file, "eq");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case GE:
 | ||
| +	    if (mode == CCSZNmode || mode == CCWZNmode)
 | ||
| +	      fprintf (file, "pl");
 | ||
| +	    else
 | ||
| +	      fprintf (file, "ge");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case GT:
 | ||
| +	    fprintf (file, "gt");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case LE:
 | ||
| +	    fprintf (file, "le");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case LT:
 | ||
| +	    if (mode == CCSZNmode || mode == CCWZNmode)
 | ||
| +	      fprintf (file, "mi");
 | ||
| +	    else
 | ||
| +	      fprintf (file, "lt");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case GEU:
 | ||
| +	    fprintf (file, "cs");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case GTU:
 | ||
| +	    fprintf (file, "hi");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case LEU:
 | ||
| +	    fprintf (file, "ls");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  case LTU:
 | ||
| +	    fprintf (file, "cc");
 | ||
| +	    break;
 | ||
| +
 | ||
| +	  default:
 | ||
| +	    abort ();
 | ||
| +	  }
 | ||
| +      }
 | ||
| +      break;
 | ||
| +
 | ||
| +    case 'C':
 | ||
| +      /* This is used for the operand to a call instruction;
 | ||
| +	 if it's a REG, enclose it in parens, else output
 | ||
| +	 the operand normally.  */
 | ||
| +      if (REG_P (x))
 | ||
| +	{
 | ||
| +	  fputc ('(', file);
 | ||
| +	  ubicom32_print_operand (file, x, 0);
 | ||
| +	  fputc (')', file);
 | ||
| +	}
 | ||
| +      else
 | ||
| +	ubicom32_print_operand (file, x, 0);
 | ||
| +      break;
 | ||
| +
 | ||
| +    case 'd':
 | ||
| +      /* Bit operations we need bit numbers. */
 | ||
| +      fprintf (file, "%d", exact_log2 (INTVAL (x)));
 | ||
| +      break;
 | ||
| +
 | ||
| +    case 'D':
 | ||
| +      /* Bit operations we need bit numbers. */
 | ||
| +      fprintf (file, "%d", exact_log2 (~ INTVAL (x)));
 | ||
| +      break;
 | ||
| +
 | ||
| +    case 'E':
 | ||
| +      /* For lea, which we use to add address registers.
 | ||
| +	 We don't want the '#' on a constant. */
 | ||
| +      if (CONST_INT_P (x))
 | ||
| +	{
 | ||
| +	  fprintf (file, "%ld", INTVAL (x));
 | ||
| +	  break;
 | ||
| +	}
 | ||
| +      /* FALL THROUGH */
 | ||
| +
 | ||
| +    default:
 | ||
| +      switch (GET_CODE (x))
 | ||
| +	{
 | ||
| +	case MEM:
 | ||
| +	  output_memory_reference_mode = GET_MODE (x);
 | ||
| +	  output_address (XEXP (x, 0));
 | ||
| +	  break;
 | ||
| +
 | ||
| +	case PLUS:
 | ||
| +	  output_address (x);
 | ||
| +	  break;
 | ||
| +
 | ||
| +	case REG:
 | ||
| +	  fprintf (file, "%s", reg_names[REGNO (x)]);
 | ||
| +	  break;
 | ||
| +
 | ||
| +	case SUBREG:
 | ||
| +	  fprintf (file, "%s", reg_names[subreg_regno (x)]);
 | ||
| +	  break;
 | ||
| +
 | ||
| +	/* This will only be single precision....  */
 | ||
| +	case CONST_DOUBLE:
 | ||
| +	  {
 | ||
| +	    unsigned long val;
 | ||
| +	    REAL_VALUE_TYPE rv;
 | ||
| +
 | ||
| +	    REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
 | ||
| +	    REAL_VALUE_TO_TARGET_SINGLE (rv, val);
 | ||
| +	    fprintf (file, "0x%lx", val);
 | ||
| +	    break;
 | ||
| +	  }
 | ||
| +
 | ||
| +	case CONST_INT:
 | ||
| +	case SYMBOL_REF:
 | ||
| +	case CONST:
 | ||
| +	case LABEL_REF:
 | ||
| +	case CODE_LABEL:
 | ||
| +	case LO_SUM:
 | ||
| +	  ubicom32_print_operand_address (file, x);
 | ||
| +	  break;
 | ||
| +
 | ||
| +	case HIGH:
 | ||
| +	  fprintf (file, "#%%hi(");
 | ||
| +	  ubicom32_print_operand_address (file, XEXP (x, 0));
 | ||
| +	  fprintf (file, ")");
 | ||
| +	  break;
 | ||
| +
 | ||
| +	case UNSPEC:
 | ||
| +	  switch (XINT (x, 1))
 | ||
| +	    {
 | ||
| +	    case UNSPEC_FDPIC_GOT:
 | ||
| +	      fprintf (file, "#%%got_lo(");
 | ||
| +	      ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
 | ||
| +	      fprintf (file, ")");
 | ||
| +	      break;
 | ||
| +
 | ||
| +	    case UNSPEC_FDPIC_GOT_FUNCDESC:
 | ||
| +	      fprintf (file, "#%%got_funcdesc_lo(");
 | ||
| +	      ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
 | ||
| +	      fprintf (file, ")");
 | ||
| +	      break;
 | ||
| +
 | ||
| +	    default:
 | ||
| +	      abort ();
 | ||
| +	    }
 | ||
| +          break;
 | ||
| +
 | ||
| +	default:
 | ||
| +	  abort ();
 | ||
| +	}
 | ||
| +      break;
 | ||
| +   }
 | ||
| +}
 | ||
| +
 | ||
| +/* Output assembly language output for the address ADDR to FILE.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_print_operand_address (FILE *file, rtx addr)
 | ||
| +{
 | ||
| +  switch (GET_CODE (addr))
 | ||
| +    {
 | ||
| +    case POST_INC:
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "%d++", GET_MODE_SIZE (output_memory_reference_mode));
 | ||
| +      break;
 | ||
| +
 | ||
| +    case PRE_INC:
 | ||
| +      fprintf (file, "%d", GET_MODE_SIZE (output_memory_reference_mode));
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "++");
 | ||
| +      break;
 | ||
| +
 | ||
| +    case POST_DEC:
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "%d++", -GET_MODE_SIZE (output_memory_reference_mode));
 | ||
| +      break;
 | ||
| +
 | ||
| +    case PRE_DEC:
 | ||
| +      fprintf (file, "%d", -GET_MODE_SIZE (output_memory_reference_mode));
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "++");
 | ||
| +      break;
 | ||
| +
 | ||
| +    case POST_MODIFY:
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "%ld++", INTVAL (XEXP (XEXP (addr,1), 1)));
 | ||
| +      break;
 | ||
| +
 | ||
| +    case PRE_MODIFY:
 | ||
| +      fprintf (file, "%ld", INTVAL (XEXP (XEXP (addr,1), 1)));
 | ||
| +      ubicom32_print_operand_address (file, XEXP (addr, 0));
 | ||
| +      fprintf (file, "++");
 | ||
| +      break;
 | ||
| +
 | ||
| +    case REG:
 | ||
| +      fputc ('(', file);
 | ||
| +      fprintf (file, "%s", reg_names[REGNO (addr)]); 
 | ||
| +      fputc (')', file);
 | ||
| +      break;
 | ||
| +
 | ||
| +    case PLUS:
 | ||
| +      {
 | ||
| +	rtx base = XEXP (addr, 0);
 | ||
| +	rtx index = XEXP (addr, 1); 
 | ||
| +
 | ||
| + 	/* Switch around addresses of the form index * scaling + base.  */
 | ||
| + 	if (! ubicom32_is_base_reg (base, 1))
 | ||
| + 	  {
 | ||
| + 	    rtx tmp = base;
 | ||
| + 	    base = index;
 | ||
| + 	    index = tmp;
 | ||
| + 	  }
 | ||
| +
 | ||
| +	if (CONST_INT_P (index)) 
 | ||
| +	  {
 | ||
| +	    fprintf (file, "%ld", INTVAL (index)); 
 | ||
| +	    fputc ('(', file);
 | ||
| +	    fputs (reg_names[REGNO (base)], file); 
 | ||
| +	  }
 | ||
| + 	else if (GET_CODE (index) == MULT
 | ||
| + 	         || REG_P (index))
 | ||
| +	  {
 | ||
| + 	    if (GET_CODE (index) == MULT)
 | ||
| + 	      index = XEXP (index, 0);
 | ||
| +	    fputc ('(', file);
 | ||
| +	    fputs (reg_names[REGNO (base)], file); 
 | ||
| +	    fputc (',', file);
 | ||
| +	    fputs (reg_names[REGNO (index)], file); 
 | ||
| +	  }
 | ||
| +	else 
 | ||
| +	  abort (); 
 | ||
| +
 | ||
| +	fputc (')', file);
 | ||
| +	break;
 | ||
| +      }
 | ||
| +
 | ||
| +    case LO_SUM:
 | ||
| +      fprintf (file, "%%lo(");
 | ||
| +      ubicom32_print_operand (file, XEXP (addr, 1), 'L');
 | ||
| +      fprintf (file, ")(");
 | ||
| +      ubicom32_print_operand (file, XEXP (addr, 0), 0);
 | ||
| +      fprintf (file, ")");
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CONST_INT:
 | ||
| +      fputc ('#', file);
 | ||
| +      output_addr_const (file, addr); 
 | ||
| +      break;
 | ||
| +
 | ||
| +    default:
 | ||
| +      output_addr_const (file, addr);
 | ||
| +      break;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* X and Y are two things to compare using CODE.  Emit the compare insn and
 | ||
| +   return the rtx for the cc reg in the proper mode.  */
 | ||
| +
 | ||
| +rtx
 | ||
| +ubicom32_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 | ||
| +{
 | ||
| +  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
 | ||
| +  rtx cc_reg;
 | ||
| +
 | ||
| +  cc_reg = gen_rtx_REG (mode, CC_REGNUM);
 | ||
| +
 | ||
| +  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
 | ||
| +			  gen_rtx_COMPARE (mode, x, y)));
 | ||
| +
 | ||
| +  return cc_reg;
 | ||
| +}
 | ||
| +
 | ||
| +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
 | ||
| +   return the mode to be used for the comparison.  */
 | ||
| +
 | ||
| +enum machine_mode
 | ||
| +ubicom32_select_cc_mode (enum rtx_code op, rtx x, rtx y)
 | ||
| +{
 | ||
| +  /* Is this a short compare?  */
 | ||
| +  if (GET_MODE (x) == QImode
 | ||
| +      || GET_MODE (x) == HImode
 | ||
| +      || GET_MODE (y) == QImode
 | ||
| +      || GET_MODE (y) == HImode)
 | ||
| +    {
 | ||
| +      switch (op)
 | ||
| +	{
 | ||
| +	case EQ :
 | ||
| +	case NE :
 | ||
| +	  return CCSZmode;
 | ||
| +
 | ||
| +	case GE:
 | ||
| +	case LT:
 | ||
| +	  if (y == const0_rtx)
 | ||
| +	    return CCSZNmode;
 | ||
| +
 | ||
| +	default :
 | ||
| +	  return CCSmode;
 | ||
| +	}
 | ||
| +    }
 | ||
| +
 | ||
| +  /* We have a word compare.  */
 | ||
| +  switch (op)
 | ||
| +    {
 | ||
| +    case EQ :
 | ||
| +    case NE :
 | ||
| +      return CCWZmode;
 | ||
| +
 | ||
| +    case GE :
 | ||
| +    case LT :
 | ||
| +      if (y == const0_rtx)
 | ||
| +	return CCWZNmode;
 | ||
| +
 | ||
| +    default :
 | ||
| +      return CCWmode;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Return TRUE or FALSE depending on whether the first SET in INSN
 | ||
| +   has source and destination with matching CC modes, and that the
 | ||
| +   CC mode is at least as constrained as REQ_MODE.  */
 | ||
| +bool
 | ||
| +ubicom32_match_cc_mode (rtx insn, enum machine_mode req_mode)
 | ||
| +{
 | ||
| +  rtx set;
 | ||
| +  enum machine_mode set_mode;
 | ||
| +
 | ||
| +  set = PATTERN (insn);
 | ||
| +  if (GET_CODE (set) == PARALLEL)
 | ||
| +    set = XVECEXP (set, 0, 0);
 | ||
| +  gcc_assert (GET_CODE (set) == SET);
 | ||
| +  gcc_assert (GET_CODE (SET_SRC (set)) == COMPARE);
 | ||
| +
 | ||
| +  /* SET_MODE is the mode we have in the instruction.  This must either
 | ||
| +     be the same or less restrictive that the required mode REQ_MODE.  */
 | ||
| +  set_mode = GET_MODE (SET_DEST (set));
 | ||
| +
 | ||
| +  switch (req_mode)
 | ||
| +    {
 | ||
| +    case CCSZmode:
 | ||
| +      if (set_mode != CCSZmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CCSZNmode:
 | ||
| +      if (set_mode != CCSZmode
 | ||
| +	  && set_mode != CCSZNmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CCSmode:
 | ||
| +      if (set_mode != CCSmode
 | ||
| +	  && set_mode != CCSZmode
 | ||
| +	  && set_mode != CCSZNmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CCWZmode:
 | ||
| +      if (set_mode != CCWZmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CCWZNmode:
 | ||
| +      if (set_mode != CCWZmode
 | ||
| +	  && set_mode != CCWZNmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    case CCWmode:
 | ||
| +      if (set_mode != CCWmode
 | ||
| +	  && set_mode != CCWZmode
 | ||
| +	  && set_mode != CCWZNmode)
 | ||
| +	return 0;
 | ||
| +      break;
 | ||
| +
 | ||
| +    default:
 | ||
| +      gcc_unreachable ();
 | ||
| +    }
 | ||
| +
 | ||
| +  return (GET_MODE (SET_SRC (set)) == set_mode);
 | ||
| +}
 | ||
| +
 | ||
| +/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
 | ||
| +   that we can implement more efficiently.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
 | ||
| +{
 | ||
| +  /* If we have a REG and a MEM then compare the MEM with the REG and not
 | ||
| +     the other way round.  */
 | ||
| +  if (REG_P (*op0) && MEM_P (*op1))
 | ||
| +    {
 | ||
| +      rtx tem = *op0;
 | ||
| +      *op0 = *op1;
 | ||
| +      *op1 = tem;
 | ||
| +      *code = swap_condition (*code);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* If we have a REG and a CONST_INT then we may want to reverse things
 | ||
| +     if the constant can be represented as an "I" constraint.  */
 | ||
| +  if (REG_P (*op0) && CONST_INT_P (*op1) && satisfies_constraint_I (*op1))
 | ||
| +    {
 | ||
| +      rtx tem = *op0;
 | ||
| +      *op0 = *op1;
 | ||
| +      *op1 = tem;
 | ||
| +      *code = swap_condition (*code);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Return the fixed registers used for condition codes.  */
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
 | ||
| +{
 | ||
| +  *p1 = CC_REGNUM;
 | ||
| +  *p2 = INVALID_REGNUM;
 | ||
| + 
 | ||
| +  return true;
 | ||
| +}
 | ||
| +
 | ||
| +/* If two condition code modes are compatible, return a condition code
 | ||
| +   mode which is compatible with both.  Otherwise, return
 | ||
| +   VOIDmode.  */
 | ||
| +
 | ||
| +static enum machine_mode
 | ||
| +ubicom32_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
 | ||
| +{
 | ||
| +  if (m1 == m2)
 | ||
| +    return m1;
 | ||
| +
 | ||
| +  if (GET_MODE_CLASS (m1) != MODE_CC || GET_MODE_CLASS (m2) != MODE_CC)
 | ||
| +    return VOIDmode;
 | ||
| +
 | ||
| +  switch (m1)
 | ||
| +    {
 | ||
| +    case CCWmode:
 | ||
| +      if (m2 == CCWZNmode || m2 == CCWZmode)
 | ||
| +	return m1;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    case CCWZNmode:
 | ||
| +      if (m2 == CCWmode)
 | ||
| +	return m2;
 | ||
| +
 | ||
| +      if (m2 == CCWZmode)
 | ||
| +	return m1;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    case CCWZmode:
 | ||
| +      if (m2 == CCWmode || m2 == CCWZNmode)
 | ||
| +	return m2;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    case CCSmode:
 | ||
| +      if (m2 == CCSZNmode || m2 == CCSZmode)
 | ||
| +	return m1;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    case CCSZNmode:
 | ||
| +      if (m2 == CCSmode)
 | ||
| +	return m2;
 | ||
| +
 | ||
| +      if (m2 == CCSZmode)
 | ||
| +	return m1;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    case CCSZmode:
 | ||
| +      if (m2 == CCSmode || m2 == CCSZNmode)
 | ||
| +	return m2;
 | ||
| +
 | ||
| +      return VOIDmode;
 | ||
| +
 | ||
| +    default:
 | ||
| +      gcc_unreachable ();
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +static rtx
 | ||
| +ubicom32_legitimize_fdpic_address_symbol (rtx orig, rtx reg, rtx fdpic_reg)
 | ||
| +{
 | ||
| +  int unspec;
 | ||
| +  rtx got_offs;
 | ||
| +  rtx got_offs_scaled;
 | ||
| +  rtx plus_scaled;
 | ||
| +  rtx tmp;
 | ||
| +  rtx new_rtx;
 | ||
| +
 | ||
| +  gcc_assert (reg != 0);
 | ||
| +
 | ||
| +  if (GET_CODE (orig) == SYMBOL_REF
 | ||
| +      && SYMBOL_REF_FUNCTION_P (orig))
 | ||
| +    unspec = UNSPEC_FDPIC_GOT_FUNCDESC;
 | ||
| +  else
 | ||
| +    unspec = UNSPEC_FDPIC_GOT;
 | ||
| +
 | ||
| +  got_offs = gen_reg_rtx (SImode);
 | ||
| +  tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig), unspec);
 | ||
| +  emit_move_insn (got_offs, tmp);
 | ||
| +
 | ||
| +  got_offs_scaled = gen_rtx_MULT (SImode, got_offs, GEN_INT (4));
 | ||
| +  plus_scaled = gen_rtx_PLUS (Pmode, fdpic_reg, got_offs_scaled);
 | ||
| +  new_rtx = gen_const_mem (Pmode, plus_scaled);
 | ||
| +  emit_move_insn (reg, new_rtx);
 | ||
| +
 | ||
| +  return reg;
 | ||
| +}
 | ||
| +
 | ||
| +static rtx
 | ||
| +ubicom32_legitimize_fdpic_address (rtx orig, rtx reg, rtx fdpic_reg)
 | ||
| +{
 | ||
| +  rtx addr = orig;
 | ||
| +  rtx new_rtx = orig;
 | ||
| +
 | ||
| +  if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
 | ||
| +    {
 | ||
| +      rtx base;
 | ||
| +
 | ||
| +      if (GET_CODE (addr) == CONST)
 | ||
| +	{
 | ||
| +	  addr = XEXP (addr, 0);
 | ||
| +	  gcc_assert (GET_CODE (addr) == PLUS);
 | ||
| +	}
 | ||
| +
 | ||
| +      base = ubicom32_legitimize_fdpic_address_symbol (XEXP (addr, 0), reg, fdpic_reg);
 | ||
| +      return gen_rtx_PLUS (Pmode, base, XEXP (addr, 1));
 | ||
| +    }
 | ||
| +
 | ||
| +  return new_rtx;
 | ||
| +}
 | ||
| +
 | ||
| +/* Code generation.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_movsi (rtx *operands)
 | ||
| +{
 | ||
| +  if (GET_CODE (operands[1]) == SYMBOL_REF
 | ||
| +      || (GET_CODE (operands[1]) == CONST
 | ||
| +	  && GET_CODE (XEXP (operands[1], 0)) == PLUS
 | ||
| +	  && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
 | ||
| +      || CONSTANT_ADDRESS_P (operands[1]))
 | ||
| +    {
 | ||
| +      if (TARGET_FDPIC)
 | ||
| +	{
 | ||
| +	  rtx tmp;
 | ||
| +	  rtx fdpic_reg;
 | ||
| +
 | ||
| +	  gcc_assert (can_create_pseudo_p ());
 | ||
| +	  tmp = gen_reg_rtx (Pmode);
 | ||
| +	  fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
 | ||
| +	  if (GET_CODE (operands[1]) == SYMBOL_REF
 | ||
| +	      || GET_CODE (operands[1]) == LABEL_REF)
 | ||
| +	    operands[1] = ubicom32_legitimize_fdpic_address_symbol (operands[1], tmp, fdpic_reg);
 | ||
| +	  else
 | ||
| +	    operands[1] = ubicom32_legitimize_fdpic_address (operands[1], tmp, fdpic_reg);
 | ||
| +	}
 | ||
| +      else
 | ||
| +	{
 | ||
| +	  rtx tmp;
 | ||
| +	  enum machine_mode mode;
 | ||
| +
 | ||
| +	  /* We want to avoid reusing operand 0 if we can because it limits
 | ||
| +	     our ability to optimize later.  */
 | ||
| +	  tmp = ! can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
 | ||
| +
 | ||
| +	  mode = GET_MODE (operands[0]);
 | ||
| +	  emit_insn (gen_rtx_SET (VOIDmode, tmp,
 | ||
| +				  gen_rtx_HIGH (mode, operands[1])));
 | ||
| +	  operands[1] = gen_rtx_LO_SUM (mode, tmp, operands[1]);
 | ||
| +	  if (can_create_pseudo_p() && ! REG_P (operands[0]))
 | ||
| +	    {
 | ||
| +	      tmp = gen_reg_rtx (mode);
 | ||
| +	      emit_insn (gen_rtx_SET (VOIDmode, tmp, operands[1]));
 | ||
| +	      operands[1] = tmp;
 | ||
| +	    }
 | ||
| +	}
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Emit code for addsi3.  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_addsi3 (rtx *operands)
 | ||
| +{
 | ||
| +  rtx op, clob;
 | ||
| +
 | ||
| +  if (can_create_pseudo_p ())
 | ||
| +    {
 | ||
| +      /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +         a CONST_INT in operand 2.  */
 | ||
| +      if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	  && CONST_INT_P (operands[2]))
 | ||
| +	operands[2] = copy_to_mode_reg (SImode, operands[2]);
 | ||
| +
 | ||
| +      if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +	operands[2] = copy_to_mode_reg (SImode, operands[2]);
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Emit the instruction.  */
 | ||
| +
 | ||
| +  op = gen_rtx_SET (VOIDmode, operands[0],
 | ||
| +		    gen_rtx_PLUS (SImode, operands[1], operands[2]));
 | ||
| +
 | ||
| +  if (! can_create_pseudo_p ())
 | ||
| +    {
 | ||
| +      /* Reload doesn't know about the flags register, and doesn't know that
 | ||
| +         it doesn't want to clobber it.  We can only do this with PLUS.  */
 | ||
| +      emit_insn (op);
 | ||
| +    }
 | ||
| +  else
 | ||
| +    {
 | ||
| +      clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
 | ||
| +      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Emit code for mulsi3.  Return 1 if we have generated all the code
 | ||
| +   necessary to do the multiplication.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_emit_mult_sequence (rtx *operands)
 | ||
| +{
 | ||
| +  if (! ubicom32_v4)
 | ||
| +    {
 | ||
| +      rtx a1, a1_1, a2;
 | ||
| +      rtx b1, b1_1, b2;
 | ||
| +      rtx mac_lo_rtx;
 | ||
| +      rtx t1, t2, t3;
 | ||
| +
 | ||
| +      /* Give up if we cannot create new pseudos.  */
 | ||
| +      if (!can_create_pseudo_p())
 | ||
| +	return 0;
 | ||
| +
 | ||
| +      /* Synthesize 32-bit multiplication using 16-bit operations:
 | ||
| +     
 | ||
| +	 a1 = highpart (a)
 | ||
| +	 a2 = lowpart (a)
 | ||
| +
 | ||
| +	 b1 = highpart (b)
 | ||
| +	 b2 = lowpart (b)
 | ||
| +
 | ||
| +	 c = (a1 * b1) << 32 + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
 | ||
| +	   =        0        + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
 | ||
| +	                       ^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^   ^^^^^^^
 | ||
| +			           Signed             Signed      Unsigned  */
 | ||
| +
 | ||
| +      if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
 | ||
| +	{
 | ||
| +	  rtx op1;
 | ||
| +
 | ||
| +	  op1 = gen_reg_rtx (SImode);
 | ||
| +	  emit_move_insn (op1, operands[1]);
 | ||
| +	  operands[1] = op1;
 | ||
| +	}
 | ||
| +
 | ||
| +      if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
 | ||
| +	{
 | ||
| +	  rtx op2;
 | ||
| +
 | ||
| +	  op2 = gen_reg_rtx (SImode);
 | ||
| +	  emit_move_insn (op2, operands[2]);
 | ||
| +	  operands[2] = op2;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* a1 = highpart (a)  */
 | ||
| +      a1 = gen_reg_rtx (HImode);
 | ||
| +      a1_1 = gen_reg_rtx (SImode);
 | ||
| +      emit_insn (gen_ashrsi3 (a1_1, operands[1], GEN_INT (16)));
 | ||
| +      emit_move_insn (a1, gen_lowpart (HImode, a1_1));
 | ||
| +
 | ||
| +      /* a2 = lowpart (a)  */
 | ||
| +      a2 = gen_reg_rtx (HImode);
 | ||
| +      emit_move_insn (a2, gen_lowpart (HImode, operands[1]));
 | ||
| +
 | ||
| +      /* b1 = highpart (b)  */
 | ||
| +      b1 = gen_reg_rtx (HImode);
 | ||
| +      b1_1 = gen_reg_rtx (SImode);
 | ||
| +      emit_insn (gen_ashrsi3 (b1_1, operands[2], GEN_INT (16)));
 | ||
| +      emit_move_insn (b1, gen_lowpart (HImode, b1_1));
 | ||
| +
 | ||
| +      /* b2 = lowpart (b)  */
 | ||
| +      b2 = gen_reg_rtx (HImode);
 | ||
| +      emit_move_insn (b2, gen_lowpart (HImode, operands[2]));
 | ||
| +
 | ||
| +      /* t1 = (a1 * b2) << 16  */
 | ||
| +      t1 = gen_reg_rtx (SImode);
 | ||
| +      mac_lo_rtx = gen_rtx_REG (SImode, ACC0_LO_REGNUM);
 | ||
| +      emit_insn (gen_mulhisi3 (mac_lo_rtx, a1, b2));
 | ||
| +      emit_insn (gen_ashlsi3 (t1, mac_lo_rtx, GEN_INT (16)));
 | ||
| +
 | ||
| +      /* t2 = (a2 * b1) << 16  */
 | ||
| +      t2 = gen_reg_rtx (SImode);
 | ||
| +      emit_insn (gen_mulhisi3 (mac_lo_rtx, a2, b1));
 | ||
| +      emit_insn (gen_ashlsi3 (t2, mac_lo_rtx, GEN_INT (16)));
 | ||
| +
 | ||
| +      /* mac_lo = a2 * b2  */
 | ||
| +      emit_insn (gen_umulhisi3 (mac_lo_rtx, a2, b2));
 | ||
| +
 | ||
| +      /* t3 = t1 + t2  */
 | ||
| +      t3 = gen_reg_rtx (SImode);
 | ||
| +      emit_insn (gen_addsi3 (t3, t1, t2));
 | ||
| +
 | ||
| +      /* c = t3 + mac_lo_rtx  */
 | ||
| +      emit_insn (gen_addsi3 (operands[0], mac_lo_rtx, t3));
 | ||
| +
 | ||
| +      return 1;
 | ||
| +    }
 | ||
| +  else
 | ||
| +    {
 | ||
| +      rtx acc_rtx;
 | ||
| +
 | ||
| +      /* Give up if we cannot create new pseudos.  */
 | ||
| +      if (!can_create_pseudo_p())
 | ||
| +	return 0;
 | ||
| +
 | ||
| +      if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
 | ||
| +        {
 | ||
| +	  rtx op1;
 | ||
| +
 | ||
| +	  op1 = gen_reg_rtx (SImode);
 | ||
| +	  emit_move_insn (op1, operands[1]);
 | ||
| +	  operands[1] = op1;
 | ||
| +	}
 | ||
| +
 | ||
| +      if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
 | ||
| +	{
 | ||
| +	  rtx op2;
 | ||
| +
 | ||
| +	  op2 = gen_reg_rtx (SImode);
 | ||
| +	  emit_move_insn (op2, operands[2]);
 | ||
| +	  operands[2] = op2;
 | ||
| +	}
 | ||
| +
 | ||
| +      acc_rtx = gen_reg_rtx (DImode);
 | ||
| +      emit_insn (gen_umulsidi3 (acc_rtx, operands[1], operands[2]));
 | ||
| +      emit_move_insn (operands[0], gen_lowpart (SImode, acc_rtx));
 | ||
| +
 | ||
| +      return 1;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Move the integer value VAL into OPERANDS[0].  */
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_emit_move_const_int (rtx dest, rtx imm)
 | ||
| +{
 | ||
| +  rtx xoperands[2];
 | ||
| +  
 | ||
| +  xoperands[0] = dest;
 | ||
| +  xoperands[1] = imm;
 | ||
| +
 | ||
| +  /* Treat mem destinations separately.  Values must be explicitly sign
 | ||
| +     extended.  */
 | ||
| +  if (MEM_P (dest))
 | ||
| +    {
 | ||
| +      rtx low_hword_mem;
 | ||
| +      rtx low_hword_addr;
 | ||
| +
 | ||
| +      /* Emit shorter sequence for signed 7-bit quantities.  */
 | ||
| +      if (satisfies_constraint_I (imm))
 | ||
| +	{
 | ||
| +          output_asm_insn ("move.4\t%0, %1", xoperands);
 | ||
| +          return;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Special case for pushing constants.  */
 | ||
| +      if (GET_CODE (XEXP (dest, 0)) == PRE_DEC
 | ||
| +	  && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
 | ||
| +	{
 | ||
| +	  output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
 | ||
| +	  output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
 | ||
| +	  return;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* See if we can add 2 to the original address.  This is only
 | ||
| +	 possible if the original address is of the form REG or
 | ||
| +	 REG+const.  */
 | ||
| +      low_hword_addr = plus_constant (XEXP (dest, 0), 2);
 | ||
| +      if (ubicom32_legitimate_address_p (HImode, low_hword_addr, 1))
 | ||
| +	{
 | ||
| +	  low_hword_mem = gen_rtx_MEM (HImode, low_hword_addr);
 | ||
| +	  MEM_COPY_ATTRIBUTES (low_hword_mem, dest);
 | ||
| +	  output_asm_insn ("movei\t%0, #%%hi(%E1)", xoperands);
 | ||
| +	  xoperands[0] = low_hword_mem;
 | ||
| +	  output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
 | ||
| +	  return;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* The original address is too complex.  We need to use a
 | ||
| +	 scratch memory by (sp) and move that to the original
 | ||
| +	 destination.  */
 | ||
| +      if (! reg_mentioned_p (stack_pointer_rtx, dest))
 | ||
| +	{
 | ||
| +	  output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
 | ||
| +	  output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
 | ||
| +	  output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
 | ||
| +	  return;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Our address mentions the stack pointer so we need to
 | ||
| +	 use our scratch data register here as well as scratch
 | ||
| +	 memory.  */
 | ||
| +      output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
 | ||
| +      output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
 | ||
| +      output_asm_insn ("move.4\td15, (sp)4++", xoperands);
 | ||
| +      output_asm_insn ("move.4\t%0, d15", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Move into registers are zero extended by default.  */
 | ||
| +  if (! REG_P (dest))
 | ||
| +    abort ();
 | ||
| +
 | ||
| +  if (satisfies_constraint_N (imm))
 | ||
| +    {
 | ||
| +      output_asm_insn ("movei\t%0, %1", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (INTVAL (xoperands[1]) >= 0xff80
 | ||
| +      && INTVAL (xoperands[1]) < 0x10000)
 | ||
| +    {
 | ||
| +      xoperands[1] = GEN_INT (INTVAL (xoperands[1]) - 0x10000);
 | ||
| +      output_asm_insn ("move.2\t%0, %1", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((REGNO_REG_CLASS (REGNO (xoperands[0])) == ADDRESS_REGS
 | ||
| +       || REGNO_REG_CLASS (REGNO (xoperands[0])) == FDPIC_REG)
 | ||
| +      && ((INTVAL (xoperands[1]) & 0x80000000) == 0))
 | ||
| +    {
 | ||
| +      output_asm_insn ("moveai\t%0, #%%hi(%E1)", xoperands);
 | ||
| +      if ((INTVAL (xoperands[1]) & 0x7f) != 0)
 | ||
| +	output_asm_insn ("lea.1\t%0, %%lo(%E1)(%0)", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((INTVAL (xoperands[1]) & 0xffff0000) == 0)
 | ||
| +    {
 | ||
| +      output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
 | ||
| +      output_asm_insn ("move.2\t%0, %0", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* This is very expensive.  The constant is so large that we
 | ||
| +     need to use the stack to do the load.  */
 | ||
| +  output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
 | ||
| +  output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
 | ||
| +  output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
 | ||
| +}
 | ||
| +
 | ||
| +/* Stack layout. Prologue/Epilogue.  */
 | ||
| +
 | ||
| +static int save_regs_size;
 | ||
| +
 | ||
| +static void 
 | ||
| +ubicom32_layout_frame (void)
 | ||
| +{
 | ||
| +  int regno;
 | ||
| +  
 | ||
| +  memset ((char *) &save_regs[0], 0, sizeof (save_regs));
 | ||
| +  nregs = 0;
 | ||
| +  frame_size = get_frame_size ();
 | ||
| +
 | ||
| +  if (frame_pointer_needed || df_regs_ever_live_p (FRAME_POINTER_REGNUM))
 | ||
| +    {
 | ||
| +      save_regs[FRAME_POINTER_REGNUM] = 1;
 | ||
| +      ++nregs;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (current_function_is_leaf && ! df_regs_ever_live_p (LINK_REGNO))
 | ||
| +    ubicom32_can_use_calli_to_ret = 1;
 | ||
| +  else
 | ||
| +    {
 | ||
| +      ubicom32_can_use_calli_to_ret = 0;
 | ||
| +      save_regs[LINK_REGNO] = 1;
 | ||
| +      ++nregs;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Figure out which register(s) needs to be saved.  */
 | ||
| +  for (regno = 0; regno <= LAST_ADDRESS_REGNUM; regno++)
 | ||
| +	if (df_regs_ever_live_p(regno)
 | ||
| +	&& ! call_used_regs[regno]
 | ||
| +	&& ! fixed_regs[regno]
 | ||
| +	&& ! save_regs[regno])
 | ||
| +    {
 | ||
| +      save_regs[regno] = 1;
 | ||
| +      ++nregs;
 | ||
| +    }
 | ||
| +
 | ||
| +  save_regs_size = 4 * nregs;
 | ||
| +}
 | ||
| +
 | ||
| +static void
 | ||
| +ubicom32_emit_add_movsi (int regno, int adj)
 | ||
| +{
 | ||
| +  rtx x;
 | ||
| +  rtx reg = gen_rtx_REG (SImode, regno);
 | ||
| +
 | ||
| +  adj += 4;
 | ||
| +  if (adj > 8 * 4) 
 | ||
| +    {
 | ||
| +      x = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +				 GEN_INT (-adj)));
 | ||
| +      RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +      x = emit_move_insn (gen_rtx_MEM (SImode, stack_pointer_rtx), reg);
 | ||
| +    }
 | ||
| +  else
 | ||
| +    {
 | ||
| +      rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
 | ||
| +				     gen_rtx_PLUS (Pmode, stack_pointer_rtx,
 | ||
| +						   GEN_INT (-adj)));
 | ||
| +      x = emit_move_insn (gen_rtx_MEM (SImode, addr), reg);
 | ||
| +    }
 | ||
| +  RTX_FRAME_RELATED_P (x) = 1;      
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_prologue (void)
 | ||
| +{
 | ||
| +  rtx x;
 | ||
| +  int regno;
 | ||
| +  int outgoing_args_size = crtl->outgoing_args_size;
 | ||
| +  int adj;
 | ||
| +
 | ||
| +  if (ubicom32_naked_function_p ())
 | ||
| +    return;
 | ||
| +
 | ||
| +  ubicom32_builtin_saveregs ();
 | ||
| +  
 | ||
| +  ubicom32_layout_frame ();
 | ||
| +  adj = (outgoing_args_size + get_frame_size () + save_regs_size
 | ||
| +	 + crtl->args.pretend_args_size);
 | ||
| +  
 | ||
| +  if (!adj)
 | ||
| +    ;
 | ||
| +  else if (outgoing_args_size + save_regs_size < 508
 | ||
| +	   && get_frame_size () + save_regs_size > 508)
 | ||
| +    {
 | ||
| +      int i = 0;
 | ||
| +      x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +		      GEN_INT (-adj));
 | ||
| +      x = emit_insn (x);
 | ||
| +      RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +
 | ||
| +      for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
 | ||
| +	if (save_regs[regno] && regno != LINK_REGNO)
 | ||
| +	  {
 | ||
| +	    x = gen_rtx_MEM (SImode,
 | ||
| +			     gen_rtx_PLUS (Pmode,
 | ||
| +					   stack_pointer_rtx,
 | ||
| +					   GEN_INT (i * 4 + outgoing_args_size)));
 | ||
| +	    x = emit_move_insn (x, gen_rtx_REG (SImode, regno));
 | ||
| +	    RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +	    ++i;
 | ||
| +	  }
 | ||
| +      if (save_regs[LINK_REGNO])
 | ||
| +	{
 | ||
| +	  x = gen_rtx_MEM (SImode,
 | ||
| +			   gen_rtx_PLUS (Pmode,
 | ||
| +					 stack_pointer_rtx,
 | ||
| +					 GEN_INT (i * 4 + outgoing_args_size)));
 | ||
| +	  x = emit_move_insn (x, gen_rtx_REG (SImode, LINK_REGNO));
 | ||
| +	  RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +	}
 | ||
| +    }
 | ||
| +  else
 | ||
| +    {
 | ||
| +      int regno;
 | ||
| +      int adj = get_frame_size () + crtl->args.pretend_args_size;
 | ||
| +      int i = 0;
 | ||
| +
 | ||
| +      if (save_regs[LINK_REGNO])
 | ||
| +	{
 | ||
| +	  ubicom32_emit_add_movsi (LINK_REGNO, adj);
 | ||
| +	  ++i;
 | ||
| +	}
 | ||
| +      
 | ||
| +      for (regno = 0; regno <= LAST_ADDRESS_REGNUM; ++regno)
 | ||
| +	if (save_regs[regno] && regno != LINK_REGNO)
 | ||
| +	  {
 | ||
| +	    if (i)
 | ||
| +	      {
 | ||
| +		rtx mem = gen_rtx_MEM (SImode,
 | ||
| +				       gen_rtx_PRE_DEC (Pmode,
 | ||
| +							stack_pointer_rtx));
 | ||
| +		x = emit_move_insn (mem, gen_rtx_REG (SImode, regno));
 | ||
| +		RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +	      }
 | ||
| +	    else
 | ||
| +	      ubicom32_emit_add_movsi (regno, adj);
 | ||
| +	    ++i;
 | ||
| +	  }
 | ||
| +      
 | ||
| +      if (outgoing_args_size || (!i && adj))
 | ||
| +	{
 | ||
| +	  x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +			  GEN_INT (-outgoing_args_size - (i ? 0 : adj)));
 | ||
| +	  x = emit_insn (x);
 | ||
| +	  RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +	}
 | ||
| +    }
 | ||
| +
 | ||
| +  if (frame_pointer_needed)
 | ||
| +    {
 | ||
| +      int fp_adj = save_regs_size + outgoing_args_size;
 | ||
| +      x = gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
 | ||
| +		      GEN_INT (fp_adj));
 | ||
| +      x = emit_insn (x);
 | ||
| +      RTX_FRAME_RELATED_P (x) = 1;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_epilogue (void)
 | ||
| +{
 | ||
| +  rtx x;
 | ||
| +  int regno;
 | ||
| +  int outgoing_args_size = crtl->outgoing_args_size;
 | ||
| +  int adj;
 | ||
| +  int i;
 | ||
| +
 | ||
| +  if (ubicom32_naked_function_p ())
 | ||
| +    {
 | ||
| +      emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
 | ||
| +						        LINK_REGNO)));
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (cfun->calls_alloca)
 | ||
| +    {
 | ||
| +      x = gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
 | ||
| +		      GEN_INT (-save_regs_size));
 | ||
| +      emit_insn (x);
 | ||
| +      outgoing_args_size = 0;
 | ||
| +    }
 | ||
| +  
 | ||
| +  if (outgoing_args_size)
 | ||
| +    {
 | ||
| +      x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +		      GEN_INT (outgoing_args_size));
 | ||
| +      emit_insn (x);
 | ||
| +    }
 | ||
| +
 | ||
| +  i = 0;
 | ||
| +  for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
 | ||
| +    if (save_regs[regno] && regno != LINK_REGNO)
 | ||
| +      {
 | ||
| +	x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
 | ||
| +	emit_move_insn (gen_rtx_REG (SImode, regno), x);
 | ||
| +	++i;
 | ||
| +      }
 | ||
| +
 | ||
| +  /* Do we have to adjust the stack after we've finished restoring regs?  */
 | ||
| +  adj = get_frame_size() + crtl->args.pretend_args_size;
 | ||
| +  if (cfun->stdarg)
 | ||
| +    adj += UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
 | ||
| + 
 | ||
| +#if 0
 | ||
| +  if (crtl->calls_eh_return && 0)
 | ||
| +    {
 | ||
| +      if (save_regs[LINK_REGNO])
 | ||
| +        {
 | ||
| +          x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
 | ||
| +          emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
 | ||
| +        }
 | ||
| +
 | ||
| +      if (adj)
 | ||
| +        {
 | ||
| +          x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +			  GEN_INT (adj));
 | ||
| +          x = emit_insn (x);
 | ||
| +        }
 | ||
| +
 | ||
| +      /* Perform the additional bump for __throw.  */
 | ||
| +      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +			     EH_RETURN_STACKADJ_RTX));
 | ||
| +      emit_jump_insn (gen_eh_return_internal ());
 | ||
| +      return;
 | ||
| +    }
 | ||
| +#endif
 | ||
| +
 | ||
| +  if (save_regs[LINK_REGNO])
 | ||
| +    {
 | ||
| +      if (adj >= 4 && adj <= (6 * 4))
 | ||
| +        {
 | ||
| +	  x = GEN_INT (adj + 4);
 | ||
| +          emit_jump_insn (gen_return_from_post_modify_sp (x));
 | ||
| +	  return;
 | ||
| +        }
 | ||
| +
 | ||
| +      if (adj == 0)
 | ||
| +	{
 | ||
| +          x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
 | ||
| +          emit_jump_insn (gen_return_internal (x));
 | ||
| +          return;
 | ||
| +	}
 | ||
| +
 | ||
| +      x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
 | ||
| +      emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
 | ||
| +    }
 | ||
| +
 | ||
| +  if (adj)
 | ||
| +    {
 | ||
| +      x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 | ||
| +		      GEN_INT (adj));
 | ||
| +      x = emit_insn (x);
 | ||
| +      adj = 0;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Given that we've just done all the hard work here we may as well use
 | ||
| +     a calli to return.  */
 | ||
| +  ubicom32_can_use_calli_to_ret = 1;
 | ||
| +  emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode, LINK_REGNO)));
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_call_fdpic (rtx *operands)
 | ||
| +{
 | ||
| +  rtx c;
 | ||
| +  rtx addr;
 | ||
| +  rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
 | ||
| +
 | ||
| +  addr = XEXP (operands[0], 0);
 | ||
| +
 | ||
| +  c = gen_call_fdpic (addr, operands[1], fdpic_reg);
 | ||
| +  emit_call_insn (c);
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_call_value_fdpic (rtx *operands)
 | ||
| +{
 | ||
| +  rtx c;
 | ||
| +  rtx addr;
 | ||
| +  rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
 | ||
| +
 | ||
| +  addr = XEXP (operands[1], 0);
 | ||
| +
 | ||
| +  c = gen_call_value_fdpic (operands[0], addr, operands[2], fdpic_reg);
 | ||
| +  emit_call_insn (c);
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_expand_eh_return (rtx *operands)
 | ||
| +{
 | ||
| +  if (REG_P (operands[0])
 | ||
| +      || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
 | ||
| +    {
 | ||
| +      rtx sp = EH_RETURN_STACKADJ_RTX;
 | ||
| +      emit_move_insn (sp, operands[0]);
 | ||
| +      operands[0] = sp;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (REG_P (operands[1])
 | ||
| +      || REGNO (operands[1]) != EH_RETURN_HANDLER_REGNO)
 | ||
| +    {
 | ||
| +      rtx ra = EH_RETURN_HANDLER_RTX;
 | ||
| +      emit_move_insn (ra, operands[1]);
 | ||
| +      operands[1] = ra;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Compute the offsets between eliminable registers.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_initial_elimination_offset (int from, int to)
 | ||
| +{
 | ||
| +  ubicom32_layout_frame ();
 | ||
| +  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
 | ||
| +    return save_regs_size + crtl->outgoing_args_size;
 | ||
| +
 | ||
| +  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
 | ||
| +    return get_frame_size ()/* + save_regs_size */;
 | ||
| +
 | ||
| +  if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
 | ||
| +    return get_frame_size ()
 | ||
| +	   + crtl->outgoing_args_size
 | ||
| +	   + save_regs_size;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| +/* Return 1 if it is appropriate to emit `ret' instructions in the
 | ||
| +   body of a function.  Do this only if the epilogue is simple, needing a
 | ||
| +   couple of insns.  Prior to reloading, we can't tell how many registers
 | ||
| +   must be saved, so return 0 then.  Return 0 if there is no frame
 | ||
| +   marker to de-allocate.
 | ||
| +
 | ||
| +   If NON_SAVING_SETJMP is defined and true, then it is not possible
 | ||
| +   for the epilogue to be simple, so return 0.  This is a special case
 | ||
| +   since NON_SAVING_SETJMP will not cause regs_ever_live to change
 | ||
| +   until final, but jump_optimize may need to know sooner if a
 | ||
| +   `return' is OK.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_can_use_return_insn_p (void)
 | ||
| +{
 | ||
| +  if (! reload_completed || frame_pointer_needed)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  return 1;
 | ||
| +}
 | ||
| +
 | ||
| +/* Attributes and CC handling.  */
 | ||
| +
 | ||
| +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
 | ||
| +   struct attribute_spec.handler.  */
 | ||
| +static tree
 | ||
| +ubicom32_handle_fndecl_attribute (tree *node, tree name,
 | ||
| +			      tree args ATTRIBUTE_UNUSED,
 | ||
| +			      int flags ATTRIBUTE_UNUSED,
 | ||
| +			      bool *no_add_attrs)
 | ||
| +{
 | ||
| +  if (TREE_CODE (*node) != FUNCTION_DECL)
 | ||
| +    {
 | ||
| +      warning ("'%s' attribute only applies to functions",
 | ||
| +	       IDENTIFIER_POINTER (name));
 | ||
| +      *no_add_attrs = true;
 | ||
| +    }
 | ||
| +
 | ||
| +  return NULL_TREE;
 | ||
| +}
 | ||
| +
 | ||
| +/* A C expression that places additional restrictions on the register class to
 | ||
| +   use when it is necessary to copy value X into a register in class CLASS.
 | ||
| +   The value is a register class; perhaps CLASS, or perhaps another, smaller
 | ||
| +   class.  On many machines, the following definition is safe:
 | ||
| +
 | ||
| +        #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
 | ||
| +
 | ||
| +   Sometimes returning a more restrictive class makes better code.  For
 | ||
| +   example, on the 68000, when X is an integer constant that is in range for a
 | ||
| +   `moveq' instruction, the value of this macro is always `DATA_REGS' as long
 | ||
| +   as CLASS includes the data registers.  Requiring a data register guarantees
 | ||
| +   that a `moveq' will be used.
 | ||
| +
 | ||
| +   If X is a `const_double', by returning `NO_REGS' you can force X into a
 | ||
| +   memory constant.  This is useful on certain machines where immediate
 | ||
| +   floating values cannot be loaded into certain kinds of registers.  */
 | ||
| +
 | ||
| +enum reg_class
 | ||
| +ubicom32_preferred_reload_class (rtx x, enum reg_class class)
 | ||
| +{
 | ||
| +  /* If a symbolic constant, HIGH or a PLUS is reloaded,
 | ||
| +     it is most likely being used as an address, so
 | ||
| +     prefer ADDRESS_REGS.  If 'class' is not a superset
 | ||
| +     of ADDRESS_REGS, e.g. DATA_REGS, then reject this reload.  */
 | ||
| +  if (GET_CODE (x) == PLUS
 | ||
| +      || GET_CODE (x) == HIGH
 | ||
| +      || GET_CODE (x) == LABEL_REF
 | ||
| +      || GET_CODE (x) == SYMBOL_REF
 | ||
| +      || GET_CODE (x) == CONST)
 | ||
| +    {
 | ||
| +      if (reg_class_subset_p (ALL_ADDRESS_REGS, class))
 | ||
| +	return ALL_ADDRESS_REGS;
 | ||
| +
 | ||
| +      return NO_REGS;
 | ||
| +    }
 | ||
| +
 | ||
| +  return class;
 | ||
| +}
 | ||
| +
 | ||
| +/* Function arguments and varargs.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_reg_parm_stack_space (tree fndecl)
 | ||
| +{
 | ||
| +  return 0;
 | ||
| +  
 | ||
| +  if (fndecl
 | ||
| +      && TYPE_ARG_TYPES (TREE_TYPE (fndecl)) != 0
 | ||
| +      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))) 
 | ||
| +	  != void_type_node))
 | ||
| +    return UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| +/* Flush the argument registers to the stack for a stdarg function;
 | ||
| +   return the new argument pointer.  */
 | ||
| +
 | ||
| +rtx
 | ||
| +ubicom32_builtin_saveregs (void)
 | ||
| +{
 | ||
| +  int regno;
 | ||
| +  
 | ||
| +  if (! cfun->stdarg)
 | ||
| +    return 0;
 | ||
| +  
 | ||
| +  for (regno = UBICOM32_FUNCTION_ARG_REGS - 1; regno >= 0; --regno)
 | ||
| +    emit_move_insn (gen_rtx_MEM (SImode,
 | ||
| +				 gen_rtx_PRE_DEC (SImode,
 | ||
| +						  stack_pointer_rtx)),
 | ||
| +		    gen_rtx_REG (SImode, regno));
 | ||
| +  
 | ||
| +  return stack_pointer_rtx;
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_va_start (tree valist, rtx nextarg)
 | ||
| +{
 | ||
| +  std_expand_builtin_va_start (valist, nextarg);
 | ||
| +}
 | ||
| +
 | ||
| +rtx
 | ||
| +ubicom32_va_arg (tree valist, tree type)
 | ||
| +{
 | ||
| +  HOST_WIDE_INT size, rsize;
 | ||
| +  tree addr, incr, tmp;
 | ||
| +  rtx addr_rtx;
 | ||
| +  int indirect = 0;
 | ||
| +
 | ||
| +  /* Round up sizeof(type) to a word.  */
 | ||
| +  size = int_size_in_bytes (type);
 | ||
| +  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
 | ||
| +
 | ||
| +  /* Large types are passed by reference.  */
 | ||
| +  if (size > 8)
 | ||
| +    {
 | ||
| +      indirect = 1;
 | ||
| +      size = rsize = UNITS_PER_WORD;
 | ||
| +    }
 | ||
| +
 | ||
| +  incr = valist;
 | ||
| +  addr = incr = save_expr (incr);
 | ||
| +
 | ||
| +  /* FIXME Nat's version - is it correct?  */
 | ||
| +  tmp = fold_convert (ptr_type_node, size_int (rsize));
 | ||
| +  tmp = build2 (PLUS_EXPR, ptr_type_node, incr, tmp);
 | ||
| +  incr = fold (tmp);
 | ||
| +
 | ||
| +  /* FIXME Nat's version - is it correct? */
 | ||
| +  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
 | ||
| +
 | ||
| +  TREE_SIDE_EFFECTS (incr) = 1;
 | ||
| +  expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
 | ||
| +
 | ||
| +  addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
 | ||
| +
 | ||
| +  if (size < UNITS_PER_WORD)
 | ||
| +    emit_insn (gen_addsi3 (addr_rtx, addr_rtx,
 | ||
| +			   GEN_INT (UNITS_PER_WORD - size)));
 | ||
| +
 | ||
| +  if (indirect)
 | ||
| +    {
 | ||
| +      addr_rtx = force_reg (Pmode, addr_rtx);
 | ||
| +      addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
 | ||
| +      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
 | ||
| +    }
 | ||
| +
 | ||
| +  return addr_rtx;
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
 | ||
| +		      int indirect ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  cum->nbytes = 0;
 | ||
| +
 | ||
| +  if (!libname)
 | ||
| +    {
 | ||
| +      cum->stdarg = (TYPE_ARG_TYPES (fntype) != 0
 | ||
| +		     && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
 | ||
| +			 != void_type_node));
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Return an RTX to represent where a value in mode MODE will be passed
 | ||
| +   to a function.  If the result is 0, the argument will be pushed.  */
 | ||
| +
 | ||
| +rtx
 | ||
| +function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
 | ||
| +	      int named ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  rtx result = 0;
 | ||
| +  int size, align;
 | ||
| +  int nregs = UBICOM32_FUNCTION_ARG_REGS;
 | ||
| +  
 | ||
| +  /* Figure out the size of the object to be passed.  */
 | ||
| +  if (mode == BLKmode)
 | ||
| +    size = int_size_in_bytes (type);
 | ||
| +  else
 | ||
| +    size = GET_MODE_SIZE (mode);
 | ||
| +
 | ||
| +  /* Figure out the alignment of the object to be passed.  */
 | ||
| +  align = size;
 | ||
| +
 | ||
| +  cum->nbytes = (cum->nbytes + 3) & ~3;
 | ||
| +
 | ||
| +  /* Don't pass this arg via a register if all the argument registers
 | ||
| +     are used up.  */
 | ||
| +  if (cum->nbytes >= nregs * UNITS_PER_WORD)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  /* Don't pass this arg via a register if it would be split between
 | ||
| +     registers and memory.  */
 | ||
| +  result = gen_rtx_REG (mode, cum->nbytes / UNITS_PER_WORD);
 | ||
| +
 | ||
| +  return result;
 | ||
| +}
 | ||
| +
 | ||
| +rtx
 | ||
| +function_incoming_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
 | ||
| +		       int named ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  if (cfun->stdarg)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  return function_arg (cum, mode, type, named);
 | ||
| +}
 | ||
| +
 | ||
| +
 | ||
| +/* Implement hook TARGET_ARG_PARTIAL_BYTES.
 | ||
| +
 | ||
| +   Returns the number of bytes at the beginning of an argument that
 | ||
| +   must be put in registers.  The value must be zero for arguments
 | ||
| +   that are passed entirely in registers or that are entirely pushed
 | ||
| +   on the stack.  */
 | ||
| +static int
 | ||
| +ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 | ||
| +			    tree type, bool named ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  int size, diff;
 | ||
| +
 | ||
| +  int nregs = UBICOM32_FUNCTION_ARG_REGS;
 | ||
| +
 | ||
| +  /* round up to full word */
 | ||
| +  cum->nbytes = (cum->nbytes + 3) & ~3;
 | ||
| +
 | ||
| +  if (targetm.calls.pass_by_reference (cum, mode, type, named))
 | ||
| +      return 0;
 | ||
| +
 | ||
| +  /* number of bytes left in registers */
 | ||
| +  diff = nregs*UNITS_PER_WORD - cum->nbytes;
 | ||
| +
 | ||
| +  /* regs all used up */
 | ||
| +  if (diff <= 0)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  /* Figure out the size of the object to be passed.  */
 | ||
| +  if (mode == BLKmode)
 | ||
| +    size = int_size_in_bytes (type);
 | ||
| +  else
 | ||
| +    size = GET_MODE_SIZE (mode);
 | ||
| +
 | ||
| +  /* enough space left in regs for size */
 | ||
| +  if (size <= diff)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  /* put diff bytes in regs and rest on stack */
 | ||
| +  return diff;
 | ||
| +
 | ||
| +}
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 | ||
| +			    enum machine_mode mode, const_tree type,
 | ||
| +			    bool named ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  int size;
 | ||
| +
 | ||
| +  if (type)
 | ||
| +    size = int_size_in_bytes (type);
 | ||
| +  else
 | ||
| +    size = GET_MODE_SIZE (mode);
 | ||
| +
 | ||
| +  return size <= 0 || size > 8;
 | ||
| +}
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 | ||
| +			enum machine_mode mode, const_tree type,
 | ||
| +			bool named ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  int size;
 | ||
| +
 | ||
| +  if (type)
 | ||
| +    size = int_size_in_bytes (type);
 | ||
| +  else
 | ||
| +    size = GET_MODE_SIZE (mode);
 | ||
| +
 | ||
| +  return size <= 0 || size > 8;
 | ||
| +}
 | ||
| + 
 | ||
| +static bool
 | ||
| +ubicom32_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  int size, mode;
 | ||
| +
 | ||
| +  if (!type)
 | ||
| +    return true;
 | ||
| +
 | ||
| +  size = int_size_in_bytes(type);
 | ||
| +  if (size > 8) 
 | ||
| +    return true;
 | ||
| +
 | ||
| +  mode = TYPE_MODE(type);
 | ||
| +  if (mode == BLKmode)
 | ||
| +    return true;
 | ||
| +
 | ||
| +  return false;
 | ||
| +}
 | ||
| +
 | ||
| +/* Return true if a given register number REGNO is acceptable for machine
 | ||
| +   mode MODE.  */
 | ||
| +bool
 | ||
| +ubicom32_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
 | ||
| +{
 | ||
| +  /* If we're not at least a v3 ISA then ACC0_HI is only 16 bits.  */
 | ||
| +  if (! ubicom32_v3)
 | ||
| +    {
 | ||
| +      if (regno == ACC0_HI_REGNUM)
 | ||
| +	return (mode == QImode || mode == HImode);
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Only the flags reg can hold CCmode.  */
 | ||
| +  if (GET_MODE_CLASS (mode) == MODE_CC)
 | ||
| +    return regno == CC_REGNUM;
 | ||
| +
 | ||
| +  /* We restrict the choice of DImode registers to only being address,
 | ||
| +     data or accumulator regs.  We also restrict them to only start on
 | ||
| +     even register numbers so we never have to worry about partial
 | ||
| +     overlaps between operands in instructions.  */
 | ||
| +  if (GET_MODE_SIZE (mode) > 4)
 | ||
| +    {
 | ||
| +      switch (REGNO_REG_CLASS (regno))
 | ||
| +	{
 | ||
| +	case ADDRESS_REGS:
 | ||
| +	case DATA_REGS:
 | ||
| +	case ACC_REGS:
 | ||
| +	  return (regno & 1) == 0;
 | ||
| +
 | ||
| +        default:
 | ||
| +	  return false;
 | ||
| +	}
 | ||
| +    }
 | ||
| +
 | ||
| +  return true;
 | ||
| +}
 | ||
| +
 | ||
| +/* 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.  
 | ||
| +
 | ||
| +   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 local-alloc.c.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_regno_ok_for_base_p (int regno, int strict)
 | ||
| +{
 | ||
| +  if ((regno >= FIRST_ADDRESS_REGNUM && regno <= STACK_POINTER_REGNUM) 
 | ||
| +      || (!strict
 | ||
| +	  && (regno >= FIRST_PSEUDO_REGISTER
 | ||
| +	      || regno == ARG_POINTER_REGNUM))
 | ||
| +      || (strict && (reg_renumber 
 | ||
| +		     && reg_renumber[regno] >= FIRST_ADDRESS_REGNUM
 | ||
| +		     && reg_renumber[regno] <= STACK_POINTER_REGNUM)))
 | ||
| +    return 1;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_regno_ok_for_index_p (int regno, int strict)
 | ||
| +{
 | ||
| +  if ((regno >= FIRST_DATA_REGNUM && regno <= LAST_DATA_REGNUM)
 | ||
| +      || (!strict && regno >= FIRST_PSEUDO_REGISTER)
 | ||
| +      || (strict && (reg_renumber 
 | ||
| +		     && reg_renumber[regno] >= FIRST_DATA_REGNUM
 | ||
| +		     && reg_renumber[regno] <= LAST_DATA_REGNUM)))
 | ||
| +    return 1;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| +/* Returns 1 if X is a valid index register.  STRICT is 1 if only hard
 | ||
| +   registers should be accepted.  Accept either REG or SUBREG where a
 | ||
| +   register is valid.  */
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_is_index_reg (rtx x, int strict)
 | ||
| +{
 | ||
| +  if ((REG_P (x) && ubicom32_regno_ok_for_index_p (REGNO (x), strict))
 | ||
| +      || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
 | ||
| +	  && ubicom32_regno_ok_for_index_p (REGNO (SUBREG_REG (x)), strict)))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  return false;
 | ||
| +}
 | ||
| +
 | ||
| +/* Return 1 if X is a valid index for a memory address.  */
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_is_index_expr (enum machine_mode mode, rtx x, int strict)
 | ||
| +{
 | ||
| +  /* Immediate index must be an unsigned 7-bit offset multiple of 1, 2
 | ||
| +     or 4 depending on mode.  */
 | ||
| +  if (CONST_INT_P (x))
 | ||
| +    {
 | ||
| +      switch (mode)
 | ||
| +	{
 | ||
| +	case QImode:
 | ||
| +	  return satisfies_constraint_J (x);
 | ||
| +	  
 | ||
| +	case HImode:
 | ||
| +	  return satisfies_constraint_K (x);
 | ||
| +
 | ||
| +	case SImode:
 | ||
| +	case SFmode:
 | ||
| +	  return satisfies_constraint_L (x);
 | ||
| +
 | ||
| +	case DImode:
 | ||
| +	  return satisfies_constraint_L (x)
 | ||
| +		 && satisfies_constraint_L (GEN_INT (INTVAL (x) + 4));
 | ||
| +	  
 | ||
| +	default:	  
 | ||
| +	  return false;
 | ||
| +	}
 | ||
| +    }
 | ||
| +
 | ||
| +  if (mode != SImode && mode != HImode && mode != QImode)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  /* Register index scaled by mode of operand: REG + REG * modesize.
 | ||
| +     Valid scaled index registers are:
 | ||
| +
 | ||
| +     SImode	(mult (dreg) 4))
 | ||
| +     HImode	(mult (dreg) 2))
 | ||
| +     QImode	(mult (dreg) 1))  */
 | ||
| +  if (GET_CODE (x) == MULT
 | ||
| +      && ubicom32_is_index_reg (XEXP (x, 0), strict)
 | ||
| +      && CONST_INT_P (XEXP (x, 1))
 | ||
| +      && INTVAL (XEXP (x, 1)) == (HOST_WIDE_INT)GET_MODE_SIZE (mode))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  /* REG + REG addressing is allowed for QImode.  */
 | ||
| +  if (ubicom32_is_index_reg (x, strict) && mode == QImode)
 | ||
| +    return true;
 | ||
| +
 | ||
| +  return false;
 | ||
| +}
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_is_valid_offset (enum machine_mode mode, HOST_WIDE_INT offs)
 | ||
| +{
 | ||
| +  if (offs < 0)
 | ||
| +    return false;
 | ||
| +
 | ||
| +  switch (mode)
 | ||
| +    {
 | ||
| +    case QImode:
 | ||
| +      return offs <= 127;
 | ||
| +
 | ||
| +    case HImode:
 | ||
| +      return offs <= 254;
 | ||
| +
 | ||
| +    case SImode:
 | ||
| +    case SFmode:
 | ||
| +      return offs <= 508;
 | ||
| +
 | ||
| +    case DImode:
 | ||
| +      return offs <= 504;
 | ||
| +
 | ||
| +    default:
 | ||
| +      return false;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +static int
 | ||
| +ubicom32_get_valid_offset_mask (enum machine_mode mode)
 | ||
| +{
 | ||
| +  switch (mode)
 | ||
| +    {
 | ||
| +    case QImode:
 | ||
| +      return 127;
 | ||
| +
 | ||
| +    case HImode:
 | ||
| +      return 255;
 | ||
| +
 | ||
| +    case SImode:
 | ||
| +    case SFmode:
 | ||
| +      return 511;
 | ||
| +
 | ||
| +    case DImode:
 | ||
| +      return 255;
 | ||
| +
 | ||
| +    default:
 | ||
| +      return 0;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Returns 1 if X is a valid base register.  STRICT is 1 if only hard
 | ||
| +   registers should be accepted.  Accept either REG or SUBREG where a
 | ||
| +   register is valid.  */
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_is_base_reg (rtx x, int strict)
 | ||
| +{
 | ||
| +  if ((REG_P (x) && ubicom32_regno_ok_for_base_p (REGNO (x), strict))
 | ||
| +      || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
 | ||
| +	  && ubicom32_regno_ok_for_base_p (REGNO (SUBREG_REG (x)), strict)))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  return false;
 | ||
| +}
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  return TARGET_FDPIC;
 | ||
| +}
 | ||
| +
 | ||
| +/* Determine if X is a legitimate constant.  */
 | ||
| +
 | ||
| +bool
 | ||
| +ubicom32_legitimate_constant_p (rtx x)
 | ||
| +{
 | ||
| +  /* Among its other duties, LEGITIMATE_CONSTANT_P decides whether
 | ||
| +     a constant can be entered into reg_equiv_constant[].  If we return true,
 | ||
| +     reload can create new instances of the constant whenever it likes.
 | ||
| +
 | ||
| +     The idea is therefore to accept as many constants as possible (to give
 | ||
| +     reload more freedom) while rejecting constants that can only be created
 | ||
| +     at certain times.  In particular, anything with a symbolic component will
 | ||
| +     require use of the pseudo FDPIC register, which is only available before
 | ||
| +     reload.  */
 | ||
| +  if (TARGET_FDPIC)
 | ||
| +    {
 | ||
| +      if (GET_CODE (x) == SYMBOL_REF
 | ||
| +	  || (GET_CODE (x) == CONST
 | ||
| +	      && GET_CODE (XEXP (x, 0)) == PLUS
 | ||
| +	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
 | ||
| +	  || CONSTANT_ADDRESS_P (x))
 | ||
| +	return false;
 | ||
| +
 | ||
| +      return true;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* For non-PIC code anything goes!  */
 | ||
| +  return true;
 | ||
| +}
 | ||
| +
 | ||
| +/* Address validation.  */
 | ||
| +
 | ||
| +bool
 | ||
| +ubicom32_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
 | ||
| +{
 | ||
| +  if (TARGET_DEBUG_ADDRESS)
 | ||
| +    {									
 | ||
| +      fprintf (stderr, "\n==> GO_IF_LEGITIMATE_ADDRESS%s\n",
 | ||
| +	       (strict) ? " (STRICT)" : "");
 | ||
| +      debug_rtx (x);
 | ||
| +    }									
 | ||
| +
 | ||
| +  if (CONSTANT_ADDRESS_P (x))
 | ||
| +    return false;
 | ||
| +
 | ||
| +  if (ubicom32_is_base_reg (x, strict)) 
 | ||
| +    return true;
 | ||
| +
 | ||
| +  if ((GET_CODE (x) == POST_INC 
 | ||
| +       || GET_CODE (x) == PRE_INC 
 | ||
| +       || GET_CODE (x) == POST_DEC 
 | ||
| +       || GET_CODE (x) == PRE_DEC)
 | ||
| +      && REG_P (XEXP (x, 0))
 | ||
| +      && ubicom32_is_base_reg (XEXP (x, 0), strict)
 | ||
| +      && mode != DImode)
 | ||
| +    return true;
 | ||
| +
 | ||
| +  if ((GET_CODE (x) == PRE_MODIFY || GET_CODE (x) == POST_MODIFY)
 | ||
| +      && ubicom32_is_base_reg (XEXP (x, 0), strict)
 | ||
| +      && GET_CODE (XEXP (x, 1)) == PLUS
 | ||
| +      && rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))
 | ||
| +      && CONST_INT_P (XEXP (XEXP (x, 1), 1))
 | ||
| +      && mode != DImode)
 | ||
| +    {
 | ||
| +      HOST_WIDE_INT disp = INTVAL (XEXP (XEXP (x, 1), 1));
 | ||
| +      switch (mode)
 | ||
| +	{
 | ||
| +	case QImode:
 | ||
| +	  return disp >= -8 && disp <= 7;
 | ||
| +	  
 | ||
| +	case HImode:
 | ||
| +	  return disp >= -16 && disp <= 14 && ! (disp & 1);
 | ||
| +	  
 | ||
| +	case SImode:
 | ||
| +	  return disp >= -32 && disp <= 28 && ! (disp & 3);
 | ||
| +	  
 | ||
| +	default:
 | ||
| +	  return false;
 | ||
| +	}
 | ||
| +    }
 | ||
| +  
 | ||
| +  /* Accept base + index * scale.  */
 | ||
| +  if (GET_CODE (x) == PLUS
 | ||
| +      && ubicom32_is_base_reg (XEXP (x, 0), strict)
 | ||
| +      && ubicom32_is_index_expr (mode, XEXP (x, 1), strict))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  /* Accept index * scale + base.  */
 | ||
| +  if (GET_CODE (x) == PLUS
 | ||
| +      && ubicom32_is_base_reg (XEXP (x, 1), strict)
 | ||
| +      && ubicom32_is_index_expr (mode, XEXP (x, 0), strict))
 | ||
| +    return true;
 | ||
| +
 | ||
| +  if (! TARGET_FDPIC)
 | ||
| +    {
 | ||
| +      /* Accept (lo_sum (reg) (symbol_ref)) that can be used as a mem+7bits
 | ||
| +	 displacement operand:
 | ||
| +
 | ||
| +	 moveai a1, #%hi(SYM)
 | ||
| +	 move.4 d3, %lo(SYM)(a1)  */
 | ||
| +      if (GET_CODE (x) == LO_SUM
 | ||
| +	  && ubicom32_is_base_reg (XEXP (x, 0), strict)
 | ||
| +	  && (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
 | ||
| +	      || GET_CODE (XEXP (x, 1)) == LABEL_REF /* FIXME: wrong */)
 | ||
| +	  && mode != DImode)
 | ||
| +	return true;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (TARGET_DEBUG_ADDRESS)
 | ||
| +    fprintf (stderr, "\nNot a legitimate address.\n");
 | ||
| +
 | ||
| +  return false;
 | ||
| +}
 | ||
| +
 | ||
| +rtx
 | ||
| +ubicom32_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 | ||
| +			     enum machine_mode mode)
 | ||
| +{
 | ||
| +  if (mode == BLKmode)
 | ||
| +    return NULL_RTX;
 | ||
| +
 | ||
| +  if (GET_CODE (x) == PLUS
 | ||
| +      && REG_P (XEXP (x, 0))
 | ||
| +      && ! REGNO_PTR_FRAME_P (REGNO (XEXP (x, 0))) 
 | ||
| +      && CONST_INT_P (XEXP (x, 1))
 | ||
| +      && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (x, 1))))
 | ||
| +    {
 | ||
| +      rtx base;
 | ||
| +      rtx plus;
 | ||
| +      rtx new_rtx;
 | ||
| +      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
 | ||
| +      HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
 | ||
| +      HOST_WIDE_INT high = val ^ low;
 | ||
| +
 | ||
| +      if (val < 0)
 | ||
| +	return NULL_RTX;
 | ||
| +
 | ||
| +      if (! low)
 | ||
| +	return NULL_RTX;
 | ||
| +
 | ||
| +      /* Reload the high part into a base reg; leave the low part
 | ||
| +	 in the mem directly.  */
 | ||
| +      base = XEXP (x, 0);
 | ||
| +      if (! ubicom32_is_base_reg (base, 0))
 | ||
| +	base = copy_to_mode_reg (Pmode, base);
 | ||
| +
 | ||
| +      plus = expand_simple_binop (Pmode, PLUS,
 | ||
| +				  gen_int_mode (high, Pmode),
 | ||
| +				  base, NULL, 0, OPTAB_WIDEN);
 | ||
| +      new_rtx = plus_constant (plus, low);
 | ||
| +
 | ||
| +      return new_rtx;
 | ||
| +    }
 | ||
| +
 | ||
| +  return NULL_RTX;
 | ||
| +}
 | ||
| +
 | ||
| +/* Try a machine-dependent way of reloading an illegitimate address AD
 | ||
| +   operand.  If we find one, push the reload and and return the new address.
 | ||
| +
 | ||
| +   MODE is the mode of the enclosing MEM.  OPNUM is the operand number
 | ||
| +   and TYPE is the reload type of the current reload.  */
 | ||
| +
 | ||
| +rtx 
 | ||
| +ubicom32_legitimize_reload_address (rtx ad, enum machine_mode mode,
 | ||
| +				    int opnum, int type)
 | ||
| +{
 | ||
| +  /* Is this an address that we've already fixed up?  If it is then
 | ||
| +     recognize it and move on.  */
 | ||
| +  if (GET_CODE (ad) == PLUS
 | ||
| +      && GET_CODE (XEXP (ad, 0)) == PLUS
 | ||
| +      && REG_P (XEXP (XEXP (ad, 0), 0))
 | ||
| +      && CONST_INT_P (XEXP (XEXP (ad, 0), 1))
 | ||
| +      && CONST_INT_P (XEXP (ad, 1)))
 | ||
| +    {
 | ||
| +      push_reload (XEXP (ad, 0), NULL_RTX, &XEXP (ad, 0), NULL,
 | ||
| +		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
 | ||
| +		   opnum, (enum reload_type) type);
 | ||
| +      return ad;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Have we got an address where the offset is simply out of range?  If
 | ||
| +     yes then reload the range as a high part and smaller offset.  */
 | ||
| +  if (GET_CODE (ad) == PLUS
 | ||
| +      && REG_P (XEXP (ad, 0))
 | ||
| +      && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
 | ||
| +      && REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0)))
 | ||
| +      && CONST_INT_P (XEXP (ad, 1))
 | ||
| +      && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (ad, 1))))
 | ||
| +    {
 | ||
| +      rtx temp;
 | ||
| +      rtx new_rtx;
 | ||
| +
 | ||
| +      HOST_WIDE_INT val = INTVAL (XEXP (ad, 1));
 | ||
| +      HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
 | ||
| +      HOST_WIDE_INT high = val ^ low;
 | ||
| +
 | ||
| +      /* Reload the high part into a base reg; leave the low part
 | ||
| +	 in the mem directly.  */
 | ||
| +      temp = gen_rtx_PLUS (Pmode, XEXP (ad, 0), GEN_INT (high));
 | ||
| +      new_rtx = gen_rtx_PLUS (Pmode, temp, GEN_INT (low));
 | ||
| +
 | ||
| +      push_reload (XEXP (new_rtx, 0), NULL_RTX, &XEXP (new_rtx, 0), NULL,
 | ||
| +		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
 | ||
| +		   opnum, (enum reload_type) type);
 | ||
| +      return new_rtx;
 | ||
| +    }
 | ||
| +
 | ||
| +  /* If we're presented with an pre/post inc/dec then we must force this
 | ||
| +     to be done in an address register.  The register allocator should
 | ||
| +     work this out for itself but at times ends up trying to use the wrong
 | ||
| +     class.  If we get the wrong class then reload will end up generating
 | ||
| +     at least 3 instructions whereas this way we can hopefully keep it to
 | ||
| +     just 2.  */
 | ||
| +  if ((GET_CODE (ad) == POST_INC 
 | ||
| +       || GET_CODE (ad) == PRE_INC 
 | ||
| +       || GET_CODE (ad) == POST_DEC 
 | ||
| +       || GET_CODE (ad) == PRE_DEC)
 | ||
| +      && REG_P (XEXP (ad, 0))
 | ||
| +      && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
 | ||
| +      && ! REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0))))
 | ||
| +    {
 | ||
| +      push_reload (XEXP (ad, 0), XEXP (ad, 0), &XEXP (ad, 0), &XEXP (ad, 0),
 | ||
| +		   BASE_REG_CLASS, GET_MODE (XEXP (ad, 0)), GET_MODE (XEXP (ad, 0)), 0, 0,
 | ||
| +		   opnum, RELOAD_OTHER);
 | ||
| +      return ad;
 | ||
| +    }
 | ||
| +
 | ||
| +  return NULL_RTX;
 | ||
| +}
 | ||
| +
 | ||
| +/* Compute a (partial) cost for rtx X.  Return true if the complete
 | ||
| +   cost has been computed, and false if subexpressions should be
 | ||
| +   scanned.  In either case, *TOTAL contains the cost result.  */
 | ||
| +
 | ||
| +static bool
 | ||
| +ubicom32_rtx_costs (rtx x, int code, int outer_code, int *total,
 | ||
| +		    bool speed ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  enum machine_mode mode = GET_MODE (x);
 | ||
| +
 | ||
| +  switch (code)
 | ||
| +    {
 | ||
| +    case CONST_INT:
 | ||
| +      /* Very short constants often fold into instructions so
 | ||
| +         we pretend that they don't cost anything!  This is
 | ||
| +	 really important as regards zero values as otherwise
 | ||
| +	 the compiler has a nasty habit of wanting to reuse
 | ||
| +	 zeroes that are in regs but that tends to pessimize
 | ||
| +	 the code.  */
 | ||
| +      if (satisfies_constraint_I (x))
 | ||
| +	{
 | ||
| +	  *total = 0;
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Bit clearing costs nothing  */
 | ||
| +      if (outer_code == AND
 | ||
| +	  && exact_log2 (~INTVAL (x)) != -1)
 | ||
| +	{
 | ||
| +	  *total = 0;
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Masking the lower set of bits costs nothing.  */
 | ||
| +      if (outer_code == AND
 | ||
| +	  && exact_log2 (INTVAL (x) + 1) != -1)
 | ||
| +	{
 | ||
| +	  *total = 0;
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Bit setting costs nothing.  */
 | ||
| +      if (outer_code == IOR
 | ||
| +	  && exact_log2 (INTVAL (x)) != -1)
 | ||
| +	{
 | ||
| +	  *total = 0;
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      /* Larger constants that can be loaded via movei aren't too
 | ||
| +         bad.  If we're just doing a set they cost nothing extra.  */
 | ||
| +      if (satisfies_constraint_N (x))
 | ||
| +	{
 | ||
| +	  if (mode == DImode)
 | ||
| +	    *total = COSTS_N_INSNS (2);
 | ||
| +	  else 
 | ||
| +	    *total = COSTS_N_INSNS (1);
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      if (mode == DImode)
 | ||
| +	*total = COSTS_N_INSNS (5);
 | ||
| +      else
 | ||
| +        *total = COSTS_N_INSNS (3);
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case CONST_DOUBLE:
 | ||
| +      /* We don't optimize CONST_DOUBLEs well nor do we relax them well,
 | ||
| +	 so their cost is very high.  */
 | ||
| +      *total = COSTS_N_INSNS (6);
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case CONST:
 | ||
| +    case SYMBOL_REF:
 | ||
| +    case MEM:
 | ||
| +      *total = 0;
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case IF_THEN_ELSE:
 | ||
| +      *total = COSTS_N_INSNS (1);
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case LABEL_REF:
 | ||
| +    case HIGH:
 | ||
| +    case LO_SUM:
 | ||
| +    case BSWAP:
 | ||
| +    case PLUS:
 | ||
| +    case MINUS:
 | ||
| +    case AND:
 | ||
| +    case IOR:
 | ||
| +    case XOR:
 | ||
| +    case ASHIFT:
 | ||
| +    case ASHIFTRT:
 | ||
| +    case LSHIFTRT:
 | ||
| +    case NEG:
 | ||
| +    case NOT:
 | ||
| +    case SIGN_EXTEND:
 | ||
| +    case ZERO_EXTEND:
 | ||
| +    case ZERO_EXTRACT:
 | ||
| +      if (outer_code == SET)
 | ||
| +	{
 | ||
| +	  if (mode == DImode)
 | ||
| +	    *total = COSTS_N_INSNS (2);
 | ||
| +	  else
 | ||
| +	    *total = COSTS_N_INSNS (1);
 | ||
| +	}
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case COMPARE:
 | ||
| +      if (outer_code == SET)
 | ||
| +	{
 | ||
| +	  if (GET_MODE (XEXP (x, 0)) == DImode
 | ||
| +	      || GET_MODE (XEXP (x, 1)) == DImode)
 | ||
| +	    *total = COSTS_N_INSNS (2);
 | ||
| +	  else
 | ||
| +	    *total = COSTS_N_INSNS (1);
 | ||
| +	}
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case UMOD:
 | ||
| +    case UDIV:
 | ||
| +    case MOD:
 | ||
| +    case DIV:
 | ||
| +      if (outer_code == SET)
 | ||
| +	{
 | ||
| +	  if (mode == DImode)
 | ||
| +	    *total = COSTS_N_INSNS (600);
 | ||
| +	  else
 | ||
| +	    *total = COSTS_N_INSNS (200);
 | ||
| +	}
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case MULT:
 | ||
| +      if (outer_code == SET)
 | ||
| +	{
 | ||
| +	  if (! ubicom32_v4)
 | ||
| +	    {
 | ||
| +	      if (mode == DImode)
 | ||
| +		*total = COSTS_N_INSNS (15);
 | ||
| +	      else
 | ||
| +		*total = COSTS_N_INSNS (5);
 | ||
| +	    }
 | ||
| +	  else
 | ||
| +	    {
 | ||
| +	      if (mode == DImode)
 | ||
| +		*total = COSTS_N_INSNS (6);
 | ||
| +	      else
 | ||
| +		*total = COSTS_N_INSNS (2);
 | ||
| +	    }
 | ||
| +	}
 | ||
| +      return true;
 | ||
| +
 | ||
| +    case UNSPEC:
 | ||
| +      if (XINT (x, 1) == UNSPEC_FDPIC_GOT
 | ||
| +	  || XINT (x, 1) == UNSPEC_FDPIC_GOT_FUNCDESC)
 | ||
| +	*total = 0;
 | ||
| +      return true;
 | ||
| +
 | ||
| +    default:
 | ||
| +      return false;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Return 1 if ADDR can have different meanings depending on the machine
 | ||
| +   mode of the memory reference it is used for or if the address is
 | ||
| +   valid for some modes but not others.
 | ||
| +
 | ||
| +   Autoincrement and autodecrement addresses typically have
 | ||
| +   mode-dependent effects because the amount of the increment or
 | ||
| +   decrement is the size of the operand being addressed.  Some machines
 | ||
| +   have other mode-dependent addresses. Many RISC machines have no
 | ||
| +   mode-dependent addresses.
 | ||
| +
 | ||
| +   You may assume that ADDR is a valid address for the machine.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_mode_dependent_address_p (rtx addr)
 | ||
| +{
 | ||
| +  if (GET_CODE (addr) == POST_INC 
 | ||
| +      || GET_CODE (addr) == PRE_INC 
 | ||
| +      || GET_CODE (addr) == POST_DEC 
 | ||
| +      || GET_CODE (addr) == PRE_DEC 
 | ||
| +      || GET_CODE (addr) == POST_MODIFY 
 | ||
| +      || GET_CODE (addr) == PRE_MODIFY)
 | ||
| +    return 1;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| +static void
 | ||
| +ubicom32_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  fprintf (file, "/* frame/pretend: %ld/%d save_regs: %d out_args: %d  %s */\n",
 | ||
| +	   get_frame_size (), crtl->args.pretend_args_size,
 | ||
| +	   save_regs_size, crtl->outgoing_args_size,
 | ||
| +	   current_function_is_leaf ? "leaf" : "nonleaf");
 | ||
| +}
 | ||
| +
 | ||
| +static void
 | ||
| +ubicom32_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
 | ||
| +			    HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  ubicom32_reorg_completed = 0;  
 | ||
| +}
 | ||
| +
 | ||
| +static void
 | ||
| +ubicom32_machine_dependent_reorg (void)
 | ||
| +{
 | ||
| +#if 0 /* Commenting out this optimization until it is fixed */
 | ||
| +  if (optimize)
 | ||
| +    {
 | ||
| +      compute_bb_for_insn ();
 | ||
| +
 | ||
| +      /* Do a very simple CSE pass over just the hard registers.  */
 | ||
| +      reload_cse_regs (get_insns ());
 | ||
| +
 | ||
| +      /* Reload_cse_regs can eliminate potentially-trapping MEMs.
 | ||
| +	 Remove any EH edges associated with them.  */
 | ||
| +      if (flag_non_call_exceptions)
 | ||
| +	purge_all_dead_edges ();
 | ||
| +    }
 | ||
| +#endif
 | ||
| +  ubicom32_reorg_completed = 1;
 | ||
| +}
 | ||
| +
 | ||
| +void
 | ||
| +ubicom32_output_cond_jump (rtx insn, rtx cond, rtx target)
 | ||
| +{
 | ||
| +  rtx note;
 | ||
| +  int mostly_false_jump;
 | ||
| +  rtx xoperands[2];
 | ||
| +  rtx cc_reg;
 | ||
| +
 | ||
| +  note = find_reg_note (insn, REG_BR_PROB, 0);
 | ||
| +  mostly_false_jump = !note || (INTVAL (XEXP (note, 0))
 | ||
| +				<= REG_BR_PROB_BASE / 2);
 | ||
| +
 | ||
| +  xoperands[0] = target;
 | ||
| +  xoperands[1] = cond;
 | ||
| +  cc_reg = XEXP (cond, 0);
 | ||
| +
 | ||
| +  if (GET_MODE (cc_reg) == CCWmode
 | ||
| +      || GET_MODE (cc_reg) == CCWZmode
 | ||
| +      || GET_MODE (cc_reg) == CCWZNmode)
 | ||
| +    {
 | ||
| +      if (mostly_false_jump)
 | ||
| +        output_asm_insn ("jmp%b1.w.f\t%0", xoperands);
 | ||
| +      else
 | ||
| +        output_asm_insn ("jmp%b1.w.t\t%0", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (GET_MODE (cc_reg) == CCSmode
 | ||
| +      || GET_MODE (cc_reg) == CCSZmode
 | ||
| +      || GET_MODE (cc_reg) == CCSZNmode)
 | ||
| +    {
 | ||
| +      if (mostly_false_jump)
 | ||
| +        output_asm_insn ("jmp%b1.s.f\t%0", xoperands);
 | ||
| +      else
 | ||
| +        output_asm_insn ("jmp%b1.s.t\t%0", xoperands);
 | ||
| +      return;
 | ||
| +    }
 | ||
| +
 | ||
| +  abort ();
 | ||
| +}
 | ||
| +
 | ||
| +/* Return non-zero if FUNC is a naked function.  */
 | ||
| +
 | ||
| +static int
 | ||
| +ubicom32_naked_function_p (void)
 | ||
| +{
 | ||
| +  return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
 | ||
| +}
 | ||
| +
 | ||
| +/* Return an RTX indicating where the return address to the
 | ||
| +   calling function can be found.  */
 | ||
| +rtx
 | ||
| +ubicom32_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  if (count != 0)
 | ||
| +    return NULL_RTX;
 | ||
| +
 | ||
| +  return get_hard_reg_initial_val (Pmode, LINK_REGNO);
 | ||
| +}
 | ||
| +
 | ||
| +/*
 | ||
| + * ubicom32_readonly_data_section: This routtine handles code
 | ||
| + * at the start of readonly data sections
 | ||
| + */
 | ||
| +static void
 | ||
| +ubicom32_readonly_data_section (const void *data ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  static int num = 0;
 | ||
| +  if (in_section == readonly_data_section){
 | ||
| +    fprintf (asm_out_file, "%s", DATA_SECTION_ASM_OP);
 | ||
| +    if (flag_data_sections){
 | ||
| +      fprintf (asm_out_file, ".rodata%d", num);
 | ||
| +      fprintf (asm_out_file, ",\"a\"");
 | ||
| +    }
 | ||
| +    fprintf (asm_out_file, "\n");
 | ||
| +  }
 | ||
| +  num++;
 | ||
| +}
 | ||
| +
 | ||
| +/*
 | ||
| + * ubicom32_text_section: not in readonly section
 | ||
| + */
 | ||
| +static void
 | ||
| +ubicom32_text_section(const void *data ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
 | ||
| +}
 | ||
| +
 | ||
| +/*
 | ||
| + * ubicom32_data_section: not in readonly section
 | ||
| + */
 | ||
| +static void
 | ||
| +ubicom32_data_section(const void *data ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
 | ||
| +}
 | ||
| +
 | ||
| +/*
 | ||
| + * ubicom32_asm_init_sections: This routine implements special
 | ||
| + * section handling
 | ||
| + */
 | ||
| +static void
 | ||
| +ubicom32_asm_init_sections(void)
 | ||
| +{
 | ||
| +  text_section = get_unnamed_section(SECTION_CODE, ubicom32_text_section, NULL);
 | ||
| +
 | ||
| +  data_section = get_unnamed_section(SECTION_WRITE, ubicom32_data_section, NULL);
 | ||
| +
 | ||
| +  readonly_data_section = get_unnamed_section(0, ubicom32_readonly_data_section, NULL);
 | ||
| +}
 | ||
| +
 | ||
| +/*
 | ||
| + * ubicom32_profiler:  This routine would call
 | ||
| + * mcount to support prof and gprof if mcount
 | ||
| + * was supported. Currently, do nothing.
 | ||
| + */
 | ||
| +void
 | ||
| +ubicom32_profiler(void)
 | ||
| +{
 | ||
| +}
 | ||
| +
 | ||
| +/* Initialise the builtin functions.  Start by initialising
 | ||
| +   descriptions of different types of functions (e.g., void fn(int),
 | ||
| +   int fn(void)), and then use these to define the builtins. */
 | ||
| +static void
 | ||
| +ubicom32_init_builtins (void)
 | ||
| +{
 | ||
| +  tree endlink;
 | ||
| +  tree short_unsigned_endlink;
 | ||
| +  tree unsigned_endlink;
 | ||
| +  tree short_unsigned_ftype_short_unsigned;
 | ||
| +  tree unsigned_ftype_unsigned;
 | ||
| +
 | ||
| +  endlink = void_list_node;
 | ||
| +
 | ||
| +  short_unsigned_endlink
 | ||
| +    = tree_cons (NULL_TREE, short_unsigned_type_node, endlink);
 | ||
| +
 | ||
| +  unsigned_endlink
 | ||
| +    = tree_cons (NULL_TREE, unsigned_type_node, endlink);
 | ||
| +
 | ||
| +  short_unsigned_ftype_short_unsigned
 | ||
| +    = build_function_type (short_unsigned_type_node, short_unsigned_endlink);
 | ||
| +
 | ||
| +  unsigned_ftype_unsigned
 | ||
| +    = build_function_type (unsigned_type_node, unsigned_endlink);
 | ||
| +
 | ||
| +  /* Initialise the byte swap function. */
 | ||
| +  add_builtin_function ("__builtin_ubicom32_swapb_2",
 | ||
| +  			short_unsigned_ftype_short_unsigned,
 | ||
| +			UBICOM32_BUILTIN_UBICOM32_SWAPB_2,
 | ||
| +			BUILT_IN_MD, NULL,
 | ||
| +			NULL_TREE);
 | ||
| +
 | ||
| +  /* Initialise the byte swap function. */
 | ||
| +  add_builtin_function ("__builtin_ubicom32_swapb_4",
 | ||
| +  			unsigned_ftype_unsigned,
 | ||
| +			UBICOM32_BUILTIN_UBICOM32_SWAPB_4,
 | ||
| +			BUILT_IN_MD, NULL,
 | ||
| +			NULL_TREE);
 | ||
| +}
 | ||
| +
 | ||
| +/* Given a builtin function taking 2 operands (i.e., target + source),
 | ||
| +   emit the RTL for the underlying instruction. */
 | ||
| +static rtx
 | ||
| +ubicom32_expand_builtin_2op (enum insn_code icode, tree arglist, rtx target)
 | ||
| +{
 | ||
| +  tree arg0;
 | ||
| +  rtx op0, pat;
 | ||
| +  enum machine_mode tmode, mode0;
 | ||
| +
 | ||
| +  /* Grab the incoming argument and emit its RTL. */
 | ||
| +  arg0 = TREE_VALUE (arglist);
 | ||
| +  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
 | ||
| +
 | ||
| +  /* Determine the modes of the instruction operands. */
 | ||
| +  tmode = insn_data[icode].operand[0].mode;
 | ||
| +  mode0 = insn_data[icode].operand[1].mode;
 | ||
| +
 | ||
| +  /* Ensure that the incoming argument RTL is in a register of the
 | ||
| +     correct mode. */
 | ||
| +  if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
 | ||
| +    op0 = copy_to_mode_reg (mode0, op0);
 | ||
| +
 | ||
| +  /* If there isn't a suitable target, emit a target register. */
 | ||
| +  if (target == 0
 | ||
| +      || GET_MODE (target) != tmode
 | ||
| +      || !(*insn_data[icode].operand[0].predicate) (target, tmode))
 | ||
| +    target = gen_reg_rtx (tmode);
 | ||
| +
 | ||
| +  /* Emit and return the new instruction. */
 | ||
| +  pat = GEN_FCN (icode) (target, op0);
 | ||
| +  if (!pat)
 | ||
| +    return 0;
 | ||
| +  emit_insn (pat);
 | ||
| +
 | ||
| +  return target;
 | ||
| +}
 | ||
| +
 | ||
| +/* Expand a call to a builtin function. */
 | ||
| +static rtx
 | ||
| +ubicom32_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 | ||
| +			 enum machine_mode mode ATTRIBUTE_UNUSED,
 | ||
| +			 int ignore ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
 | ||
| +  tree arglist = CALL_EXPR_ARGS(exp);
 | ||
| +  int fcode = DECL_FUNCTION_CODE (fndecl);
 | ||
| +
 | ||
| +  switch (fcode)
 | ||
| +    {
 | ||
| +    case UBICOM32_BUILTIN_UBICOM32_SWAPB_2:
 | ||
| +      return ubicom32_expand_builtin_2op (CODE_FOR_bswaphi, arglist, target);
 | ||
| +
 | ||
| +    case UBICOM32_BUILTIN_UBICOM32_SWAPB_4:
 | ||
| +      return ubicom32_expand_builtin_2op (CODE_FOR_bswapsi, arglist, target);
 | ||
| +
 | ||
| +    default:
 | ||
| +      gcc_unreachable();
 | ||
| +    }
 | ||
| +
 | ||
| +  /* Should really do something sensible here.  */
 | ||
| +  return NULL_RTX;
 | ||
| +}
 | ||
| +
 | ||
| +/* Fold any constant argument for a swapb.2 instruction.  */
 | ||
| +static tree
 | ||
| +ubicom32_fold_builtin_ubicom32_swapb_2 (tree fndecl, tree arglist)
 | ||
| +{
 | ||
| +  tree arg0;
 | ||
| +
 | ||
| +  arg0 = TREE_VALUE (arglist);
 | ||
| +
 | ||
| +  /* Optimize constant value.  */
 | ||
| +  if (TREE_CODE (arg0) == INTEGER_CST)
 | ||
| +    {
 | ||
| +      HOST_WIDE_INT v;
 | ||
| +      HOST_WIDE_INT res;
 | ||
| +
 | ||
| +      v = TREE_INT_CST_LOW (arg0);
 | ||
| +      res = ((v >> 8) & 0xff)
 | ||
| +	     | ((v & 0xff) << 8);
 | ||
| +
 | ||
| +      return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), res);
 | ||
| +    }
 | ||
| +
 | ||
| +  return NULL_TREE;
 | ||
| +}
 | ||
| +
 | ||
| +/* Fold any constant argument for a swapb.4 instruction.  */
 | ||
| +static tree
 | ||
| +ubicom32_fold_builtin_ubicom32_swapb_4 (tree fndecl, tree arglist)
 | ||
| +{
 | ||
| +  tree arg0;
 | ||
| +
 | ||
| +  arg0 = TREE_VALUE (arglist);
 | ||
| +
 | ||
| +  /* Optimize constant value.  */
 | ||
| +  if (TREE_CODE (arg0) == INTEGER_CST)
 | ||
| +    {
 | ||
| +      unsigned HOST_WIDE_INT v;
 | ||
| +      unsigned HOST_WIDE_INT res;
 | ||
| +
 | ||
| +      v = TREE_INT_CST_LOW (arg0);
 | ||
| +      res = ((v >> 24) & 0xff)
 | ||
| +	     | (((v >> 16) & 0xff) << 8)
 | ||
| +	     | (((v >> 8) & 0xff) << 16)
 | ||
| +	     | ((v & 0xff) << 24);
 | ||
| +
 | ||
| +      return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), res, 0);
 | ||
| +    }
 | ||
| +
 | ||
| +  return NULL_TREE;
 | ||
| +}
 | ||
| +
 | ||
| +/* Fold any constant arguments for builtin functions.  */
 | ||
| +static tree
 | ||
| +ubicom32_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED)
 | ||
| +{
 | ||
| +  switch (DECL_FUNCTION_CODE (fndecl))
 | ||
| +    {
 | ||
| +    case UBICOM32_BUILTIN_UBICOM32_SWAPB_2:
 | ||
| +      return ubicom32_fold_builtin_ubicom32_swapb_2 (fndecl, arglist);
 | ||
| +
 | ||
| +    case UBICOM32_BUILTIN_UBICOM32_SWAPB_4:
 | ||
| +      return ubicom32_fold_builtin_ubicom32_swapb_4 (fndecl, arglist);
 | ||
| +
 | ||
| +    default:
 | ||
| +      return NULL;
 | ||
| +    }
 | ||
| +}
 | ||
| +
 | ||
| +/* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
 | ||
| +   tell the assembler to generate pointers to function descriptors in
 | ||
| +   some cases.  */
 | ||
| +static bool
 | ||
| +ubicom32_assemble_integer (rtx value, unsigned int size, int aligned_p)
 | ||
| +{
 | ||
| +  if (TARGET_FDPIC && size == UNITS_PER_WORD)
 | ||
| +    {
 | ||
| +      if (GET_CODE (value) == SYMBOL_REF
 | ||
| +	  && SYMBOL_REF_FUNCTION_P (value))
 | ||
| +	{
 | ||
| +	  fputs ("\t.picptr\t%funcdesc(", asm_out_file);
 | ||
| +	  output_addr_const (asm_out_file, value);
 | ||
| +	  fputs (")\n", asm_out_file);
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +
 | ||
| +      if (!aligned_p)
 | ||
| +	{
 | ||
| +	  /* We've set the unaligned SI op to NULL, so we always have to
 | ||
| +	     handle the unaligned case here.  */
 | ||
| +	  assemble_integer_with_op ("\t.4byte\t", value);
 | ||
| +	  return true;
 | ||
| +	}
 | ||
| +    }
 | ||
| +
 | ||
| +  return default_assemble_integer (value, size, aligned_p);
 | ||
| +}
 | ||
| +
 | ||
| +/* If the constant I can be constructed by shifting a source-1 immediate
 | ||
| +   by a constant number of bits then return the bit count.  If not
 | ||
| +   return 0.  */
 | ||
| +
 | ||
| +int
 | ||
| +ubicom32_shiftable_const_int (int i)
 | ||
| +{
 | ||
| +  int shift = 0;
 | ||
| +
 | ||
| +  /* Note that any constant that can be represented as an immediate to
 | ||
| +     a movei instruction is automatically ignored here in the interests
 | ||
| +     of the clarity of the output asm code.  */
 | ||
| +  if (i >= -32768 && i <= 32767)
 | ||
| +    return 0;
 | ||
| +
 | ||
| +  /* Find the number of trailing zeroes.  We could use __builtin_ctz
 | ||
| +     here but it's not obvious if this is supported on all build
 | ||
| +     compilers so we err on the side of caution.  */
 | ||
| +  if ((i & 0xffff) == 0)
 | ||
| +    {
 | ||
| +      shift += 16;
 | ||
| +      i >>= 16;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((i & 0xff) == 0)
 | ||
| +    {
 | ||
| +      shift += 8;
 | ||
| +      i >>= 8;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((i & 0xf) == 0)
 | ||
| +    {
 | ||
| +      shift += 4;
 | ||
| +      i >>= 4;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((i & 0x3) == 0)
 | ||
| +    {
 | ||
| +      shift += 2;
 | ||
| +      i >>= 2;
 | ||
| +    }
 | ||
| +
 | ||
| +  if ((i & 0x1) == 0)
 | ||
| +    {
 | ||
| +      shift += 1;
 | ||
| +      i >>= 1;
 | ||
| +    }
 | ||
| +
 | ||
| +  if (i >= -128 && i <= 127)
 | ||
| +    return shift;
 | ||
| +
 | ||
| +  return 0;
 | ||
| +}
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32.h
 | ||
| @@ -0,0 +1,1564 @@
 | ||
| +/* Definitions of target machine for Ubicom32
 | ||
| +
 | ||
| +   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 | ||
| +   2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, 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 OBJECT_FORMAT_ELF
 | ||
| +
 | ||
| +/* Run-time target specifications. */
 | ||
| +
 | ||
| +/* Target CPU builtins.  */
 | ||
| +#define TARGET_CPU_CPP_BUILTINS()			\
 | ||
| +  do							\
 | ||
| +    {							\
 | ||
| +      builtin_define_std ("__UBICOM32__");		\
 | ||
| +      builtin_define_std ("__ubicom32__");		\
 | ||
| +							\
 | ||
| +      if (TARGET_FDPIC)					\
 | ||
| +	{						\
 | ||
| +	  builtin_define ("__UBICOM32_FDPIC__");	\
 | ||
| +	  builtin_define ("__FDPIC__");			\
 | ||
| +	}						\
 | ||
| +    }							\
 | ||
| +  while (0)
 | ||
| +
 | ||
| +#ifndef TARGET_DEFAULT
 | ||
| +#define TARGET_DEFAULT 0
 | ||
| +#endif
 | ||
| +
 | ||
| +extern int ubicom32_case_values_threshold;
 | ||
| +
 | ||
| +/* Nonzero if this chip supports the Ubicom32 v3 ISA.  */
 | ||
| +extern int ubicom32_v3;
 | ||
| +
 | ||
| +/* Nonzero if this chip supports the Ubicom32 v4 ISA.  */
 | ||
| +extern int ubicom32_v4;
 | ||
| +
 | ||
| +extern int ubicom32_stack_size;
 | ||
| +
 | ||
| +/* Flag for whether we can use calli instead of ret in returns.  */
 | ||
| +extern int ubicom32_can_use_calli_to_ret;
 | ||
| +
 | ||
| +/* This macro is a C statement to print on `stderr' a string describing the
 | ||
| +   particular machine description choice.  Every machine description should
 | ||
| +   define `TARGET_VERSION'. */
 | ||
| +#define TARGET_VERSION fprintf (stderr, " (UBICOM32)");
 | ||
| +
 | ||
| +/* We don't need a frame pointer to debug things.  Doing this means
 | ||
| +   that gcc can turn on -fomit-frame-pointer when '-O' is specified.  */
 | ||
| +#define CAN_DEBUG_WITHOUT_FP
 | ||
| +
 | ||
| +/* We need to handle processor-specific options.  */
 | ||
| +#define OVERRIDE_OPTIONS ubicom32_override_options ()
 | ||
| +
 | ||
| +#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) \
 | ||
| +  ubicom32_optimization_options (LEVEL, SIZE)
 | ||
| +
 | ||
| +/* For Ubicom32 the least significant bit has the lowest bit number
 | ||
| +   so we define this to be 0.  */
 | ||
| +#define BITS_BIG_ENDIAN 0
 | ||
| +
 | ||
| +/* For Ubicom32 the most significant byte in a word has the lowest
 | ||
| +   number.  */
 | ||
| +#define BYTES_BIG_ENDIAN 1
 | ||
| +
 | ||
| +/* For Ubicom32, in a multiword object, the most signifant word has the
 | ||
| +   lowest number.  */
 | ||
| +#define WORDS_BIG_ENDIAN 1
 | ||
| +
 | ||
| +/* Ubicom32 has 8 bits per byte.  */
 | ||
| +#define BITS_PER_UNIT 8
 | ||
| +
 | ||
| +/* Ubicom32 has 32 bits per word.  */
 | ||
| +#define BITS_PER_WORD 32
 | ||
| +
 | ||
| +/* Width of a word, in units (bytes).  */
 | ||
| +#define UNITS_PER_WORD 4
 | ||
| +
 | ||
| +/* Width of a pointer, in bits.  */
 | ||
| +#define POINTER_SIZE 32
 | ||
| +
 | ||
| +/* Alias for pointers.  Ubicom32 is a 32-bit architecture so we use
 | ||
| +   SImode.  */
 | ||
| +#define Pmode SImode
 | ||
| +
 | ||
| +/* Normal alignment required for function parameters on the stack, in
 | ||
| +   bits.  */
 | ||
| +#define PARM_BOUNDARY 32
 | ||
| +
 | ||
| +/* We need to maintain the stack on a 32-bit boundary.  */
 | ||
| +#define STACK_BOUNDARY 32
 | ||
| +
 | ||
| +/* Alignment required for a function entry point, in bits.  */
 | ||
| +#define FUNCTION_BOUNDARY 32
 | ||
| +
 | ||
| +/* Alias for the machine mode used for memory references to functions being
 | ||
| +   called, in `call' RTL expressions.  We use byte-oriented addresses
 | ||
| +   here.  */
 | ||
| +#define FUNCTION_MODE QImode
 | ||
| +
 | ||
| +/* Biggest alignment that any data type can require on this machine,
 | ||
| +   in bits.  */
 | ||
| +#define BIGGEST_ALIGNMENT 32
 | ||
| +
 | ||
| +/* this default to BIGGEST_ALIGNMENT unless defined       */
 | ||
| +/* ART: What's the correct value here? Default is (((unsigned int)1<<28)*8)*/
 | ||
| +#undef MAX_OFILE_ALIGNMENT
 | ||
| +#define MAX_OFILE_ALIGNMENT (128 * 8)
 | ||
| +
 | ||
| +/* Alignment in bits to be given to a structure bit field that follows an empty
 | ||
| +   field such as `int : 0;'.  */
 | ||
| +#define EMPTY_FIELD_BOUNDARY 32
 | ||
| +
 | ||
| +/* All structures must be a multiple of 32 bits in size.  */
 | ||
| +#define STRUCTURE_SIZE_BOUNDARY 32
 | ||
| +
 | ||
| +/* A bit-field declared as `int' forces `int' alignment for the struct.  */
 | ||
| +#define PCC_BITFIELD_TYPE_MATTERS 1
 | ||
| +
 | ||
| +/* For Ubicom32 we absolutely require that data be aligned with nominal
 | ||
| +   alignment.  */
 | ||
| +#define STRICT_ALIGNMENT 1
 | ||
| +
 | ||
| +/* Make strcpy of constants fast.  */
 | ||
| +#define CONSTANT_ALIGNMENT(EXP, ALIGN)  \
 | ||
| +  (TREE_CODE (EXP) == STRING_CST	\
 | ||
| +   && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
 | ||
| +
 | ||
| +/* Define this macro as an expression for the alignment of a structure
 | ||
| +   (given by STRUCT as a tree node) if the alignment computed in the
 | ||
| +   usual way is COMPUTED and the alignment explicitly specified was
 | ||
| +   SPECIFIED. */
 | ||
| +#define DATA_ALIGNMENT(TYPE, ALIGN)					\
 | ||
| +  ((((ALIGN) < BITS_PER_WORD)						\
 | ||
| +    && (TREE_CODE (TYPE) == ARRAY_TYPE					\
 | ||
| +	|| TREE_CODE (TYPE) == UNION_TYPE				\
 | ||
| +	|| TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
 | ||
| +
 | ||
| +#define LOCAL_ALIGNMENT(TYPE,ALIGN) DATA_ALIGNMENT(TYPE,ALIGN)
 | ||
| +
 | ||
| +/* For Ubicom32 we default to unsigned chars.  */
 | ||
| +#define DEFAULT_SIGNED_CHAR 0
 | ||
| +
 | ||
| +/* Machine-specific data register numbers.  */
 | ||
| +#define FIRST_DATA_REGNUM 0
 | ||
| +#define D10_REGNUM 10
 | ||
| +#define D11_REGNUM 11
 | ||
| +#define D12_REGNUM 12
 | ||
| +#define D13_REGNUM 13
 | ||
| +#define LAST_DATA_REGNUM 15
 | ||
| +
 | ||
| +/* Machine-specific address register numbers.  */
 | ||
| +#define FIRST_ADDRESS_REGNUM 16
 | ||
| +#define LAST_ADDRESS_REGNUM 22
 | ||
| +
 | ||
| +/* Register numbers used for passing a function's static chain pointer.  If
 | ||
| +   register windows are used, the register number as seen by the called
 | ||
| +   function is `STATIC_CHAIN_INCOMING_REGNUM', while the register number as
 | ||
| +   seen by the calling function is `STATIC_CHAIN_REGNUM'.  If these registers
 | ||
| +   are the same, `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
 | ||
| +
 | ||
| +   The static chain register need not be a fixed register.
 | ||
| +
 | ||
| +   If the static chain is passed in memory, these macros should not be defined;
 | ||
| +   instead, the next two macros should be defined.  */
 | ||
| +#define STATIC_CHAIN_REGNUM (FIRST_ADDRESS_REGNUM + 1)
 | ||
| +
 | ||
| +/* The register number of the frame pointer register, which is used to access
 | ||
| +   automatic variables in the stack frame.  We generally eliminate this anyway
 | ||
| +   for Ubicom32 but we make it A6 by default.  */
 | ||
| +#define FRAME_POINTER_REGNUM (LAST_ADDRESS_REGNUM)
 | ||
| +
 | ||
| +/* The register number of the stack pointer register, which is also be a
 | ||
| +   fixed register according to `FIXED_REGISTERS'.  For Ubicom32 we don't
 | ||
| +   have a hardware requirement about which register this is, but by convention
 | ||
| +   we use A7.  */
 | ||
| +#define STACK_POINTER_REGNUM (LAST_ADDRESS_REGNUM + 1)
 | ||
| +
 | ||
| +/* Machine-specific accumulator register numbers.  */
 | ||
| +#define ACC0_HI_REGNUM 24
 | ||
| +#define ACC0_LO_REGNUM 25
 | ||
| +#define ACC1_HI_REGNUM 26
 | ||
| +#define ACC1_LO_REGNUM 27
 | ||
| +
 | ||
| +/* source3 register number */
 | ||
| +#define SOURCE3_REGNUM 28
 | ||
| +
 | ||
| +/* The register number of the arg pointer register, which is used to access the
 | ||
| +   function's argument list.  On some machines, this is the same as the frame
 | ||
| +   pointer register.  On some machines, the hardware determines which register
 | ||
| +   this is.  On other machines, you can choose any register you wish for this
 | ||
| +   purpose.  If this is not the same register as the frame pointer register,
 | ||
| +   then you must mark it as a fixed register according to `FIXED_REGISTERS', or
 | ||
| +   arrange to be able to eliminate it.  */
 | ||
| +#define ARG_POINTER_REGNUM 29
 | ||
| +
 | ||
| +/* Pseudo-reg for condition code.  */
 | ||
| +#define CC_REGNUM 30
 | ||
| +
 | ||
| +/* Interrupt set/clear registers.  */
 | ||
| +#define INT_SET0_REGNUM 31
 | ||
| +#define INT_SET1_REGNUM 32
 | ||
| +#define INT_CLR0_REGNUM 33
 | ||
| +#define INT_CLR1_REGNUM 34
 | ||
| +
 | ||
| +/* Scratchpad registers.  */
 | ||
| +#define SCRATCHPAD0_REGNUM 35
 | ||
| +#define SCRATCHPAD1_REGNUM 36
 | ||
| +#define SCRATCHPAD2_REGNUM 37
 | ||
| +#define SCRATCHPAD3_REGNUM 38
 | ||
| +
 | ||
| +/* FDPIC register.  */
 | ||
| +#define FDPIC_REGNUM 16
 | ||
| +
 | ||
| +/* Number of hardware registers known to the compiler.  They receive numbers 0
 | ||
| +   through `FIRST_PSEUDO_REGISTER-1'; thus, the first pseudo register's number
 | ||
| +   really is assigned the number `FIRST_PSEUDO_REGISTER'.  */
 | ||
| +#define FIRST_PSEUDO_REGISTER 39
 | ||
| +
 | ||
| +/* An initializer that says which registers are used for fixed purposes all
 | ||
| +   throughout the compiled code and are therefore not available for general
 | ||
| +   allocation.  These would include the stack pointer, the frame pointer
 | ||
| +   (except on machines where that can be used as a general register when no
 | ||
| +   frame pointer is needed), the program counter on machines where that is
 | ||
| +   considered one of the addressable registers, and any other numbered register
 | ||
| +   with a standard use.
 | ||
| +
 | ||
| +   This information is expressed as a sequence of numbers, separated by commas
 | ||
| +   and surrounded by braces.  The Nth number is 1 if register N is fixed, 0
 | ||
| +   otherwise.
 | ||
| +
 | ||
| +   The table initialized from this macro, and the table initialized by the
 | ||
| +   following one, may be overridden at run time either automatically, by the
 | ||
| +   actions of the macro `CONDITIONAL_REGISTER_USAGE', or by the user with the
 | ||
| +   command options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'.  */
 | ||
| +#define FIXED_REGISTERS					\
 | ||
| +  {							\
 | ||
| +    0, 0, 0, 0, 0, 0, 0, 0,	/* d0 - d7 */		\
 | ||
| +    0, 0, 0, 0, 0, 0, 0, 1,	/* d8 - d15 */		\
 | ||
| +    0, 0, 0, 0, 0, 0, 0, 1,	/* a0 - a7 */		\
 | ||
| +    0, 0,			/* acc0 hi/lo */	\
 | ||
| +    0, 0,			/* acc1 hi/lo */	\
 | ||
| +    0,				/* source3 */		\
 | ||
| +    1,				/* arg */		\
 | ||
| +    1,				/* cc */		\
 | ||
| +    1, 1,			/* int_set[01] */	\
 | ||
| +    1, 1,			/* int_clr[01] */	\
 | ||
| +    1, 1, 1, 1			/* scratchpad[0123] */	\
 | ||
| +  }
 | ||
| +
 | ||
| +/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
 | ||
| +   general) by function calls as well as for fixed registers.  This macro
 | ||
| +   therefore identifies the registers that are not available for general
 | ||
| +   allocation of values that must live across function calls.
 | ||
| +
 | ||
| +   If a register has 0 in `CALL_USED_REGISTERS', the compiler automatically
 | ||
| +   saves it on function entry and restores it on function exit, if the register
 | ||
| +   is used within the function.  */
 | ||
| +#define CALL_USED_REGISTERS				\
 | ||
| +  {							\
 | ||
| +    1, 1, 1, 1, 1, 1, 1, 1,	/* d0 - d7 */		\
 | ||
| +    1, 1, 0, 0, 0, 0, 1, 1,	/* d8 - d15 */		\
 | ||
| +    1, 0, 0, 1, 1, 1, 0, 1,	/* a0 - a7 */		\
 | ||
| +    1, 1,			/* acc0 hi/lo */	\
 | ||
| +    1, 1,			/* acc1 hi/lo */	\
 | ||
| +    1,				/* source3 */		\
 | ||
| +    1,				/* arg */		\
 | ||
| +    1,				/* cc */		\
 | ||
| +    1, 1,			/* int_set[01] */	\
 | ||
| +    1, 1,			/* int_clr[01] */	\
 | ||
| +    1, 1, 1, 1			/* scratchpad[0123] */	\
 | ||
| +  }
 | ||
| +
 | ||
| +/* How to refer to registers in assembler output.
 | ||
| +   This sequence is indexed by compiler's hard-register-number (see above).  */
 | ||
| +
 | ||
| +/* A C initializer containing the assembler's names for the machine registers,
 | ||
| +   each one as a C string constant.  This is what translates register numbers
 | ||
| +   in the compiler into assembler language.  */
 | ||
| +#define REGISTER_NAMES						\
 | ||
| +  {								\
 | ||
| +    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",		\
 | ||
| +    "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",	\
 | ||
| +    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",		\
 | ||
| +    "acc0_hi", "acc0_lo",					\
 | ||
| +    "acc1_hi", "acc1_lo",					\
 | ||
| +    "source3",							\
 | ||
| +    "arg",							\
 | ||
| +    "cc",							\
 | ||
| +    "int_set0", "int_set1",					\
 | ||
| +    "int_clr0", "int_clr1",					\
 | ||
| +    "scratchpad0", "scratchpad1", "scratchpad2", "scratchpad3"	\
 | ||
| +  }
 | ||
| +
 | ||
| +#define CONDITIONAL_REGISTER_USAGE				\
 | ||
| +  ubicom32_conditional_register_usage ();
 | ||
| +
 | ||
| +/* Order of allocation of registers.  */
 | ||
| +
 | ||
| +/* If defined, an initializer for a vector of integers, containing the numbers
 | ||
| +   of hard registers in the order in which GNU CC should prefer to use them
 | ||
| +   (from most preferred to least).
 | ||
| +
 | ||
| +   For Ubicom32 we try using caller-clobbered data registers first, then
 | ||
| +   callee-saved data registers, then caller-clobbered address registers,
 | ||
| +   then callee-saved address registers and finally everything else.
 | ||
| +
 | ||
| +   The caller-clobbered registers are usually slightly cheaper to use because
 | ||
| +   there's no need to save/restore.  */
 | ||
| +#define REG_ALLOC_ORDER						\
 | ||
| +  {								\
 | ||
| +    0, 1, 2, 3, 4,		/* d0 - d4 */			\
 | ||
| +    5, 6, 7, 8, 9,		/* d5 - d9 */			\
 | ||
| +    14,				/* d14 */			\
 | ||
| +    10, 11, 12, 13,		/* d10 - d13 */			\
 | ||
| +    19, 20, 16, 21,		/* a3, a4, a0, a5 */		\
 | ||
| +    17, 18, 22,			/* a1, a2, a6 */		\
 | ||
| +    24, 25,			/* acc0 hi/lo */		\
 | ||
| +    26, 27,			/* acc0 hi/lo */		\
 | ||
| +    28				/* source3 */			\
 | ||
| +  }
 | ||
| +
 | ||
| +/* C expression for the number of consecutive hard registers, starting at
 | ||
| +   register number REGNO, required to hold a value of mode MODE.  */
 | ||
| +#define HARD_REGNO_NREGS(REGNO, MODE) \
 | ||
| +  ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 | ||
| +
 | ||
| +/* Most registers can hold QImode, HImode and SImode values but we have to
 | ||
| +   be able to indicate any hard registers that cannot hold values with some
 | ||
| +   modes.  */
 | ||
| +#define HARD_REGNO_MODE_OK(REGNO, MODE) \
 | ||
| +  ubicom32_hard_regno_mode_ok(REGNO, MODE)
 | ||
| +
 | ||
| +/* We can rename most registers aside from the FDPIC register if we're using
 | ||
| +   FDPIC.  */
 | ||
| +#define HARD_REGNO_RENAME_OK(from, to) (TARGET_FDPIC ? ((to) != FDPIC_REGNUM) : 1)
 | ||
| +
 | ||
| +/* A C expression that is nonzero if it is desirable to choose register
 | ||
| +   allocation so as to avoid move instructions between a value of mode MODE1
 | ||
| +   and a value of mode MODE2.
 | ||
| +
 | ||
| +   If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, MODE2)' are
 | ||
| +   ever different for any R, then `MODES_TIEABLE_P (MODE1, MODE2)' must be
 | ||
| +   zero.  */
 | ||
| +#define MODES_TIEABLE_P(MODE1, MODE2) 1
 | ||
| +
 | ||
| +/* An enumeral type that must be defined with all the register class names as
 | ||
| +   enumeral values.  `NO_REGS' must be first.  `ALL_REGS' must be the last
 | ||
| +   register class, followed by one more enumeral value, `LIM_REG_CLASSES',
 | ||
| +   which is not a register class but rather tells how many classes there are.
 | ||
| +
 | ||
| +   Each register class has a number, which is the value of casting the class
 | ||
| +   name to type `int'.  The number serves as an index in many of the tables
 | ||
| +   described below.  */
 | ||
| +
 | ||
| +enum reg_class
 | ||
| +{
 | ||
| +  NO_REGS,
 | ||
| +  DATA_REGS,
 | ||
| +  FDPIC_REG,
 | ||
| +  ADDRESS_REGS,
 | ||
| +  ALL_ADDRESS_REGS,
 | ||
| +  ACC_LO_REGS,
 | ||
| +  ACC_REGS,
 | ||
| +  CC_REG,
 | ||
| +  DATA_ACC_REGS,
 | ||
| +  SOURCE3_REG,
 | ||
| +  SPECIAL_REGS,
 | ||
| +  GENERAL_REGS,
 | ||
| +  ALL_REGS,
 | ||
| +  LIM_REG_CLASSES
 | ||
| +};
 | ||
| +
 | ||
| +/* The number of distinct register classes.  */
 | ||
| +#define N_REG_CLASSES (int) LIM_REG_CLASSES
 | ||
| +
 | ||
| +/* An initializer containing the names of the register classes as C string
 | ||
| +   constants.  These names are used in writing some of the debugging dumps.  */
 | ||
| +
 | ||
| +#define REG_CLASS_NAMES		\
 | ||
| +{				\
 | ||
| +  "NO_REGS",			\
 | ||
| +  "DATA_REGS",			\
 | ||
| +  "FDPIC_REG",			\
 | ||
| +  "ADDRESS_REGS",		\
 | ||
| +  "ALL_ADDRESS_REGS",		\
 | ||
| +  "ACC_LO_REGS",		\
 | ||
| +  "ACC_REGS",			\
 | ||
| +  "CC_REG",			\
 | ||
| +  "DATA_ACC_REGS",		\
 | ||
| +  "SOURCE3_REG",		\
 | ||
| +  "SPECIAL_REGS",		\
 | ||
| +  "GENERAL_REGS",		\
 | ||
| +  "ALL_REGS",			\
 | ||
| +  "LIM_REGS"			\
 | ||
| +}
 | ||
| +
 | ||
| +/* An initializer containing the contents of the register classes, as integers
 | ||
| +   which are bit masks.  The Nth integer specifies the contents of class N.
 | ||
| +   The way the integer MASK is interpreted is that register R is in the class
 | ||
| +   if `MASK & (1 << R)' is 1.
 | ||
| +
 | ||
| +   When the machine has more than 32 registers, an integer does not suffice.
 | ||
| +   Then the integers are replaced by sub-initializers, braced groupings
 | ||
| +   containing several integers.  Each sub-initializer must be suitable as an
 | ||
| +   initializer for the type `HARD_REG_SET' which is defined in
 | ||
| +   `hard-reg-set.h'.  */
 | ||
| +#define REG_CLASS_CONTENTS					\
 | ||
| +{								\
 | ||
| +  {0x00000000, 0x00000000},	/* No regs */			\
 | ||
| +  {0x0000ffff, 0x00000000},	/* DATA_REGS */			\
 | ||
| +  {0x00010000, 0x00000000},	/* FDPIC_REG */			\
 | ||
| +  {0x20fe0000, 0x00000000},	/* ADDRESS_REGS */		\
 | ||
| +  {0x20ff0000, 0x00000000},	/* ALL_ADDRESS_REGS */		\
 | ||
| +  {0x0a000000, 0x00000000},	/* ACC_LO_REGS */		\
 | ||
| +  {0x0f000000, 0x00000000},	/* ACC_REGS */			\
 | ||
| +  {0x40000000, 0x00000000},	/* CC_REG */			\
 | ||
| +  {0x0f00ffff, 0x00000000},	/* DATA_ACC_REGS */		\
 | ||
| +  {0x10000000, 0x00000000},	/* SOURGE3_REG */		\
 | ||
| +  {0x80000000, 0x0000007f},	/* SPECIAL_REGS */		\
 | ||
| +  {0xbfffffff, 0x0000007f},	/* GENERAL_REGS */		\
 | ||
| +  {0xbfffffff, 0x0000007f}	/* ALL_REGS	*/		\
 | ||
| +}
 | ||
| +
 | ||
| +extern enum reg_class const ubicom32_regclass_map[FIRST_PSEUDO_REGISTER];
 | ||
| +
 | ||
| +/* A C expression whose value is a register class containing hard register
 | ||
| +   REGNO.  In general there is more than one such class; choose a class which
 | ||
| +   is "minimal", meaning that no smaller class also contains the register.  */
 | ||
| +#define REGNO_REG_CLASS(REGNO) (ubicom32_regclass_map[REGNO])
 | ||
| +
 | ||
| +#define IRA_COVER_CLASSES		\
 | ||
| +{					\
 | ||
| +  GENERAL_REGS,				\
 | ||
| +  LIM_REG_CLASSES			\
 | ||
| +}
 | ||
| +
 | ||
| +/* Ubicom32 base registers must be address registers since addresses can
 | ||
| +   only be reached via address registers.  */
 | ||
| +#define BASE_REG_CLASS ALL_ADDRESS_REGS
 | ||
| +
 | ||
| +/* Ubicom32 index registers must be data registers since we cannot add
 | ||
| +   two address registers together to form an address.  */
 | ||
| +#define INDEX_REG_CLASS DATA_REGS
 | ||
| +
 | ||
| +/* A C expression which is nonzero if register number NUM is suitable for use
 | ||
| +   as a base register in operand addresses.  It may be either a suitable hard
 | ||
| +   register or a pseudo register that has been allocated such a hard register.  */
 | ||
| +
 | ||
| +#ifndef REG_OK_STRICT
 | ||
| +#define REGNO_OK_FOR_BASE_P(regno) \
 | ||
| +  ubicom32_regno_ok_for_base_p (regno, 0)
 | ||
| +#else
 | ||
| +#define REGNO_OK_FOR_BASE_P(regno) \
 | ||
| +  ubicom32_regno_ok_for_base_p (regno, 1)
 | ||
| +#endif
 | ||
| +
 | ||
| +/* A C expression which is nonzero if register number NUM is suitable for use
 | ||
| +   as an index register in operand addresses.  It may be either a suitable hard
 | ||
| +   register or a pseudo register that has been allocated such a hard register.
 | ||
| +
 | ||
| +   The difference between an index register and a base register is that the
 | ||
| +   index register may be scaled.  If an address involves the sum of two
 | ||
| +   registers, neither one of them scaled, then either one may be labeled the
 | ||
| +   "base" and the other the "index"; but whichever labeling is used must fit
 | ||
| +   the machine's constraints of which registers may serve in each capacity.
 | ||
| +   The compiler will try both labelings, looking for one that is valid, and
 | ||
| +   will reload one or both registers only if neither labeling works.  */
 | ||
| +#ifndef REG_OK_STRICT
 | ||
| +#define REGNO_OK_FOR_INDEX_P(regno) \
 | ||
| +  ubicom32_regno_ok_for_index_p (regno, 0)
 | ||
| +#else
 | ||
| +#define REGNO_OK_FOR_INDEX_P(regno) \
 | ||
| +  ubicom32_regno_ok_for_index_p (regno, 1)
 | ||
| +#endif
 | ||
| +
 | ||
| +/* Attempt to restrict the register class we need to copy value X intoto the
 | ||
| +   would-be register class CLASS.  Most things are fine for Ubicom32 but we
 | ||
| +   have to restrict certain types of address loads.  */
 | ||
| +#define PREFERRED_RELOAD_CLASS(X, CLASS) \
 | ||
| +  ubicom32_preferred_reload_class (X, CLASS)
 | ||
| +
 | ||
| +/* A C expression for the maximum number of consecutive registers of
 | ||
| +   class CLASS needed to hold a value of mode MODE.  For Ubicom32 this
 | ||
| +   is pretty much identical to HARD_REGNO_NREGS.  */
 | ||
| +#define CLASS_MAX_NREGS(CLASS, MODE)	\
 | ||
| +  ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 | ||
| +
 | ||
| +/* For Ubicom32 the stack grows downwards when we push a word onto the stack
 | ||
| +   - i.e. it moves to a smaller address.  */
 | ||
| +#define STACK_GROWS_DOWNWARD 1
 | ||
| +
 | ||
| +/* Offset from the frame pointer to the first local variable slot to
 | ||
| +   be allocated.  */
 | ||
| +#define STARTING_FRAME_OFFSET 0
 | ||
| +
 | ||
| +/* Offset from the argument pointer register to the first argument's
 | ||
| +   address.  */
 | ||
| +#define FIRST_PARM_OFFSET(FNDECL) 0
 | ||
| +
 | ||
| +/* A C expression whose value is RTL representing the value of the return
 | ||
| +   address for the frame COUNT steps up from the current frame, after the
 | ||
| +   prologue.  FRAMEADDR is the frame pointer of the COUNT frame, or the frame
 | ||
| +   pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
 | ||
| +   defined.
 | ||
| +
 | ||
| +   The value of the expression must always be the correct address when COUNT is
 | ||
| +   zero, but may be `NULL_RTX' if there is not way to determine the return
 | ||
| +   address of other frames.  */
 | ||
| +#define RETURN_ADDR_RTX(COUNT, FRAME) \
 | ||
| +  ubicom32_return_addr_rtx (COUNT, FRAME)
 | ||
| +
 | ||
| +/* Register That Address the Stack Frame.  */
 | ||
| +
 | ||
| +/* We don't actually require a frame pointer in most functions with the
 | ||
| +   Ubicom32 architecture so we allow it to be eliminated.  */
 | ||
| +#define FRAME_POINTER_REQUIRED 0
 | ||
| +
 | ||
| +/* Macro that defines a table of register pairs used to eliminate unecessary
 | ||
| +   registers that point into the stack frame.
 | ||
| +
 | ||
| +   For Ubicom32 we don't generally need an arg pointer of a frame pointer
 | ||
| +   so we allow the arg pointer to be replaced by either the frame pointer or
 | ||
| +   the stack pointer.  We also allow the frame pointer to be replaced by
 | ||
| +   the stack pointer.  */
 | ||
| +#define ELIMINABLE_REGS					\
 | ||
| +{							\
 | ||
| +  {ARG_POINTER_REGNUM,	 STACK_POINTER_REGNUM},		\
 | ||
| +  {ARG_POINTER_REGNUM,	 FRAME_POINTER_REGNUM},		\
 | ||
| +  {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}		\
 | ||
| +}
 | ||
| +
 | ||
| +/* Let the compiler know that we want to use the ELIMINABLE_REGS macro
 | ||
| +   above.  */
 | ||
| +#define CAN_ELIMINATE(FROM, TO) 1
 | ||
| +
 | ||
| +/* 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) \
 | ||
| +  (OFFSET) = ubicom32_initial_elimination_offset (FROM, TO)
 | ||
| +
 | ||
| +/* If defined, the maximum amount of space required for outgoing arguments will
 | ||
| +   be computed and placed into the variable
 | ||
| +   `current_function_outgoing_args_size'.  No space will be pushed onto the
 | ||
| +   stack for each call; instead, the function prologue should increase the
 | ||
| +   stack frame size by this amount.
 | ||
| +
 | ||
| +   Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is not
 | ||
| +   proper.  */
 | ||
| +#define ACCUMULATE_OUTGOING_ARGS 1
 | ||
| +
 | ||
| +/* Define this macro if functions should assume that stack space has been
 | ||
| +   allocated for arguments even when their values are passed in registers.
 | ||
| +
 | ||
| +   The value of this macro is the size, in bytes, of the area reserved for
 | ||
| +   arguments passed in registers for the function represented by FNDECL.
 | ||
| +
 | ||
| +   This space can be allocated by the caller, or be a part of the
 | ||
| +   machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says
 | ||
| +   which.  */
 | ||
| +#define REG_PARM_STACK_SPACE(FNDECL) ubicom32_reg_parm_stack_space(FNDECL)
 | ||
| +
 | ||
| +/* A C expression that should indicate the number of bytes of its own arguments
 | ||
| +   that a function pops on returning, or 0 if the function pops no arguments
 | ||
| +   and the caller must therefore pop them all after the function returns.
 | ||
| +
 | ||
| +   FUNDECL is a C variable whose value is a tree node that describes the
 | ||
| +   function in question.  Normally it is a node of type `FUNCTION_DECL' that
 | ||
| +   describes the declaration of the function.  From this it is possible to
 | ||
| +   obtain the DECL_MACHINE_ATTRIBUTES of the function.
 | ||
| +
 | ||
| +   FUNTYPE is a C variable whose value is a tree node that describes the
 | ||
| +   function in question.  Normally it is a node of type `FUNCTION_TYPE' that
 | ||
| +   describes the data type of the function.  From this it is possible to obtain
 | ||
| +   the data types of the value and arguments (if known).
 | ||
| +
 | ||
| +   When a call to a library function is being considered, FUNTYPE will contain
 | ||
| +   an identifier node for the library function.  Thus, if you need to
 | ||
| +   distinguish among various library functions, you can do so by their names.
 | ||
| +   Note that "library function" in this context means a function used to
 | ||
| +   perform arithmetic, whose name is known specially in the compiler and was
 | ||
| +   not mentioned in the C code being compiled.
 | ||
| +
 | ||
| +   STACK-SIZE is the number of bytes of arguments passed on the stack.  If a
 | ||
| +   variable number of bytes is passed, it is zero, and argument popping will
 | ||
| +   always be the responsibility of the calling function.
 | ||
| +
 | ||
| +   On the Vax, all functions always pop their arguments, so the definition of
 | ||
| +   this macro is STACK-SIZE.  On the 68000, using the standard calling
 | ||
| +   convention, no functions pop their arguments, so the value of the macro is
 | ||
| +   always 0 in this case.  But an alternative calling convention is available
 | ||
| +   in which functions that take a fixed number of arguments pop them but other
 | ||
| +   functions (such as `printf') pop nothing (the caller pops all).  When this
 | ||
| +   convention is in use, FUNTYPE is examined to determine whether a function
 | ||
| +   takes a fixed number of arguments.  */
 | ||
| +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
 | ||
| +
 | ||
| +/* A C expression that controls whether a function argument is passed in a
 | ||
| +   register, and which register.
 | ||
| +
 | ||
| +   The arguments are CUM, of type CUMULATIVE_ARGS, which summarizes (in a way
 | ||
| +   defined by INIT_CUMULATIVE_ARGS and FUNCTION_ARG_ADVANCE) all of the previous
 | ||
| +   arguments so far passed in registers; MODE, the machine mode of the argument;
 | ||
| +   TYPE, the data type of the argument as a tree node or 0 if that is not known
 | ||
| +   (which happens for C support library functions); and NAMED, which is 1 for an
 | ||
| +   ordinary argument and 0 for nameless arguments that correspond to `...' in the
 | ||
| +   called function's prototype.
 | ||
| +
 | ||
| +   The value of the expression should either be a `reg' RTX for the hard
 | ||
| +   register in which to pass the argument, or zero to pass the argument on the
 | ||
| +   stack.
 | ||
| +
 | ||
| +   For machines like the Vax and 68000, where normally all arguments are
 | ||
| +   pushed, zero suffices as a definition.
 | ||
| +
 | ||
| +   The usual way to make the ANSI library `stdarg.h' work on a machine where
 | ||
| +   some arguments are usually passed in registers, is to cause nameless
 | ||
| +   arguments to be passed on the stack instead.  This is done by making
 | ||
| +   `FUNCTION_ARG' return 0 whenever NAMED is 0.
 | ||
| +
 | ||
| +   You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the definition of
 | ||
| +   this macro to determine if this argument is of a type that must be passed in
 | ||
| +   the stack.  If `REG_PARM_STACK_SPACE' is not defined and `FUNCTION_ARG'
 | ||
| +   returns non-zero for such an argument, the compiler will abort.  If
 | ||
| +   `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the
 | ||
| +   stack and then loaded into a register.  */
 | ||
| +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
 | ||
| +  function_arg (&CUM, MODE, TYPE, NAMED)
 | ||
| +
 | ||
| +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
 | ||
| +  function_incoming_arg (&CUM, MODE, TYPE, NAMED)
 | ||
| +
 | ||
| +/* A C expression for the number of words, at the beginning of an argument,
 | ||
| +   must be put in registers.  The value must be zero for arguments that are
 | ||
| +   passed entirely in registers or that are entirely pushed on the stack.
 | ||
| +
 | ||
| +   On some machines, certain arguments must be passed partially in registers
 | ||
| +   and partially in memory.  On these machines, typically the first N words of
 | ||
| +   arguments are passed in registers, and the rest on the stack.  If a
 | ||
| +   multi-word argument (a `double' or a structure) crosses that boundary, its
 | ||
| +   first few words must be passed in registers and the rest must be pushed.
 | ||
| +   This macro tells the compiler when this occurs, and how many of the words
 | ||
| +   should go in registers.
 | ||
| +
 | ||
| +   `FUNCTION_ARG' for these arguments should return the first register to be
 | ||
| +   used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
 | ||
| +   the called function.  */
 | ||
| +
 | ||
| +/* A C expression that indicates when an argument must be passed by reference.
 | ||
| +   If nonzero for an argument, a copy of that argument is made in memory and a
 | ||
| +   pointer to the argument is passed instead of the argument itself.  The
 | ||
| +   pointer is passed in whatever way is appropriate for passing a pointer to
 | ||
| +   that type.
 | ||
| +
 | ||
| +   On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable
 | ||
| +   definition of this macro might be
 | ||
| +	#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)  \
 | ||
| +	  MUST_PASS_IN_STACK (MODE, TYPE)  */
 | ||
| +
 | ||
| +/* If defined, a C expression that indicates when it is the called function's
 | ||
| +   responsibility to make a copy of arguments passed by invisible reference.
 | ||
| +   Normally, the caller makes a copy and passes the address of the copy to the
 | ||
| +   routine being called.  When FUNCTION_ARG_CALLEE_COPIES is defined and is
 | ||
| +   nonzero, the caller does not make a copy.  Instead, it passes a pointer to
 | ||
| +   the "live" value.  The called function must not modify this value.  If it
 | ||
| +   can be determined that the value won't be modified, it need not make a copy;
 | ||
| +   otherwise a copy must be made.  */
 | ||
| +
 | ||
| +/* A C type for declaring a variable that is used as the first argument of
 | ||
| +   `FUNCTION_ARG' and other related values.  For some target machines, the type
 | ||
| +   `int' suffices and can hold the number of bytes of argument so far.
 | ||
| +
 | ||
| +   There is no need to record in `CUMULATIVE_ARGS' anything about the arguments
 | ||
| +   that have been passed on the stack.  The compiler has other variables to
 | ||
| +   keep track of that.  For target machines on which all arguments are passed
 | ||
| +   on the stack, there is no need to store anything in `CUMULATIVE_ARGS';
 | ||
| +   however, the data structure must exist and should not be empty, so use
 | ||
| +   `int'.  */
 | ||
| +struct cum_arg
 | ||
| +{
 | ||
| +  int nbytes;
 | ||
| +  int reg;
 | ||
| +  int stdarg;
 | ||
| +};
 | ||
| +#define CUMULATIVE_ARGS struct cum_arg
 | ||
| +
 | ||
| +/* A C statement (sans semicolon) for initializing the variable CUM for the
 | ||
| +   state at the beginning of the argument list.  The variable has type
 | ||
| +   `CUMULATIVE_ARGS'.  The value of FNTYPE is the tree node for the data type
 | ||
| +   of the function which will receive the args, or 0 if the args are to a
 | ||
| +   compiler support library function.  The value of INDIRECT is nonzero when
 | ||
| +   processing an indirect call, for example a call through a function pointer.
 | ||
| +   The value of INDIRECT is zero for a call to an explicitly named function, a
 | ||
| +   library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
 | ||
| +   arguments for the function being compiled.
 | ||
| +
 | ||
| +   When processing a call to a compiler support library function, LIBNAME
 | ||
| +   identifies which one.  It is a `symbol_ref' rtx which contains the name of
 | ||
| +   the function, as a string.  LIBNAME is 0 when an ordinary C function call is
 | ||
| +   being processed.  Thus, each time this macro is called, either LIBNAME or
 | ||
| +   FNTYPE is nonzero, but never both of them at once.  */
 | ||
| +
 | ||
| +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT, NAMED_ARGS)	\
 | ||
| + init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT);
 | ||
| +
 | ||
| +/* A C statement (sans semicolon) to update the summarizer variable CUM to
 | ||
| +   advance past an argument in the argument list.  The values MODE, TYPE and
 | ||
| +   NAMED describe that argument.  Once this is done, the variable CUM is
 | ||
| +   suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
 | ||
| +
 | ||
| +   This macro need not do anything if the argument in question was passed on
 | ||
| +   the stack.  The compiler knows how to track the amount of stack space used
 | ||
| +   for arguments without any special help.  */
 | ||
| +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)	\
 | ||
| + ((CUM).nbytes += ((MODE) != BLKmode			\
 | ||
| +		   ? (GET_MODE_SIZE (MODE) + 3) & ~3	\
 | ||
| +		   : (int_size_in_bytes (TYPE) + 3) & ~3))
 | ||
| +
 | ||
| +/* For the Ubicom32 we define the upper function argument register here.  */
 | ||
| +#define UBICOM32_FUNCTION_ARG_REGS 10
 | ||
| +
 | ||
| +/* A C expression that is nonzero if REGNO is the number of a hard register in
 | ||
| +   which function arguments are sometimes passed.  This does *not* include
 | ||
| +   implicit arguments such as the static chain and the structure-value address.
 | ||
| +   On many machines, no registers can be used for this purpose since all
 | ||
| +   function arguments are pushed on the stack.  */
 | ||
| +#define FUNCTION_ARG_REGNO_P(N) ((N) < UBICOM32_FUNCTION_ARG_REGS)
 | ||
| +
 | ||
| +
 | ||
| +/* How Scalar Function Values are Returned.  */
 | ||
| +
 | ||
| +/* The number of the hard register that is used to return a scalar value from a
 | ||
| +   function call.  */
 | ||
| +#define RETURN_VALUE_REGNUM 0
 | ||
| +
 | ||
| +/* A C expression to create an RTX representing the place where a function
 | ||
| +   returns a value of data type VALTYPE.  VALTYPE is a tree node representing a
 | ||
| +   data type.  Write `TYPE_MODE (VALTYPE)' to get the machine mode used to
 | ||
| +   represent that type.  On many machines, only the mode is relevant.
 | ||
| +   (Actually, on most machines, scalar values are returned in the same place
 | ||
| +   regardless of mode).
 | ||
| +
 | ||
| +   If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same promotion
 | ||
| +   rules specified in `PROMOTE_MODE' if VALTYPE is a scalar type.
 | ||
| +
 | ||
| +   If the precise function being called is known, FUNC is a tree node
 | ||
| +   (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer.  This makes it
 | ||
| +   possible to use a different value-returning convention for specific
 | ||
| +   functions when all their calls are known.
 | ||
| +
 | ||
| +   `FUNCTION_VALUE' is not used for return vales with aggregate data types,
 | ||
| +   because these are returned in another way.  See `STRUCT_VALUE_REGNUM' and
 | ||
| +   related macros, below.  */
 | ||
| +#define FUNCTION_VALUE(VALTYPE, FUNC) \
 | ||
| +  gen_rtx_REG (TYPE_MODE (VALTYPE), FIRST_DATA_REGNUM)
 | ||
| +
 | ||
| +/* A C expression to create an RTX representing the place where a library
 | ||
| +   function returns a value of mode MODE.
 | ||
| +
 | ||
| +   Note that "library function" in this context means a compiler support
 | ||
| +   routine, used to perform arithmetic, whose name is known specially by the
 | ||
| +   compiler and was not mentioned in the C code being compiled.
 | ||
| +
 | ||
| +   The definition of `LIBRARY_VALUE' need not be concerned aggregate data
 | ||
| +   types, because none of the library functions returns such types.  */
 | ||
| +#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, FIRST_DATA_REGNUM)
 | ||
| +
 | ||
| +/* A C expression that is nonzero if REGNO is the number of a hard register in
 | ||
| +   which the values of called function may come back.
 | ||
| +
 | ||
| +   A register whose use for returning values is limited to serving as the
 | ||
| +   second of a pair (for a value of type `double', say) need not be recognized
 | ||
| +   by this macro.  So for most machines, this definition suffices:
 | ||
| +
 | ||
| +	#define FUNCTION_VALUE_REGNO_P(N) ((N) == RETURN)
 | ||
| +
 | ||
| +   If the machine has register windows, so that the caller and the called
 | ||
| +   function use different registers for the return value, this macro should
 | ||
| +   recognize only the caller's register numbers.  */
 | ||
| +#define FUNCTION_VALUE_REGNO_P(N) ((N) == FIRST_DATA_REGNUM)
 | ||
| +
 | ||
| +
 | ||
| +/* How Large Values are Returned.  */
 | ||
| +
 | ||
| +/* A C expression which can inhibit the returning of certain function values in
 | ||
| +   registers, based on the type of value.  A nonzero value says to return the
 | ||
| +   function value in memory, just as large structures are always returned.
 | ||
| +   Here TYPE will be a C expression of type `tree', representing the data type
 | ||
| +   of the value.
 | ||
| +
 | ||
| +   Note that values of mode `BLKmode' must be explicitly handled by this macro.
 | ||
| +   Also, the option `-fpcc-struct-return' takes effect regardless of this
 | ||
| +   macro.  On most systems, it is possible to leave the macro undefined; this
 | ||
| +   causes a default definition to be used, whose value is the constant 1 for
 | ||
| +   `BLKmode' values, and 0 otherwise.
 | ||
| +
 | ||
| +   Do not use this macro to indicate that structures and unions should always
 | ||
| +   be returned in memory.  You should instead use `DEFAULT_PCC_STRUCT_RETURN'
 | ||
| +   to indicate this.  */
 | ||
| +#define RETURN_IN_MEMORY(TYPE)  \
 | ||
| +  (int_size_in_bytes (TYPE) > 8 || TYPE_MODE (TYPE) == BLKmode)
 | ||
| +
 | ||
| +/* Define this macro to be 1 if all structure and union return values must be
 | ||
| +   in memory.  Since this results in slower code, this should be defined only
 | ||
| +   if needed for compatibility with other compilers or with an ABI.  If you
 | ||
| +   define this macro to be 0, then the conventions used for structure and union
 | ||
| +   return values are decided by the `RETURN_IN_MEMORY' macro.
 | ||
| +
 | ||
| +   If not defined, this defaults to the value 1.  */
 | ||
| +#define DEFAULT_PCC_STRUCT_RETURN 0
 | ||
| +
 | ||
| +/*   If the structure value address is not passed in a register, define
 | ||
| +     `STRUCT_VALUE' as an expression returning an RTX for the place
 | ||
| +     where the address is passed.  If it returns 0, the address is
 | ||
| +     passed as an "invisible" first argument.  */
 | ||
| +#define STRUCT_VALUE 0
 | ||
| +
 | ||
| +/* Define this macro as a C expression that is nonzero if the return
 | ||
| +   instruction or the function epilogue ignores the value of the stack pointer;
 | ||
| +   in other words, if it is safe to delete an instruction to adjust the stack
 | ||
| +   pointer before a return from the function.
 | ||
| +
 | ||
| +   Note that this macro's value is relevant only for functions for which frame
 | ||
| +   pointers are maintained.  It is never safe to delete a final stack
 | ||
| +   adjustment in a function that has no frame pointer, and the compiler knows
 | ||
| +   this regardless of `EXIT_IGNORE_STACK'.  */
 | ||
| +#define EXIT_IGNORE_STACK 1
 | ||
| +
 | ||
| +/* A C statement or compound statement to output to FILE some assembler code to
 | ||
| +   call the profiling subroutine `mcount'.  Before calling, the assembler code
 | ||
| +   must load the address of a counter variable into a register where `mcount'
 | ||
| +   expects to find the address.  The name of this variable is `LP' followed by
 | ||
| +   the number LABELNO, so you would generate the name using `LP%d' in a
 | ||
| +   `fprintf'.
 | ||
| +
 | ||
| +   The details of how the address should be passed to `mcount' are determined
 | ||
| +   by your operating system environment, not by GNU CC.  To figure them out,
 | ||
| +   compile a small program for profiling using the system's installed C
 | ||
| +   compiler and look at the assembler code that results.
 | ||
| +
 | ||
| +   This declaration must be present, but it can be an abort if profiling is
 | ||
| +   not implemented.  */
 | ||
| +
 | ||
| +#define FUNCTION_PROFILER(file, labelno) ubicom32_profiler(file, labelno)
 | ||
| +
 | ||
| +/* A C statement to output, on the stream FILE, assembler code for a block of
 | ||
| +   data that contains the constant parts of a trampoline.  This code should not
 | ||
| +   include a label--the label is taken care of automatically.  */
 | ||
| +#if 0
 | ||
| +#define TRAMPOLINE_TEMPLATE(FILE)			\
 | ||
| +  do {							\
 | ||
| +    fprintf (FILE, "\tadd -4,sp\n");			\
 | ||
| +    fprintf (FILE, "\t.long 0x0004fffa\n");		\
 | ||
| +    fprintf (FILE, "\tmov (0,sp),a0\n");		\
 | ||
| +    fprintf (FILE, "\tadd 4,sp\n");			\
 | ||
| +    fprintf (FILE, "\tmov (13,a0),a1\n");		\
 | ||
| +    fprintf (FILE, "\tmov (17,a0),a0\n");		\
 | ||
| +    fprintf (FILE, "\tjmp (a0)\n");			\
 | ||
| +    fprintf (FILE, "\t.long 0\n");			\
 | ||
| +    fprintf (FILE, "\t.long 0\n");			\
 | ||
| +  } while (0)
 | ||
| +#endif
 | ||
| +
 | ||
| +/* A C expression for the size in bytes of the trampoline, as an integer.  */
 | ||
| +#define TRAMPOLINE_SIZE 0x1b
 | ||
| +
 | ||
| +/* Alignment required for trampolines, in bits.
 | ||
| +
 | ||
| +   If you don't define this macro, the value of `BIGGEST_ALIGNMENT' is used for
 | ||
| +   aligning trampolines.  */
 | ||
| +#define TRAMPOLINE_ALIGNMENT 32
 | ||
| +
 | ||
| +/* A C statement to initialize the variable parts of a trampoline.  ADDR is an
 | ||
| +   RTX for the address of the trampoline; FNADDR is an RTX for the address of
 | ||
| +   the nested function; STATIC_CHAIN is an RTX for the static chain value that
 | ||
| +   should be passed to the function when it is called.  */
 | ||
| +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)			\
 | ||
| +{									\
 | ||
| +  emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 0x14)),	\
 | ||
| +		 (CXT));						\
 | ||
| +  emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 0x18)),	\
 | ||
| +		 (FNADDR));						\
 | ||
| +}
 | ||
| +
 | ||
| +/* Ubicom32 supports pre and post increment/decrement addressing.  */
 | ||
| +#define HAVE_POST_INCREMENT 1
 | ||
| +#define HAVE_PRE_INCREMENT 1
 | ||
| +#define HAVE_POST_DECREMENT 1
 | ||
| +#define HAVE_PRE_DECREMENT 1
 | ||
| +
 | ||
| +/* Ubicom32 supports pre and post address side-effects with constants
 | ||
| +   other than the size of the memory operand.  */
 | ||
| +#define HAVE_PRE_MODIFY_DISP 1
 | ||
| +#define HAVE_POST_MODIFY_DISP 1
 | ||
| +
 | ||
| +/* A C expression that is 1 if the RTX X is a constant which is a valid
 | ||
| +   address.  On most machines, this can be defined as `CONSTANT_P (X)',
 | ||
| +   but a few machines are more restrictive in which constant addresses
 | ||
| +   are supported.
 | ||
| +
 | ||
| +   `CONSTANT_P' accepts integer-values expressions whose values are not
 | ||
| +   explicitly known, such as `symbol_ref', `label_ref', and `high'
 | ||
| +   expressions and `const' arithmetic expressions, in addition to
 | ||
| +   `const_int' and `const_double' expressions.  */
 | ||
| +#define CONSTANT_ADDRESS_P(X)						\
 | ||
| +  (GET_CODE (X) == LABEL_REF						\
 | ||
| +   || (GET_CODE (X) == CONST						\
 | ||
| +       && GET_CODE (XEXP (X, 0)) == PLUS				\
 | ||
| +       && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF))
 | ||
| +
 | ||
| +/* Ubicom32 supports a maximum of 2 registers in a valid memory address.
 | ||
| +   One is always an address register while a second, optional, one may be a
 | ||
| +   data register.  */
 | ||
| +#define MAX_REGS_PER_ADDRESS 2
 | ||
| +
 | ||
| +/* A C compound statement with a conditional `goto LABEL;' executed if X (an
 | ||
| +   RTX) is a legitimate memory address on the target machine for a memory
 | ||
| +   operand of mode MODE.
 | ||
| +
 | ||
| +   It usually pays to define several simpler macros to serve as subroutines for
 | ||
| +   this one.  Otherwise it may be too complicated to understand.
 | ||
| +
 | ||
| +   This macro must exist in two variants: a strict variant and a non-strict
 | ||
| +   one.  The strict variant is used in the reload pass.  It must be defined so
 | ||
| +   that any pseudo-register that has not been allocated a hard register is
 | ||
| +   considered a memory reference.  In contexts where some kind of register is
 | ||
| +   required, a pseudo-register with no hard register must be rejected.
 | ||
| +
 | ||
| +   The non-strict variant is used in other passes.  It must be defined to
 | ||
| +   accept all pseudo-registers in every context where some kind of register is
 | ||
| +   required.
 | ||
| +
 | ||
| +   Compiler source files that want to use the strict variant of this macro
 | ||
| +   define the macro `REG_OK_STRICT'.  You should use an `#ifdef REG_OK_STRICT'
 | ||
| +   conditional to define the strict variant in that case and the non-strict
 | ||
| +   variant otherwise.
 | ||
| +
 | ||
| +   Subroutines to check for acceptable registers for various purposes (one for
 | ||
| +   base registers, one for index registers, and so on) are typically among the
 | ||
| +   subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'.  Then only these
 | ||
| +   subroutine macros need have two variants; the higher levels of macros may be
 | ||
| +   the same whether strict or not.
 | ||
| +
 | ||
| +   Normally, constant addresses which are the sum of a `symbol_ref' and an
 | ||
| +   integer are stored inside a `const' RTX to mark them as constant.
 | ||
| +   Therefore, there is no need to recognize such sums specifically as
 | ||
| +   legitimate addresses.  Normally you would simply recognize any `const' as
 | ||
| +   legitimate.
 | ||
| +
 | ||
| +   Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant sums that
 | ||
| +   are not marked with `const'.  It assumes that a naked `plus' indicates
 | ||
| +   indexing.  If so, then you *must* reject such naked constant sums as
 | ||
| +   illegitimate addresses, so that none of them will be given to
 | ||
| +   `PRINT_OPERAND_ADDRESS'.
 | ||
| +
 | ||
| +   On some machines, whether a symbolic address is legitimate depends on the
 | ||
| +   section that the address refers to.  On these machines, define the macro
 | ||
| +   `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
 | ||
| +   then check for it here.  When you see a `const', you will have to look
 | ||
| +   inside it to find the `symbol_ref' in order to determine the section.
 | ||
| +
 | ||
| +   The best way to modify the name string is by adding text to the beginning,
 | ||
| +   with suitable punctuation to prevent any ambiguity.  Allocate the new name
 | ||
| +   in `saveable_obstack'.  You will have to modify `ASM_OUTPUT_LABELREF' to
 | ||
| +   remove and decode the added text and output the name accordingly, and define
 | ||
| +   `STRIP_NAME_ENCODING' to access the original name string.
 | ||
| +
 | ||
| +   You can check the information stored here into the `symbol_ref' in the
 | ||
| +   definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
 | ||
| +   `PRINT_OPERAND_ADDRESS'.  */
 | ||
| +/* On the ubicom32, the value in the address register must be
 | ||
| +   in the same memory space/segment as the effective address.
 | ||
| +
 | ||
| +   This is problematical for reload since it does not understand
 | ||
| +   that base+index != index+base in a memory reference.  */
 | ||
| +
 | ||
| +#ifdef REG_OK_STRICT
 | ||
| +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)	\
 | ||
| +  if (ubicom32_legitimate_address_p (MODE, X, 1)) goto ADDR;
 | ||
| +#else
 | ||
| +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)	\
 | ||
| +  if (ubicom32_legitimate_address_p (MODE, X, 0)) goto ADDR;
 | ||
| +#endif
 | ||
| +
 | ||
| +/* Try machine-dependent ways of modifying an illegitimate address
 | ||
| +   to be legitimate.  If we find one, return the new, valid address.
 | ||
| +   This macro is used in only one place: `memory_address' in explow.c.
 | ||
| +
 | ||
| +   OLDX is the address as it was before break_out_memory_refs was called.
 | ||
| +   In some cases it is useful to look at this to decide what needs to be done.
 | ||
| +
 | ||
| +   MODE and WIN are passed so that this macro can use
 | ||
| +   GO_IF_LEGITIMATE_ADDRESS.
 | ||
| +
 | ||
| +   It is always safe for this macro to do nothing.  It exists to recognize
 | ||
| +   opportunities to optimize the output.
 | ||
| +
 | ||
| +   On RS/6000, first check for the sum of a register with a constant
 | ||
| +   integer that is out of range.  If so, generate code to add the
 | ||
| +   constant with the low-order 16 bits masked to the register and force
 | ||
| +   this result into another register (this can be done with `cau').
 | ||
| +   Then generate an address of REG+(CONST&0xffff), allowing for the
 | ||
| +   possibility of bit 16 being a one.
 | ||
| +
 | ||
| +   Then check for the sum of a register and something not constant, try to
 | ||
| +   load the other things into a register and return the sum.  */
 | ||
| +
 | ||
| +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)				\
 | ||
| +{									\
 | ||
| +   rtx result = ubicom32_legitimize_address ((X), (OLDX), (MODE));	\
 | ||
| +   if (result != NULL_RTX)						\
 | ||
| +     {									\
 | ||
| +       (X) = result;							\
 | ||
| +       goto WIN;							\
 | ||
| +     }									\
 | ||
| +}
 | ||
| +
 | ||
| +/* Try a machine-dependent way of reloading an illegitimate address
 | ||
| +   operand.  If we find one, push the reload and jump to WIN.  This
 | ||
| +   macro is used in only one place: `find_reloads_address' in reload.c.  */
 | ||
| +#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN)	\
 | ||
| +{									\
 | ||
| +  rtx new_rtx = ubicom32_legitimize_reload_address ((AD), (MODE), (OPNUM), (int)(TYPE));	\
 | ||
| +  if (new_rtx)								\
 | ||
| +    {									\
 | ||
| +      (AD) = new_rtx;							\
 | ||
| +      goto WIN;								\
 | ||
| +    }									\
 | ||
| +}
 | ||
| +
 | ||
| +/* A C statement or compound statement with a conditional `goto LABEL;'
 | ||
| +   executed if memory address X (an RTX) can have different meanings depending
 | ||
| +   on the machine mode of the memory reference it is used for or if the address
 | ||
| +   is valid for some modes but not others.
 | ||
| +
 | ||
| +   Autoincrement and autodecrement addresses typically have mode-dependent
 | ||
| +   effects because the amount of the increment or decrement is the size of the
 | ||
| +   operand being addressed.  Some machines have other mode-dependent addresses.
 | ||
| +   Many RISC machines have no mode-dependent addresses.
 | ||
| +
 | ||
| +   You may assume that ADDR is a valid address for the machine.  */
 | ||
| +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)	\
 | ||
| +  if (ubicom32_mode_dependent_address_p (ADDR))		\
 | ||
| +    goto LABEL;
 | ||
| +
 | ||
| +/* A C expression that is nonzero if X is a legitimate constant for an
 | ||
| +   immediate operand on the target machine.  You can assume that X
 | ||
| +   satisfies `CONSTANT_P', so you need not check this.  In fact, `1' is
 | ||
| +   a suitable definition for this macro on machines where anything
 | ||
| +   `CONSTANT_P' is valid.  */
 | ||
| +#define LEGITIMATE_CONSTANT_P(X) \
 | ||
| +  ubicom32_legitimate_constant_p ((X))
 | ||
| +
 | ||
| +/* Moves between registers are pretty-much single instructions for
 | ||
| +   Ubicom32.  We make this the default "2" that gcc likes.  */
 | ||
| +#define REGISTER_MOVE_COST(MODE, FROM, TO) 2
 | ||
| +
 | ||
| +/* This is a little bit of magic from the S390 port that wins 2% on code
 | ||
| +   size when building the Linux kernel!  Unfortunately while it wins on
 | ||
| +   that size the user-space apps built using FD-PIC don't improve and the
 | ||
| +   performance is lower because we put more pressure on the caches.  We may
 | ||
| +   want this back on some future CPU that has higher cache performance.  */
 | ||
| +/* #define IRA_HARD_REGNO_ADD_COST_MULTIPLIER(regno) 0.5 */
 | ||
| +
 | ||
| +/* Moves between registers and memory are more expensive than between
 | ||
| +   registers because we have caches and write buffers that slow things
 | ||
| +   down!  */
 | ||
| +#define MEMORY_MOVE_COST(MODE, CLASS, IN) 2
 | ||
| +
 | ||
| +/* A fall-through branch is very low cost but anything that changes the PC
 | ||
| +   incurs a major pipeline hazard.  We don't make the full extent of this
 | ||
| +   hazard visible because we hope that multiple threads will absorb much
 | ||
| +   of the cost and so we don't want a jump being replaced with, say, 7
 | ||
| +   instructions.  */
 | ||
| +#define BRANCH_COST(SPEED_P, PREDICTABLE_P) \
 | ||
| +  ((PREDICTABLE_P) ? 1 : 3)
 | ||
| +
 | ||
| +/* Define this macro as a C expression which is nonzero if accessing less than
 | ||
| +   a word of memory (i.e. a `char' or a `short') is no faster than accessing a
 | ||
| +   word of memory, i.e., if such access require more than one instruction or if
 | ||
| +   there is no difference in cost between byte and (aligned) word loads.
 | ||
| +
 | ||
| +   When this macro is not defined, the compiler will access a field by finding
 | ||
| +   the smallest containing object; when it is defined, a fullword load will be
 | ||
| +   used if alignment permits.  Unless bytes accesses are faster than word
 | ||
| +   accesses, using word accesses is preferable since it may eliminate
 | ||
| +   subsequent memory access if subsequent accesses occur to other fields in the
 | ||
| +   same word of the structure, but to different bytes.  */
 | ||
| +#define SLOW_BYTE_ACCESS 0
 | ||
| +
 | ||
| +/* The number of scalar move insns which should be generated instead of a
 | ||
| +   string move insn or a library call.  Increasing the value will always make
 | ||
| +   code faster, but eventually incurs high cost in increased code size.
 | ||
| +
 | ||
| +   If you don't define this, a reasonable default is used.  */
 | ||
| +/* According to expr.c, a value of around 6 should minimize code size.  */
 | ||
| +#define MOVE_RATIO(SPEED) 6
 | ||
| +
 | ||
| +/* We're much better off calling a constant function address with the
 | ||
| +   Ubicom32 architecture because we have an opcode for doing so.  Don't
 | ||
| +   let the compiler extract function addresses as common subexpressions
 | ||
| +   into an address register.  */
 | ||
| +#define NO_FUNCTION_CSE
 | ||
| +
 | ||
| +#define SELECT_CC_MODE(OP, X, Y) ubicom32_select_cc_mode (OP, X, Y)
 | ||
| +
 | ||
| +#define REVERSIBLE_CC_MODE(MODE) 1
 | ||
| +
 | ||
| +/* Canonicalize a comparison from one we don't have to one we do have.  */
 | ||
| +#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
 | ||
| +  ubicom32_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
 | ||
| +
 | ||
| +/* Dividing the output into sections.  */
 | ||
| +
 | ||
| +/* A C expression whose value is a string containing the assembler operation
 | ||
| +   that should precede instructions and read-only data.  Normally `".text"' is
 | ||
| +   right.  */
 | ||
| +#define TEXT_SECTION_ASM_OP "\t.section .text"
 | ||
| +
 | ||
| +/* A C expression whose value is a string containing the assembler operation to
 | ||
| +   identify the following data as writable initialized data.  Normally
 | ||
| +   `".data"' is right.  */
 | ||
| +#define DATA_SECTION_ASM_OP "\t.section .data"
 | ||
| +
 | ||
| +
 | ||
| +/* If defined, a C expression whose value is a string containing the
 | ||
| +   assembler operation to identify the following data as
 | ||
| +   uninitialized global data.  If not defined, and neither
 | ||
| +   `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined,
 | ||
| +   uninitialized global data will be output in the data section if
 | ||
| +   `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
 | ||
| +   used.  */
 | ||
| +#define BSS_SECTION_ASM_OP "\t.section .bss"
 | ||
| +
 | ||
| +/* This is how we tell the assembler that a symbol is weak.  */
 | ||
| +
 | ||
| +#define ASM_WEAKEN_LABEL(FILE, NAME)	\
 | ||
| +  do					\
 | ||
| +    {					\
 | ||
| +      fputs ("\t.weak\t", (FILE));	\
 | ||
| +      assemble_name ((FILE), (NAME));	\
 | ||
| +      fputc ('\n', (FILE));		\
 | ||
| +    }					\
 | ||
| +  while (0)
 | ||
| +
 | ||
| +/* The Overall Framework of an Assembler File.  */
 | ||
| +
 | ||
| +#undef SET_ASM_OP
 | ||
| +#define SET_ASM_OP "\t.set\t"
 | ||
| +
 | ||
| +/* A C string constant describing how to begin a comment in the target
 | ||
| +   assembler language.  The compiler assumes that the comment will end at the
 | ||
| +   end of the line.  */
 | ||
| +#define ASM_COMMENT_START ";"
 | ||
| +
 | ||
| +/* A C string constant for text to be output before each `asm' statement or
 | ||
| +   group of consecutive ones.  Normally this is `"#APP"', which is a comment
 | ||
| +   that has no effect on most assemblers but tells the GNU assembler that it
 | ||
| +   must check the lines that follow for all valid assembler constructs.  */
 | ||
| +#define ASM_APP_ON "#APP\n"
 | ||
| +
 | ||
| +/* A C string constant for text to be output after each `asm' statement or
 | ||
| +   group of consecutive ones.  Normally this is `"#NO_APP"', which tells the
 | ||
| +   GNU assembler to resume making the time-saving assumptions that are valid
 | ||
| +   for ordinary compiler output.  */
 | ||
| +#define ASM_APP_OFF "#NO_APP\n"
 | ||
| +
 | ||
| +/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a separate,
 | ||
| +   explicit argument.  If you define this macro, it is used in place of
 | ||
| +   `ASM_OUTPUT_BSS', and gives you more flexibility in handling the required
 | ||
| +   alignment of the variable.  The alignment is specified as the number of
 | ||
| +   bits.
 | ||
| +
 | ||
| +   Try to use function `asm_output_aligned_bss' defined in file `varasm.c' when
 | ||
| +   defining this macro.  */
 | ||
| +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
 | ||
| +  asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
 | ||
| +
 | ||
| +/* A C expression to assign to OUTVAR (which is a variable of type `char *') a
 | ||
| +   newly allocated string made from the string NAME and the number NUMBER, with
 | ||
| +   some suitable punctuation added.  Use `alloca' to get space for the string.
 | ||
| +
 | ||
| +   The string will be used as an argument to `ASM_OUTPUT_LABELREF' to produce
 | ||
| +   an assembler label for an internal static variable whose name is NAME.
 | ||
| +   Therefore, the string must be such as to result in valid assembler code.
 | ||
| +   The argument NUMBER is different each time this macro is executed; it
 | ||
| +   prevents conflicts between similarly-named internal static variables in
 | ||
| +   different scopes.
 | ||
| +
 | ||
| +   Ideally this string should not be a valid C identifier, to prevent any
 | ||
| +   conflict with the user's own symbols.  Most assemblers allow periods or
 | ||
| +   percent signs in assembler symbols; putting at least one of these between
 | ||
| +   the name and the number will suffice.  */
 | ||
| +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO)	\
 | ||
| +  ((OUTPUT) = (char *) alloca (strlen ((NAME)) + 10),	\
 | ||
| +   sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO)))
 | ||
| +
 | ||
| +#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM)	\
 | ||
| +  sprintf (STRING, "*.%s%ld", PREFIX, (long)(NUM))
 | ||
| +/* A C statement to store into the string STRING a label whose name
 | ||
| +   is made from the string PREFIX and the number NUM.
 | ||
| +
 | ||
| +   This string, when output subsequently by `assemble_name', should
 | ||
| +   produce the output that `(*targetm.asm_out.internal_label)' would produce
 | ||
| +   with the same PREFIX and NUM.
 | ||
| +
 | ||
| +   If the string begins with `*', then `assemble_name' will output
 | ||
| +   the rest of the string unchanged.  It is often convenient for
 | ||
| +   `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way.  If the
 | ||
| +   string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to
 | ||
| +   output the string, and may change it.  (Of course,
 | ||
| +   `ASM_OUTPUT_LABELREF' is also part of your machine description, so
 | ||
| +   you should know what it does on your machine.)  */
 | ||
| +
 | ||
| +/* This says how to output assembler code to declare an
 | ||
| +   uninitialized external linkage data object.  Under SVR4,
 | ||
| +   the linker seems to want the alignment of data objects
 | ||
| +   to depend on their types.  We do exactly that here.  */
 | ||
| +
 | ||
| +#define COMMON_ASM_OP	"\t.comm\t"
 | ||
| +
 | ||
| +#undef  ASM_OUTPUT_COMMON
 | ||
| +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED)		\
 | ||
| +  do								\
 | ||
| +    {								\
 | ||
| +      fprintf ((FILE), "%s", COMMON_ASM_OP);			\
 | ||
| +      assemble_name ((FILE), (NAME));				\
 | ||
| +      fprintf ((FILE), ", %u\n", (SIZE));			\
 | ||
| +    }								\
 | ||
| +  while (0)
 | ||
| +
 | ||
| +/* This says how to output assembler code to declare an
 | ||
| +   uninitialized internal linkage data object.  Under SVR4,
 | ||
| +   the linker seems to want the alignment of data objects
 | ||
| +   to depend on their types.  We do exactly that here.  */
 | ||
| +#define LOCAL_ASM_OP	"\t.lcomm\t"
 | ||
| +
 | ||
| +#undef  ASM_OUTPUT_LOCAL
 | ||
| +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED)		\
 | ||
| +  do								\
 | ||
| +    {								\
 | ||
| +      fprintf ((FILE), "%s", LOCAL_ASM_OP);			\
 | ||
| +      assemble_name ((FILE), (NAME));				\
 | ||
| +      fprintf ((FILE), ", %u\n", (SIZE));			\
 | ||
| +    }								\
 | ||
| +  while (0)
 | ||
| +
 | ||
| +/* Globalizing directive for a label.  */
 | ||
| +#define GLOBAL_ASM_OP ".global\t"
 | ||
| +
 | ||
| +/* Output the operand of an instruction.  */
 | ||
| +#define PRINT_OPERAND(FILE, X, CODE) \
 | ||
| +  ubicom32_print_operand(FILE, X, CODE)
 | ||
| +
 | ||
| +/* Output the address of an operand.  */
 | ||
| +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
 | ||
| +  ubicom32_print_operand_address (FILE, ADDR)
 | ||
| +
 | ||
| +/* A C expression to output to STREAM some assembler code which will push hard
 | ||
| +   register number REGNO onto the stack.  The code need not be optimal, since
 | ||
| +   this macro is used only when profiling.  */
 | ||
| +#define ASM_OUTPUT_REG_PUSH(FILE, REGNO)
 | ||
| +
 | ||
| +/* A C expression to output to STREAM some assembler code which will pop hard
 | ||
| +   register number REGNO off of the stack.  The code need not be optimal, since
 | ||
| +   this macro is used only when profiling.  */
 | ||
| +#define ASM_OUTPUT_REG_POP(FILE, REGNO)
 | ||
| +
 | ||
| +/* This macro should be provided on machines where the addresses in a dispatch
 | ||
| +   table are relative to the table's own address.
 | ||
| +
 | ||
| +   The definition should be a C statement to output to the stdio stream STREAM
 | ||
| +   an assembler pseudo-instruction to generate a difference between two labels.
 | ||
| +   VALUE and REL are the numbers of two internal labels.  The definitions of
 | ||
| +   these labels are output using `ASM_OUTPUT_INTERNAL_LABEL', and they must be
 | ||
| +   printed in the same way here.  For example,
 | ||
| +
 | ||
| +	fprintf (STREAM, "\t.word L%d-L%d\n", VALUE, REL)  */
 | ||
| +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
 | ||
| +  fprintf (FILE, "\t%s .L%d-.L%d\n", ".long", VALUE, REL)
 | ||
| +
 | ||
| +/* This macro should be provided on machines where the addresses in a dispatch
 | ||
| +   table are absolute.
 | ||
| +
 | ||
| +   The definition should be a C statement to output to the stdio stream STREAM
 | ||
| +   an assembler pseudo-instruction to generate a reference to a label.  VALUE
 | ||
| +   is the number of an internal label whose definition is output using
 | ||
| +   `ASM_OUTPUT_INTERNAL_LABEL'.  For example,
 | ||
| +
 | ||
| +	fprintf (STREAM, "\t.word L%d\n", VALUE)  */
 | ||
| +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
 | ||
| +  fprintf (STREAM, "\t.word .L%d\n", VALUE)
 | ||
| +
 | ||
| +/* Switch into a generic section.  */
 | ||
| +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
 | ||
| +
 | ||
| +/* Assembler Commands for Alignment.  */
 | ||
| +
 | ||
| +#define ASM_OUTPUT_SKIP(STREAM, N) fprintf (STREAM, "\t.skip %d,0\n", N)
 | ||
| +/* A C statement to output to the stdio stream STREAM an assembler
 | ||
| +   instruction to advance the location counter by NBYTES bytes.
 | ||
| +   Those bytes should be zero when loaded.  NBYTES will be a C
 | ||
| +   expression of type `int'.  */
 | ||
| +
 | ||
| +/* A C statement to output to the stdio stream STREAM an assembler command to
 | ||
| +   advance the location counter to a multiple of 2 to the POWER bytes.  POWER
 | ||
| +   will be a C expression of type `int'.  */
 | ||
| +#define ASM_OUTPUT_ALIGN(FILE, LOG)	\
 | ||
| +  if ((LOG) != 0)			\
 | ||
| +    fprintf (FILE, "\t.align %d\n", (LOG))
 | ||
| +
 | ||
| +/* A C expression that returns the DBX register number for the compiler
 | ||
| +   register number REGNO.  In simple cases, the value of this expression may be
 | ||
| +   REGNO itself.  But sometimes there are some registers that the compiler
 | ||
| +   knows about and DBX does not, or vice versa.  In such cases, some register
 | ||
| +   may need to have one number in the compiler and another for DBX.
 | ||
| +
 | ||
| +   If two registers have consecutive numbers inside GNU CC, and they can be
 | ||
| +   used as a pair to hold a multiword value, then they *must* have consecutive
 | ||
| +   numbers after renumbering with `DBX_REGISTER_NUMBER'.  Otherwise, debuggers
 | ||
| +   will be unable to access such a pair, because they expect register pairs to
 | ||
| +   be consecutive in their own numbering scheme.
 | ||
| +
 | ||
| +   If you find yourself defining `DBX_REGISTER_NUMBER' in way that does not
 | ||
| +   preserve register pairs, then what you must do instead is redefine the
 | ||
| +   actual register numbering scheme.
 | ||
| +
 | ||
| +   This declaration is required.  */
 | ||
| +#define DBX_REGISTER_NUMBER(REGNO) REGNO
 | ||
| +
 | ||
| +/* A C expression that returns the integer offset value for an automatic
 | ||
| +   variable having address X (an RTL expression).  The default computation
 | ||
| +   assumes that X is based on the frame-pointer and gives the offset from the
 | ||
| +   frame-pointer.  This is required for targets that produce debugging output
 | ||
| +   for DBX or COFF-style debugging output for SDB and allow the frame-pointer
 | ||
| +   to be eliminated when the `-g' options is used.  */
 | ||
| +#define DEBUGGER_AUTO_OFFSET(X)						\
 | ||
| +  ((GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0)			\
 | ||
| +    + (frame_pointer_needed						\
 | ||
| +       ? 0 : -initial_elimination_offset (FRAME_POINTER_REGNUM,		\
 | ||
| +					  STACK_POINTER_REGNUM)))
 | ||
| +
 | ||
| +/* A C expression that returns the integer offset value for an argument having
 | ||
| +   address X (an RTL expression).  The nominal offset is OFFSET.  */
 | ||
| +#define DEBUGGER_ARG_OFFSET(OFFSET, X)					\
 | ||
| +  ((GET_CODE (X) == PLUS ? OFFSET : 0)					\
 | ||
| +    + (frame_pointer_needed						\
 | ||
| +       ? 0 : -initial_elimination_offset (ARG_POINTER_REGNUM,		\
 | ||
| +					  STACK_POINTER_REGNUM)))
 | ||
| +
 | ||
| +/* A C expression that returns the type of debugging output GNU CC produces
 | ||
| +   when the user specifies `-g' or `-ggdb'.  Define this if you have arranged
 | ||
| +   for GNU CC to support more than one format of debugging output.  Currently,
 | ||
| +   the allowable values are `DBX_DEBUG', `SDB_DEBUG', `DWARF_DEBUG',
 | ||
| +   `DWARF2_DEBUG', and `XCOFF_DEBUG'.
 | ||
| +
 | ||
| +   The value of this macro only affects the default debugging output; the user
 | ||
| +   can always get a specific type of output by using `-gstabs', `-gcoff',
 | ||
| +   `-gdwarf-1', `-gdwarf-2', or `-gxcoff'.
 | ||
| +
 | ||
| +   Defined in svr4.h.
 | ||
| +*/
 | ||
| +#undef PREFERRED_DEBUGGING_TYPE
 | ||
| +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 | ||
| +
 | ||
| +/* Define this macro if GNU CC should produce dwarf version 2 format debugging
 | ||
| +   output in response to the `-g' option.
 | ||
| +
 | ||
| +   To support optional call frame debugging information, you must also define
 | ||
| +   `INCOMING_RETURN_ADDR_RTX' and either set `RTX_FRAME_RELATED_P' on the
 | ||
| +   prologue insns if you use RTL for the prologue, or call `dwarf2out_def_cfa'
 | ||
| +   and `dwarf2out_reg_save' as appropriate from `FUNCTION_PROLOGUE' if you
 | ||
| +   don't.
 | ||
| +
 | ||
| +   Defined in svr4.h.  */
 | ||
| +
 | ||
| +#define DWARF2_DEBUGGING_INFO 1
 | ||
| +/*#define DWARF2_UNWIND_INFO 1*/
 | ||
| +#define DWARF2_UNWIND_INFO 0
 | ||
| +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGNO)
 | ||
| +#define INCOMING_FRAME_SP_OFFSET 0
 | ||
| +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGNO)
 | ||
| +#define EH_RETURN_FIRST 9
 | ||
| +#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + EH_RETURN_FIRST : INVALID_REGNUM)
 | ||
| +
 | ||
| +/* The EH_RETURN_STACKADJ_RTX macro returns RTL which describes the
 | ||
| +   location used to store the amount to ajdust the stack.  This is
 | ||
| +   usually a registers that is available from end of the function's body
 | ||
| +   to the end of the epilogue. Thus, this cannot be a register used as a
 | ||
| +   temporary by the epilogue.
 | ||
| +
 | ||
| +   This must be an integer register.  */
 | ||
| +#define EH_RETURN_STACKADJ_REGNO	11
 | ||
| +#define EH_RETURN_STACKADJ_RTX		\
 | ||
| +	gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO)
 | ||
| +
 | ||
| +/* The EH_RETURN_HANDLER_RTX macro returns RTL which describes the
 | ||
| +   location used to store the address the processor should jump to
 | ||
| +   catch exception.  This is usually a registers that is available from
 | ||
| +   end of the function's body to the end of the epilogue. Thus, this
 | ||
| +   cannot be a register used as a temporary by the epilogue.
 | ||
| +
 | ||
| +   This must be an address register.  */
 | ||
| +#define EH_RETURN_HANDLER_REGNO		18
 | ||
| +#define EH_RETURN_HANDLER_RTX		\
 | ||
| +	gen_rtx_REG (Pmode, EH_RETURN_HANDLER_REGNO)
 | ||
| +
 | ||
| +/* #define DWARF2_DEBUGGING_INFO */
 | ||
| +
 | ||
| +/* Define this macro if GNU CC should produce dwarf version 2-style
 | ||
| +   line numbers.  This usually requires extending the assembler to
 | ||
| +   support them, and #defining DWARF2_LINE_MIN_INSN_LENGTH in the
 | ||
| +   assembler configuration header files.  */
 | ||
| +/* #define DWARF2_ASM_LINE_DEBUG_INFO 1 */
 | ||
| +
 | ||
| +
 | ||
| +/* An alias for a machine mode name.  This is the machine mode that elements
 | ||
| +   of a jump-table have.  */
 | ||
| +#define CASE_VECTOR_MODE Pmode
 | ||
| +
 | ||
| +/* Smallest number of different values for which it is best to use a
 | ||
| +   jump-table instead of a tree of conditional branches.  For most Ubicom32
 | ||
| +   targets this is quite small, but for the v1 architecture implementations
 | ||
| +   we had very little data memory and so heavily prefer the tree approach
 | ||
| +   rather than the jump tables.  */
 | ||
| +#define CASE_VALUES_THRESHOLD ubicom32_case_values_threshold
 | ||
| +
 | ||
| +/* Register operations within the Ubicom32 architecture always operate on
 | ||
| +   the whole register word and not just the sub-bits required for the opcode
 | ||
| +   mode size.  */
 | ||
| +#define WORD_REGISTER_OPERATIONS
 | ||
| +
 | ||
| +/* The maximum number of bytes that a single instruction can move quickly from
 | ||
| +   memory to memory.  */
 | ||
| +#define MOVE_MAX 4
 | ||
| +
 | ||
| +/* A C expression that is nonzero if on this machine the number of bits
 | ||
| +   actually used for the count of a shift operation is equal to the number of
 | ||
| +   bits needed to represent the size of the object being shifted.  When this
 | ||
| +   macro is non-zero, the compiler will assume that it is safe to omit a
 | ||
| +   sign-extend, zero-extend, and certain bitwise `and' instructions that
 | ||
| +   truncates the count of a shift operation.  On machines that have
 | ||
| +   instructions that act on bitfields at variable positions, which may include
 | ||
| +   `bit test' instructions, a nonzero `SHIFT_COUNT_TRUNCATED' also enables
 | ||
| +   deletion of truncations of the values that serve as arguments to bitfield
 | ||
| +   instructions.
 | ||
| +
 | ||
| +   If both types of instructions truncate the count (for shifts) and position
 | ||
| +   (for bitfield operations), or if no variable-position bitfield instructions
 | ||
| +   exist, you should define this macro.
 | ||
| +
 | ||
| +   However, on some machines, such as the 80386 and the 680x0, truncation only
 | ||
| +   applies to shift operations and not the (real or pretended) bitfield
 | ||
| +   operations.  Define `SHIFT_COUNT_TRUNCATED' to be zero on such machines.
 | ||
| +   Instead, add patterns to the `md' file that include the implied truncation
 | ||
| +   of the shift instructions.
 | ||
| +
 | ||
| +   You need not define this macro if it would always have the value of zero.  */
 | ||
| +#define SHIFT_COUNT_TRUNCATED 1
 | ||
| +
 | ||
| +/* A C expression which is nonzero if on this machine it is safe to "convert"
 | ||
| +   an integer of INPREC bits to one of OUTPREC bits (where OUTPREC is smaller
 | ||
| +   than INPREC) by merely operating on it as if it had only OUTPREC bits.
 | ||
| +
 | ||
| +   On many machines, this expression can be 1.
 | ||
| +
 | ||
| +   When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for modes for
 | ||
| +   which `MODES_TIEABLE_P' is 0, suboptimal code can result.  If this is the
 | ||
| +   case, making `TRULY_NOOP_TRUNCATION' return 0 in such cases may improve
 | ||
| +   things.  */
 | ||
| +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
 | ||
| +
 | ||
| +/* A C string constant that tells the GNU CC driver program options to pass
 | ||
| +   to the assembler.  It can also specify how to translate options you give
 | ||
| +   to GNU CC into options for GNU CC to pass to the assembler.  See the
 | ||
| +   file `sun3.h' for an example of this.
 | ||
| +
 | ||
| +   Defined in svr4.h.  */
 | ||
| +#undef ASM_SPEC
 | ||
| +#define ASM_SPEC \
 | ||
| +  "%{march=*:-m%*} %{!march=*:-mubicom32v4} %{mfdpic:-mfdpic}"
 | ||
| +
 | ||
| +#define LINK_SPEC "\
 | ||
| +%{h*} %{v:-V} \
 | ||
| +%{b} \
 | ||
| +%{mfdpic:-melf32ubicom32fdpic -z text} \
 | ||
| +%{static:-dn -Bstatic} \
 | ||
| +%{shared:-G -Bdynamic} \
 | ||
| +%{symbolic:-Bsymbolic} \
 | ||
| +%{G*} \
 | ||
| +%{YP,*} \
 | ||
| +%{Qy:} %{!Qn:-Qy}"
 | ||
| +
 | ||
| +#undef STARTFILE_SPEC
 | ||
| +#undef ENDFILE_SPEC
 | ||
| +
 | ||
| +/* The svr4.h LIB_SPEC with -leval and --*group tacked on */
 | ||
| +
 | ||
| +#undef  LIB_SPEC
 | ||
| +#define LIB_SPEC "%{!shared:%{!symbolic:--start-group -lc -leval -lgcc --end-group}}"
 | ||
| +
 | ||
| +#undef HAVE_GAS_SHF_MERGE
 | ||
| +#define HAVE_GAS_SHF_MERGE 0
 | ||
| +
 | ||
| +#define HANDLE_SYSV_PRAGMA 1
 | ||
| +#undef HANDLE_PRAGMA_PACK
 | ||
| +
 | ||
| +typedef void (*ubicom32_func_ptr) (void);
 | ||
| +
 | ||
| +/* Define builtins for selected special-purpose instructions. */
 | ||
| +enum ubicom32_builtins
 | ||
| +{
 | ||
| +  UBICOM32_BUILTIN_UBICOM32_SWAPB_2,
 | ||
| +  UBICOM32_BUILTIN_UBICOM32_SWAPB_4
 | ||
| +};
 | ||
| +
 | ||
| +extern rtx ubicom32_compare_op0;
 | ||
| +extern rtx ubicom32_compare_op1;
 | ||
| +
 | ||
| +#define TYPE_ASM_OP	"\t.type\t"
 | ||
| +#define TYPE_OPERAND_FMT	"@%s"
 | ||
| +
 | ||
| +#ifndef ASM_DECLARE_RESULT
 | ||
| +#define ASM_DECLARE_RESULT(FILE, RESULT)
 | ||
| +#endif
 | ||
| +
 | ||
| +/* These macros generate the special .type and .size directives which
 | ||
| +   are used to set the corresponding fields of the linker symbol table
 | ||
| +   entries in an ELF object file under SVR4.  These macros also output
 | ||
| +   the starting labels for the relevant functions/objects.  */
 | ||
| +
 | ||
| +/* Write the extra assembler code needed to declare a function properly.
 | ||
| +   Some svr4 assemblers need to also have something extra said about the
 | ||
| +   function's return value.  We allow for that here.  */
 | ||
| +
 | ||
| +#ifndef ASM_DECLARE_FUNCTION_NAME
 | ||
| +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
 | ||
| +  do								\
 | ||
| +    {								\
 | ||
| +      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
 | ||
| +      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
 | ||
| +      ASM_OUTPUT_LABEL (FILE, NAME);				\
 | ||
| +    }								\
 | ||
| +  while (0)
 | ||
| +#endif
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32.md
 | ||
| @@ -0,0 +1,3753 @@
 | ||
| +; GCC machine description for Ubicom32
 | ||
| +;
 | ||
| +; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software
 | ||
| +; Foundation, Inc.
 | ||
| +; Contributed by Ubicom, 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_constants
 | ||
| +  [(AUX_DATA_REGNO 15)
 | ||
| +   (LINK_REGNO     21)
 | ||
| +   (SP_REGNO       23)
 | ||
| +   (ACC0_HI_REGNO  24)
 | ||
| +   (ACC1_HI_REGNO  26)
 | ||
| +   (CC_REGNO       30)])
 | ||
| +
 | ||
| +(define_constants
 | ||
| +  [(UNSPEC_FDPIC_GOT 0)
 | ||
| +   (UNSPEC_FDPIC_GOT_FUNCDESC 1)])
 | ||
| +
 | ||
| +(define_constants
 | ||
| +  [(UNSPEC_VOLATILE_LOAD_FDPIC_FUNCDESC 0)])
 | ||
| +
 | ||
| +;; Types of instructions (for scheduling purposes).
 | ||
| +
 | ||
| +(define_attr "type" "mul,addr,other"
 | ||
| +  (const_string "other"))
 | ||
| +
 | ||
| +; Define instruction scheduling characteristics.  We can only issue
 | ||
| +; one instruction per clock so we don't need to define CPU units.
 | ||
| +;
 | ||
| +(define_automaton "ubicom32")
 | ||
| +
 | ||
| +(define_cpu_unit "i_pipeline" "ubicom32");
 | ||
| +
 | ||
| +; We have a 4 cycle hazard associated with address calculations which
 | ||
| +; seems rather tricky to avoid so we go with a defensive assumption
 | ||
| +; that almost anything can be used to generate addresses.
 | ||
| +;
 | ||
| +;(define_insn_reservation "ubicom32_other" 4
 | ||
| +;			 (eq_attr "type" "other")
 | ||
| +;			 "i_pipeline")
 | ||
| +
 | ||
| +; Some moves don't generate hazards.
 | ||
| +;
 | ||
| +;(define_insn_reservation "ubicom32_addr" 1
 | ||
| +;			 (eq_attr "type" "addr")
 | ||
| +;			 "i_pipeline")
 | ||
| +
 | ||
| +; We need 3 cycles between a multiply instruction and any use of the
 | ||
| +; matching accumulator register(s).
 | ||
| +;
 | ||
| +(define_insn_reservation "ubicom32_mul" 4
 | ||
| +			 (eq_attr "type" "mul")
 | ||
| +			 "i_pipeline")
 | ||
| +
 | ||
| +(define_attr "length" ""
 | ||
| +  (const_int 4))
 | ||
| +
 | ||
| +(include "predicates.md")
 | ||
| +(include "constraints.md")
 | ||
| +
 | ||
| +; 8-bit move with no change to the flags reg.
 | ||
| +;
 | ||
| +(define_insn "movqi"
 | ||
| +  [(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
 | ||
| +	(match_operand:QI 1 "ubicom32_move_operand"  "g"))]
 | ||
| +  ""
 | ||
| +  "move.1\\t%0, %1")
 | ||
| +
 | ||
| +; Combiner-generated 8-bit move with the zero flag set accordingly.
 | ||
| +;
 | ||
| +(define_insn "movqi_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:QI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:QI 1 "nonimmediate_operand"	   "=rm")
 | ||
| +	(match_dup 0))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "ext.1\\t%1, %0")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:QI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:QI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(match_operator 3 "ubicom32_compare_operator"
 | ||
| +	  [(match_dup 0)
 | ||
| +	   (const_int 0)]))]
 | ||
| +  "(GET_MODE (operands[2]) == CCSZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCSZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:QI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:QI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(match_operator 3 "ubicom32_compare_operator"
 | ||
| +	  [(match_dup 1)
 | ||
| +	   (const_int 0)]))]
 | ||
| +  "(GET_MODE (operands[2]) == CCSZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCSZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; 16-bit move with no change to the flags reg.
 | ||
| +;
 | ||
| +(define_insn "movhi"
 | ||
| +  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
 | ||
| +	(match_operand:HI 1 "ubicom32_move_operand"  "g"))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     if (CONST_INT_P (operands[1]))
 | ||
| +       return \"movei\\t%0, %1\";
 | ||
| +
 | ||
| +     return \"move.2\\t%0, %1\";
 | ||
| +   }")
 | ||
| +
 | ||
| +; Combiner-generated 16-bit move with the zero flag set accordingly.
 | ||
| +;
 | ||
| +(define_insn "movhi_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:HI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:HI 1 "nonimmediate_operand"	   "=rm")
 | ||
| +	(match_dup 0))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "ext.2\\t%1, %0")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:HI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:HI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(match_operator 3 "ubicom32_compare_operator"
 | ||
| +	  [(match_dup 0)
 | ||
| +	   (const_int 0)]))]
 | ||
| +  "(GET_MODE (operands[2]) == CCSZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCSZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:HI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:HI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(match_operator 3 "ubicom32_compare_operator"
 | ||
| +	  [(match_dup 1)
 | ||
| +	   (const_int 0)]))]
 | ||
| +  "(GET_MODE (operands[2]) == CCSZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCSZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; 32-bit move with no change to the flags reg.
 | ||
| +;
 | ||
| +(define_expand "movsi"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "general_operand" ""))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     /* Convert any complexities in operand 1 into something that can just
 | ||
| +        fall into the default expander code.  */
 | ||
| +     ubicom32_expand_movsi (operands);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "movsi_high"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_address_register_operand"		"=a")
 | ||
| +	(high:SI (match_operand:SI 1 "ubicom32_symbolic_address_operand" "s")))]
 | ||
| +  ""
 | ||
| +  "moveai\\t%0, #%%hi(%E1)")
 | ||
| +
 | ||
| +(define_insn "movsi_lo_sum"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"			 "=rm")
 | ||
| +	(lo_sum:SI (match_operand:SI 1 "ubicom32_address_register_operand" "a")
 | ||
| +                   (match_operand:SI 2 "immediate_operand"		   "s")))]
 | ||
| +  ""
 | ||
| +  "lea.1\\t%0, %%lo(%E2)(%1)")
 | ||
| +
 | ||
| +(define_insn "movsi_internal"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"   "=rm")
 | ||
| +	(match_operand:SI 1 "ubicom32_move_operand" "rmnY"))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     if (CONST_INT_P (operands[1]))
 | ||
| +       {
 | ||
| +         ubicom32_emit_move_const_int (operands[0], operands[1]);
 | ||
| +         return \"\";
 | ||
| +       }
 | ||
| +
 | ||
| +     if (GET_CODE (operands[1]) == CONST_DOUBLE)
 | ||
| +       {
 | ||
| +         HOST_WIDE_INT i = CONST_DOUBLE_LOW (operands[1]);
 | ||
| +
 | ||
| +         ubicom32_emit_move_const_int (operands[0], GEN_INT (i));
 | ||
| +         return \"\";
 | ||
| +       }
 | ||
| +
 | ||
| +     if (ubicom32_address_register_operand (operands[0], VOIDmode)
 | ||
| +	 && register_operand (operands[1], VOIDmode))
 | ||
| +       {
 | ||
| +	 if (ubicom32_address_register_operand (operands[1], VOIDmode))
 | ||
| +	   return \"lea.1\\t%0, 0(%1)\";
 | ||
| +
 | ||
| +	 /* Use movea here to utilize the hazard bypass in the >= v4 ISA.  */
 | ||
| +         if (ubicom32_v4)
 | ||
| +	   return \"movea\\t%0, %1\";
 | ||
| +
 | ||
| +         return \"move.4\\t%0, %1\";
 | ||
| +       }
 | ||
| +
 | ||
| +     return \"move.4\\t%0, %1\";
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; constants of value 2^n by using a bset.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(exact_log2 (INTVAL (operands[1])) > 14
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (ior:SI (const_int 0)
 | ||
| +		   (match_dup 1)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; constants of value ~(2^n) by using a bclr.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(exact_log2 (~INTVAL (operands[1])) > 14
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (and:SI (const_int -1)
 | ||
| +		   (match_dup 1)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +; For 32-bit constants that have bits 0 through 24 and bit 31 set the same
 | ||
| +; we can use swapb.4!
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[1]) & 0xffffffff) != 0xffffffff
 | ||
| +    && (INTVAL (operands[1]) & 0xffffffff) != 0
 | ||
| +    && ((INTVAL (operands[1]) & 0x80ffffff) == 0
 | ||
| +	|| (INTVAL (operands[1]) & 0x80ffffff) == 0x80ffffff))"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(bswap:SI (match_dup 2)))]
 | ||
| +  "{
 | ||
| +     operands[2] = GEN_INT (INTVAL (operands[1]) >> 24);
 | ||
| +   }")
 | ||
| +
 | ||
| +; If this is a write of a constant to memory look to see if we can usefully
 | ||
| +; transform this into 2 smaller writes.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "memory_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "! satisfies_constraint_I (operands[1])
 | ||
| +   && ubicom32_legitimate_address_p (HImode, plus_constant (XEXP (operands[0], 0), 2), 1)"
 | ||
| +  [(set (match_dup 4) (match_dup 2))
 | ||
| +   (set (match_dup 5) (match_dup 3))]
 | ||
| +  "{
 | ||
| +     rtx low_hword_addr;
 | ||
| +
 | ||
| +     operands[2] = gen_highpart_mode (HImode, SImode, operands[1]);
 | ||
| +     operands[3] = gen_lowpart (HImode, operands[1]);
 | ||
| +
 | ||
| +     operands[4] = gen_rtx_MEM (HImode, XEXP (operands[0], 0));
 | ||
| +     MEM_COPY_ATTRIBUTES (operands[4], operands[0]);
 | ||
| +
 | ||
| +     low_hword_addr = plus_constant (XEXP (operands[0], 0), 2);
 | ||
| +     operands[5] = gen_rtx_MEM (HImode, low_hword_addr);
 | ||
| +     MEM_COPY_ATTRIBUTES (operands[5], operands[0]);
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're writing memory and we've not found a better way to do this then
 | ||
| +; try loading into a D register and then copying to memory.  This will
 | ||
| +; perform the fewest possible memory read/writes.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "d")
 | ||
| +   (set (match_operand:SI 0 "memory_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "! satisfies_constraint_I (operands[1])"
 | ||
| +  [(set (match_dup 2) (match_dup 1))
 | ||
| +   (set (match_dup 0) (match_dup 2))]
 | ||
| +  "")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; constants of value (2^n - 1) by using an lsr.4.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(exact_log2 (INTVAL (operands[1]) + 1) > 14
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (lshiftrt:SI (const_int -1)
 | ||
| +			(match_dup 2)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[2] = GEN_INT (32 - exact_log2 (INTVAL (operands[1]) + 1));
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; constants of value (2^n - 1) by using an lsr.4.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "d")
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(exact_log2 (INTVAL (operands[1]) + 1) > 14
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (lshiftrt:SI (const_int -1)
 | ||
| +			(match_dup 3)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (set (match_dup 0)
 | ||
| +	(match_dup 2))]
 | ||
| +  "{
 | ||
| +     operands[3] = GEN_INT (32 - exact_log2 (INTVAL (operands[1]) + 1));
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; some other constants by using an lsl.4 to shift 7 bits left by some
 | ||
| +; constant.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(ubicom32_shiftable_const_int (INTVAL (operands[1]))
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (ashift:SI (match_dup 2)
 | ||
| +		      (match_dup 3)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     int shift = ubicom32_shiftable_const_int (INTVAL (operands[1]));
 | ||
| +     operands[2] = GEN_INT (INTVAL (operands[1]) >> shift);
 | ||
| +     operands[3] = GEN_INT (shift);
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; some other constants by using an lsl.4 to shift 7 bits left by some
 | ||
| +; constant.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "d")
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(ubicom32_shiftable_const_int (INTVAL (operands[1]))
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (ashift:SI (match_dup 3)
 | ||
| +		      (match_dup 4)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (set (match_dup 0)
 | ||
| +	(match_dup 2))]
 | ||
| +  "{
 | ||
| +     int shift = ubicom32_shiftable_const_int (INTVAL (operands[1]));
 | ||
| +     operands[3] = GEN_INT (INTVAL (operands[1]) >> shift);
 | ||
| +     operands[4] = GEN_INT (shift);
 | ||
| +   }")
 | ||
| +
 | ||
| +; For some 16-bit unsigned constants that have bit 15 set we can use
 | ||
| +; swapb.2!
 | ||
| +;
 | ||
| +; Note that the movsi code emits the same sequence but by using a peephole2
 | ||
| +; we split the pattern early enough to allow instruction scheduling to
 | ||
| +; occur.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[1]) & 0xffff80ff) == 0x80ff)"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(zero_extend:SI (bswap:HI (match_dup 2))))]
 | ||
| +  "{
 | ||
| +     HOST_WIDE_INT i = INTVAL (operands[1]) >> 8;
 | ||
| +     if (i >= 0x80)
 | ||
| +       i -= 0x100;
 | ||
| +     operands[2] = GEN_INT (i);
 | ||
| +   }")
 | ||
| +
 | ||
| +; In general for a 16-bit unsigned constant that has bit 15 set
 | ||
| +; then we need a movei/move.2 pair unless we can represent it
 | ||
| +; via just a move.2.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(INTVAL (operands[1]) & 0xffff8000) == 0x8000
 | ||
| +    && (INTVAL (operands[1]) & 0xffff) < 0xff80"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 1))
 | ||
| +   (set (match_dup 0)
 | ||
| +	(zero_extend:SI (match_dup 2)))]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_rtx_REG (HImode, REGNO (operands[0]));
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; 32-bit constants that have bits 16 through 31 set to arbitrary values
 | ||
| +; and have bits 0 through 15 set to something representable as a default
 | ||
| +; source-1 immediate - we use movei/shmrg.2
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(((INTVAL (operands[1]) >= 0x8000
 | ||
| +      && INTVAL (operands[1]) < 0xff80)
 | ||
| +     || INTVAL (operands[1]) >= 0x10000
 | ||
| +     || INTVAL (operands[1]) < -0x8000)
 | ||
| +    && ((INTVAL (operands[1]) & 0xffff) >= 0xff80
 | ||
| +	|| (INTVAL (operands[1]) & 0xffff) < 0x80)
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(match_dup 2))
 | ||
| +   (parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (ior:SI
 | ||
| +	     (ashift:SI (match_dup 0)
 | ||
| +			(const_int 16))
 | ||
| +	     (zero_extend:SI
 | ||
| +	       (match_dup 3))))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_highpart_mode (HImode, SImode, operands[1]);
 | ||
| +     operands[3] = gen_lowpart (HImode, operands[1]);
 | ||
| +   }")
 | ||
| +
 | ||
| +; Exactly the same as the peephole2 preceding except that this targets a
 | ||
| +; general register instead of D register.  Hopefully the later optimization
 | ||
| +; passes will notice that the value ended up in a D register first here
 | ||
| +; and eliminate away the other register!
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "d")
 | ||
| +   (set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(((INTVAL (operands[1]) >= 0x8000
 | ||
| +      && INTVAL (operands[1]) < 0xff80)
 | ||
| +     || INTVAL (operands[1]) >= 0x10000
 | ||
| +     || INTVAL (operands[1]) < -0x8000)
 | ||
| +    && ((INTVAL (operands[1]) & 0xffff) >= 0xff80
 | ||
| +	|| (INTVAL (operands[1]) & 0xffff) < 0x80)
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 3))
 | ||
| +   (parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (ior:SI
 | ||
| +	     (ashift:SI (match_dup 2)
 | ||
| +			(const_int 16))
 | ||
| +	     (zero_extend:SI
 | ||
| +	       (match_dup 4))))
 | ||
| +      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (set (match_dup 0)
 | ||
| +	(match_dup 2))]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_highpart_mode (HImode, SImode, operands[1]);
 | ||
| +     operands[4] = gen_lowpart (HImode, operands[1]);
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we have a load of a large integer constant which does not have bit 31
 | ||
| +; set and we have a spare A reg then construct it with a moveai/lea.1 pair
 | ||
| +; instead.  This avoids constructing it in 3 instructions on the stack.
 | ||
| +;
 | ||
| +; Note that we have to be careful not to match anything that matches
 | ||
| +; something we can do in a single instruction!  There aren't many such
 | ||
| +; constants but there are some.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "a")
 | ||
| +   (set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))]
 | ||
| +  "(! (INTVAL (operands[1]) & 0x80000000)
 | ||
| +    && ((INTVAL (operands[1]) >= 0x8000
 | ||
| +	 && INTVAL (operands[1]) < 0xff80)
 | ||
| +	|| INTVAL (operands[1]) >= 0x10000))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 3))
 | ||
| +   (set (match_dup 0)
 | ||
| +	(plus:SI (match_dup 2)
 | ||
| +		 (match_dup 4)))]
 | ||
| +  "{
 | ||
| +     HOST_WIDE_INT i = INTVAL (operands[1]);
 | ||
| +     operands[3] = GEN_INT (i & 0xffffff80);
 | ||
| +     operands[4] = GEN_INT (i & 0x7f);
 | ||
| +   }")
 | ||
| +
 | ||
| +; If we're not dependent on the state of the condition codes we can construct
 | ||
| +; a 32-bit constant with a movei/movei/shmrg.2 sequence if possible.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:HI 2 "d")
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))
 | ||
| +   (match_dup 2)]
 | ||
| +  "(INTVAL (operands[1]) & 0x80000000
 | ||
| +    && INTVAL (operands[1]) < -0x8000
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(match_dup 3))
 | ||
| +   (set (match_dup 2)
 | ||
| +	(match_dup 4))
 | ||
| +   (parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (ior:SI
 | ||
| +	     (ashift:SI (match_dup 0)
 | ||
| +			(const_int 16))
 | ||
| +	     (zero_extend:SI
 | ||
| +	       (match_dup 2))))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_highpart_mode (HImode, SImode, operands[1]);
 | ||
| +     operands[4] = gen_lowpart (HImode, operands[1]);
 | ||
| +   }")
 | ||
| +
 | ||
| +; Exactly the same as the peephole2 preceding except that this targets a
 | ||
| +; general register instead of D register.  Hopefully the later optimization
 | ||
| +; passes will notice that the value ended up in a D register first here
 | ||
| +; and eliminate away the other register!
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(match_scratch:SI 2 "d")
 | ||
| +   (match_scratch:HI 3 "d")
 | ||
| +   (set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))
 | ||
| +   (match_dup 3)]
 | ||
| +  "(INTVAL (operands[1]) & 0x80000000
 | ||
| +    && INTVAL (operands[1]) < -0x8000
 | ||
| +    && peep2_regno_dead_p (0, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 4))
 | ||
| +   (set (match_dup 3)
 | ||
| +	(match_dup 5))
 | ||
| +   (parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (ior:SI
 | ||
| +	     (ashift:SI (match_dup 2)
 | ||
| +			(const_int 16))
 | ||
| +	     (zero_extend:SI
 | ||
| +	       (match_dup 3))))
 | ||
| +      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (set (match_dup 0)
 | ||
| +	(match_dup 2))]
 | ||
| +  "{
 | ||
| +     operands[4] = gen_highpart_mode (HImode, SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (HImode, operands[1]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "movsi_fdpic_got_offset"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"   "=d")
 | ||
| +	(match_operand:SI 1 "ubicom32_fdpic_got_offset_operand" "Y"))]
 | ||
| +  ""
 | ||
| +  "movei\\t%0, %1")
 | ||
| +
 | ||
| +; The explicit MEM inside the UNSPEC prevents the compiler from moving
 | ||
| +; the load before a branch after a NULL test, or before a store that
 | ||
| +; initializes a function descriptor.
 | ||
| +
 | ||
| +(define_insn_and_split "load_fdpic_funcdesc"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_address_register_operand" "=a")
 | ||
| +	(unspec_volatile:SI [(mem:SI (match_operand:SI 1 "address_operand" "p"))]
 | ||
| +			     UNSPEC_VOLATILE_LOAD_FDPIC_FUNCDESC))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(mem:SI (match_dup 1)))])
 | ||
| +
 | ||
| +; Combiner-generated 32-bit move with the zero flag set accordingly.
 | ||
| +;
 | ||
| +(define_insn "movsi_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "nonimmediate_operand" "rm, d")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:SI 1 "nonimmediate_operand"	    "=d,rm")
 | ||
| +	(match_dup 0))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   lsl.4\\t%1, %0, #0
 | ||
| +   add.4\\t%1, #0, %0")
 | ||
| +
 | ||
| +; Combiner-generated 32-bit move with all flags set accordingly.
 | ||
| +;
 | ||
| +(define_insn "movsi_ccw"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:SI 1 "nonimmediate_operand"		    "=rm")
 | ||
| +	(match_dup 0))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWmode)"
 | ||
| +  "add.4\\t%1, #0, %0")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (parallel
 | ||
| +     [(set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	   (match_operator 3 "ubicom32_compare_operator"
 | ||
| +	     [(match_dup 0)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
 | ||
| +  "(GET_MODE (operands[2]) == CCWZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCWZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(match_operand:SI 1 "ubicom32_data_register_operand" ""))
 | ||
| +   (parallel
 | ||
| +     [(set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	   (match_operator 3 "ubicom32_compare_operator"
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
 | ||
| +  "(GET_MODE (operands[2]) == CCWZNmode
 | ||
| +    || GET_MODE (operands[2]) == CCWZmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 0)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; Combine isn't very good at merging some types of operations so we
 | ||
| +; have to make do with a peephole.  It's not as effective but it's better
 | ||
| +; than doing nothing.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (parallel
 | ||
| +     [(set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	   (match_operator 3 "ubicom32_compare_operator"
 | ||
| +	     [(match_dup 0)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_operand:SI 4 "ubicom32_data_register_operand" "")
 | ||
| +	   (match_dup 0))])]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && (GET_MODE (operands[2]) == CCWZNmode
 | ||
| +	|| GET_MODE (operands[2]) == CCWZmode))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (set (match_dup 4)
 | ||
| +	   (match_dup 1))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +; Register renaming may make a general reg into a D reg in which case
 | ||
| +; we may be able to simplify a compare.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (parallel
 | ||
| +     [(set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	   (match_operator 3 "ubicom32_compare_operator"
 | ||
| +	     [(match_dup 0)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && (GET_MODE (operands[2]) == CCWZNmode
 | ||
| +	|| GET_MODE (operands[2]) == CCWZmode))"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 2)
 | ||
| +	   (match_op_dup 3
 | ||
| +	     [(match_dup 1)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (clobber (match_dup 4))])]
 | ||
| +   "")
 | ||
| +
 | ||
| +(define_insn_and_split "movdi"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm")
 | ||
| +	(match_operand:DI 1 "general_operand"	  "rmi,ri"))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 2) (match_dup 3))
 | ||
| +   (set (match_dup 4) (match_dup 5))]
 | ||
| +  "{
 | ||
| +     rtx dest_low;
 | ||
| +     rtx src_low;
 | ||
| +
 | ||
| +     dest_low = gen_lowpart (SImode, operands[0]);
 | ||
| +     src_low = gen_lowpart (SImode, operands[1]);
 | ||
| +
 | ||
| +     if (REG_P (operands[0])
 | ||
| +	 && REG_P (operands[1])
 | ||
| +	 && REGNO (operands[0]) < REGNO (operands[1]))
 | ||
| +       {
 | ||
| +	 operands[2] = gen_highpart (SImode, operands[0]);
 | ||
| +	 operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +	 operands[4] = dest_low;
 | ||
| +	 operands[5] = src_low;
 | ||
| +       }
 | ||
| +     else if (reg_mentioned_p (dest_low, src_low))
 | ||
| +       {
 | ||
| +	 operands[2] = gen_highpart (SImode, operands[0]);
 | ||
| +	 operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +	 operands[4] = dest_low;
 | ||
| +	 operands[5] = src_low;
 | ||
| +       }
 | ||
| +     else
 | ||
| +       {
 | ||
| +	 operands[2] = dest_low;
 | ||
| +	 operands[3] = src_low;
 | ||
| +	 operands[4] = gen_highpart (SImode, operands[0]);
 | ||
| +	 operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +       }
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +; Combiner-generated 64-bit move with all flags set accordingly.
 | ||
| +;
 | ||
| +(define_insn "movdi_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:DI 0 "nonimmediate_operand" "d, m,   r")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:DI 1 "nonimmediate_operand"	 "=&rm,rm,!&rm")
 | ||
| +	(match_dup 0))
 | ||
| +   (clobber (match_scratch:SI 2				   "=X, d,   d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[1]);
 | ||
| +
 | ||
| +     if (ubicom32_data_register_operand (operands[0], VOIDmode))
 | ||
| +       return \"add.4\\t%4, #0, %3\;addc\\t%6, #0, %5\";
 | ||
| +
 | ||
| +     return \"movei\\t%2, #0\;add.4\\t%4, %3, %2\;addc\\t%6, %5, %2\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "movdi_ccw"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:DI 0 "nonimmediate_operand" "d, m,   r")
 | ||
| +		 (const_int 0)))
 | ||
| +   (set (match_operand:DI 1 "nonimmediate_operand"	 "=&rm,rm,!&rm")
 | ||
| +	(match_dup 0))
 | ||
| +   (clobber (match_scratch:SI 2				   "=X, d,   d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWmode)"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[1]);
 | ||
| +
 | ||
| +     if (ubicom32_data_register_operand (operands[0], VOIDmode))
 | ||
| +       return \"add.4\\t%4, #0, %3\;addc\\t%6, #0, %5\";
 | ||
| +
 | ||
| +     return \"movei\\t%2, #0\;add.4\\t%4, %3, %2\;addc\\t%6, %5, %2\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "movsf"
 | ||
| +  [(set (match_operand:SF 0 "nonimmediate_operand"  "=!d,*rm")
 | ||
| +	(match_operand:SF 1 "ubicom32_move_operand" "rmF,rmF"))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     if (GET_CODE (operands[1]) == CONST_DOUBLE)
 | ||
| +       {
 | ||
| +	 HOST_WIDE_INT val;
 | ||
| +	 REAL_VALUE_TYPE rv;
 | ||
| +
 | ||
| +	 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
 | ||
| +	 REAL_VALUE_TO_TARGET_SINGLE (rv, val);
 | ||
| +
 | ||
| +	 ubicom32_emit_move_const_int (operands[0], GEN_INT (val));
 | ||
| +	 return \"\";
 | ||
| +       }
 | ||
| +
 | ||
| +     return \"move.4\\t%0, %1\";
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "zero_extendqihi2"
 | ||
| +  [(set (match_operand:HI 0 "register_operand"			   "=r")
 | ||
| +	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "move.1\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "zero_extendqisi2"
 | ||
| +  [(set (match_operand:SI 0 "register_operand"			   "=r")
 | ||
| +	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "move.1\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "zero_extendqisi2_ccwz_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm"))
 | ||
| +          (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"	     "=d")
 | ||
| +	(zero_extend:SI (match_dup 1)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "shmrg.1\\t%0, %1, #0")
 | ||
| +
 | ||
| +(define_insn "zero_extendhisi2"
 | ||
| +  [(set (match_operand:SI 0 "register_operand"			   "=r")
 | ||
| +	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "move.2\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "zero_extendhisi2_ccwz_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm"))
 | ||
| +          (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"	     "=d")
 | ||
| +	(zero_extend:SI (match_dup 1)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "shmrg.2\\t%0, %1, #0")
 | ||
| +
 | ||
| +(define_insn_and_split "zero_extendqidi2"
 | ||
| +  [(set (match_operand:DI 0 "register_operand"			   "=r")
 | ||
| +	(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(zero_extend:SI (match_dup 1)))
 | ||
| +   (set (match_dup 3)
 | ||
| +	(const_int 0))]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_highpart (SImode, operands[0]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn_and_split "zero_extendhidi2"
 | ||
| +  [(set (match_operand:DI 0 "register_operand"			   "=r")
 | ||
| +	(zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(zero_extend:SI (match_dup 1)))
 | ||
| +   (set (match_dup 3)
 | ||
| +	(const_int 0))]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_highpart (SImode, operands[0]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn_and_split "zero_extendsidi2"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"		  "=rm")
 | ||
| +	(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 1))
 | ||
| +   (set (match_dup 3)
 | ||
| +	(const_int 0))]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_highpart (SImode, operands[0]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "extendqihi2"
 | ||
| +  [(set (match_operand:HI 0 "register_operand"			   "=r")
 | ||
| +	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "ext.1\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "extendqisi2"
 | ||
| +  [(set (match_operand:SI 0 "register_operand"			   "=r")
 | ||
| +	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "ext.1\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "extendhisi2"
 | ||
| +  [(set (match_operand:SI 0 "register_operand"			   "=r")
 | ||
| +	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "ext.2\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn_and_split "extendsidi2"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"		   "=d")
 | ||
| +	(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(match_dup 1))
 | ||
| +   (parallel
 | ||
| +     [(set (match_dup 3)
 | ||
| +	   (ashiftrt:SI (match_dup 2)
 | ||
| +		        (const_int 31)))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_highpart (SImode, operands[0]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "bswaphi"
 | ||
| +  [(set (match_operand:HI 0 "nonimmediate_operand"	       "=rm")
 | ||
| +	(bswap:HI (match_operand:HI 1 "ubicom32_arith_operand" "rmI")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "swapb.2\\t%0, %1");
 | ||
| +
 | ||
| +(define_insn "bswaphisi"
 | ||
| +  [(set (match_operand:SI 0 "register_operand"			  "=r")
 | ||
| +	(zero_extend:SI
 | ||
| +	  (bswap:HI (match_operand:HI 1 "ubicom32_arith_operand" "rmI"))))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "swapb.2\\t%0, %1");
 | ||
| +
 | ||
| +(define_insn "bswapsi"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	       "=rm")
 | ||
| +	(bswap:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "swapb.4\\t%0, %1");
 | ||
| +
 | ||
| +(define_insn "tstqi_ext1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:QI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "ext.1\\t#0, %0")
 | ||
| +
 | ||
| +(define_expand "cmpqi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:QI 0 "ubicom32_arith_operand" "")
 | ||
| +		 (match_operand:QI 1 "ubicom32_data_register_operand" "")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     ubicom32_compare_op0 = operands[0];
 | ||
| +     ubicom32_compare_op1 = operands[1];
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "sub1_ccs"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:QI 0 "ubicom32_arith_operand"       "rmI")
 | ||
| +		 (match_operand:QI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "sub.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +; If we're testing for equality we don't have to worry about reversing conditions.
 | ||
| +;
 | ||
| +(define_insn "sub1_ccsz_1"
 | ||
| +  [(set (reg:CCSZ CC_REGNO)
 | ||
| +	(compare:CCSZ (match_operand:QI 0 "nonimmediate_operand"	  "rm")
 | ||
| +		      (match_operand:QI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "sub.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "sub1_ccsz_2"
 | ||
| +  [(set (reg:CCSZ CC_REGNO)
 | ||
| +	(compare:CCSZ (match_operand:QI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		      (match_operand:QI 1 "ubicom32_arith_operand"	 "rmI")))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "sub.1\\t#0, %1, %0")
 | ||
| +
 | ||
| +; When the combiner runs it doesn't have any insight into whether or not an argument
 | ||
| +; to a compare is spilled to the stack and therefore can't swap the comparison in
 | ||
| +; an attempt to use sub.1 more effectively.  We peephole this case here.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:QI 0 "register_operand" "")
 | ||
| +	(match_operand:QI 1 "ubicom32_arith_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(compare (match_operand:QI 3 "ubicom32_data_register_operand" "")
 | ||
| +		 (match_dup 0)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_operator 4 "comparison_operator"
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_operand 5 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && peep2_regno_dead_p (3, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(compare (match_dup 1)
 | ||
| +		 (match_dup 3)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_op_dup 6
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_dup 5))
 | ||
| +		      (pc)))]
 | ||
| +  "{
 | ||
| +     rtx cc_reg;
 | ||
| +
 | ||
| +     cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
 | ||
| +     operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
 | ||
| +	 			   GET_MODE (operands[4]),
 | ||
| +				   cc_reg,
 | ||
| +				   const0_rtx);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "tsthi_ext2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:HI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "ext.2\\t#0, %0")
 | ||
| +
 | ||
| +(define_expand "cmphi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:HI 0 "ubicom32_arith_operand" "")
 | ||
| +		 (match_operand:HI 1 "ubicom32_compare_operand" "")))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     do
 | ||
| +       {
 | ||
| +	 /* Is this a cmpi? */
 | ||
| +	 if (CONST_INT_P (operands[1]))
 | ||
| +	   break;
 | ||
| +
 | ||
| +	 /* Must be a sub.2 - if necessary copy an operand into a reg.  */
 | ||
| +	 if (! ubicom32_data_register_operand (operands[1], HImode))
 | ||
| +	   operands[1] = copy_to_mode_reg (HImode, operands[1]);
 | ||
| +       }
 | ||
| +     while (0);
 | ||
| +
 | ||
| +     ubicom32_compare_op0 = operands[0];
 | ||
| +     ubicom32_compare_op1 = operands[1];
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "cmpi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:HI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (match_operand 1 "const_int_operand"	     "N")))]
 | ||
| +  ""
 | ||
| +  "cmpi\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "sub2_ccs"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:HI 0 "ubicom32_arith_operand"	    "rmI")
 | ||
| +		 (match_operand:HI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  ""
 | ||
| +  "sub.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +; If we're testing for equality we don't have to worry about reversing conditions.
 | ||
| +;
 | ||
| +(define_insn "sub2_ccsz_1"
 | ||
| +  [(set (reg:CCSZ CC_REGNO)
 | ||
| +	(compare:CCSZ (match_operand:HI 0 "nonimmediate_operand"	  "rm")
 | ||
| +		      (match_operand:HI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  ""
 | ||
| +  "sub.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "sub2_ccsz_2"
 | ||
| +  [(set (reg:CCSZ CC_REGNO)
 | ||
| +	(compare:CCSZ (match_operand:HI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		      (match_operand:HI 1 "ubicom32_arith_operand"	 "rmI")))]
 | ||
| +  ""
 | ||
| +  "sub.2\\t#0, %1, %0")
 | ||
| +
 | ||
| +; When the combiner runs it doesn't have any insight into whether or not an argument
 | ||
| +; to a compare is spilled to the stack and therefore can't swap the comparison in
 | ||
| +; an attempt to use sub.2 more effectively.  We peephole this case here.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:HI 0 "register_operand" "")
 | ||
| +	(match_operand:HI 1 "ubicom32_arith_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(compare (match_operand:HI 3 "ubicom32_data_register_operand" "")
 | ||
| +		 (match_dup 0)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_operator 4 "comparison_operator"
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_operand 5 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && peep2_regno_dead_p (3, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(compare (match_dup 1)
 | ||
| +		 (match_dup 3)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_op_dup 6
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_dup 5))
 | ||
| +		      (pc)))]
 | ||
| +  "{
 | ||
| +     rtx cc_reg;
 | ||
| +
 | ||
| +     cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
 | ||
| +     operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
 | ||
| +	 			   GET_MODE (operands[4]),
 | ||
| +				   cc_reg,
 | ||
| +				   const0_rtx);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn_and_split "tstsi_lsl4"
 | ||
| +  [(set (match_operand 0 "ubicom32_cc_register_operand" "=r")
 | ||
| +	(match_operator 1 "ubicom32_compare_operator"
 | ||
| +	  [(match_operand:SI 2 "nonimmediate_operand"   "rm")
 | ||
| +	   (const_int 0)]))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "#"
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (match_op_dup 1
 | ||
| +	     [(match_dup 2)
 | ||
| +	      (const_int 0)]))
 | ||
| +      (clobber (match_dup 3))])]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_reg_rtx (SImode);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "tstsi_lsl4_d"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int 0)))
 | ||
| +   (clobber (match_operand:SI 1 "ubicom32_data_register_operand" "=d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "lsl.4\\t%1, %0, #0")
 | ||
| +
 | ||
| +; Comparison for equality with -1.
 | ||
| +;
 | ||
| +(define_insn "cmpsi_not4_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "nonimmediate_operand" "rm")
 | ||
| +		 (const_int -1)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "not.4\\t#0, %0")
 | ||
| +
 | ||
| +(define_expand "cmpsi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "ubicom32_arith_operand" "")
 | ||
| +		 (match_operand:SI 1 "ubicom32_compare_operand" "")))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     do
 | ||
| +       {
 | ||
| +	 /* Is this a cmpi?  We can't take a memory address as cmpi takes
 | ||
| +            16-bit operands.  */
 | ||
| +	 if (register_operand (operands[0], SImode)
 | ||
| +	     && CONST_INT_P (operands[1])
 | ||
| +	     && satisfies_constraint_N (operands[1]))
 | ||
| +	   break;
 | ||
| +
 | ||
| +	 /* Must be a sub.4 - if necessary copy an operand into a reg.  */
 | ||
| +	 if (! ubicom32_data_register_operand (operands[1], SImode))
 | ||
| +	   operands[1] = copy_to_mode_reg (SImode, operands[1]);
 | ||
| +       }
 | ||
| +     while (0);
 | ||
| +
 | ||
| +     ubicom32_compare_op0 = operands[0];
 | ||
| +     ubicom32_compare_op1 = operands[1];
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "cmpsi_cmpi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "register_operand" "r")
 | ||
| +		 (match_operand 1 "const_int_operand"   "N")))]
 | ||
| +  "(satisfies_constraint_N (operands[1]))"
 | ||
| +  "cmpi\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "cmpsi_sub4"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "ubicom32_arith_operand"	    "rmI")
 | ||
| +		 (match_operand:SI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  ""
 | ||
| +  "sub.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +; If we're testing for equality we don't have to worry about reversing conditions.
 | ||
| +;
 | ||
| +(define_insn "cmpsi_sub4_ccwz_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "nonimmediate_operand"	     "rm")
 | ||
| +		 (match_operand:SI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "sub.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "cmpsi_sub4_ccwz_2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		 (match_operand:SI 1 "nonimmediate_operand"	     "rm")))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "sub.4\\t#0, %1, %0")
 | ||
| +
 | ||
| +; When the combiner runs it doesn't have any insight into whether or not an argument
 | ||
| +; to a compare is spilled to the stack and therefore can't swap the comparison in
 | ||
| +; an attempt to use sub.4 more effectively.  We peephole this case here.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "ubicom32_arith_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(compare (match_operand:SI 3 "ubicom32_data_register_operand" "")
 | ||
| +		 (match_dup 0)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_operator 4 "comparison_operator"
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_operand 5 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && peep2_regno_dead_p (3, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(compare (match_dup 1)
 | ||
| +		 (match_dup 3)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_op_dup 6
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_dup 5))
 | ||
| +		      (pc)))]
 | ||
| +  "{
 | ||
| +     rtx cc_reg;
 | ||
| +
 | ||
| +     cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
 | ||
| +     operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
 | ||
| +	 			   GET_MODE (operands[4]),
 | ||
| +				   cc_reg,
 | ||
| +				   const0_rtx);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn_and_split "tstdi_or4"
 | ||
| +  [(set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ (match_operand:DI 0 "nonimmediate_operand" "rm")
 | ||
| +		      (const_int 0)))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel
 | ||
| +     [(set (reg:CCWZ CC_REGNO)
 | ||
| +	   (compare:CCWZ (match_dup 0)
 | ||
| +			 (const_int 0)))
 | ||
| +      (clobber (match_dup 1))])]
 | ||
| +  "{
 | ||
| +     operands[1] = gen_reg_rtx (SImode);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "tstdi_or4_d"
 | ||
| +  [(set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ (match_operand:DI 0 "nonimmediate_operand" "rm")
 | ||
| +		      (const_int 0)))
 | ||
| +   (clobber (match_operand:SI 1 "ubicom32_data_register_operand" "=d"))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_highpart_mode (SImode, DImode, operands[0]);
 | ||
| +
 | ||
| +     if (ubicom32_data_register_operand (operands[0], GET_MODE (operands[0])))
 | ||
| +       return \"or.4\\t#0, %2, %3\";
 | ||
| +
 | ||
| +     return \"move.4\\t%1, %2\;or.4\\t%1, %3, %1\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_expand "cmpdi"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:DI 0 "ubicom32_arith_operand" "")
 | ||
| +		 (match_operand:DI 1 "ubicom32_data_register_operand" "")))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_compare_op0 = operands[0];
 | ||
| +     ubicom32_compare_op1 = operands[1];
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "cmpdi_sub4subc"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare (match_operand:DI 0 "ubicom32_arith_operand"	    "rmI")
 | ||
| +		 (match_operand:DI 1 "ubicom32_data_register_operand" "d")))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[4] = gen_highpart_mode (SImode, DImode, operands[0]);
 | ||
| +     operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +
 | ||
| +     return \"sub.4\\t#0, %2, %3\;subc\\t#0, %4, %5\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +; When the combiner runs it doesn't have any insight into whether or not an argument
 | ||
| +; to a compare is spilled to the stack and therefore can't swap the comparison in
 | ||
| +; an attempt to use sub.4/subc more effectively.  We peephole this case here.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:DI 0 "register_operand" "")
 | ||
| +	(match_operand:DI 1 "ubicom32_arith_operand" ""))
 | ||
| +   (set (match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +	(compare (match_operand:DI 3 "ubicom32_data_register_operand" "")
 | ||
| +		 (match_dup 0)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_operator 4 "comparison_operator"
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_operand 5 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    && peep2_regno_dead_p (3, CC_REGNO))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(compare (match_dup 1)
 | ||
| +		 (match_dup 3)))
 | ||
| +   (set (pc)
 | ||
| +	(if_then_else (match_op_dup 6
 | ||
| +			[(match_dup 2)
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_dup 5))
 | ||
| +		      (pc)))]
 | ||
| +  "{
 | ||
| +     rtx cc_reg;
 | ||
| +
 | ||
| +     cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
 | ||
| +     operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
 | ||
| +	 			   GET_MODE (operands[4]),
 | ||
| +				   cc_reg,
 | ||
| +				   const0_rtx);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "btst"
 | ||
| +  [(set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ
 | ||
| +	  (zero_extract:SI
 | ||
| +	    (match_operand:SI 0 "nonimmediate_operand"   "rm")
 | ||
| +	    (const_int 1)
 | ||
| +	    (match_operand:SI 1 "ubicom32_arith_operand" "dM"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  ""
 | ||
| +  "btst\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "bfextu_ccwz_null"
 | ||
| +  [(set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ
 | ||
| +	  (zero_extract:SI
 | ||
| +	    (match_operand:SI 0 "nonimmediate_operand" "rm")
 | ||
| +	    (match_operand 1 "const_int_operand"        "M")
 | ||
| +	    (const_int 0))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2			       "=d"))]
 | ||
| +  ""
 | ||
| +  "bfextu\\t%2, %0, %1")
 | ||
| +
 | ||
| +(define_expand "addqi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:QI 0 "memory_operand" "")
 | ||
| +	   (plus:QI (match_operand:QI 1 "nonimmediate_operand" "")
 | ||
| +		    (match_operand:QI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], QImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "addqi3_add1"
 | ||
| +  [(set (match_operand:QI 0 "memory_operand"		       "=m, m")
 | ||
| +	(plus:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		 (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   add.1\\t%0, %2, %1
 | ||
| +   add.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "addqi3_add1_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (neg:QI (match_operand:QI 0 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (match_operand:QI 1 "ubicom32_arith_operand"      "rmI, d")))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "@
 | ||
| +   add.1\\t#0, %1, %0
 | ||
| +   add.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "addhi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:HI 0 "memory_operand" "")
 | ||
| +	   (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
 | ||
| +		    (match_operand:HI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], HImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "addhi3_add2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"		       "=m, m")
 | ||
| +	(plus:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		 (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   add.2\\t%0, %2, %1
 | ||
| +   add.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "addhi3_add2_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (neg:HI (match_operand:HI 0 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (match_operand:HI 1 "ubicom32_arith_operand"      "rmI, d")))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "@
 | ||
| +   add.2\\t#0, %1, %0
 | ||
| +   add.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "addsi3"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	(plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
 | ||
| +		 (match_operand:SI 2 "ubicom32_move_operand" "")))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_expand_addsi3 (operands);
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +; We start with an instruction pattern that can do all sorts of interesting
 | ||
| +; things but we split out any uses of lea or pdec instructions because
 | ||
| +; those instructions don't clobber the condition codes.
 | ||
| +;
 | ||
| +(define_insn_and_split "addsi3_1"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	   "=rm,rm,rm,rm,rm, rm,rm")
 | ||
| +	(plus:SI (match_operand:SI 1 "nonimmediate_operand" "%a, a, a, a, a,  d,rm")
 | ||
| +		 (match_operand:SI 2 "ubicom32_move_operand" "L, K, J, P, d,rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   #
 | ||
| +   #
 | ||
| +   #
 | ||
| +   #
 | ||
| +   #
 | ||
| +   add.4\\t%0, %2, %1
 | ||
| +   add.4\\t%0, %1, %2"
 | ||
| +  "(reload_completed
 | ||
| +    && ubicom32_address_register_operand (operands[1], GET_MODE (operands[1])))"
 | ||
| +  [(set (match_dup 0)
 | ||
| +	(plus:SI (match_dup 1)
 | ||
| +		 (match_dup 2)))]
 | ||
| +  ""
 | ||
| +)
 | ||
| +
 | ||
| +(define_insn "addsi3_1_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (plus:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"	        "=rm,rm")
 | ||
| +	(plus:SI (match_dup 1)
 | ||
| +		 (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   add.4\\t%0, %2, %1
 | ||
| +   add.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "addsi3_1_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (neg:SI (match_operand:SI 0 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (match_operand:SI 1 "ubicom32_arith_operand"      "rmI, d")))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   add.4\\t#0, %1, %0
 | ||
| +   add.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn_and_split "addsi3_2"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"			"=rm,rm,rm,rm,rm,rm")
 | ||
| +	(plus:SI (match_operand:SI 1 "ubicom32_address_register_operand" "%a, a, a, a, a, a")
 | ||
| +		 (match_operand:SI 2 "ubicom32_move_operand"		  "L, K, J, P, d, n")))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   lea.4\\t%0, %E2(%1)
 | ||
| +   lea.2\\t%0, %E2(%1)
 | ||
| +   lea.1\\t%0, %E2(%1)
 | ||
| +   pdec\\t%0, %n2(%1)
 | ||
| +   lea.1\\t%0, (%1,%2)
 | ||
| +   #"
 | ||
| +  "(reload_completed
 | ||
| +    && ! satisfies_constraint_L (operands[2])
 | ||
| +    && ! satisfies_constraint_K (operands[2])
 | ||
| +    && ! satisfies_constraint_J (operands[2])
 | ||
| +    && ! satisfies_constraint_P (operands[2])
 | ||
| +    && ! ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))"
 | ||
| +  [(set (reg:SI AUX_DATA_REGNO)
 | ||
| +  	(match_dup 2))
 | ||
| +   (set (match_dup 0)
 | ||
| +	(plus:SI (match_dup 1)
 | ||
| +		 (reg:SI AUX_DATA_REGNO)))]
 | ||
| +  ""
 | ||
| +)
 | ||
| +
 | ||
| +(define_insn "lea_2"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"			     "=rm")
 | ||
| +	(plus:SI (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +			  (const_int 2))
 | ||
| +		 (match_operand:SI 2 "ubicom32_address_register_operand"       "a")))]
 | ||
| +  ""
 | ||
| +  "lea.2\\t%0, (%2,%1)")
 | ||
| +
 | ||
| +(define_insn "lea_4"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"			     "=rm")
 | ||
| +	(plus:SI (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +			  (const_int 4))
 | ||
| +		 (match_operand:SI 2 "ubicom32_address_register_operand"       "a")))]
 | ||
| +  ""
 | ||
| +  "lea.4\\t%0, (%2,%1)")
 | ||
| +
 | ||
| +(define_expand "adddi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:DI 0 "nonimmediate_operand" "")
 | ||
| +	   (plus:DI (match_operand:DI 1 "nonimmediate_operand" "")
 | ||
| +		    (match_operand:DI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +; We construct a 64-bit add from 32-bit operations.  Note that we use the
 | ||
| +; & constraint to prevent overlapping registers being allocated.  We do
 | ||
| +; allow identical registers though as that won't break anything.
 | ||
| +;
 | ||
| +(define_insn "adddi3_add4addc"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"	      "=&r,&r,rm,  d,  m, m")
 | ||
| +	(plus:DI (match_operand:DI 1 "nonimmediate_operand"    "%d,rm, 0,  0,  d,rm")
 | ||
| +		 (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d, d,rmI,rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart (SImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
 | ||
| +
 | ||
| +     if (ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
 | ||
| +       return \"add.4\\t%3, %4, %5\;addc\\t%6, %7, %8\";
 | ||
| +
 | ||
| +     return \"add.4\\t%3, %5, %4\;addc\\t%6, %8, %7\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "adddi3_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (plus:DI (match_operand:DI 1 "nonimmediate_operand"    "%d,rm, 0,  0,  d,rm")
 | ||
| +		   (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d, d,rmI,rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:DI 0 "nonimmediate_operand"		"=&r,&r,rm,  d,  m, m")
 | ||
| +	(plus:DI (match_dup 1)
 | ||
| +		 (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +
 | ||
| +     if (ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
 | ||
| +       {
 | ||
| +	 operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +	 operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +	 operands[7] = gen_highpart (SImode, operands[1]);
 | ||
| +	 operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
 | ||
| +       }
 | ||
| +     else
 | ||
| +       {
 | ||
| +	 operands[4] = gen_lowpart (SImode, operands[2]);
 | ||
| +	 operands[5] = gen_lowpart (SImode, operands[1]);
 | ||
| +	 operands[7] = gen_highpart (SImode, operands[2]);
 | ||
| +	 operands[8] = gen_highpart (SImode, operands[1]);
 | ||
| +       }
 | ||
| +
 | ||
| +     return \"add.4\\t%3, %5, %4\;addc\\t%6, %8, %7\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "adddi3_ccwz_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (neg:DI (match_operand:DI 0 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (match_operand:DI 1 "ubicom32_arith_operand"      "rmI, d")))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     if (ubicom32_data_register_operand (operands[0], GET_MODE (operands[0])))
 | ||
| +       {
 | ||
| +	 operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +	 operands[3] = gen_lowpart (SImode, operands[1]);
 | ||
| +	 operands[4] = gen_highpart (SImode, operands[0]);
 | ||
| +	 operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +       }
 | ||
| +     else
 | ||
| +       {
 | ||
| +	 operands[2] = gen_lowpart (SImode, operands[1]);
 | ||
| +	 operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +	 operands[4] = gen_highpart (SImode, operands[1]);
 | ||
| +	 operands[5] = gen_highpart (SImode, operands[0]);
 | ||
| +       }
 | ||
| +
 | ||
| +     return \"add.4\\t#0, %3, %2\;addc\\t#0, %5, %4\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_expand "subqi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:QI 0 "memory_operand" "")
 | ||
| +	   (minus:QI (match_operand:QI 1 "ubicom32_arith_operand" "")
 | ||
| +		     (match_operand:QI 2 "ubicom32_data_register_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], QImode))
 | ||
| +       FAIL;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "subqi3_sub1"
 | ||
| +  [(set (match_operand:QI 0 "memory_operand"			      "=m")
 | ||
| +	(minus:QI (match_operand:QI 1 "ubicom32_arith_operand"	     "rmI")
 | ||
| +		  (match_operand:QI 2 "ubicom32_data_register_operand" "d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "sub.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_expand "subhi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:HI 0 "memory_operand" "")
 | ||
| +	   (minus:HI (match_operand:HI 1 "ubicom32_arith_operand" "")
 | ||
| +		     (match_operand:HI 2 "ubicom32_data_register_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], HImode))
 | ||
| +       FAIL;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "subhi3_sub2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"			      "=m")
 | ||
| +	(minus:HI (match_operand:HI 1 "ubicom32_arith_operand"	     "rmI")
 | ||
| +		  (match_operand:HI 2 "ubicom32_data_register_operand" "d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "sub.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "subsi3"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"		     "=rm")
 | ||
| +	(minus:SI (match_operand:SI 1 "ubicom32_arith_operand"	     "rmI")
 | ||
| +		  (match_operand:SI 2 "ubicom32_data_register_operand" "d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "sub.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "subsi3_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (minus:SI (match_operand:SI 1 "ubicom32_arith_operand"       "rmI")
 | ||
| +		    (match_operand:SI 2 "ubicom32_data_register_operand" "d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"		       "=rm")
 | ||
| +	(minus:SI (match_dup 1)
 | ||
| +		  (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "sub.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +; We construct a 64-bit add from 32-bit operations.  Note that we use the
 | ||
| +; & constraint to prevent overlapping registers being allocated.  We do
 | ||
| +; allow identical registers though as that won't break anything.
 | ||
| +;
 | ||
| +(define_insn "subdi3"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"		     "=&r,r,  d,  m")
 | ||
| +	(minus:DI (match_operand:DI 1 "ubicom32_arith_operand"	     "rmI,0,rmI,rmI")
 | ||
| +		  (match_operand:DI 2 "ubicom32_data_register_operand" "d,d,  0,  d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart (SImode, operands[2]);
 | ||
| +
 | ||
| +     return \"sub.4\\t%3, %4, %5\;subc\\t%6, %7, %8\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "subdi3_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (minus:DI (match_operand:DI 1 "ubicom32_arith_operand"       "rmI,rmI")
 | ||
| +		    (match_operand:DI 2 "ubicom32_data_register_operand" "d,  d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:DI 0 "nonimmediate_operand"		       "=&r,  m")
 | ||
| +	(minus:DI (match_dup 1)
 | ||
| +		  (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart (SImode, operands[2]);
 | ||
| +
 | ||
| +     return \"sub.4\\t%3, %4, %5\;subc\\t%6, %7, %8\";
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +;(define_insn "negqi2"
 | ||
| +;  [(set (match_operand:QI 0 "nonimmediate_operand"		   "=rm")
 | ||
| +;	(neg:QI (match_operand:QI 1 "ubicom32_data_register_operand" "d")))
 | ||
| +;   (clobber (reg:CC CC_REGNO))]
 | ||
| +;  "(ubicom32_v4)"
 | ||
| +;  "sub.1\\t%0, #0, %1")
 | ||
| +
 | ||
| +;(define_insn "neghi2"
 | ||
| +;  [(set (match_operand:HI 0 "nonimmediate_operand"		   "=rm")
 | ||
| +;	(neg:HI (match_operand:HI 1 "ubicom32_data_register_operand" "d")))
 | ||
| +;   (clobber (reg:CC CC_REGNO))]
 | ||
| +;  ""
 | ||
| +;  "sub.2\\t%0, #0, %1")
 | ||
| +
 | ||
| +(define_insn "negsi2"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"		   "=rm")
 | ||
| +	(neg:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "sub.4\\t%0, #0, %1")
 | ||
| +
 | ||
| +(define_insn_and_split "negdi2"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"		  "=&rm")
 | ||
| +	(neg:DI (match_operand:DI 1 "ubicom32_data_register_operand" "d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(parallel [(set (match_dup 0)
 | ||
| +		   (minus:DI (const_int 0)
 | ||
| +			     (match_dup 1)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "umulhisi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_acc_lo_register_operand"	     "=l, l")
 | ||
| +	(mult:SI
 | ||
| +	  (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm, d"))))
 | ||
| +   (clobber (reg:HI ACC0_HI_REGNO))
 | ||
| +   (clobber (reg:HI ACC1_HI_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   mulu\\t%A0, %2, %1
 | ||
| +   mulu\\t%A0, %1, %2"
 | ||
| +  [(set_attr "type" "mul,mul")])
 | ||
| +
 | ||
| +(define_insn "mulhisi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_acc_lo_register_operand"	     "=l, l")
 | ||
| +	(mult:SI
 | ||
| +	  (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm, d"))))
 | ||
| +   (clobber (reg:HI ACC0_HI_REGNO))
 | ||
| +   (clobber (reg:HI ACC1_HI_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   muls\\t%A0, %2, %1
 | ||
| +   muls\\t%A0, %1, %2"
 | ||
| +  [(set_attr "type" "mul,mul")])
 | ||
| +
 | ||
| +(define_expand "mulsi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_acc_hi_register_operand" "")
 | ||
| +	(mult:SI (match_operand:SI 1 "ubicom32_arith_operand" "")
 | ||
| +		 (match_operand:SI 2 "ubicom32_arith_operand" "")))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (ubicom32_emit_mult_sequence (operands))
 | ||
| +       DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "umulsidi3"
 | ||
| +  [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand"	     "=h, h")
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm, d"))))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   mulu.4\\t%A0, %2, %1
 | ||
| +   mulu.4\\t%A0, %1, %2"
 | ||
| +  [(set_attr "type" "mul,mul")])
 | ||
| +
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_dup 0))
 | ||
| +	  (zero_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2]) + 1)
 | ||
| +   && ! rtx_equal_p (operands[0], operands[3])"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_dup 1))
 | ||
| +	  (zero_extend:DI (match_dup 3))))]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))
 | ||
| +	  (zero_extend:DI (match_dup 0))))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2]) + 1)
 | ||
| +   && ! rtx_equal_p (operands[0], operands[3])"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_dup 1))
 | ||
| +	  (zero_extend:DI (match_dup 3))))]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "umulsidi3_const"
 | ||
| +  [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand"		       "=h")
 | ||
| +	(mult:DI
 | ||
| +	  (zero_extend:DI (match_operand:SI 1 "ubicom32_data_register_operand" "%d"))
 | ||
| +	  (match_operand 2 "const_int_operand"					"I")))]
 | ||
| +  "(ubicom32_v4 && satisfies_constraint_I (operands[2]))"
 | ||
| +  "mulu.4\\t%A0, %2, %1"
 | ||
| +  [(set_attr "type" "mul")])
 | ||
| +
 | ||
| +(define_insn "mulsidi3"
 | ||
| +  [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand"	     "=h, h")
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%d,rm"))
 | ||
| +	  (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm, d"))))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   muls.4\\t%A0, %2, %1
 | ||
| +   muls.4\\t%A0, %1, %2"
 | ||
| +  [(set_attr "type" "mul,mul")])
 | ||
| +
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_dup 0))
 | ||
| +	  (sign_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2]) + 1)
 | ||
| +   && ! rtx_equal_p (operands[0], operands[3])"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_dup 1))
 | ||
| +	  (sign_extend:DI (match_dup 3))))]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "nonimmediate_operand" ""))
 | ||
| +   (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))
 | ||
| +	  (sign_extend:DI (match_dup 0))))]
 | ||
| +  "(peep2_reg_dead_p (2, operands[0])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2])
 | ||
| +    || REGNO (operands[0]) == REGNO (operands[2]) + 1)
 | ||
| +   && ! rtx_equal_p (operands[0], operands[3])"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_dup 1))
 | ||
| +	  (sign_extend:DI (match_dup 3))))]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "mulsidi3_const"
 | ||
| +  [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand"		       "=h")
 | ||
| +	(mult:DI
 | ||
| +	  (sign_extend:DI (match_operand:SI 1 "ubicom32_data_register_operand" "%d"))
 | ||
| +	  (match_operand 2 "const_int_operand"					"I")))]
 | ||
| +  "(ubicom32_v4 && satisfies_constraint_I (operands[2]))"
 | ||
| +  "muls.4\\t%A0, %2, %1"
 | ||
| +  [(set_attr "type" "mul")])
 | ||
| +
 | ||
| +(define_expand "andqi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:QI 0 "memory_operand" "")
 | ||
| +	   (and:QI (match_operand:QI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:QI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], QImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andqi3_and1"
 | ||
| +  [(set (match_operand:QI 0 "memory_operand"		      "=m, m")
 | ||
| +	(and:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   and.1\\t%0, %2, %1
 | ||
| +   and.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andqi3_and1_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:QI 0 "memory_operand"		        "=m, m")
 | ||
| +	(and:QI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "@
 | ||
| +   and.1\\t%0, %2, %1
 | ||
| +   and.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andqi3_and1_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:QI (match_operand:QI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:QI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "@
 | ||
| +   and.1\\t#0, %1, %0
 | ||
| +   and.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "and1_ccszn_null_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
 | ||
| +		    (match_operand:SI 1 "ubicom32_arith_operand"	 "rI"))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "and.1\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "and1_ccszn_null_2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		    (subreg:SI
 | ||
| +		      (match_operand:QI 1 "memory_operand"		 "m")
 | ||
| +		      0))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "and.1\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "and1_ccszn_null_3"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (and:SI (subreg:SI
 | ||
| +		      (match_operand:QI 0 "memory_operand"		 "m")
 | ||
| +		      0)
 | ||
| +		    (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "and.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "andhi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:HI 0 "memory_operand" "")
 | ||
| +	   (and:HI (match_operand:HI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:HI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], HImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andhi3_and2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"		      "=m, m")
 | ||
| +	(and:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   and.2\\t%0, %2, %1
 | ||
| +   and.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andhi3_and2_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:HI 0 "memory_operand"		        "=m, m")
 | ||
| +	(and:HI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "@
 | ||
| +   and.2\\t%0, %2, %1
 | ||
| +   and.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andhi3_and2_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:HI (match_operand:HI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:HI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "@
 | ||
| +   and.2\\t#0, %1, %0
 | ||
| +   and.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "and2_ccszn_null_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
 | ||
| +		    (match_operand:SI 1 "ubicom32_arith_operand"	 "rI"))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "and.2\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "and2_ccszn_null_2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		    (subreg:SI
 | ||
| +		      (match_operand:HI 1 "memory_operand"		 "m")
 | ||
| +		      0))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "and.2\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "and2_ccszn_null_3"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (and:SI (subreg:SI
 | ||
| +		      (match_operand:HI 0 "memory_operand"		 "m")
 | ||
| +		      0)
 | ||
| +		    (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "and.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "andsi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	   (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:SI 2 "ubicom32_and_or_si3_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     do
 | ||
| +       {
 | ||
| +	 /* Is this a bfextu?  */
 | ||
| +	 if (ubicom32_data_register_operand (operands[0], SImode)
 | ||
| +	     && CONST_INT_P (operands[2])
 | ||
| +	     && exact_log2 (INTVAL (operands[2]) + 1) != -1)
 | ||
| +	   break;
 | ||
| +
 | ||
| +	 /* Is this a bclr?  */
 | ||
| +	 if (CONST_INT_P (operands[2])
 | ||
| +	     && exact_log2 (~INTVAL (operands[2])) != -1)
 | ||
| +	   break;
 | ||
| +
 | ||
| +	 /* Must be an and.4  */
 | ||
| +	 if (!ubicom32_data_register_operand (operands[1], SImode))
 | ||
| +	   operands[1] = copy_to_mode_reg (SImode, operands[1]);
 | ||
| +
 | ||
| +	 if (!ubicom32_arith_operand (operands[2], SImode))
 | ||
| +	   operands[2] = copy_to_mode_reg (SImode, operands[2]);
 | ||
| +       }
 | ||
| +     while (0);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andsi3_bfextu"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
 | ||
| +  	(and:SI (match_operand:SI 1 "nonimmediate_operand"  "%rm")
 | ||
| +		(match_operand:SI 2 "const_int_operand"	      "O")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(satisfies_constraint_O (operands[2]))"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1));
 | ||
| +
 | ||
| +     return \"bfextu\\t%0, %1, %3\";
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andsi3_bfextu_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:SI (match_operand:SI 1 "nonimmediate_operand" "%rm")
 | ||
| +		  (match_operand:SI 2 "const_int_operand"      "O"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"  "=d")
 | ||
| +	(and:SI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "(satisfies_constraint_O (operands[2])
 | ||
| +    && ubicom32_match_cc_mode(insn, CCWZmode))"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1));
 | ||
| +
 | ||
| +     return \"bfextu\\t%0, %1, %3\";
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andsi3_bfextu_ccwz_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
 | ||
| +		  (match_operand:SI 1 "const_int_operand"      "O"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2				      "=d"))]
 | ||
| +  "(satisfies_constraint_O (operands[1])
 | ||
| +    && ubicom32_match_cc_mode(insn, CCWZmode))"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1));
 | ||
| +
 | ||
| +     return \"bfextu\\t%2, %0, %3\";
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "andsi3_bclr"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	      "=rm")
 | ||
| +	(and:SI (match_operand:SI 1 "ubicom32_arith_operand" "%rmI")
 | ||
| +		(match_operand:SI 2 "const_int_operand"	        "n")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(exact_log2 (~INTVAL (operands[2])) != -1)"
 | ||
| +  "bclr\\t%0, %1, #%D2")
 | ||
| +
 | ||
| +(define_insn "andsi3_and4"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	     "=rm,rm")
 | ||
| +	(and:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   and.4\\t%0, %2, %1
 | ||
| +   and.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andsi3_and4_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"	       "=rm,rm")
 | ||
| +	(and:SI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   and.4\\t%0, %2, %1
 | ||
| +   and.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "andsi3_and4_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:SI (match_operand:SI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   and.4\\t#0, %1, %0
 | ||
| +   and.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "andsi3_lsr4_ccwz_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
 | ||
| +		  (match_operand:SI 1 "const_int_operand"      "n"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2				      "=d"))]
 | ||
| +  "(exact_log2 ((~(INTVAL (operands[1]))) + 1) != -1
 | ||
| +    && ubicom32_match_cc_mode(insn, CCWZmode))"
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     operands[3] = GEN_INT (exact_log2 ((~(INTVAL (operands[1]))) + 1));
 | ||
| +
 | ||
| +     return \"lsr.4\\t%2, %0, %3\";
 | ||
| +   }")
 | ||
| +
 | ||
| +; We really would like the combiner to recognize this scenario and deal with
 | ||
| +; it but unfortunately it tries to canonicalize zero_extract ops on MEMs
 | ||
| +; into QImode operations and we can't match them in any useful way.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(match_operand:SI 1 "const_int_operand" ""))
 | ||
| +   (set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ
 | ||
| +	  (and:SI (match_operand:SI 2 "nonimmediate_operand" "")
 | ||
| +		  (match_dup 0))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(exact_log2 (INTVAL (operands[1])) != -1
 | ||
| +    && peep2_reg_dead_p (2, operands[0]))"
 | ||
| +  [(set (reg:CCWZ CC_REGNO)
 | ||
| +	(compare:CCWZ
 | ||
| +	  (zero_extract:SI
 | ||
| +	    (match_dup 2)
 | ||
| +	    (const_int 1)
 | ||
| +	    (match_dup 3))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "{
 | ||
| +     operands[3] = GEN_INT (exact_log2 (INTVAL (operands[1])));
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "anddi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:DI 0 "nonimmediate_operand" "")
 | ||
| +	   (and:DI (match_operand:DI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:DI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn_and_split "anddi3_and4"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"	     "=&r,&r,  d,rm,  m, m")
 | ||
| +	(and:DI (match_operand:DI 1 "nonimmediate_operand"    "%d,rm,  0, 0,  d,rm")
 | ||
| +		(match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(parallel [(set (match_dup 3)
 | ||
| +		   (and:SI (match_dup 4)
 | ||
| +			   (match_dup 5)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (parallel [(set (match_dup 6)
 | ||
| +		   (and:SI (match_dup 7)
 | ||
| +			   (match_dup 8)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart (SImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_expand "iorqi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:QI 0 "memory_operand" "")
 | ||
| +	   (ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:QI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], QImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "iorqi3_or1"
 | ||
| +  [(set (match_operand:QI 0 "memory_operand"		      "=m, m")
 | ||
| +	(ior:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   or.1\\t%0, %2, %1
 | ||
| +   or.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_expand "iorhi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:HI 0 "memory_operand" "")
 | ||
| +	   (ior:HI (match_operand:HI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:HI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], HImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "iorhi3_or2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"		      "=m, m")
 | ||
| +	(ior:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   or.2\\t%0, %2, %1
 | ||
| +   or.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_expand "iorsi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:SI 0 "nonimmediate_operand" "")
 | ||
| +	   (ior:SI (match_operand:SI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:SI 2 "ubicom32_and_or_si3_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     do
 | ||
| +       {
 | ||
| +	 /* Is this a bset?  */
 | ||
| +	 if (CONST_INT_P (operands[2])
 | ||
| +	     && exact_log2 (INTVAL (operands[2])) != -1)
 | ||
| +	   break;
 | ||
| +
 | ||
| +	 /* Must be an or.4  */
 | ||
| +	 if (!ubicom32_data_register_operand (operands[1], SImode))
 | ||
| +	   operands[1] = copy_to_mode_reg (SImode, operands[1]);
 | ||
| +
 | ||
| +	 if (!ubicom32_arith_operand (operands[2], SImode))
 | ||
| +	   operands[2] = copy_to_mode_reg (SImode, operands[2]);
 | ||
| +       } 
 | ||
| +     while (0);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "iorsi3_bset"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	      "=rm")
 | ||
| +  	(ior:SI (match_operand:SI 1 "ubicom32_arith_operand" "%rmI")
 | ||
| +		(match_operand 2 "const_int_operand"	        "n")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(exact_log2 (INTVAL (operands[2])) != -1)"
 | ||
| +  "bset\\t%0, %1, #%d2")
 | ||
| +
 | ||
| +(define_insn "iorsi3_or4"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	     "=rm,rm")
 | ||
| +	(ior:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   or.4\\t%0, %2, %1
 | ||
| +   or.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "iorsi3_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ior:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"	       "=rm,rm")
 | ||
| +	(ior:SI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   or.4\\t%0, %2, %1
 | ||
| +   or.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "iorsi3_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ior:SI (match_operand:SI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   or.4\\t#0, %1, %0
 | ||
| +   or.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "iordi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:DI 0 "nonimmediate_operand" "")
 | ||
| +	   (ior:DI (match_operand:DI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:DI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn_and_split "iordi3_or4"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"	     "=&r,&r,  d,rm,  m, m")
 | ||
| +	(ior:DI (match_operand:DI 1 "nonimmediate_operand"    "%d,rm,  0, 0,  d,rm")
 | ||
| +		(match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(parallel [(set (match_dup 3)
 | ||
| +		   (ior:SI (match_dup 4)
 | ||
| +			   (match_dup 5)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (parallel [(set (match_dup 6)
 | ||
| +		   (ior:SI (match_dup 7)
 | ||
| +			   (match_dup 8)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart (SImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_expand "xorqi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:QI 0 "memory_operand" "")
 | ||
| +	   (xor:QI (match_operand:QI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:QI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], QImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (QImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "xorqi3_xor1"
 | ||
| +  [(set (match_operand:QI 0 "memory_operand"		      "=m, m")
 | ||
| +	(xor:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "@
 | ||
| +   xor.1\\t%0, %2, %1
 | ||
| +   xor.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorqi3_xor1_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:QI (match_operand:QI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:QI 0 "memory_operand"		        "=m, m")
 | ||
| +	(xor:QI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "@
 | ||
| +   xor.1\\t%0, %2, %1
 | ||
| +   xor.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorqi3_xor1_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:QI (match_operand:QI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:QI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "@
 | ||
| +   xor.1\\t#0, %1, %0
 | ||
| +   xor.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "xor1_ccszn_null_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
 | ||
| +		    (match_operand:SI 1 "ubicom32_arith_operand"	 "rI"))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "xor.1\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "xor1_ccszn_null_2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		    (subreg:SI
 | ||
| +		      (match_operand:QI 1 "memory_operand"		 "m")
 | ||
| +		      0))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "xor.1\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "xor1_ccwzn_null_3"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:QI
 | ||
| +	    (xor:SI (subreg:SI
 | ||
| +		      (match_operand:QI 0 "memory_operand"		 "m")
 | ||
| +		      0)
 | ||
| +		    (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
 | ||
| +	    3)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && ubicom32_match_cc_mode(insn, CCSZNmode))"
 | ||
| +  "xor.1\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "xorhi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:HI 0 "memory_operand" "")
 | ||
| +	   (xor:HI (match_operand:HI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:HI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (!memory_operand (operands[0], HImode))
 | ||
| +       FAIL;
 | ||
| +
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (HImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "xorhi3_xor2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"		      "=m, m")
 | ||
| +	(xor:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   xor.2\\t%0, %2, %1
 | ||
| +   xor.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorhi3_xor2_ccszn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:HI (match_operand:HI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:HI 0 "memory_operand"		        "=m, m")
 | ||
| +	(xor:HI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "@
 | ||
| +   xor.2\\t%0, %2, %1
 | ||
| +   xor.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorhi3_xor2_ccszn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:HI (match_operand:HI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:HI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "@
 | ||
| +   xor.2\\t#0, %1, %0
 | ||
| +   xor.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "xor2_ccszn_null_1"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
 | ||
| +		    (match_operand:SI 1 "ubicom32_arith_operand"	 "rI"))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "xor.2\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "xor2_ccszn_null_2"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
 | ||
| +		    (subreg:SI
 | ||
| +		      (match_operand:HI 1 "memory_operand"		 "m")
 | ||
| +		      0))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "xor.2\\t#0, %1, %0")
 | ||
| +
 | ||
| +(define_insn "xor2_ccszn_null_3"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (subreg:HI
 | ||
| +	    (xor:SI (subreg:SI
 | ||
| +		      (match_operand:HI 0 "memory_operand"		 "m")
 | ||
| +		      0)
 | ||
| +		    (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
 | ||
| +	    2)
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCSZNmode)"
 | ||
| +  "xor.2\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_insn "xorsi3"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	     "=rm,rm")
 | ||
| +	(xor:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		(match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "@
 | ||
| +   xor.4\\t%0, %2, %1
 | ||
| +   xor.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorsi3_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:SI (match_operand:SI 1 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"	       "=rm,rm")
 | ||
| +	(xor:SI (match_dup 1)
 | ||
| +		(match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   xor.4\\t%0, %2, %1
 | ||
| +   xor.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "xorsi3_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (xor:SI (match_operand:SI 0 "nonimmediate_operand"    "%d,rm")
 | ||
| +		  (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "@
 | ||
| +   xor.4\\t#0, %1, %0
 | ||
| +   xor.4\\t#0, %0, %1")
 | ||
| +
 | ||
| +(define_expand "xordi3"
 | ||
| +  [(parallel
 | ||
| +     [(set (match_operand:DI 0 "nonimmediate_operand" "")
 | ||
| +	   (xor:DI (match_operand:DI 1 "nonimmediate_operand" "")
 | ||
| +		   (match_operand:DI 2 "ubicom32_arith_operand" "")))
 | ||
| +      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     /* If we have a non-data reg for operand 1 then prefer that over
 | ||
| +        a CONST_INT in operand 2.  */
 | ||
| +     if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
 | ||
| +	 && CONST_INT_P (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +
 | ||
| +     if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
 | ||
| +       operands[2] = copy_to_mode_reg (DImode, operands[2]);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn_and_split "xordi3_xor4"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"	     "=&r,&r,  d,rm,  m, m")
 | ||
| +	(xor:DI (match_operand:DI 1 "nonimmediate_operand"    "%d,rm,  0, 0,  d,rm")
 | ||
| +		(match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(parallel [(set (match_dup 3)
 | ||
| +		   (xor:SI (match_dup 4)
 | ||
| +			   (match_dup 5)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (parallel [(set (match_dup 6)
 | ||
| +		   (xor:SI (match_dup 7)
 | ||
| +			   (match_dup 8)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[4] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[5] = gen_lowpart (SImode, operands[2]);
 | ||
| +     operands[6] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[7] = gen_highpart (SImode, operands[1]);
 | ||
| +     operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +(define_insn "not2_2"
 | ||
| +  [(set (match_operand:HI 0 "memory_operand"		        "=m")
 | ||
| +	(subreg:HI
 | ||
| +	  (not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI"))
 | ||
| +	  2))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "not.2\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "one_cmplsi2"
 | ||
| +  [(set (match_operand:SI 0 "nonimmediate_operand"	     "=rm")
 | ||
| +	(not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "not.4\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "one_cmplsi2_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "nonimmediate_operand"	       "=rm")
 | ||
| +	(not:SI (match_dup 1)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "not.4\\t%0, %1")
 | ||
| +
 | ||
| +(define_insn "one_cmplsi2_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (not:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI"))
 | ||
| +	  (const_int 0)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "not.4\\t#0, %0")
 | ||
| +
 | ||
| +(define_insn_and_split "one_cmpldi2"
 | ||
| +  [(set (match_operand:DI 0 "nonimmediate_operand"	   "=&rm")
 | ||
| +	(not:DI (match_operand:DI 1 "nonimmediate_operand" "rmI0")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel [(set (match_dup 2)
 | ||
| +		   (not:SI (match_dup 3)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])
 | ||
| +   (parallel [(set (match_dup 4)
 | ||
| +		   (not:SI (match_dup 5)))
 | ||
| +	      (clobber (reg:CC CC_REGNO))])]
 | ||
| +  "{
 | ||
| +     operands[2] = gen_lowpart (SImode, operands[0]);
 | ||
| +     operands[3] = gen_lowpart (SImode, operands[1]);
 | ||
| +     operands[4] = gen_highpart (SImode, operands[0]);
 | ||
| +     operands[5] = gen_highpart (SImode, operands[1]);
 | ||
| +   }"
 | ||
| +  [(set_attr "length" "8")])
 | ||
| +
 | ||
| +; Conditional jump instructions
 | ||
| +
 | ||
| +(define_expand "beq"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (eq (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (EQ, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bne"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (ne (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (NE, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bgt"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (gt (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (GT, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "ble"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (le (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (LE, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bge"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (ge (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (GE, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "blt"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (lt (match_dup 1)
 | ||
| +			  (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (LT, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bgtu"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (gtu (match_dup 1)
 | ||
| +			   (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (GTU, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bleu"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (leu (match_dup 1)
 | ||
| +			   (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (LEU, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bgeu"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (geu (match_dup 1)
 | ||
| +			   (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (GEU, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "bltu"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (ltu (match_dup 1)
 | ||
| +			   (const_int 0))
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     operands[1] = ubicom32_gen_compare_reg (LTU, ubicom32_compare_op0,
 | ||
| +					     ubicom32_compare_op1);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "jcc"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (match_operator 1 "comparison_operator"
 | ||
| +			[(match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +			 (const_int 0)])
 | ||
| +		      (label_ref (match_operand 0 "" ""))
 | ||
| +		      (pc)))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     ubicom32_output_cond_jump (insn, operands[1], operands[0]);
 | ||
| +     return \"\";
 | ||
| +   }")
 | ||
| +
 | ||
| +; Reverse branch - reverse our comparison condition so that we can
 | ||
| +; branch in the opposite sense.
 | ||
| +;
 | ||
| +(define_insn_and_split "jcc_reverse"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (match_operator 1 "comparison_operator"
 | ||
| +			[(match_operand 2 "ubicom32_cc_register_operand" "")
 | ||
| +			 (const_int 0)])
 | ||
| +		      (pc)
 | ||
| +		      (label_ref (match_operand 0 "" ""))))]
 | ||
| +  ""
 | ||
| +  "#"
 | ||
| +  "reload_completed"
 | ||
| +  [(set (pc)
 | ||
| +	(if_then_else (match_dup 3)
 | ||
| +		      (label_ref (match_dup 0))
 | ||
| +		      (pc)))]
 | ||
| +  "{
 | ||
| +     rtx cc_reg;
 | ||
| +
 | ||
| +     cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
 | ||
| +     operands[3] = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
 | ||
| +	 			   GET_MODE (operands[1]),
 | ||
| +				   cc_reg,
 | ||
| +				   const0_rtx);
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "jump"
 | ||
| +  [(set (pc)
 | ||
| +	(label_ref (match_operand 0 "" "")))]
 | ||
| +  ""
 | ||
| +  "jmpt\\t%l0")
 | ||
| +
 | ||
| +(define_expand "indirect_jump"
 | ||
| +  [(parallel [(set (pc)
 | ||
| +  		   (match_operand:SI 0 "register_operand" ""))
 | ||
| +	      (clobber (match_dup 0))])]
 | ||
| +  ""
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "indirect_jump_internal"
 | ||
| +  [(set (pc)
 | ||
| + 	(match_operand:SI 0 "register_operand" "a"))
 | ||
| +  (clobber (match_dup 0))]
 | ||
| +  ""
 | ||
| +  "calli\\t%0,0(%0)")
 | ||
| +
 | ||
| +; Program Space: The table contains instructions, typically jumps. 
 | ||
| +; CALL An,TABLE_SIZE(PC)	;An = Jump Table Base Address. 
 | ||
| +; <Jump Table is Here>	;An -> Here. 
 | ||
| +; LEA Ak, (An,Dn) 	;Ak -> Table Entry
 | ||
| +; JMP/CALL (Ak) 
 | ||
| +
 | ||
| +(define_expand "tablejump"
 | ||
| +  [(parallel [(set (pc)
 | ||
| +  		   (match_operand:SI 0 "nonimmediate_operand" ""))
 | ||
| +	      (use (label_ref (match_operand 1 "" "")))])]
 | ||
| +  ""
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "tablejump_internal"
 | ||
| +  [(set (pc)
 | ||
| +	(match_operand:SI 0 "nonimmediate_operand" "rm"))
 | ||
| +   (use (label_ref (match_operand 1 "" "")))]
 | ||
| +  ""
 | ||
| +  "ret\\t%0")
 | ||
| +
 | ||
| +; Call subroutine with no return value.
 | ||
| +;
 | ||
| +(define_expand "call"
 | ||
| +  [(call (match_operand:QI 0 "general_operand" "")
 | ||
| +	 (match_operand:SI 1 "general_operand" ""))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     if (TARGET_FDPIC)
 | ||
| +       {
 | ||
| +	 ubicom32_expand_call_fdpic (operands);
 | ||
| +	 DONE;
 | ||
| +       }
 | ||
| +
 | ||
| +     if (! ubicom32_call_address_operand (XEXP (operands[0], 0), VOIDmode))
 | ||
| +       XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
 | ||
| +   }")
 | ||
| +
 | ||
| +; We expand to a simple form that doesn't clobber the link register and
 | ||
| +; then split to a form that does.  This allows the RTL optimizers that
 | ||
| +; run before the splitter to have the opportunity to eliminate the call
 | ||
| +; without marking A5 as being clobbered and this in turn avoids saves
 | ||
| +; and returns in a number of cases.
 | ||
| +;
 | ||
| +(define_insn_and_split "call_1"
 | ||
| +  [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	 (match_operand:SI 1 "general_operand"			     "g,g"))]
 | ||
| +  "! TARGET_FDPIC"
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel
 | ||
| +     [(call (mem:QI (match_dup 0))
 | ||
| +	    (match_dup 1))
 | ||
| +      (clobber (reg:SI LINK_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "call_slow"
 | ||
| +  [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	 (match_operand:SI 1 "general_operand"			     "g,g"))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "(! TARGET_FDPIC && ! TARGET_FASTCALL)"
 | ||
| +  "@
 | ||
| +   calli\\ta5, 0(%0)
 | ||
| +   moveai\\ta5, #%%hi(%C0)\;calli\\ta5, %%lo(%C0)(a5)")
 | ||
| +
 | ||
| +(define_insn "call_fast"
 | ||
| +  [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	 (match_operand:SI 1 "general_operand"			     "g,g"))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "(! TARGET_FDPIC && TARGET_FASTCALL)"
 | ||
| +  "@
 | ||
| +   calli\\ta5, 0(%0)
 | ||
| +   call\\ta5, %C0")
 | ||
| +
 | ||
| +; We expand to a simple form that doesn't clobber the link register and
 | ||
| +; then split to a form that does.  This allows the RTL optimizers that
 | ||
| +; run before the splitter to have the opportunity to eliminate the call
 | ||
| +; without marking A5 as being clobbered and this in turn avoids saves
 | ||
| +; and returns in a number of cases.
 | ||
| +;
 | ||
| +(define_insn_and_split "call_fdpic"
 | ||
| +  [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	 (match_operand:SI 1 "general_operand"			     "g,g"))
 | ||
| +   (use (match_operand:SI 2 "ubicom32_fdpic_operand"		     "Z,Z"))]
 | ||
| +  "TARGET_FDPIC"
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel
 | ||
| +     [(call (mem:QI (match_dup 0))
 | ||
| +	    (match_dup 1))
 | ||
| +      (use (match_dup 2))
 | ||
| +      (clobber (reg:SI LINK_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "call_fdpic_clobber"
 | ||
| +  [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	 (match_operand:SI 1 "general_operand"			     "g,g"))
 | ||
| +   (use (match_operand:SI 2 "ubicom32_fdpic_operand"		     "Z,Z"))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "TARGET_FDPIC"
 | ||
| +  "@
 | ||
| +   move.4\\ta5, 0(%0)\;move.4\\t%2, 4(%0)\;calli\\ta5, 0(a5)
 | ||
| +   call\\ta5, %C0")
 | ||
| +
 | ||
| +; 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 (TARGET_FDPIC)
 | ||
| +       {
 | ||
| +	 ubicom32_expand_call_value_fdpic (operands);
 | ||
| +	 DONE;
 | ||
| +       }
 | ||
| +
 | ||
| +     if (! ubicom32_call_address_operand (XEXP (operands[1], 0), VOIDmode))
 | ||
| +       XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
 | ||
| +   }")
 | ||
| +
 | ||
| +; We expand to a simple form that doesn't clobber the link register and
 | ||
| +; then split to a form that does.  This allows the RTL optimizers that
 | ||
| +; run before the splitter to have the opportunity to eliminate the call
 | ||
| +; without marking A5 as being clobbered and this in turn avoids saves
 | ||
| +; and returns in a number of cases.
 | ||
| +;
 | ||
| +(define_insn_and_split "call_value_1"
 | ||
| +  [(set (match_operand 0 "register_operand"				 "=r,r")
 | ||
| +	(call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	      (match_operand:SI 2 "general_operand"			  "g,g")))]
 | ||
| +  "! TARGET_FDPIC"
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (call (mem:QI (match_dup 1))
 | ||
| +		 (match_dup 2)))
 | ||
| +      (clobber (reg:SI LINK_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "call_value_slow"
 | ||
| +  [(set (match_operand 0 "register_operand"				 "=r,r")
 | ||
| +	(call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	      (match_operand:SI 2 "general_operand"			  "g,g")))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "(! TARGET_FDPIC && ! TARGET_FASTCALL)"
 | ||
| +  "@
 | ||
| +   calli\\ta5, 0(%1)
 | ||
| +   moveai\\ta5, #%%hi(%C1)\;calli\\ta5, %%lo(%C1)(a5)")
 | ||
| +
 | ||
| +(define_insn "call_value_fast"
 | ||
| +  [(set (match_operand 0 "register_operand"				 "=r,r")
 | ||
| +	(call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	      (match_operand:SI 2 "general_operand"			  "g,g")))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "(! TARGET_FDPIC && TARGET_FASTCALL)"
 | ||
| +  "@
 | ||
| +   calli\\ta5, 0(%1)
 | ||
| +   call\\ta5, %C1")
 | ||
| +
 | ||
| +; We expand to a simple form that doesn't clobber the link register and
 | ||
| +; then split to a form that does.  This allows the RTL optimizers that
 | ||
| +; run before the splitter to have the opportunity to eliminate the call
 | ||
| +; without marking A5 as being clobbered and this in turn avoids saves
 | ||
| +; and returns in a number of cases.
 | ||
| +;
 | ||
| +(define_insn_and_split "call_value_fdpic"
 | ||
| +  [(set (match_operand 0 "register_operand"				 "=r,r")
 | ||
| +	(call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	      (match_operand:SI 2 "general_operand"			  "g,g")))
 | ||
| +   (use (match_operand:SI 3 "ubicom32_fdpic_operand"			  "Z,Z"))]
 | ||
| +  "TARGET_FDPIC"
 | ||
| +  "#"
 | ||
| +  ""
 | ||
| +  [(parallel
 | ||
| +     [(set (match_dup 0)
 | ||
| +	   (call (mem:QI (match_dup 1))
 | ||
| +		 (match_dup 2)))
 | ||
| +      (use (match_dup 3))
 | ||
| +      (clobber (reg:SI LINK_REGNO))])]
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "call_value_fdpic_clobber"
 | ||
| +  [(set (match_operand 0 "register_operand"				 "=r,r")
 | ||
| +	(call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
 | ||
| +	      (match_operand:SI 2 "general_operand"			  "g,g")))
 | ||
| +   (use (match_operand:SI 3 "ubicom32_fdpic_operand"			  "Z,Z"))
 | ||
| +   (clobber (reg:SI LINK_REGNO))]
 | ||
| +  "TARGET_FDPIC"
 | ||
| +  "@
 | ||
| +   move.4\\ta5, 0(%1)\;move.4\\t%3, 4(%1)\;calli\\ta5, 0(a5)
 | ||
| +   call\\ta5, %C1")
 | ||
| +
 | ||
| +(define_expand "untyped_call"
 | ||
| +  [(parallel [(call (match_operand 0 "" "")
 | ||
| +                    (const_int 0))
 | ||
| +              (match_operand 1 "" "")
 | ||
| +              (match_operand 2 "" "")])]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     int i;
 | ||
| +
 | ||
| +     emit_call_insn (gen_call (operands[0], const0_rtx));
 | ||
| +
 | ||
| +     for (i = 0; i < XVECLEN (operands[2], 0); i++)
 | ||
| +       {
 | ||
| +         rtx set = XVECEXP (operands[2], 0, i);
 | ||
| +         emit_move_insn (SET_DEST (set), SET_SRC (set));
 | ||
| +       }
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "lsl1_1"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(ashift:SI (subreg:SI
 | ||
| +		     (match_operand:QI 1 "memory_operand"	  "m")
 | ||
| +		     0)
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "lsl.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +; The combiner gets rather creative about left shifts of sub-word memory
 | ||
| +; operands because it's uncertain about whether the memory is sign or
 | ||
| +; zero extended.  It only wants zero-extended behaviour and so throws
 | ||
| +; in an extra and operation.
 | ||
| +;
 | ||
| +(define_insn "lsl1_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
 | ||
| +	(and:SI
 | ||
| +	  (ashift:SI (subreg:SI
 | ||
| +		       (match_operand:QI 1 "memory_operand"   "m")
 | ||
| +		       0)
 | ||
| +		     (match_operand:SI 2 "const_int_operand"  "M"))
 | ||
| +	  (match_operand:SI 3 "const_int_operand"	      "n")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && INTVAL (operands[3]) == (0xff << INTVAL (operands[2])))"
 | ||
| +  "lsl.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "lsl2_1"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(ashift:SI (subreg:SI
 | ||
| +		     (match_operand:HI 1 "memory_operand"	  "m")
 | ||
| +		     0)
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "lsl.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +; The combiner gets rather creative about left shifts of sub-word memory
 | ||
| +; operands because it's uncertain about whether the memory is sign or
 | ||
| +; zero extended.  It only wants zero-extended behaviour and so throws
 | ||
| +; in an extra and operation.
 | ||
| +;
 | ||
| +(define_insn "lsl2_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
 | ||
| +	(and:SI
 | ||
| +	  (ashift:SI (subreg:SI
 | ||
| +		       (match_operand:HI 1 "memory_operand"   "m")
 | ||
| +		       0)
 | ||
| +		     (match_operand:SI 2 "const_int_operand"  "M"))
 | ||
| +	  (match_operand:SI 3 "const_int_operand"	      "n")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && INTVAL (operands[3]) == (0xffff << INTVAL (operands[2])))"
 | ||
| +  "lsl.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "ashlsi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(ashift:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "lsl.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "lshlsi3_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ashift:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
 | ||
| +		     (match_operand:SI 2 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"	   "=d")
 | ||
| +	(ashift:SI (match_dup 1)
 | ||
| +		   (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "lsl.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "lshlsi3_ccwz_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ashift:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI")
 | ||
| +		     (match_operand:SI 1 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2					   "=d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "lsl.4\\t%2, %0, %1")
 | ||
| +
 | ||
| +; The combiner finds this canonical form for what is in essence a right
 | ||
| +; shift.
 | ||
| +;
 | ||
| +(define_insn "asr1_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(sign_extract:SI (match_operand:QI 1 "memory_operand"	  "m")
 | ||
| +			 (match_operand:SI 2 "const_int_operand"  "M")
 | ||
| +			 (match_operand:SI 3 "const_int_operand"  "M")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[2]) + INTVAL (operands[3]) == 8))"
 | ||
| +  "asr.1\\t%0, %1, %3")
 | ||
| +
 | ||
| +; The combiner finds this canonical form for what is in essence a right
 | ||
| +; shift.
 | ||
| +;
 | ||
| +(define_insn "asr2_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(sign_extract:SI (match_operand:HI 1 "memory_operand"	  "m")
 | ||
| +			 (match_operand:SI 2 "const_int_operand"  "M")
 | ||
| +			 (match_operand:SI 3 "const_int_operand"  "M")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[2]) + INTVAL (operands[3]) == 16))"
 | ||
| +  "asr.2\\t%0, %1, %3")
 | ||
| +
 | ||
| +(define_insn "ashrsi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	   "=d")
 | ||
| +	(ashiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmJ")
 | ||
| +		     (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "asr.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "ashrsi3_ccwzn"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ashiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmJ")
 | ||
| +		       (match_operand:SI 2 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"	     "=d")
 | ||
| +	(ashiftrt:SI (match_dup 1)
 | ||
| +		     (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "asr.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "ashrsi3_ccwzn_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (ashiftrt:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmJ")
 | ||
| +		       (match_operand:SI 1 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2					     "=d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZNmode)"
 | ||
| +  "asr.4\\t%2, %0, %1")
 | ||
| +
 | ||
| +(define_insn "lsr1_1"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(lshiftrt:SI (subreg:SI
 | ||
| +		       (match_operand:QI 1 "memory_operand"	  "m")
 | ||
| +		       0)
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "lsr.1\\t%0, %1, %2")
 | ||
| +
 | ||
| +; The combiner finds this canonical form for what is in essence a right
 | ||
| +; shift.
 | ||
| +;
 | ||
| +(define_insn "lsr1_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(zero_extract:SI (match_operand:QI 1 "memory_operand"	  "m")
 | ||
| +			 (match_operand:SI 2 "const_int_operand"  "M")
 | ||
| +			 (match_operand:SI 3 "const_int_operand"  "M")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[2]) + INTVAL (operands[3]) == 8))"
 | ||
| +  "lsr.1\\t%0, %1, %3")
 | ||
| +
 | ||
| +(define_insn "lsr2_1"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(lshiftrt:SI (subreg:SI
 | ||
| +		       (match_operand:HI 1 "memory_operand"	  "m")
 | ||
| +		       0)
 | ||
| +		   (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4)"
 | ||
| +  "lsr.2\\t%0, %1, %2")
 | ||
| +
 | ||
| +; The combiner finds this canonical form for what is in essence a right
 | ||
| +; shift.
 | ||
| +;
 | ||
| +(define_insn "lsr2_2"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	 "=d")
 | ||
| +	(zero_extract:SI (match_operand:HI 1 "memory_operand"	  "m")
 | ||
| +			 (match_operand:SI 2 "const_int_operand"  "M")
 | ||
| +			 (match_operand:SI 3 "const_int_operand"  "M")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  "(ubicom32_v4
 | ||
| +    && (INTVAL (operands[2]) + INTVAL (operands[3]) == 16))"
 | ||
| +  "lsr.2\\t%0, %1, %3")
 | ||
| +
 | ||
| +(define_insn "lshrsi3"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	   "=d")
 | ||
| +	(lshiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
 | ||
| +		     (match_operand:SI 2 "ubicom32_arith_operand"  "dM")))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "lsr.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "lshrsi3_ccwz"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (lshiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
 | ||
| +		       (match_operand:SI 2 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (set (match_operand:SI 0 "ubicom32_data_register_operand"	     "=d")
 | ||
| +	(lshiftrt:SI (match_dup 1)
 | ||
| +		     (match_dup 2)))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "lsr.4\\t%0, %1, %2")
 | ||
| +
 | ||
| +(define_insn "lshrsi3_ccwz_null"
 | ||
| +  [(set (reg CC_REGNO)
 | ||
| +	(compare
 | ||
| +	  (lshiftrt:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI")
 | ||
| +		       (match_operand:SI 1 "ubicom32_arith_operand"  "dM"))
 | ||
| +	  (const_int 0)))
 | ||
| +   (clobber (match_scratch:SI 2					     "=d"))]
 | ||
| +  "ubicom32_match_cc_mode(insn, CCWZmode)"
 | ||
| +  "lsr.4\\t%2, %0, %1")
 | ||
| +
 | ||
| +(define_expand "prologue"
 | ||
| +  [(const_int 0)]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_expand_prologue ();
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "epilogue"
 | ||
| +  [(return)]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_expand_epilogue ();
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "return"
 | ||
| +  [(return)]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_expand_epilogue ();
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_expand "_eh_return"
 | ||
| +  [(use (match_operand:SI 0 "register_operand" "r"))
 | ||
| +   (use (match_operand:SI 1 "register_operand" "r"))]
 | ||
| +  ""
 | ||
| +  "{
 | ||
| +     ubicom32_expand_eh_return (operands);
 | ||
| +     DONE;
 | ||
| +   }")
 | ||
| +
 | ||
| +; XXX - it looks almost certain that we could make return_internal use a Dn
 | ||
| +; register too.  In that instance we'd have to use a ret instruction
 | ||
| +; rather than a calli but it might save cycles.
 | ||
| +;
 | ||
| +(define_insn "return_internal"
 | ||
| +  [(const_int 2)
 | ||
| +   (return)
 | ||
| +   (use (match_operand:SI 0 "ubicom32_mem_or_address_register_operand" "rm"))]
 | ||
| +  ""
 | ||
| +  "*
 | ||
| +   {
 | ||
| +     if (REG_P (operands[0]) && REGNO (operands[0]) == LINK_REGNO
 | ||
| +	 && ubicom32_can_use_calli_to_ret)
 | ||
| +       return \"calli\\t%0, 0(%0)\";
 | ||
| +
 | ||
| +     return \"ret\\t%0\";
 | ||
| +   }")
 | ||
| +
 | ||
| +(define_insn "return_from_post_modify_sp"
 | ||
| +  [(parallel
 | ||
| +     [(const_int 2)
 | ||
| +      (return)
 | ||
| +      (use (mem:SI (post_modify:SI
 | ||
| +		     (reg:SI SP_REGNO)
 | ||
| +		     (plus:SI (reg:SI SP_REGNO)
 | ||
| +			      (match_operand:SI 0 "const_int_operand" "n")))))])]
 | ||
| +  "INTVAL (operands[0]) >= 4 && INTVAL (operands[0]) <= 7 * 4"
 | ||
| +  "ret\\t(sp)%E0++")
 | ||
| +
 | ||
| +;(define_insn "eh_return_internal"
 | ||
| +;  [(const_int 4)
 | ||
| +;   (return)
 | ||
| +;   (use (reg:SI 34))]
 | ||
| +;  ""
 | ||
| +;  "ret\\ta2")
 | ||
| +
 | ||
| +; No operation, needed in case the user uses -g but not -O.
 | ||
| +(define_expand "nop"
 | ||
| +  [(const_int 0)]
 | ||
| +  ""
 | ||
| +  "")
 | ||
| +
 | ||
| +(define_insn "nop_internal"
 | ||
| +  [(const_int 0)]
 | ||
| +  ""
 | ||
| +  "nop")
 | ||
| +
 | ||
| +; The combiner will generate this pattern given shift and add operations.
 | ||
| +; The canonical form that the combiner wants to use appears to be multiplies
 | ||
| +; instead of shifts even if the compiled sources use shifts.
 | ||
| +;
 | ||
| +(define_insn "shmrg1_add"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	       "=d")
 | ||
| +  	(plus:SI
 | ||
| +	  (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +		   (const_int 256))
 | ||
| +	  (zero_extend:SI
 | ||
| +	    (match_operand:QI 2 "ubicom32_arith_operand"	      "rmI"))))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "shmrg.1\\t%0, %2, %1")
 | ||
| +
 | ||
| +; The combiner will generate this pattern given shift and or operations.
 | ||
| +;
 | ||
| +(define_insn "shmrg1_ior"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"		 "=d")
 | ||
| +  	(ior:SI
 | ||
| +	  (ashift:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +		     (const_int 8))
 | ||
| +	  (zero_extend:SI
 | ||
| +	    (match_operand:QI 2 "ubicom32_arith_operand"		"rmI"))))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "shmrg.1\\t%0, %2, %1")
 | ||
| +
 | ||
| +; The combiner will generate this pattern given shift and add operations.
 | ||
| +; The canonical form that the combiner wants to use appears to be multiplies
 | ||
| +; instead of shifts even if the compiled sources use shifts.
 | ||
| +;
 | ||
| +(define_insn "shmrg2_add"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"	       "=d")
 | ||
| +  	(plus:SI
 | ||
| +	  (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +		   (const_int 65536))
 | ||
| +	  (zero_extend:SI
 | ||
| +	    (match_operand:HI 2 "ubicom32_arith_operand"	      "rmI"))))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "shmrg.2\\t%0, %2, %1")
 | ||
| +
 | ||
| +; The combiner will generate this pattern given shift and or operations.
 | ||
| +;
 | ||
| +(define_insn "shmrg2_ior"
 | ||
| +  [(set (match_operand:SI 0 "ubicom32_data_register_operand"		 "=d")
 | ||
| +  	(ior:SI
 | ||
| +	  (ashift:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
 | ||
| +		     (const_int 16))
 | ||
| +	  (zero_extend:SI
 | ||
| +	    (match_operand:HI 2 "ubicom32_arith_operand"		"rmI"))))
 | ||
| +   (clobber (reg:CC CC_REGNO))]
 | ||
| +  ""
 | ||
| +  "shmrg.2\\t%0, %2, %1")
 | ||
| +
 | ||
| +; Match the case where we load a word from the stack but then discard the
 | ||
| +; upper 16 bits.  We turn this into a zero-extended load of that useful
 | ||
| +; 16 bits direct from the stack where possible.
 | ||
| +;
 | ||
| +
 | ||
| +; XXX - do these peephole2 ops actually work after the CCmode conversion?
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(mem:SI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_operand:SI 1 "const_int_operand" ""))))
 | ||
| +   (set (match_operand:SI 2 "nonimmediate_operand" "")
 | ||
| +	(zero_extend:SI (match_operand:HI 3 "register_operand" "")))]
 | ||
| +  "(INTVAL (operands[1]) <= 252
 | ||
| +    && REGNO (operands[3]) == REGNO (operands[0])
 | ||
| +    && ((peep2_reg_dead_p (2, operands[0])
 | ||
| +	 && ! reg_mentioned_p (operands[0], operands[2]))
 | ||
| +        || rtx_equal_p (operands[0], operands[2])))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(zero_extend:SI (mem:HI (plus:SI (reg:SI SP_REGNO)
 | ||
| +					 (match_dup 4)))))]
 | ||
| +  "{
 | ||
| +     operands[4] = GEN_INT (INTVAL (operands[1]) + 2);
 | ||
| +   }")
 | ||
| +
 | ||
| +; Match the case where we load a word from the stack but then discard the
 | ||
| +; upper 16 bits.  We turn this into a 16-bit load of that useful
 | ||
| +; 16 bits direct from the stack where possible.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(mem:SI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_operand:SI 1 "const_int_operand" ""))))
 | ||
| +   (set (match_operand:HI 2 "nonimmediate_operand" "")
 | ||
| +	(match_operand:HI 3 "register_operand" ""))]
 | ||
| +  "(INTVAL (operands[1]) <= 252
 | ||
| +    && REGNO (operands[3]) == REGNO (operands[0])
 | ||
| +    && ((peep2_reg_dead_p (2, operands[0])
 | ||
| +	 && ! reg_mentioned_p (operands[0], operands[2]))
 | ||
| +        || rtx_equal_p (operands[0], operands[2])))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mem:HI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_dup 4))))]
 | ||
| +  "{
 | ||
| +     operands[4] = GEN_INT (INTVAL (operands[1]) + 2);
 | ||
| +   }")
 | ||
| +
 | ||
| +; Match the case where we load a word from the stack but then discard the
 | ||
| +; upper 24 bits.  We turn this into a zero-extended load of that useful
 | ||
| +; 8 bits direct from the stack where possible.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(mem:SI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_operand:SI 1 "const_int_operand" ""))))
 | ||
| +   (set (match_operand:SI 2 "nonimmediate_operand" "")
 | ||
| +	(zero_extend:SI (match_operand:QI 3 "register_operand" "")))]
 | ||
| +  "(INTVAL (operands[1]) <= 124
 | ||
| +    && REGNO (operands[3]) == REGNO (operands[0])
 | ||
| +    && ((peep2_reg_dead_p (2, operands[0])
 | ||
| +	 && ! reg_mentioned_p (operands[0], operands[2]))
 | ||
| +        || rtx_equal_p (operands[0], operands[2])))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(zero_extend:SI (mem:QI (plus:SI (reg:SI SP_REGNO)
 | ||
| +					 (match_dup 4)))))]
 | ||
| +  "{
 | ||
| +     operands[4] = GEN_INT (INTVAL (operands[1]) + 3);
 | ||
| +   }")
 | ||
| +
 | ||
| +; Match the case where we load a word from the stack but then discard the
 | ||
| +; upper 24 bits.  We turn this into an 8-bit load of that useful
 | ||
| +; 8 bits direct from the stack where possible.
 | ||
| +;
 | ||
| +(define_peephole2
 | ||
| +  [(set (match_operand:SI 0 "register_operand" "")
 | ||
| +	(mem:SI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_operand:SI 1 "const_int_operand" ""))))
 | ||
| +   (set (match_operand:QI 2 "nonimmediate_operand" "")
 | ||
| +	(match_operand:QI 3 "register_operand" ""))]
 | ||
| +  "(INTVAL (operands[1]) <= 124
 | ||
| +    && REGNO (operands[3]) == REGNO (operands[0])
 | ||
| +    && ((peep2_reg_dead_p (2, operands[0])
 | ||
| +	 && ! reg_mentioned_p (operands[0], operands[2]))
 | ||
| +        || rtx_equal_p (operands[0], operands[2])))"
 | ||
| +  [(set (match_dup 2)
 | ||
| +	(mem:QI (plus:SI (reg:SI SP_REGNO)
 | ||
| +			 (match_dup 4))))]
 | ||
| +  "{
 | ||
| +     operands[4] = GEN_INT (INTVAL (operands[1]) + 3);
 | ||
| +   }")
 | ||
| +
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/ubicom32.opt
 | ||
| @@ -0,0 +1,27 @@
 | ||
| +mdebug-address
 | ||
| +Target RejectNegative Report Undocumented Mask(DEBUG_ADDRESS)
 | ||
| +Debug addresses
 | ||
| +
 | ||
| +mdebug-context
 | ||
| +Target RejectNegative Report Undocumented Mask(DEBUG_CONTEXT)
 | ||
| +Debug contexts
 | ||
| +
 | ||
| +march=
 | ||
| +Target Report Var(ubicom32_arch_name) Init("ubicom32v4") Joined
 | ||
| +Specify the name of the target architecture
 | ||
| +
 | ||
| +mfdpic
 | ||
| +Target Report Mask(FDPIC)
 | ||
| +Enable Function Descriptor PIC mode
 | ||
| +
 | ||
| +minline-plt
 | ||
| +Target Report Mask(INLINE_PLT)
 | ||
| +Enable inlining of PLT in function calls
 | ||
| +
 | ||
| +mfastcall
 | ||
| +Target Report Mask(FASTCALL)
 | ||
| +Enable default fast (call) calling sequence for smaller applications
 | ||
| +
 | ||
| +mipos-abi
 | ||
| +Target Report Mask(IPOS_ABI)
 | ||
| +Enable the ipOS ABI in which D10-D13 are caller-clobbered
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/uclinux.h
 | ||
| @@ -0,0 +1,67 @@
 | ||
| +/* Definitions of target machine for Ubicom32-uclinux
 | ||
| +
 | ||
| +   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
 | ||
| +   2009 Free Software Foundation, Inc.
 | ||
| +   Contributed by Ubicom, 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/>.  */
 | ||
| +
 | ||
| +/* Don't assume anything about the header files.  */
 | ||
| +#define NO_IMPLICIT_EXTERN_C
 | ||
| +
 | ||
| +#undef  LIB_SPEC
 | ||
| +#define LIB_SPEC  \
 | ||
| +	"%{pthread:-lpthread} " \
 | ||
| +	"%{!shared:%{!symbolic: -lc}} "
 | ||
| +
 | ||
| +
 | ||
| +#undef LINK_GCC_C_SEQUENCE_SPEC
 | ||
| +#define LINK_GCC_C_SEQUENCE_SPEC \
 | ||
| +  "%{!shared:--start-group} %G %L %{!shared:--end-group}%{shared:%G} "
 | ||
| +
 | ||
| +#undef STARTFILE_SPEC
 | ||
| +#define STARTFILE_SPEC \
 | ||
| +	"%{!shared: crt1%O%s}" \
 | ||
| +	" crti%O%s crtbegin%O%s"
 | ||
| +
 | ||
| +#undef ENDFILE_SPEC
 | ||
| +#define ENDFILE_SPEC "crtend%O%s crtn%O%s"
 | ||
| +
 | ||
| +/* This macro applies on top of OBJECT_FORMAT_ELF and indicates that
 | ||
| +   we want to support both flat and ELF output.  */
 | ||
| +#define OBJECT_FORMAT_FLAT
 | ||
| +
 | ||
| +#undef DRIVER_SELF_SPECS
 | ||
| +#define DRIVER_SELF_SPECS \
 | ||
| +  "%{!mno-fastcall:-mfastcall}"
 | ||
| +
 | ||
| +/* taken from linux.h */
 | ||
| +/* The GNU C++ standard library requires that these macros be defined.  */
 | ||
| +#undef CPLUSPLUS_CPP_SPEC
 | ||
| +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
 | ||
| +
 | ||
| +#define TARGET_OS_CPP_BUILTINS()				\
 | ||
| +    do {							\
 | ||
| +	builtin_define_std ("__UBICOM32__");			\
 | ||
| +	builtin_define_std ("__ubicom32__");			\
 | ||
| +	builtin_define ("__gnu_linux__");			\
 | ||
| +	builtin_define_std ("linux");				\
 | ||
| +	builtin_define_std ("unix");				\
 | ||
| +	builtin_assert ("system=linux");			\
 | ||
| +	builtin_assert ("system=unix");				\
 | ||
| +	builtin_assert ("system=posix");			\
 | ||
| +    } while (0)
 | ||
| --- /dev/null
 | ||
| +++ b/gcc/config/ubicom32/xm-ubicom32.h
 | ||
| @@ -0,0 +1,36 @@
 | ||
| +/* Configuration for Ubicom's Ubicom32 architecture.
 | ||
| +   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software
 | ||
| +   Foundation, Inc.
 | ||
| +   Contributed by Ubicom Inc.
 | ||
| +
 | ||
| +This file is part of GNU CC.
 | ||
| +
 | ||
| +GNU CC is free software; you can redistribute it and/or modify
 | ||
| +it under the terms of the GNU General Public License as published by
 | ||
| +the Free Software Foundation; either version 2, or (at your option)
 | ||
| +any later version.
 | ||
| +
 | ||
| +GNU CC is distributed in the hope that it will be useful,
 | ||
| +but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
| +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||
| +GNU General Public License for more details.
 | ||
| +
 | ||
| +You should have received a copy of the GNU General Public License
 | ||
| +along with GNU CC; see the file COPYING.  If not, write to
 | ||
| +the Free Software Foundation, 59 Temple Place - Suite 330,
 | ||
| +Boston, MA 02111-1307, USA.  */
 | ||
| +
 | ||
| +/* #defines that need visibility everywhere.  */
 | ||
| +#define FALSE 0
 | ||
| +#define TRUE 1
 | ||
| +
 | ||
| +/* This describes the machine the compiler is hosted on.  */
 | ||
| +#define HOST_BITS_PER_CHAR 8
 | ||
| +#define HOST_BITS_PER_SHORT 16
 | ||
| +#define HOST_BITS_PER_INT 32
 | ||
| +#define HOST_BITS_PER_LONG 32
 | ||
| +#define HOST_BITS_PER_LONGLONG 64
 | ||
| +
 | ||
| +/* Arguments to use with `exit'.  */
 | ||
| +#define SUCCESS_EXIT_CODE 0
 | ||
| +#define FATAL_EXIT_CODE 33
 | ||
| --- a/gcc/config.gcc
 | ||
| +++ b/gcc/config.gcc
 | ||
| @@ -2497,6 +2497,34 @@ spu-*-elf*)
 | ||
|  	c_target_objs="${c_target_objs} spu-c.o"
 | ||
|  	cxx_target_objs="${cxx_target_objs} spu-c.o"
 | ||
|  	;;
 | ||
| +ubicom32-*-elf)
 | ||
| +	xm_file=ubicom32/xm-ubicom32.h
 | ||
| +	tm_file="${tm_file} ubicom32/elf.h" # still need dbxelf.h elfos.h
 | ||
| +	tmake_file=ubicom32/t-ubicom32
 | ||
| +	;;
 | ||
| +ubicom32-*-uclinux*)
 | ||
| +	xm_file=ubicom32/xm-ubicom32.h
 | ||
| +	tm_file="${tm_file} ubicom32/elf.h ubicom32/uclinux.h"  # still need dbxelf.h elfos.h linux.h
 | ||
| +	tm_defines="${tm_defines} UCLIBC_DEFAULT=1"
 | ||
| +	extra_options="${extra_options} linux.opt"
 | ||
| +	tmake_file=ubicom32/t-ubicom32-uclinux
 | ||
| +	use_collect2=no
 | ||
| +	;;
 | ||
| +ubicom32-*-linux-uclibc)
 | ||
| +	xm_file=ubicom32/xm-ubicom32.h
 | ||
| +	tm_file="${tm_file} ubicom32/elf.h linux.h ubicom32/linux.h"  # still need dbxelf.h elfos.h
 | ||
| +	tmake_file="t-slibgcc-elf-ver ubicom32/t-ubicom32-linux"
 | ||
| +	extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
 | ||
| +	use_collect2=no
 | ||
| +	;;
 | ||
| +ubicom32-*-linux*)
 | ||
| +	xm_file=ubicom32/xm-ubicom32.h
 | ||
| +	tm_file="${tm_file} ubicom32/elf.h linux.h ubicom32/linux.h"  # still need dbxelf.h elfos.h
 | ||
| +	tmake_file="t-slibgcc-elf-ver ubicom32/t-ubicom32-linux"
 | ||
| +	tm_defines="${tm_defines} UCLIBC_DEFAULT=1"
 | ||
| +	extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
 | ||
| +	use_collect2=no
 | ||
| +	;;
 | ||
|  v850e1-*-*)
 | ||
|  	target_cpu_default="TARGET_CPU_v850e1"
 | ||
|  	tm_file="dbxelf.h elfos.h svr4.h newlib-stdint.h v850/v850.h"
 | ||
| --- a/libgcc/config.host
 | ||
| +++ b/libgcc/config.host
 | ||
| @@ -560,6 +560,15 @@ sparc64-*-netbsd*)
 | ||
|  	;;
 | ||
|  spu-*-elf*)
 | ||
|  	;;
 | ||
| +ubicom32*-*-elf*)
 | ||
| +	;;
 | ||
| +ubicom32*-*-uclinux*)
 | ||
| +        ;;
 | ||
| +ubicom32*-*-linux*)
 | ||
| +	# No need to build crtbeginT.o on uClibc systems.  Should probably
 | ||
| +	# be moved to the OS specific section above.
 | ||
| +	extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
 | ||
| +        ;;
 | ||
|  v850e1-*-*)
 | ||
|  	;;
 | ||
|  v850e-*-*)
 |