From: Imre Kaloz Date: Tue, 21 Dec 2010 08:13:21 +0000 (+0000) Subject: add gcc 4.5.2 (replaces 4.5.1) X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=30439e70920e5d91f551d3a35be2efbd89e1852b;p=openwrt%2Fstaging%2Fldir.git add gcc 4.5.2 (replaces 4.5.1) SVN-Revision: 24746 --- diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk index 3a4a94a46a..b3025a62e6 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -66,8 +66,8 @@ else ifeq ($(PKG_VERSION),4.4.5) PKG_MD5SUM:=44b3192c4c584b9be5243d9e8e7e0ed1 endif - ifeq ($(PKG_VERSION),4.5.1) - PKG_MD5SUM:=48231a8e33ed6e058a341c53b819de1a + ifeq ($(PKG_VERSION),4.5.2) + PKG_MD5SUM:=e31fe695d7235f11fb5a63eafdfbfe88 endif endif endif diff --git a/toolchain/gcc/patches/4.5.1/002-fix_pr44392.patch b/toolchain/gcc/patches/4.5.1/002-fix_pr44392.patch deleted file mode 100644 index 4ad6c448d9..0000000000 --- a/toolchain/gcc/patches/4.5.1/002-fix_pr44392.patch +++ /dev/null @@ -1,70 +0,0 @@ ->From d0557763b0713a4c006bd2405eede3924569cafd Mon Sep 17 00:00:00 2001 -From: Ramana Radhakrishnan -Date: Mon, 5 Jul 2010 11:28:49 +0100 -Subject: [PATCH 2/2] Fix PR44392 - ---- - gcc/config/arm/arm.md | 43 +++++++++++++++++++------------------------ - 1 files changed, 19 insertions(+), 24 deletions(-) - -diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md -index 2096ec6..f0348f3 100644 ---- a/gcc/config/arm/arm.md -+++ b/gcc/config/arm/arm.md -@@ -11318,34 +11318,29 @@ - (define_expand "bswapsi2" - [(set (match_operand:SI 0 "s_register_operand" "=r") - (bswap:SI (match_operand:SI 1 "s_register_operand" "r")))] --"TARGET_EITHER" -+"TARGET_EITHER && (arm_arch6 || !optimize_size)" - " -- if (!arm_arch6) -- { -- if (!optimize_size) -- { -- rtx op2 = gen_reg_rtx (SImode); -- rtx op3 = gen_reg_rtx (SImode); -+ if (!arm_arch6) -+ { -+ rtx op2 = gen_reg_rtx (SImode); -+ rtx op3 = gen_reg_rtx (SImode); - -- if (TARGET_THUMB) -- { -- rtx op4 = gen_reg_rtx (SImode); -- rtx op5 = gen_reg_rtx (SImode); -+ if (TARGET_THUMB) -+ { -+ rtx op4 = gen_reg_rtx (SImode); -+ rtx op5 = gen_reg_rtx (SImode); - -- emit_insn (gen_thumb_legacy_rev (operands[0], operands[1], -- op2, op3, op4, op5)); -- } -- else -- { -- emit_insn (gen_arm_legacy_rev (operands[0], operands[1], -- op2, op3)); -- } -+ emit_insn (gen_thumb_legacy_rev (operands[0], operands[1], -+ op2, op3, op4, op5)); -+ } -+ else -+ { -+ emit_insn (gen_arm_legacy_rev (operands[0], operands[1], -+ op2, op3)); -+ } - -- DONE; -- } -- else -- FAIL; -- } -+ DONE; -+ } - " - ) - --- -1.6.2 - diff --git a/toolchain/gcc/patches/4.5.1/100-uclibc-conf.patch b/toolchain/gcc/patches/4.5.1/100-uclibc-conf.patch deleted file mode 100644 index 7c6b791162..0000000000 --- a/toolchain/gcc/patches/4.5.1/100-uclibc-conf.patch +++ /dev/null @@ -1,33 +0,0 @@ ---- a/contrib/regression/objs-gcc.sh -+++ b/contrib/regression/objs-gcc.sh -@@ -106,6 +106,10 @@ - then - make all-gdb all-dejagnu all-ld || exit 1 - make install-gdb install-dejagnu install-ld || exit 1 -+elif [ $H_REAL_TARGET = $H_REAL_HOST -a $H_REAL_TARGET = i686-pc-linux-uclibc ] -+ then -+ make all-gdb all-dejagnu all-ld || exit 1 -+ make install-gdb install-dejagnu install-ld || exit 1 - elif [ $H_REAL_TARGET = $H_REAL_HOST ] ; then - make bootstrap || exit 1 - make install || exit 1 ---- a/libjava/classpath/ltconfig -+++ b/libjava/classpath/ltconfig -@@ -603,7 +603,7 @@ - - # Transform linux* to *-*-linux-gnu*, to support old configure scripts. - case $host_os in --linux-gnu*) ;; -+linux-gnu*|linux-uclibc*) ;; - linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` - esac - -@@ -1251,7 +1251,7 @@ - ;; - - # This must be Linux ELF. --linux-gnu*) -+linux*) - version_type=linux - need_lib_prefix=no - need_version=no diff --git a/toolchain/gcc/patches/4.5.1/301-missing-execinfo_h.patch b/toolchain/gcc/patches/4.5.1/301-missing-execinfo_h.patch deleted file mode 100644 index 5a7aa4e47d..0000000000 --- a/toolchain/gcc/patches/4.5.1/301-missing-execinfo_h.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/boehm-gc/include/gc.h -+++ b/boehm-gc/include/gc.h -@@ -503,7 +503,7 @@ - #if defined(__linux__) || defined(__GLIBC__) - # include - # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ -- && !defined(__ia64__) -+ && !defined(__ia64__) && !defined(__UCLIBC__) - # ifndef GC_HAVE_BUILTIN_BACKTRACE - # define GC_HAVE_BUILTIN_BACKTRACE - # endif diff --git a/toolchain/gcc/patches/4.5.1/302-c99-snprintf.patch b/toolchain/gcc/patches/4.5.1/302-c99-snprintf.patch deleted file mode 100644 index f0ba5411ed..0000000000 --- a/toolchain/gcc/patches/4.5.1/302-c99-snprintf.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/libstdc++-v3/include/c_global/cstdio -+++ b/libstdc++-v3/include/c_global/cstdio -@@ -139,7 +139,7 @@ - - _GLIBCXX_END_NAMESPACE - --#if _GLIBCXX_USE_C99 -+#if _GLIBCXX_USE_C99 || defined __UCLIBC__ - - #undef snprintf - #undef vfscanf diff --git a/toolchain/gcc/patches/4.5.1/305-libmudflap-susv3-legacy.patch b/toolchain/gcc/patches/4.5.1/305-libmudflap-susv3-legacy.patch deleted file mode 100644 index 5bc4aebb67..0000000000 --- a/toolchain/gcc/patches/4.5.1/305-libmudflap-susv3-legacy.patch +++ /dev/null @@ -1,47 +0,0 @@ ---- a/libmudflap/mf-hooks2.c -+++ b/libmudflap/mf-hooks2.c -@@ -421,7 +421,7 @@ - { - TRACE ("%s\n", __PRETTY_FUNCTION__); - MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "bzero region"); -- bzero (s, n); -+ memset (s, 0, n); - } - - -@@ -431,7 +431,7 @@ - TRACE ("%s\n", __PRETTY_FUNCTION__); - MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "bcopy src"); - MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "bcopy dest"); -- bcopy (src, dest, n); -+ memmove (dest, src, n); - } - - -@@ -441,7 +441,7 @@ - TRACE ("%s\n", __PRETTY_FUNCTION__); - MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "bcmp 1st arg"); - MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "bcmp 2nd arg"); -- return bcmp (s1, s2, n); -+ return n == 0 ? 0 : memcmp (s1, s2, n); - } - - -@@ -450,7 +450,7 @@ - size_t n = strlen (s); - TRACE ("%s\n", __PRETTY_FUNCTION__); - MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "index region"); -- return index (s, c); -+ return strchr (s, c); - } - - -@@ -459,7 +459,7 @@ - size_t n = strlen (s); - TRACE ("%s\n", __PRETTY_FUNCTION__); - MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "rindex region"); -- return rindex (s, c); -+ return strrchr (s, c); - } - - /* XXX: stpcpy, memccpy */ diff --git a/toolchain/gcc/patches/4.5.1/600-ubicom_support.patch b/toolchain/gcc/patches/4.5.1/600-ubicom_support.patch deleted file mode 100644 index a8dbaf466d..0000000000 --- a/toolchain/gcc/patches/4.5.1/600-ubicom_support.patch +++ /dev/null @@ -1,9368 +0,0 @@ ---- a/configure -+++ b/configure -@@ -2688,6 +2688,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 -+; . -+ -+(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 -+ . */ -+ -+/* 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 -+; . -+ -+(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 -+ . */ -+ -+/* 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 -+ . */ -+ -+#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 -+ . */ -+ -+ -+ -+#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 -+; . -+ -+(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. -+; ;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 -+ . */ -+ -+/* 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 -@@ -2314,6 +2314,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 v850/v850.h" ---- a/libgcc/config.host -+++ b/libgcc/config.host -@@ -551,6 +551,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-*-*) diff --git a/toolchain/gcc/patches/4.5.1/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches/4.5.1/810-arm-softfloat-libgcc.patch deleted file mode 100644 index 4ca297a41a..0000000000 --- a/toolchain/gcc/patches/4.5.1/810-arm-softfloat-libgcc.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/gcc/config/arm/linux-elf.h -+++ b/gcc/config/arm/linux-elf.h -@@ -60,7 +60,7 @@ - %{shared:-lc} \ - %{!shared:%{profile:-lc_p}%{!profile:-lc}}" - --#define LIBGCC_SPEC "%{msoft-float:-lfloat} %{mfloat-abi=soft*:-lfloat} -lgcc" -+#define LIBGCC_SPEC "-lgcc" - - #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2" - ---- a/gcc/config/arm/t-linux -+++ b/gcc/config/arm/t-linux -@@ -4,7 +4,10 @@ - - LIB1ASMSRC = arm/lib1funcs.asm - LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \ -- _arm_addsubdf3 _arm_addsubsf3 -+ _arm_addsubdf3 _arm_addsubsf3 \ -+ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ -+ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ -+ _fixsfsi _fixunssfsi _floatdidf _floatundidf _floatdisf _floatundisf - - # MULTILIB_OPTIONS = mhard-float/msoft-float - # MULTILIB_DIRNAMES = hard-float soft-float diff --git a/toolchain/gcc/patches/4.5.1/820-libgcc_pic.patch b/toolchain/gcc/patches/4.5.1/820-libgcc_pic.patch deleted file mode 100644 index 18386dfd42..0000000000 --- a/toolchain/gcc/patches/4.5.1/820-libgcc_pic.patch +++ /dev/null @@ -1,36 +0,0 @@ ---- a/libgcc/Makefile.in -+++ b/libgcc/Makefile.in -@@ -729,11 +729,12 @@ $(libgcov-objects): %$(objext): $(gcc_sr - - # Static libraries. - libgcc.a: $(libgcc-objects) -+libgcc_pic.a: $(libgcc-s-objects) - libgcov.a: $(libgcov-objects) - libunwind.a: $(libunwind-objects) - libgcc_eh.a: $(libgcc-eh-objects) - --libgcc.a libgcov.a libunwind.a libgcc_eh.a: -+libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a: - -rm -f $@ - - objects="$(objects)"; \ -@@ -755,7 +756,7 @@ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_E - endif - - ifeq ($(enable_shared),yes) --all: libgcc_eh.a libgcc_s$(SHLIB_EXT) -+all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT) - ifneq ($(LIBUNWIND),) - all: libunwind$(SHLIB_EXT) - endif -@@ -928,6 +929,10 @@ install-shared: - chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a - $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a - -+ $(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/ -+ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a -+ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a -+ - $(subst @multilib_dir@,$(MULTIDIR),$(subst \ - @shlib_base_name@,libgcc_s,$(subst \ - @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL)))) diff --git a/toolchain/gcc/patches/4.5.1/910-mbsd_multi.patch b/toolchain/gcc/patches/4.5.1/910-mbsd_multi.patch deleted file mode 100644 index 0d5815a546..0000000000 --- a/toolchain/gcc/patches/4.5.1/910-mbsd_multi.patch +++ /dev/null @@ -1,253 +0,0 @@ - - This patch brings over a few features from MirBSD: - * -fhonour-copts - If this option is not given, it's warned (depending - on environment variables). This is to catch errors - of misbuilt packages which override CFLAGS themselves. - * -Werror-maybe-reset - Has the effect of -Wno-error if GCC_NO_WERROR is - set and not '0', a no-operation otherwise. This is - to be able to use -Werror in "make" but prevent - GNU autoconf generated configure scripts from - freaking out. - * Make -fno-strict-aliasing and -fno-delete-null-pointer-checks - the default for -O2/-Os, because they trigger gcc bugs - and can delete code with security implications. - - This patch was authored by Thorsten Glaser - with copyright assignment to the FSF in effect. - ---- a/gcc/c-opts.c -+++ b/gcc/c-opts.c -@@ -105,6 +105,9 @@ - /* Number of deferred options scanned for -include. */ - static size_t include_cursor; - -+/* Check if a port honours COPTS. */ -+static int honour_copts = 0; -+ - static void set_Wimplicit (int); - static void handle_OPT_d (const char *); - static void set_std_cxx98 (int); -@@ -454,6 +457,9 @@ - enable_warning_as_error ("implicit-function-declaration", value, CL_C | CL_ObjC); - break; - -+ case OPT_Werror_maybe_reset: -+ break; -+ - case OPT_Wformat: - set_Wformat (value); - break; -@@ -690,6 +701,12 @@ - flag_exceptions = value; - break; - -+ case OPT_fhonour_copts: -+ if (c_language == clk_c) { -+ honour_copts++; -+ } -+ break; -+ - case OPT_fimplement_inlines: - flag_implement_inlines = value; - break; -@@ -1209,6 +1226,47 @@ - return false; - } - -+ if (c_language == clk_c) { -+ char *ev = getenv ("GCC_HONOUR_COPTS"); -+ int evv; -+ if (ev == NULL) -+ evv = -1; -+ else if ((*ev == '0') || (*ev == '\0')) -+ evv = 0; -+ else if (*ev == '1') -+ evv = 1; -+ else if (*ev == '2') -+ evv = 2; -+ else if (*ev == 's') -+ evv = -1; -+ else { -+ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); -+ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ -+ } -+ if (evv == 1) { -+ if (honour_copts == 0) { -+ error ("someone does not honour COPTS at all in lenient mode"); -+ return false; -+ } else if (honour_copts != 1) { -+ warning (0, "someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ } -+ } else if (evv == 2) { -+ if (honour_copts == 0) { -+ error ("someone does not honour COPTS at all in strict mode"); -+ return false; -+ } else if (honour_copts != 1) { -+ error ("someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ return false; -+ } -+ } else if (evv == 0) { -+ if (honour_copts != 1) -+ inform (0, "someone does not honour COPTS correctly, passed %d times", -+ honour_copts); -+ } -+ } -+ - return true; - } - ---- a/gcc/c.opt -+++ b/gcc/c.opt -@@ -215,6 +215,10 @@ - C ObjC RejectNegative Warning - This switch is deprecated; use -Werror=implicit-function-declaration instead - -+Werror-maybe-reset -+C ObjC C++ ObjC++ -+; Documented in common.opt -+ - Wfloat-equal - C ObjC C++ ObjC++ Var(warn_float_equal) Warning - Warn if testing floating point numbers for equality -@@ -609,6 +613,9 @@ - fhonor-std - C++ ObjC++ - -+fhonour-copts -+C ObjC C++ ObjC++ RejectNegative -+ - fhosted - C ObjC - Assume normal C execution environment ---- a/gcc/common.opt -+++ b/gcc/common.opt -@@ -102,6 +102,10 @@ - Common Joined - Treat specified warning as error - -+Werror-maybe-reset -+Common -+If environment variable GCC_NO_WERROR is set, act as -Wno-error -+ - Wextra - Common Warning - Print extra (possibly unwanted) warnings -@@ -573,6 +577,9 @@ - Common Report Var(flag_guess_branch_prob) Optimization - Enable guessing of branch probabilities - -+fhonour-copts -+Common RejectNegative -+ - ; Nonzero means ignore `#ident' directives. 0 means handle them. - ; Generate position-independent code for executables if possible - ; On SVR4 targets, it also controls whether or not to emit a ---- a/gcc/opts.c -+++ b/gcc/opts.c -@@ -896,8 +896,6 @@ - flag_schedule_insns_after_reload = opt2; - #endif - flag_regmove = opt2; -- flag_strict_aliasing = opt2; -- flag_strict_overflow = opt2; - flag_reorder_blocks = opt2; - flag_reorder_functions = opt2; - flag_tree_vrp = opt2; -@@ -922,6 +919,8 @@ - - /* -O3 optimizations. */ - opt3 = (optimize >= 3); -+ flag_strict_aliasing = opt3; -+ flag_strict_overflow = opt3; - flag_predictive_commoning = opt3; - flag_inline_functions = opt3; - flag_unswitch_loops = opt3; -@@ -1601,6 +1601,17 @@ - enable_warning_as_error (arg, value, lang_mask); - break; - -+ case OPT_Werror_maybe_reset: -+ { -+ char *ev = getenv ("GCC_NO_WERROR"); -+ if ((ev != NULL) && (*ev != '0')) -+ warnings_are_errors = 0; -+ } -+ break; -+ -+ case OPT_fhonour_copts: -+ break; -+ - case OPT_Wlarger_than_: - /* This form corresponds to -Wlarger-than-. - Kept for backward compatibility. ---- a/gcc/doc/cppopts.texi -+++ b/gcc/doc/cppopts.texi -@@ -164,6 +164,11 @@ - Make all warnings into hard errors. Source code which triggers warnings - will be rejected. - -+ at item -Werror-maybe-reset -+ at opindex Werror-maybe-reset -+Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment -+variable is set to anything other than 0 or empty. -+ - @item -Wsystem-headers - @opindex Wsystem-headers - Issue warnings for code in system headers. These are normally unhelpful ---- a/gcc/doc/invoke.texi -+++ b/gcc/doc/invoke.texi -@@ -234,7 +234,7 @@ - -Wconversion -Wcoverage-mismatch -Wno-deprecated @gol - -Wno-deprecated-declarations -Wdisabled-optimization @gol - -Wno-div-by-zero -Wempty-body -Wenum-compare -Wno-endif-labels @gol ---Werror -Werror=* @gol -+-Werror -Werror=* -Werror-maybe-reset @gol - -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol - -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol - -Wformat-security -Wformat-y2k @gol -@@ -4161,6 +4161,22 @@ - @option{-Wall} and by @option{-pedantic}, which can be disabled with - @option{-Wno-pointer-sign}. - -+ at item -Werror-maybe-reset -+ at opindex Werror-maybe-reset -+Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment -+variable is set to anything other than 0 or empty. -+ -+ at item -fhonour-copts -+ at opindex fhonour-copts -+If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not -+given at least once, and warn if it is given more than once. -+If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not -+given exactly once. -+If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option -+is not given exactly once. -+The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. -+This flag and environment variable only affect the C language. -+ - @item -Wstack-protector - @opindex Wstack-protector - @opindex Wno-stack-protector -@@ -5699,7 +5715,7 @@ - second branch or a point immediately following it, depending on whether - the condition is known to be true or false. - --Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. -+Enabled at levels @option{-O3}. - - @item -fsplit-wide-types - @opindex fsplit-wide-types ---- a/gcc/java/jvspec.c -+++ b/gcc/java/jvspec.c -@@ -670,6 +670,7 @@ - class name. Append dummy `.c' that can be stripped by set_input so %b - is correct. */ - set_input (concat (main_class_name, "main.c", NULL)); -+ putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack! */ - err = do_spec (jvgenmain_spec); - if (err == 0) - { diff --git a/toolchain/gcc/patches/4.5.1/993-arm_insn-opinit-RTX_CODE-fixup.patch b/toolchain/gcc/patches/4.5.1/993-arm_insn-opinit-RTX_CODE-fixup.patch deleted file mode 100644 index 4c4be9f2a0..0000000000 --- a/toolchain/gcc/patches/4.5.1/993-arm_insn-opinit-RTX_CODE-fixup.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- gcc-4.4.0/gcc/config/arm/arm-protos.h 2009-02-20 16:20:38.000000000 +0100 -+++ gcc-4.4.0.new/gcc/config/arm/arm-protos.h 2009-04-22 16:00:58.000000000 +0200 -@@ -43,10 +43,10 @@ - extern void arm_output_fn_unwind (FILE *, bool); - - --#ifdef RTX_CODE - extern bool arm_vector_mode_supported_p (enum machine_mode); - extern int arm_hard_regno_mode_ok (unsigned int, enum machine_mode); - extern int const_ok_for_arm (HOST_WIDE_INT); -+#ifdef RTX_CODE - extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx, - HOST_WIDE_INT, rtx, rtx, int); - extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, enum machine_mode, diff --git a/toolchain/gcc/patches/4.5.1/999-coldfire.patch b/toolchain/gcc/patches/4.5.1/999-coldfire.patch deleted file mode 100644 index 980e276947..0000000000 --- a/toolchain/gcc/patches/4.5.1/999-coldfire.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: gcc-4.4.2/gcc/config.gcc -=================================================================== ---- gcc-4.4.2.orig/gcc/config.gcc 2009-10-21 16:19:39.000000000 +0200 -+++ gcc-4.4.2/gcc/config.gcc 2009-10-21 16:19:40.000000000 +0200 -@@ -1506,6 +1506,7 @@ - if test x$sjlj != x1; then - tmake_file="$tmake_file m68k/t-slibgcc-elf-ver" - fi -+ tmake_file="m68k/t-floatlib m68k/t-m68kbare m68k/t-m68kelf" - ;; - m68k-*-rtems*) - default_m68k_cpu=68020 diff --git a/toolchain/gcc/patches/4.5.2/002-fix_pr44392.patch b/toolchain/gcc/patches/4.5.2/002-fix_pr44392.patch new file mode 100644 index 0000000000..4ad6c448d9 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/002-fix_pr44392.patch @@ -0,0 +1,70 @@ +>From d0557763b0713a4c006bd2405eede3924569cafd Mon Sep 17 00:00:00 2001 +From: Ramana Radhakrishnan +Date: Mon, 5 Jul 2010 11:28:49 +0100 +Subject: [PATCH 2/2] Fix PR44392 + +--- + gcc/config/arm/arm.md | 43 +++++++++++++++++++------------------------ + 1 files changed, 19 insertions(+), 24 deletions(-) + +diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md +index 2096ec6..f0348f3 100644 +--- a/gcc/config/arm/arm.md ++++ b/gcc/config/arm/arm.md +@@ -11318,34 +11318,29 @@ + (define_expand "bswapsi2" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (bswap:SI (match_operand:SI 1 "s_register_operand" "r")))] +-"TARGET_EITHER" ++"TARGET_EITHER && (arm_arch6 || !optimize_size)" + " +- if (!arm_arch6) +- { +- if (!optimize_size) +- { +- rtx op2 = gen_reg_rtx (SImode); +- rtx op3 = gen_reg_rtx (SImode); ++ if (!arm_arch6) ++ { ++ rtx op2 = gen_reg_rtx (SImode); ++ rtx op3 = gen_reg_rtx (SImode); + +- if (TARGET_THUMB) +- { +- rtx op4 = gen_reg_rtx (SImode); +- rtx op5 = gen_reg_rtx (SImode); ++ if (TARGET_THUMB) ++ { ++ rtx op4 = gen_reg_rtx (SImode); ++ rtx op5 = gen_reg_rtx (SImode); + +- emit_insn (gen_thumb_legacy_rev (operands[0], operands[1], +- op2, op3, op4, op5)); +- } +- else +- { +- emit_insn (gen_arm_legacy_rev (operands[0], operands[1], +- op2, op3)); +- } ++ emit_insn (gen_thumb_legacy_rev (operands[0], operands[1], ++ op2, op3, op4, op5)); ++ } ++ else ++ { ++ emit_insn (gen_arm_legacy_rev (operands[0], operands[1], ++ op2, op3)); ++ } + +- DONE; +- } +- else +- FAIL; +- } ++ DONE; ++ } + " + ) + +-- +1.6.2 + diff --git a/toolchain/gcc/patches/4.5.2/100-uclibc-conf.patch b/toolchain/gcc/patches/4.5.2/100-uclibc-conf.patch new file mode 100644 index 0000000000..7c6b791162 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/100-uclibc-conf.patch @@ -0,0 +1,33 @@ +--- a/contrib/regression/objs-gcc.sh ++++ b/contrib/regression/objs-gcc.sh +@@ -106,6 +106,10 @@ + then + make all-gdb all-dejagnu all-ld || exit 1 + make install-gdb install-dejagnu install-ld || exit 1 ++elif [ $H_REAL_TARGET = $H_REAL_HOST -a $H_REAL_TARGET = i686-pc-linux-uclibc ] ++ then ++ make all-gdb all-dejagnu all-ld || exit 1 ++ make install-gdb install-dejagnu install-ld || exit 1 + elif [ $H_REAL_TARGET = $H_REAL_HOST ] ; then + make bootstrap || exit 1 + make install || exit 1 +--- a/libjava/classpath/ltconfig ++++ b/libjava/classpath/ltconfig +@@ -603,7 +603,7 @@ + + # Transform linux* to *-*-linux-gnu*, to support old configure scripts. + case $host_os in +-linux-gnu*) ;; ++linux-gnu*|linux-uclibc*) ;; + linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` + esac + +@@ -1251,7 +1251,7 @@ + ;; + + # This must be Linux ELF. +-linux-gnu*) ++linux*) + version_type=linux + need_lib_prefix=no + need_version=no diff --git a/toolchain/gcc/patches/4.5.2/301-missing-execinfo_h.patch b/toolchain/gcc/patches/4.5.2/301-missing-execinfo_h.patch new file mode 100644 index 0000000000..5a7aa4e47d --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- a/boehm-gc/include/gc.h ++++ b/boehm-gc/include/gc.h +@@ -503,7 +503,7 @@ + #if defined(__linux__) || defined(__GLIBC__) + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/toolchain/gcc/patches/4.5.2/302-c99-snprintf.patch b/toolchain/gcc/patches/4.5.2/302-c99-snprintf.patch new file mode 100644 index 0000000000..f0ba5411ed --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- a/libstdc++-v3/include/c_global/cstdio ++++ b/libstdc++-v3/include/c_global/cstdio +@@ -139,7 +139,7 @@ + + _GLIBCXX_END_NAMESPACE + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined __UCLIBC__ + + #undef snprintf + #undef vfscanf diff --git a/toolchain/gcc/patches/4.5.2/305-libmudflap-susv3-legacy.patch b/toolchain/gcc/patches/4.5.2/305-libmudflap-susv3-legacy.patch new file mode 100644 index 0000000000..5bc4aebb67 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/305-libmudflap-susv3-legacy.patch @@ -0,0 +1,47 @@ +--- a/libmudflap/mf-hooks2.c ++++ b/libmudflap/mf-hooks2.c +@@ -421,7 +421,7 @@ + { + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "bzero region"); +- bzero (s, n); ++ memset (s, 0, n); + } + + +@@ -431,7 +431,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "bcopy src"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "bcopy dest"); +- bcopy (src, dest, n); ++ memmove (dest, src, n); + } + + +@@ -441,7 +441,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "bcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "bcmp 2nd arg"); +- return bcmp (s1, s2, n); ++ return n == 0 ? 0 : memcmp (s1, s2, n); + } + + +@@ -450,7 +450,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "index region"); +- return index (s, c); ++ return strchr (s, c); + } + + +@@ -459,7 +459,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "rindex region"); +- return rindex (s, c); ++ return strrchr (s, c); + } + + /* XXX: stpcpy, memccpy */ diff --git a/toolchain/gcc/patches/4.5.2/600-ubicom_support.patch b/toolchain/gcc/patches/4.5.2/600-ubicom_support.patch new file mode 100644 index 0000000000..a8dbaf466d --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/600-ubicom_support.patch @@ -0,0 +1,9368 @@ +--- a/configure ++++ b/configure +@@ -2688,6 +2688,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 ++; . ++ ++(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 ++ . */ ++ ++/* 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 ++; . ++ ++(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 ++ . */ ++ ++/* 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 ++ . */ ++ ++#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 ++ . */ ++ ++ ++ ++#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 ++; . ++ ++(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. ++; ;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 ++ . */ ++ ++/* 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 +@@ -2314,6 +2314,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 v850/v850.h" +--- a/libgcc/config.host ++++ b/libgcc/config.host +@@ -551,6 +551,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-*-*) diff --git a/toolchain/gcc/patches/4.5.2/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches/4.5.2/810-arm-softfloat-libgcc.patch new file mode 100644 index 0000000000..4ca297a41a --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/810-arm-softfloat-libgcc.patch @@ -0,0 +1,25 @@ +--- a/gcc/config/arm/linux-elf.h ++++ b/gcc/config/arm/linux-elf.h +@@ -60,7 +60,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} %{mfloat-abi=soft*:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2" + +--- a/gcc/config/arm/t-linux ++++ b/gcc/config/arm/t-linux +@@ -4,7 +4,10 @@ + + LIB1ASMSRC = arm/lib1funcs.asm + LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \ +- _arm_addsubdf3 _arm_addsubsf3 ++ _arm_addsubdf3 _arm_addsubsf3 \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi _floatdidf _floatundidf _floatdisf _floatundisf + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float diff --git a/toolchain/gcc/patches/4.5.2/820-libgcc_pic.patch b/toolchain/gcc/patches/4.5.2/820-libgcc_pic.patch new file mode 100644 index 0000000000..18386dfd42 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/820-libgcc_pic.patch @@ -0,0 +1,36 @@ +--- a/libgcc/Makefile.in ++++ b/libgcc/Makefile.in +@@ -729,11 +729,12 @@ $(libgcov-objects): %$(objext): $(gcc_sr + + # Static libraries. + libgcc.a: $(libgcc-objects) ++libgcc_pic.a: $(libgcc-s-objects) + libgcov.a: $(libgcov-objects) + libunwind.a: $(libunwind-objects) + libgcc_eh.a: $(libgcc-eh-objects) + +-libgcc.a libgcov.a libunwind.a libgcc_eh.a: ++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a: + -rm -f $@ + + objects="$(objects)"; \ +@@ -755,7 +756,7 @@ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_E + endif + + ifeq ($(enable_shared),yes) +-all: libgcc_eh.a libgcc_s$(SHLIB_EXT) ++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT) + ifneq ($(LIBUNWIND),) + all: libunwind$(SHLIB_EXT) + endif +@@ -928,6 +929,10 @@ install-shared: + chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a + $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a + ++ $(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/ ++ chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a ++ $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a ++ + $(subst @multilib_dir@,$(MULTIDIR),$(subst \ + @shlib_base_name@,libgcc_s,$(subst \ + @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL)))) diff --git a/toolchain/gcc/patches/4.5.2/910-mbsd_multi.patch b/toolchain/gcc/patches/4.5.2/910-mbsd_multi.patch new file mode 100644 index 0000000000..0d5815a546 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/910-mbsd_multi.patch @@ -0,0 +1,253 @@ + + This patch brings over a few features from MirBSD: + * -fhonour-copts + If this option is not given, it's warned (depending + on environment variables). This is to catch errors + of misbuilt packages which override CFLAGS themselves. + * -Werror-maybe-reset + Has the effect of -Wno-error if GCC_NO_WERROR is + set and not '0', a no-operation otherwise. This is + to be able to use -Werror in "make" but prevent + GNU autoconf generated configure scripts from + freaking out. + * Make -fno-strict-aliasing and -fno-delete-null-pointer-checks + the default for -O2/-Os, because they trigger gcc bugs + and can delete code with security implications. + + This patch was authored by Thorsten Glaser + with copyright assignment to the FSF in effect. + +--- a/gcc/c-opts.c ++++ b/gcc/c-opts.c +@@ -105,6 +105,9 @@ + /* Number of deferred options scanned for -include. */ + static size_t include_cursor; + ++/* Check if a port honours COPTS. */ ++static int honour_copts = 0; ++ + static void set_Wimplicit (int); + static void handle_OPT_d (const char *); + static void set_std_cxx98 (int); +@@ -454,6 +457,9 @@ + enable_warning_as_error ("implicit-function-declaration", value, CL_C | CL_ObjC); + break; + ++ case OPT_Werror_maybe_reset: ++ break; ++ + case OPT_Wformat: + set_Wformat (value); + break; +@@ -690,6 +701,12 @@ + flag_exceptions = value; + break; + ++ case OPT_fhonour_copts: ++ if (c_language == clk_c) { ++ honour_copts++; ++ } ++ break; ++ + case OPT_fimplement_inlines: + flag_implement_inlines = value; + break; +@@ -1209,6 +1226,47 @@ + return false; + } + ++ if (c_language == clk_c) { ++ char *ev = getenv ("GCC_HONOUR_COPTS"); ++ int evv; ++ if (ev == NULL) ++ evv = -1; ++ else if ((*ev == '0') || (*ev == '\0')) ++ evv = 0; ++ else if (*ev == '1') ++ evv = 1; ++ else if (*ev == '2') ++ evv = 2; ++ else if (*ev == 's') ++ evv = -1; ++ else { ++ warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1"); ++ evv = 1; /* maybe depend this on something like MIRBSD_NATIVE? */ ++ } ++ if (evv == 1) { ++ if (honour_copts == 0) { ++ error ("someone does not honour COPTS at all in lenient mode"); ++ return false; ++ } else if (honour_copts != 1) { ++ warning (0, "someone does not honour COPTS correctly, passed %d times", ++ honour_copts); ++ } ++ } else if (evv == 2) { ++ if (honour_copts == 0) { ++ error ("someone does not honour COPTS at all in strict mode"); ++ return false; ++ } else if (honour_copts != 1) { ++ error ("someone does not honour COPTS correctly, passed %d times", ++ honour_copts); ++ return false; ++ } ++ } else if (evv == 0) { ++ if (honour_copts != 1) ++ inform (0, "someone does not honour COPTS correctly, passed %d times", ++ honour_copts); ++ } ++ } ++ + return true; + } + +--- a/gcc/c.opt ++++ b/gcc/c.opt +@@ -215,6 +215,10 @@ + C ObjC RejectNegative Warning + This switch is deprecated; use -Werror=implicit-function-declaration instead + ++Werror-maybe-reset ++C ObjC C++ ObjC++ ++; Documented in common.opt ++ + Wfloat-equal + C ObjC C++ ObjC++ Var(warn_float_equal) Warning + Warn if testing floating point numbers for equality +@@ -609,6 +613,9 @@ + fhonor-std + C++ ObjC++ + ++fhonour-copts ++C ObjC C++ ObjC++ RejectNegative ++ + fhosted + C ObjC + Assume normal C execution environment +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -102,6 +102,10 @@ + Common Joined + Treat specified warning as error + ++Werror-maybe-reset ++Common ++If environment variable GCC_NO_WERROR is set, act as -Wno-error ++ + Wextra + Common Warning + Print extra (possibly unwanted) warnings +@@ -573,6 +577,9 @@ + Common Report Var(flag_guess_branch_prob) Optimization + Enable guessing of branch probabilities + ++fhonour-copts ++Common RejectNegative ++ + ; Nonzero means ignore `#ident' directives. 0 means handle them. + ; Generate position-independent code for executables if possible + ; On SVR4 targets, it also controls whether or not to emit a +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -896,8 +896,6 @@ + flag_schedule_insns_after_reload = opt2; + #endif + flag_regmove = opt2; +- flag_strict_aliasing = opt2; +- flag_strict_overflow = opt2; + flag_reorder_blocks = opt2; + flag_reorder_functions = opt2; + flag_tree_vrp = opt2; +@@ -922,6 +919,8 @@ + + /* -O3 optimizations. */ + opt3 = (optimize >= 3); ++ flag_strict_aliasing = opt3; ++ flag_strict_overflow = opt3; + flag_predictive_commoning = opt3; + flag_inline_functions = opt3; + flag_unswitch_loops = opt3; +@@ -1601,6 +1601,17 @@ + enable_warning_as_error (arg, value, lang_mask); + break; + ++ case OPT_Werror_maybe_reset: ++ { ++ char *ev = getenv ("GCC_NO_WERROR"); ++ if ((ev != NULL) && (*ev != '0')) ++ warnings_are_errors = 0; ++ } ++ break; ++ ++ case OPT_fhonour_copts: ++ break; ++ + case OPT_Wlarger_than_: + /* This form corresponds to -Wlarger-than-. + Kept for backward compatibility. +--- a/gcc/doc/cppopts.texi ++++ b/gcc/doc/cppopts.texi +@@ -164,6 +164,11 @@ + Make all warnings into hard errors. Source code which triggers warnings + will be rejected. + ++ at item -Werror-maybe-reset ++ at opindex Werror-maybe-reset ++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment ++variable is set to anything other than 0 or empty. ++ + @item -Wsystem-headers + @opindex Wsystem-headers + Issue warnings for code in system headers. These are normally unhelpful +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi +@@ -234,7 +234,7 @@ + -Wconversion -Wcoverage-mismatch -Wno-deprecated @gol + -Wno-deprecated-declarations -Wdisabled-optimization @gol + -Wno-div-by-zero -Wempty-body -Wenum-compare -Wno-endif-labels @gol +--Werror -Werror=* @gol ++-Werror -Werror=* -Werror-maybe-reset @gol + -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol + -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol + -Wformat-security -Wformat-y2k @gol +@@ -4161,6 +4161,22 @@ + @option{-Wall} and by @option{-pedantic}, which can be disabled with + @option{-Wno-pointer-sign}. + ++ at item -Werror-maybe-reset ++ at opindex Werror-maybe-reset ++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment ++variable is set to anything other than 0 or empty. ++ ++ at item -fhonour-copts ++ at opindex fhonour-copts ++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not ++given at least once, and warn if it is given more than once. ++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not ++given exactly once. ++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option ++is not given exactly once. ++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}. ++This flag and environment variable only affect the C language. ++ + @item -Wstack-protector + @opindex Wstack-protector + @opindex Wno-stack-protector +@@ -5699,7 +5715,7 @@ + second branch or a point immediately following it, depending on whether + the condition is known to be true or false. + +-Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. ++Enabled at levels @option{-O3}. + + @item -fsplit-wide-types + @opindex fsplit-wide-types +--- a/gcc/java/jvspec.c ++++ b/gcc/java/jvspec.c +@@ -670,6 +670,7 @@ + class name. Append dummy `.c' that can be stripped by set_input so %b + is correct. */ + set_input (concat (main_class_name, "main.c", NULL)); ++ putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack! */ + err = do_spec (jvgenmain_spec); + if (err == 0) + { diff --git a/toolchain/gcc/patches/4.5.2/993-arm_insn-opinit-RTX_CODE-fixup.patch b/toolchain/gcc/patches/4.5.2/993-arm_insn-opinit-RTX_CODE-fixup.patch new file mode 100644 index 0000000000..4c4be9f2a0 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/993-arm_insn-opinit-RTX_CODE-fixup.patch @@ -0,0 +1,14 @@ +--- gcc-4.4.0/gcc/config/arm/arm-protos.h 2009-02-20 16:20:38.000000000 +0100 ++++ gcc-4.4.0.new/gcc/config/arm/arm-protos.h 2009-04-22 16:00:58.000000000 +0200 +@@ -43,10 +43,10 @@ + extern void arm_output_fn_unwind (FILE *, bool); + + +-#ifdef RTX_CODE + extern bool arm_vector_mode_supported_p (enum machine_mode); + extern int arm_hard_regno_mode_ok (unsigned int, enum machine_mode); + extern int const_ok_for_arm (HOST_WIDE_INT); ++#ifdef RTX_CODE + extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx, + HOST_WIDE_INT, rtx, rtx, int); + extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, enum machine_mode, diff --git a/toolchain/gcc/patches/4.5.2/999-coldfire.patch b/toolchain/gcc/patches/4.5.2/999-coldfire.patch new file mode 100644 index 0000000000..980e276947 --- /dev/null +++ b/toolchain/gcc/patches/4.5.2/999-coldfire.patch @@ -0,0 +1,12 @@ +Index: gcc-4.4.2/gcc/config.gcc +=================================================================== +--- gcc-4.4.2.orig/gcc/config.gcc 2009-10-21 16:19:39.000000000 +0200 ++++ gcc-4.4.2/gcc/config.gcc 2009-10-21 16:19:40.000000000 +0200 +@@ -1506,6 +1506,7 @@ + if test x$sjlj != x1; then + tmake_file="$tmake_file m68k/t-slibgcc-elf-ver" + fi ++ tmake_file="m68k/t-floatlib m68k/t-m68kbare m68k/t-m68kelf" + ;; + m68k-*-rtems*) + default_m68k_cpu=68020