|
@@ -1,9368 +0,0 @@
|
|
|
---- a/configure
|
|
|
-+++ b/configure
|
|
|
-@@ -3350,6 +3350,9 @@ case "${target}" in
|
|
|
- *-*-freebsd*)
|
|
|
- noconfigdirs="$noconfigdirs target-newlib target-libgloss"
|
|
|
- ;;
|
|
|
-+ ubicom32-*-*)
|
|
|
-+ noconfigdirs="$noconfigdirs target-libffi"
|
|
|
-+ ;;
|
|
|
- *-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
|
|
|
- noconfigdirs="$noconfigdirs target-newlib target-libgloss"
|
|
|
- ;;
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/constraints.md
|
|
|
-@@ -0,0 +1,149 @@
|
|
|
-+; Constraint definitions for Ubicom32
|
|
|
-+
|
|
|
-+; Copyright (C) 2009 Free Software Foundation, Inc.
|
|
|
-+; Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+; This file is part of GCC.
|
|
|
-+
|
|
|
-+; GCC is free software; you can redistribute it and/or modify it
|
|
|
-+; under the terms of the GNU General Public License as published
|
|
|
-+; by the Free Software Foundation; either version 3, or (at your
|
|
|
-+; option) any later version.
|
|
|
-+
|
|
|
-+; GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+; License for more details.
|
|
|
-+
|
|
|
-+; You should have received a copy of the GNU General Public License
|
|
|
-+; along with GCC; see the file COPYING3. If not see
|
|
|
-+; <http://www.gnu.org/licenses/>.
|
|
|
-+
|
|
|
-+(define_register_constraint "a" "ALL_ADDRESS_REGS"
|
|
|
-+ "An An register.")
|
|
|
-+
|
|
|
-+(define_register_constraint "d" "DATA_REGS"
|
|
|
-+ "A Dn register.")
|
|
|
-+
|
|
|
-+(define_register_constraint "h" "ACC_REGS"
|
|
|
-+ "An accumulator register.")
|
|
|
-+
|
|
|
-+(define_register_constraint "l" "ACC_LO_REGS"
|
|
|
-+ "An accn_lo register.")
|
|
|
-+
|
|
|
-+(define_register_constraint "Z" "FDPIC_REG"
|
|
|
-+ "The FD-PIC GOT pointer: A0.")
|
|
|
-+
|
|
|
-+(define_constraint "I"
|
|
|
-+ "An 8-bit signed constant value."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= -128) && (ival <= 127)")))
|
|
|
-+
|
|
|
-+(define_constraint "Q"
|
|
|
-+ "An 8-bit signed constant value represented as unsigned."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= 0x00) && (ival <= 0xff)")))
|
|
|
-+
|
|
|
-+(define_constraint "R"
|
|
|
-+ "An 8-bit signed constant value represented as unsigned."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "((ival >= 0x0000) && (ival <= 0x007f)) || ((ival >= 0xff80) && (ival <= 0xffff))")))
|
|
|
-+
|
|
|
-+(define_constraint "J"
|
|
|
-+ "A 7-bit unsigned constant value."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= 0) && (ival <= 127)")))
|
|
|
-+
|
|
|
-+(define_constraint "K"
|
|
|
-+ "A 7-bit unsigned constant value shifted << 1."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= 0) && (ival <= 254) && ((ival & 1) == 0)")))
|
|
|
-+
|
|
|
-+(define_constraint "L"
|
|
|
-+ "A 7-bit unsigned constant value shifted << 2."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= 0) && (ival <= 508) && ((ival & 3) == 0)")))
|
|
|
-+
|
|
|
-+(define_constraint "M"
|
|
|
-+ "A 5-bit unsigned constant value."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= 0) && (ival <= 31)")))
|
|
|
-+
|
|
|
-+(define_constraint "N"
|
|
|
-+ "A signed 16 bit constant value."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= -32768) && (ival <= 32767)")))
|
|
|
-+
|
|
|
-+(define_constraint "O"
|
|
|
-+ "An exact bitmask of contiguous 1 bits starting at bit 0."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "exact_log2 (ival + 1) != -1")))
|
|
|
-+
|
|
|
-+(define_constraint "P"
|
|
|
-+ "A 7-bit negative constant value shifted << 2."
|
|
|
-+ (and (match_code "const_int")
|
|
|
-+ (match_test "(ival >= -504) && (ival <= 0) && ((ival & 3) == 0)")))
|
|
|
-+
|
|
|
-+(define_constraint "S"
|
|
|
-+ "A symbolic reference."
|
|
|
-+ (match_code "symbol_ref"))
|
|
|
-+
|
|
|
-+(define_constraint "Y"
|
|
|
-+ "An FD-PIC symbolic reference."
|
|
|
-+ (and (match_test "TARGET_FDPIC")
|
|
|
-+ (match_test "GET_CODE (op) == UNSPEC")
|
|
|
-+ (ior (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT")
|
|
|
-+ (match_test "XINT (op, 1) == UNSPEC_FDPIC_GOT_FUNCDESC"))))
|
|
|
-+
|
|
|
-+(define_memory_constraint "T1"
|
|
|
-+ "A memory operand that can be used for .1 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (match_test "GET_MODE (op) == QImode")))
|
|
|
-+
|
|
|
-+(define_memory_constraint "T2"
|
|
|
-+ "A memory operand that can be used for .2 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (match_test "GET_MODE (op) == HImode")))
|
|
|
-+
|
|
|
-+(define_memory_constraint "T4"
|
|
|
-+ "A memory operand that can be used for .4 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (ior (match_test "GET_MODE (op) == SImode")
|
|
|
-+ (match_test "GET_MODE (op) == DImode")
|
|
|
-+ (match_test "GET_MODE (op) == SFmode"))))
|
|
|
-+
|
|
|
-+(define_memory_constraint "U1"
|
|
|
-+ "An offsettable memory operand that can be used for .1 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (match_test "GET_MODE (op) == QImode")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
|
|
|
-+
|
|
|
-+(define_memory_constraint "U2"
|
|
|
-+ "An offsettable memory operand that can be used for .2 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (match_test "GET_MODE (op) == HImode")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
|
|
|
-+
|
|
|
-+(define_memory_constraint "U4"
|
|
|
-+ "An offsettable memory operand that can be used for .4 instruction."
|
|
|
-+ (and (match_test "memory_operand (op, GET_MODE(op))")
|
|
|
-+ (ior (match_test "GET_MODE (op) == SImode")
|
|
|
-+ (match_test "GET_MODE (op) == DImode")
|
|
|
-+ (match_test "GET_MODE (op) == SFmode"))
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_INC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_DEC")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != POST_MODIFY")
|
|
|
-+ (match_test "GET_CODE (XEXP (op, 0)) != PRE_MODIFY")))
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/crti.S
|
|
|
-@@ -0,0 +1,54 @@
|
|
|
-+/* Specialized code needed to support construction and destruction of
|
|
|
-+ file-scope objects in C++ and Java code, and to support exception handling.
|
|
|
-+ Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Charles-Antoine Gauthier ([email protected]).
|
|
|
-+
|
|
|
-+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 ([email protected]).
|
|
|
-+
|
|
|
-+This file is part of GCC.
|
|
|
-+
|
|
|
-+GCC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GCC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GCC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+/* As a special exception, if you link this library with files
|
|
|
-+ compiled with GCC to produce an executable, this does not cause
|
|
|
-+ the resulting executable to be covered by the GNU General Public License.
|
|
|
-+ This exception does not however invalidate any other reasons why
|
|
|
-+ the executable file might be covered by the GNU General Public License. */
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This file supplies function epilogues for the .init and .fini sections.
|
|
|
-+ * It is linked in after all other files.
|
|
|
-+ */
|
|
|
-+
|
|
|
-+ .file "crtn.o"
|
|
|
-+ .ident "GNU C crtn.o"
|
|
|
-+
|
|
|
-+ .section .init
|
|
|
-+#ifdef __UBICOM32_FDPIC__
|
|
|
-+ move.4 a0, (sp)4++
|
|
|
-+#endif
|
|
|
-+ ret (sp)4++
|
|
|
-+
|
|
|
-+ .section .fini
|
|
|
-+#ifdef __UBICOM32_FDPIC__
|
|
|
-+ move.4 a0, (sp)4++
|
|
|
-+#endif
|
|
|
-+ ret (sp)4++
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/elf.h
|
|
|
-@@ -0,0 +1,29 @@
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#define STARTFILE_SPEC "\
|
|
|
-+%{msim:%{!shared:crt0%O%s}} \
|
|
|
-+crti%O%s crtbegin%O%s"
|
|
|
-+
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+#define ENDFILE_SPEC "crtend%O%s crtn%O%s"
|
|
|
-+
|
|
|
-+#ifdef __UBICOM32_FDPIC__
|
|
|
-+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
|
|
|
-+ asm (SECTION_OP); \
|
|
|
-+ asm ("move.4 a0, 0(sp);\n\t" \
|
|
|
-+ "call a5," USER_LABEL_PREFIX #FUNC ";"); \
|
|
|
-+ asm (TEXT_SECTION_ASM_OP);
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#undef SUBTARGET_DRIVER_SELF_SPECS
|
|
|
-+#define SUBTARGET_DRIVER_SELF_SPECS \
|
|
|
-+ "%{mfdpic:-msim} "
|
|
|
-+
|
|
|
-+#define NO_IMPLICIT_EXTERN_C
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * We need this to compile crtbegin/crtend. This should really be picked
|
|
|
-+ * up from elfos.h but at the moment including elfos.h causes other more
|
|
|
-+ * serous linker issues.
|
|
|
-+ */
|
|
|
-+#define INIT_SECTION_ASM_OP "\t.section\t.init"
|
|
|
-+#define FINI_SECTION_ASM_OP "\t.section\t.fini"
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/linux.h
|
|
|
-@@ -0,0 +1,80 @@
|
|
|
-+/* Definitions of target machine for Ubicom32-uclinux
|
|
|
-+
|
|
|
-+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
|
-+ 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GCC.
|
|
|
-+
|
|
|
-+ GCC is free software; you can redistribute it and/or modify it
|
|
|
-+ under the terms of the GNU General Public License as published
|
|
|
-+ by the Free Software Foundation; either version 3, or (at your
|
|
|
-+ option) any later version.
|
|
|
-+
|
|
|
-+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+ License for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License
|
|
|
-+ along with GCC; see the file COPYING3. If not see
|
|
|
-+ <http://www.gnu.org/licenses/>. */
|
|
|
-+
|
|
|
-+/* Don't assume anything about the header files. */
|
|
|
-+#define NO_IMPLICIT_EXTERN_C
|
|
|
-+
|
|
|
-+#undef LIB_SPEC
|
|
|
-+#define LIB_SPEC \
|
|
|
-+ "%{pthread:-lpthread} " \
|
|
|
-+ "-lc"
|
|
|
-+
|
|
|
-+#undef LINK_GCC_C_SEQUENCE_SPEC
|
|
|
-+#define LINK_GCC_C_SEQUENCE_SPEC \
|
|
|
-+ "%{static:--start-group} %G %L %{static:--end-group} " \
|
|
|
-+ "%{!static: %G}"
|
|
|
-+
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#define STARTFILE_SPEC \
|
|
|
-+ "%{!shared: %{pg|p|profile:gcrt1%O%s;pie:Scrt1%O%s;:crt1%O%s}} " \
|
|
|
-+ "crtreloc%O%s crti%O%s %{shared|pie:crtbeginS%O%s;:crtbegin%O%s}"
|
|
|
-+
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+#define ENDFILE_SPEC \
|
|
|
-+ "%{shared|pie:crtendS%O%s;:crtend%O%s} crtn%O%s"
|
|
|
-+
|
|
|
-+/* taken from linux.h */
|
|
|
-+/* The GNU C++ standard library requires that these macros be defined. */
|
|
|
-+#undef CPLUSPLUS_CPP_SPEC
|
|
|
-+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
|
|
|
-+
|
|
|
-+#define TARGET_OS_CPP_BUILTINS() \
|
|
|
-+ do { \
|
|
|
-+ builtin_define_std ("__UBICOM32__"); \
|
|
|
-+ builtin_define_std ("__ubicom32__"); \
|
|
|
-+ builtin_define ("__gnu_linux__"); \
|
|
|
-+ builtin_define_std ("linux"); \
|
|
|
-+ builtin_define_std ("unix"); \
|
|
|
-+ builtin_assert ("system=linux"); \
|
|
|
-+ builtin_assert ("system=unix"); \
|
|
|
-+ builtin_assert ("system=posix"); \
|
|
|
-+ } while (0)
|
|
|
-+
|
|
|
-+#define OBJECT_FORMAT_ELF
|
|
|
-+
|
|
|
-+
|
|
|
-+#undef DRIVER_SELF_SPECS
|
|
|
-+#define DRIVER_SELF_SPECS \
|
|
|
-+ "%{!mno-fdpic:-mfdpic}"
|
|
|
-+
|
|
|
-+#undef LINK_SPEC
|
|
|
-+#define LINK_SPEC "%{mfdpic: -m elf32ubicom32fdpic -z text } %{shared} %{pie} \
|
|
|
-+ %{static:-dn -Bstatic} \
|
|
|
-+ %{shared:-G -Bdynamic} \
|
|
|
-+ %{!shared: %{!static: \
|
|
|
-+ %{rdynamic:-export-dynamic} \
|
|
|
-+ %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} \
|
|
|
-+ %{static}} "
|
|
|
-+
|
|
|
-+/*
|
|
|
-+#define MD_UNWIND_SUPPORT "config/bfin/linux-unwind.h"
|
|
|
-+*/
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/predicates.md
|
|
|
-@@ -0,0 +1,327 @@
|
|
|
-+; Predicate definitions for Ubicom32.
|
|
|
-+
|
|
|
-+; Copyright (C) 2009 Free Software Foundation, Inc.
|
|
|
-+; Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+; This file is part of GCC.
|
|
|
-+
|
|
|
-+; GCC is free software; you can redistribute it and/or modify it
|
|
|
-+; under the terms of the GNU General Public License as published
|
|
|
-+; by the Free Software Foundation; either version 3, or (at your
|
|
|
-+; option) any later version.
|
|
|
-+
|
|
|
-+; GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+; License for more details.
|
|
|
-+
|
|
|
-+; You should have received a copy of the GNU General Public License
|
|
|
-+; along with GCC; see the file COPYING3. If not see
|
|
|
-+; <http://www.gnu.org/licenses/>.
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_move_operand"
|
|
|
-+ (match_code "const_int, const_double, const, mem, subreg, reg, lo_sum")
|
|
|
-+{
|
|
|
-+ if (CONST_INT_P (op))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if (GET_CODE (op) == CONST_DOUBLE)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if (GET_CODE (op) == CONST)
|
|
|
-+ return memory_address_p (mode, op);
|
|
|
-+
|
|
|
-+ if (GET_MODE (op) != mode)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (MEM_P (op))
|
|
|
-+ return memory_address_p (mode, XEXP (op, 0));
|
|
|
-+
|
|
|
-+ if (GET_CODE (op) == SUBREG) {
|
|
|
-+ op = SUBREG_REG (op);
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if (! MEM_P (op))
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ /* Paradoxical SUBREG. */
|
|
|
-+ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (op)))
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return memory_address_p (GET_MODE (op), XEXP (op, 0));
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+})
|
|
|
-+
|
|
|
-+;; Returns true if OP is either a symbol reference or a sum of a
|
|
|
-+;; symbol reference and a constant.
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_symbolic_address_operand"
|
|
|
-+ (match_code "symbol_ref, label_ref, const")
|
|
|
-+{
|
|
|
-+ switch (GET_CODE (op))
|
|
|
-+ {
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ case LABEL_REF:
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case CONST:
|
|
|
-+ op = XEXP (op, 0);
|
|
|
-+ return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|
|
|
-+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
|
|
|
-+ && CONST_INT_P (XEXP (op, 1)));
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+})
|
|
|
-+
|
|
|
-+;; Return true if operand is the uClinux FD-PIC register.
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_fdpic_operand"
|
|
|
-+ (match_code "reg")
|
|
|
-+{
|
|
|
-+ if (! TARGET_FDPIC)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (!REG_P (op))
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (GET_MODE (op) != mode && mode != VOIDmode)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (REGNO (op) != FDPIC_REGNUM && REGNO (op) < FIRST_PSEUDO_REGISTER)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return true;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_fdpic_got_offset_operand"
|
|
|
-+ (match_code "unspec")
|
|
|
-+{
|
|
|
-+ if (! TARGET_FDPIC)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (GET_CODE (op) != UNSPEC)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (XINT (op, 1) != UNSPEC_FDPIC_GOT
|
|
|
-+ && XINT (op, 1) != UNSPEC_FDPIC_GOT_FUNCDESC)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return true;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_arith_operand"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_move_operand (op, mode)
|
|
|
-+ && ! ubicom32_symbolic_address_operand (op, mode)
|
|
|
-+ && (! CONST_INT_P (op)
|
|
|
-+ || satisfies_constraint_I (op)));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_arith_operand_dot1"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_move_operand (op, mode)
|
|
|
-+ && ! ubicom32_symbolic_address_operand (op, mode)
|
|
|
-+ && (! CONST_INT_P (op)
|
|
|
-+ || satisfies_constraint_Q (op)));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_arith_operand_dot2"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_move_operand (op, mode)
|
|
|
-+ && ! ubicom32_symbolic_address_operand (op, mode)
|
|
|
-+ && (! CONST_INT_P (op)
|
|
|
-+ || satisfies_constraint_R (op)));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_compare_operand"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_move_operand (op, mode)
|
|
|
-+ && ! ubicom32_symbolic_address_operand (op, mode)
|
|
|
-+ && (! CONST_INT_P (op)
|
|
|
-+ || satisfies_constraint_N (op)));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_compare_operator"
|
|
|
-+ (match_code "compare"))
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_and_or_si3_operand"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_arith_operand (op, mode)
|
|
|
-+ || (CONST_INT_P (op)
|
|
|
-+ && ((exact_log2 (INTVAL (op) + 1) != -1
|
|
|
-+ && exact_log2 (INTVAL (op) + 1) <= 31)
|
|
|
-+ || (exact_log2 (INTVAL (op)) != -1
|
|
|
-+ && exact_log2 (INTVAL (op)) <= 31)
|
|
|
-+ || (exact_log2 (~INTVAL (op)) != -1
|
|
|
-+ && exact_log2 (~INTVAL (op)) <= 31))));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_and_or_hi3_operand"
|
|
|
-+ (match_code "subreg, reg, const_int, lo_sum, mem")
|
|
|
-+{
|
|
|
-+ return (ubicom32_arith_operand (op, mode)
|
|
|
-+ || (CONST_INT_P (op)
|
|
|
-+ && exact_log2 (INTVAL (op) + 1) != -1
|
|
|
-+ && exact_log2 (INTVAL (op) + 1) <= 15));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_mem_or_address_register_operand"
|
|
|
-+ (match_code "subreg, reg, mem")
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+
|
|
|
-+ if (MEM_P (op)
|
|
|
-+ && memory_operand (op, mode))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ regno = REGNO (op);
|
|
|
-+ else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
|
|
|
-+ {
|
|
|
-+ int offset;
|
|
|
-+ if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
|
|
|
-+ else
|
|
|
-+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
|
|
|
-+ GET_MODE (SUBREG_REG (op)),
|
|
|
-+ SUBREG_BYTE (op),
|
|
|
-+ GET_MODE (op));
|
|
|
-+ regno = REGNO (SUBREG_REG (op)) + offset;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return (regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ || REGNO_REG_CLASS (regno) == FDPIC_REG
|
|
|
-+ || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_data_register_operand"
|
|
|
-+ (match_code "subreg, reg")
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ regno = REGNO (op);
|
|
|
-+ else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
|
|
|
-+ {
|
|
|
-+ int offset;
|
|
|
-+ if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
|
|
|
-+ else
|
|
|
-+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
|
|
|
-+ GET_MODE (SUBREG_REG (op)),
|
|
|
-+ SUBREG_BYTE (op),
|
|
|
-+ GET_MODE (op));
|
|
|
-+ regno = REGNO (SUBREG_REG (op)) + offset;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return ((regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ && regno != REGNO (virtual_stack_vars_rtx))
|
|
|
-+ || REGNO_REG_CLASS (regno) == DATA_REGS);
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_address_register_operand"
|
|
|
-+ (match_code "subreg, reg")
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ regno = REGNO (op);
|
|
|
-+ else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
|
|
|
-+ {
|
|
|
-+ int offset;
|
|
|
-+ if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
|
|
|
-+ else
|
|
|
-+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
|
|
|
-+ GET_MODE (SUBREG_REG (op)),
|
|
|
-+ SUBREG_BYTE (op),
|
|
|
-+ GET_MODE (op));
|
|
|
-+ regno = REGNO (SUBREG_REG (op)) + offset;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return (regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ || REGNO_REG_CLASS (regno) == FDPIC_REG
|
|
|
-+ || REGNO_REG_CLASS (regno) == ADDRESS_REGS);
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_acc_lo_register_operand"
|
|
|
-+ (match_code "subreg, reg")
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ regno = REGNO (op);
|
|
|
-+ else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
|
|
|
-+ {
|
|
|
-+ int offset;
|
|
|
-+ if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
|
|
|
-+ else
|
|
|
-+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
|
|
|
-+ GET_MODE (SUBREG_REG (op)),
|
|
|
-+ SUBREG_BYTE (op),
|
|
|
-+ GET_MODE (op));
|
|
|
-+ regno = REGNO (SUBREG_REG (op)) + offset;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return ((regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ && regno != REGNO (virtual_stack_vars_rtx))
|
|
|
-+ || REGNO_REG_CLASS (regno) == ACC_LO_REGS);
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_acc_hi_register_operand"
|
|
|
-+ (match_code "subreg, reg")
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+
|
|
|
-+ if (REG_P (op))
|
|
|
-+ regno = REGNO (op);
|
|
|
-+ else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
|
|
|
-+ {
|
|
|
-+ int offset;
|
|
|
-+ if (REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ offset = SUBREG_BYTE (op) / (GET_MODE_SIZE (GET_MODE (op)));
|
|
|
-+ else
|
|
|
-+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
|
|
|
-+ GET_MODE (SUBREG_REG (op)),
|
|
|
-+ SUBREG_BYTE (op),
|
|
|
-+ GET_MODE (op));
|
|
|
-+ regno = REGNO (SUBREG_REG (op)) + offset;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return ((regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ && regno != REGNO (virtual_stack_vars_rtx))
|
|
|
-+ || REGNO_REG_CLASS (regno) == ACC_REGS);
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_predicate "ubicom32_call_address_operand"
|
|
|
-+ (match_code "symbol_ref, subreg, reg")
|
|
|
-+{
|
|
|
-+ return (GET_CODE (op) == SYMBOL_REF || REG_P (op));
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_special_predicate "ubicom32_cc_register_operand"
|
|
|
-+ (and (match_code "reg")
|
|
|
-+ (match_test "REGNO (op) == CC_REGNUM")))
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/t-ubicom32
|
|
|
-@@ -0,0 +1,52 @@
|
|
|
-+# Name of assembly file containing libgcc1 functions.
|
|
|
-+# This entry must be present, but it can be empty if the target does
|
|
|
-+# not need any assembler functions to support its code generation.
|
|
|
-+CROSS_LIBGCC1 =
|
|
|
-+
|
|
|
-+# Alternatively if assembler functions *are* needed then define the
|
|
|
-+# entries below:
|
|
|
-+# CROSS_LIBGCC1 = libgcc1-asm.a
|
|
|
-+
|
|
|
-+LIB2FUNCS_EXTRA = \
|
|
|
-+ $(srcdir)/config/udivmodsi4.c \
|
|
|
-+ $(srcdir)/config/divmod.c \
|
|
|
-+ $(srcdir)/config/udivmod.c
|
|
|
-+
|
|
|
-+# If any special flags are necessary when building libgcc2 put them here.
|
|
|
-+#
|
|
|
-+# TARGET_LIBGCC2_CFLAGS =
|
|
|
-+
|
|
|
-+# We want fine grained libraries, so use the new code to build the
|
|
|
-+# floating point emulation libraries.
|
|
|
-+FPBIT = fp-bit.c
|
|
|
-+DPBIT = dp-bit.c
|
|
|
-+
|
|
|
-+fp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ echo '#define FLOAT' > fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
|
|
-+
|
|
|
-+dp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
|
|
|
-+
|
|
|
-+# Commented out to speed up compiler development!
|
|
|
-+#
|
|
|
-+# MULTILIB_OPTIONS = march=ubicom32v1/march=ubicom32v2/march=ubicom32v3/march=ubicom32v4
|
|
|
-+# MULTILIB_DIRNAMES = ubicom32v1 ubicom32v2 ubicom32v3 ubicom32v4
|
|
|
-+
|
|
|
-+MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
|
|
|
-+MULTILIB_OPTIONS += mfdpic
|
|
|
-+MULTILIB_OPTIONS += mno-ipos-abi/mipos-abi
|
|
|
-+MULTILIB_OPTIONS += fno-leading-underscore/fleading-underscore
|
|
|
-+
|
|
|
-+# Assemble startup files.
|
|
|
-+$(T)crti.o: $(srcdir)/config/ubicom32/crti.S $(GCC_PASSES)
|
|
|
-+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
|
|
|
-+ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crti.S
|
|
|
-+
|
|
|
-+$(T)crtn.o: $(srcdir)/config/ubicom32/crtn.S $(GCC_PASSES)
|
|
|
-+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
|
|
|
-+ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/ubicom32/crtn.S
|
|
|
-+
|
|
|
-+# these parts are required because uClibc ldso needs them to link.
|
|
|
-+# they are not in the specfile so they will not be included automatically.
|
|
|
-+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crti.o crtn.o
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/t-ubicom32-linux
|
|
|
-@@ -0,0 +1,35 @@
|
|
|
-+# Name of assembly file containing libgcc1 functions.
|
|
|
-+# This entry must be present, but it can be empty if the target does
|
|
|
-+# not need any assembler functions to support its code generation.
|
|
|
-+CROSS_LIBGCC1 =
|
|
|
-+
|
|
|
-+# Alternatively if assembler functions *are* needed then define the
|
|
|
-+# entries below:
|
|
|
-+# CROSS_LIBGCC1 = libgcc1-asm.a
|
|
|
-+
|
|
|
-+LIB2FUNCS_EXTRA = \
|
|
|
-+ $(srcdir)/config/udivmodsi4.c \
|
|
|
-+ $(srcdir)/config/divmod.c \
|
|
|
-+ $(srcdir)/config/udivmod.c
|
|
|
-+
|
|
|
-+# If any special flags are necessary when building libgcc2 put them here.
|
|
|
-+#
|
|
|
-+# TARGET_LIBGCC2_CFLAGS =
|
|
|
-+
|
|
|
-+# We want fine grained libraries, so use the new code to build the
|
|
|
-+# floating point emulation libraries.
|
|
|
-+FPBIT = fp-bit.c
|
|
|
-+DPBIT = dp-bit.c
|
|
|
-+
|
|
|
-+fp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ echo '#define FLOAT' > fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
|
|
-+
|
|
|
-+dp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
|
|
|
-+
|
|
|
-+# We only support v3 and v4 ISAs for uClinux.
|
|
|
-+
|
|
|
-+MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
|
|
|
-+
|
|
|
-+#EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/t-ubicom32-uclinux
|
|
|
-@@ -0,0 +1,35 @@
|
|
|
-+# Name of assembly file containing libgcc1 functions.
|
|
|
-+# This entry must be present, but it can be empty if the target does
|
|
|
-+# not need any assembler functions to support its code generation.
|
|
|
-+CROSS_LIBGCC1 =
|
|
|
-+
|
|
|
-+# Alternatively if assembler functions *are* needed then define the
|
|
|
-+# entries below:
|
|
|
-+# CROSS_LIBGCC1 = libgcc1-asm.a
|
|
|
-+
|
|
|
-+LIB2FUNCS_EXTRA = \
|
|
|
-+ $(srcdir)/config/udivmodsi4.c \
|
|
|
-+ $(srcdir)/config/divmod.c \
|
|
|
-+ $(srcdir)/config/udivmod.c
|
|
|
-+
|
|
|
-+# If any special flags are necessary when building libgcc2 put them here.
|
|
|
-+#
|
|
|
-+# TARGET_LIBGCC2_CFLAGS =
|
|
|
-+
|
|
|
-+# We want fine grained libraries, so use the new code to build the
|
|
|
-+# floating point emulation libraries.
|
|
|
-+FPBIT = fp-bit.c
|
|
|
-+DPBIT = dp-bit.c
|
|
|
-+
|
|
|
-+fp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ echo '#define FLOAT' > fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
|
|
-+
|
|
|
-+dp-bit.c: $(srcdir)/config/fp-bit.c
|
|
|
-+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
|
|
|
-+
|
|
|
-+# We only support v3 and v4 ISAs for uClinux.
|
|
|
-+
|
|
|
-+MULTILIB_OPTIONS = march=ubicom32v3/march=ubicom32v4
|
|
|
-+
|
|
|
-+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o # crtbeginS.o crtendS.o
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32-modes.def
|
|
|
-@@ -0,0 +1,30 @@
|
|
|
-+/* Definitions of target machine for GNU compiler, Ubicom32 architecture.
|
|
|
-+ Copyright (C) 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GCC.
|
|
|
-+
|
|
|
-+ GCC is free software; you can redistribute it and/or modify it
|
|
|
-+ under the terms of the GNU General Public License as published
|
|
|
-+ by the Free Software Foundation; either version 3, or (at your
|
|
|
-+ option) any later version.
|
|
|
-+
|
|
|
-+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+ License for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License
|
|
|
-+ along with GCC; see the file COPYING3. If not see
|
|
|
-+ <http://www.gnu.org/licenses/>. */
|
|
|
-+
|
|
|
-+/* Some insns set all condition code flags, some only set the Z and N flags, and
|
|
|
-+ some only set the Z flag. */
|
|
|
-+
|
|
|
-+CC_MODE (CCW);
|
|
|
-+CC_MODE (CCWZN);
|
|
|
-+CC_MODE (CCWZ);
|
|
|
-+CC_MODE (CCS);
|
|
|
-+CC_MODE (CCSZN);
|
|
|
-+CC_MODE (CCSZ);
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32-protos.h
|
|
|
-@@ -0,0 +1,84 @@
|
|
|
-+/* Function prototypes for Ubicom IP3000.
|
|
|
-+
|
|
|
-+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
|
-+ 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GNU CC.
|
|
|
-+
|
|
|
-+ GNU CC is free software; you can redistribute it and/or modify it under
|
|
|
-+ the terms of the GNU General Public License as published by the Free
|
|
|
-+ Software Foundation; either version 2, or (at your option) any later
|
|
|
-+ version.
|
|
|
-+
|
|
|
-+ GNU CC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
-+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
-+ for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License along
|
|
|
-+ with GNU CC; see the file COPYING. If not, write to the Free Software
|
|
|
-+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+#ifdef RTX_CODE
|
|
|
-+
|
|
|
-+#ifdef TREE_CODE
|
|
|
-+extern void ubicom32_va_start (tree, rtx);
|
|
|
-+#endif /* TREE_CODE */
|
|
|
-+
|
|
|
-+extern void ubicom32_print_operand (FILE *, rtx, int);
|
|
|
-+extern void ubicom32_print_operand_address (FILE *, rtx);
|
|
|
-+
|
|
|
-+extern void ubicom32_conditional_register_usage (void);
|
|
|
-+extern enum reg_class ubicom32_preferred_reload_class (rtx, enum reg_class);
|
|
|
-+extern int ubicom32_regno_ok_for_index_p (int, int);
|
|
|
-+extern void ubicom32_expand_movsi (rtx *);
|
|
|
-+extern void ubicom32_expand_addsi3 (rtx *);
|
|
|
-+extern int ubicom32_emit_mult_sequence (rtx *);
|
|
|
-+extern void ubicom32_emit_move_const_int (rtx, rtx);
|
|
|
-+extern bool ubicom32_legitimate_constant_p (rtx);
|
|
|
-+extern bool ubicom32_legitimate_address_p (enum machine_mode, rtx, int);
|
|
|
-+extern rtx ubicom32_legitimize_address (rtx, rtx, enum machine_mode);
|
|
|
-+extern rtx ubicom32_legitimize_reload_address (rtx, enum machine_mode, int, int);
|
|
|
-+extern void ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1);
|
|
|
-+extern int ubicom32_mode_dependent_address_p (rtx);
|
|
|
-+extern void ubicom32_output_cond_jump (rtx, rtx, rtx);
|
|
|
-+extern void ubicom32_expand_eh_return (rtx *);
|
|
|
-+extern void ubicom32_expand_call_fdpic (rtx *);
|
|
|
-+extern void ubicom32_expand_call_value_fdpic (rtx *);
|
|
|
-+extern enum machine_mode ubicom32_select_cc_mode (RTX_CODE, rtx, rtx);
|
|
|
-+extern rtx ubicom32_gen_compare_reg (RTX_CODE, rtx, rtx);
|
|
|
-+extern int ubicom32_shiftable_const_int (int);
|
|
|
-+#endif /* RTX_CODE */
|
|
|
-+
|
|
|
-+#ifdef TREE_CODE
|
|
|
-+extern void init_cumulative_args (CUMULATIVE_ARGS *cum,
|
|
|
-+ tree fntype,
|
|
|
-+ struct rtx_def *libname,
|
|
|
-+ int indirect);
|
|
|
-+extern struct rtx_def *function_arg (CUMULATIVE_ARGS *,
|
|
|
-+ enum machine_mode, tree, int);
|
|
|
-+extern struct rtx_def *function_incoming_arg (CUMULATIVE_ARGS *,
|
|
|
-+ enum machine_mode,
|
|
|
-+ tree, int);
|
|
|
-+extern int function_arg_partial_nregs (CUMULATIVE_ARGS *,
|
|
|
-+ enum machine_mode, tree, int);
|
|
|
-+extern struct rtx_def *ubicom32_va_arg (tree, tree);
|
|
|
-+extern int ubicom32_reg_parm_stack_space (tree);
|
|
|
-+#endif /* TREE_CODE */
|
|
|
-+
|
|
|
-+extern struct rtx_def * ubicom32_builtin_saveregs (void);
|
|
|
-+extern void asm_file_start (FILE *);
|
|
|
-+extern void ubicom32_expand_prologue (void);
|
|
|
-+extern void ubicom32_expand_epilogue (void);
|
|
|
-+extern int ubicom32_initial_elimination_offset (int, int);
|
|
|
-+extern int ubicom32_regno_ok_for_base_p (int, int);
|
|
|
-+extern bool ubicom32_hard_regno_mode_ok (unsigned int, enum machine_mode);
|
|
|
-+extern int ubicom32_can_use_return_insn_p (void);
|
|
|
-+extern rtx ubicom32_return_addr_rtx (int, rtx);
|
|
|
-+extern void ubicom32_optimization_options (int, int);
|
|
|
-+extern void ubicom32_override_options (void);
|
|
|
-+extern bool ubicom32_match_cc_mode (rtx, enum machine_mode);
|
|
|
-+
|
|
|
-+extern int ubicom32_reorg_completed;
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32.c
|
|
|
-@@ -0,0 +1,2881 @@
|
|
|
-+/* Subroutines for insn-output.c for Ubicom32
|
|
|
-+
|
|
|
-+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
|
-+ 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GCC.
|
|
|
-+
|
|
|
-+ GCC is free software; you can redistribute it and/or modify it
|
|
|
-+ under the terms of the GNU General Public License as published
|
|
|
-+ by the Free Software Foundation; either version 3, or (at your
|
|
|
-+ option) any later version.
|
|
|
-+
|
|
|
-+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+ License for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License
|
|
|
-+ along with GCC; see the file COPYING3. If not see
|
|
|
-+ <http://www.gnu.org/licenses/>. */
|
|
|
-+
|
|
|
-+#include "config.h"
|
|
|
-+#include "system.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+#include "rtl.h"
|
|
|
-+#include "tree.h"
|
|
|
-+#include "regs.h"
|
|
|
-+#include "hard-reg-set.h"
|
|
|
-+#include "real.h"
|
|
|
-+#include "insn-config.h"
|
|
|
-+#include "conditions.h"
|
|
|
-+#include "insn-flags.h"
|
|
|
-+#include "output.h"
|
|
|
-+#include "insn-attr.h"
|
|
|
-+#include "insn-codes.h"
|
|
|
-+#include "flags.h"
|
|
|
-+#include "recog.h"
|
|
|
-+#include "expr.h"
|
|
|
-+#include "function.h"
|
|
|
-+#include "obstack.h"
|
|
|
-+#include "toplev.h"
|
|
|
-+#include "tm_p.h"
|
|
|
-+#include "tm-constrs.h"
|
|
|
-+#include "basic-block.h"
|
|
|
-+#include "integrate.h"
|
|
|
-+#include "target.h"
|
|
|
-+#include "target-def.h"
|
|
|
-+#include "reload.h"
|
|
|
-+#include "df.h"
|
|
|
-+#include "langhooks.h"
|
|
|
-+#include "optabs.h"
|
|
|
-+
|
|
|
-+static tree ubicom32_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
|
|
|
-+static void ubicom32_layout_frame (void);
|
|
|
-+static void ubicom32_function_prologue (FILE *, HOST_WIDE_INT);
|
|
|
-+static void ubicom32_function_epilogue (FILE *, HOST_WIDE_INT);
|
|
|
-+static bool ubicom32_rtx_costs (rtx, int, int, int *, bool speed);
|
|
|
-+static bool ubicom32_fixed_condition_code_regs (unsigned int *,
|
|
|
-+ unsigned int *);
|
|
|
-+static enum machine_mode ubicom32_cc_modes_compatible (enum machine_mode,
|
|
|
-+ enum machine_mode);
|
|
|
-+static int ubicom32_naked_function_p (void);
|
|
|
-+static void ubicom32_machine_dependent_reorg (void);
|
|
|
-+static bool ubicom32_assemble_integer (rtx, unsigned int, int);
|
|
|
-+static void ubicom32_asm_init_sections (void);
|
|
|
-+static int ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,tree,
|
|
|
-+ bool);
|
|
|
-+static bool ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode, const_tree type,
|
|
|
-+ bool named ATTRIBUTE_UNUSED);
|
|
|
-+static bool ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode, const_tree type,
|
|
|
-+ bool named ATTRIBUTE_UNUSED);
|
|
|
-+
|
|
|
-+static bool ubicom32_return_in_memory (const_tree type,
|
|
|
-+ const_tree fntype ATTRIBUTE_UNUSED);
|
|
|
-+static bool ubicom32_is_base_reg (rtx, int);
|
|
|
-+static void ubicom32_init_builtins (void);
|
|
|
-+static rtx ubicom32_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static tree ubicom32_fold_builtin (tree, tree, bool);
|
|
|
-+static int ubicom32_get_valid_offset_mask (enum machine_mode);
|
|
|
-+static bool ubicom32_cannot_force_const_mem (rtx);
|
|
|
-+
|
|
|
-+/* Case values threshold */
|
|
|
-+int ubicom32_case_values_threshold = 6;
|
|
|
-+
|
|
|
-+/* Nonzero if this chip supports the Ubicom32 v3 ISA. */
|
|
|
-+int ubicom32_v3 = 1;
|
|
|
-+
|
|
|
-+/* Nonzero if this chip supports the Ubicom32 v4 ISA. */
|
|
|
-+int ubicom32_v4 = 1;
|
|
|
-+
|
|
|
-+/* Valid attributes:
|
|
|
-+ naked - don't generate function prologue/epilogue and `ret' command. */
|
|
|
-+const struct attribute_spec ubicom32_attribute_table[] =
|
|
|
-+{
|
|
|
-+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
|
|
|
-+ { "naked", 0, 0, true, false, false, ubicom32_handle_fndecl_attribute },
|
|
|
-+ { NULL, 0, 0, false, false, false, NULL }
|
|
|
-+};
|
|
|
-+
|
|
|
-+#undef TARGET_ASM_FUNCTION_PROLOGUE
|
|
|
-+#define TARGET_ASM_FUNCTION_PROLOGUE ubicom32_function_prologue
|
|
|
-+
|
|
|
-+#undef TARGET_ASM_FUNCTION_EPILOGUE
|
|
|
-+#define TARGET_ASM_FUNCTION_EPILOGUE ubicom32_function_epilogue
|
|
|
-+
|
|
|
-+#undef TARGET_ATTRIBUTE_TABLE
|
|
|
-+#define TARGET_ATTRIBUTE_TABLE ubicom32_attribute_table
|
|
|
-+
|
|
|
-+/* All addresses cost the same amount. */
|
|
|
-+#undef TARGET_ADDRESS_COST
|
|
|
-+#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
|
|
|
-+
|
|
|
-+#undef TARGET_RTX_COSTS
|
|
|
-+#define TARGET_RTX_COSTS ubicom32_rtx_costs
|
|
|
-+
|
|
|
-+#undef TARGET_FIXED_CONDITION_CODE_REGS
|
|
|
-+#define TARGET_FIXED_CONDITION_CODE_REGS ubicom32_fixed_condition_code_regs
|
|
|
-+
|
|
|
-+#undef TARGET_CC_MODES_COMPATIBLE
|
|
|
-+#define TARGET_CC_MODES_COMPATIBLE ubicom32_cc_modes_compatible
|
|
|
-+
|
|
|
-+#undef TARGET_MACHINE_DEPENDENT_REORG
|
|
|
-+#define TARGET_MACHINE_DEPENDENT_REORG ubicom32_machine_dependent_reorg
|
|
|
-+
|
|
|
-+#undef TARGET_ASM_INTEGER
|
|
|
-+#define TARGET_ASM_INTEGER ubicom32_assemble_integer
|
|
|
-+
|
|
|
-+#undef TARGET_ASM_INIT_SECTIONS
|
|
|
-+#define TARGET_ASM_INIT_SECTIONS ubicom32_asm_init_sections
|
|
|
-+
|
|
|
-+#undef TARGET_ARG_PARTIAL_BYTES
|
|
|
-+#define TARGET_ARG_PARTIAL_BYTES ubicom32_arg_partial_bytes
|
|
|
-+
|
|
|
-+#undef TARGET_PASS_BY_REFERENCE
|
|
|
-+#define TARGET_PASS_BY_REFERENCE ubicom32_pass_by_reference
|
|
|
-+
|
|
|
-+#undef TARGET_CALLEE_COPIES
|
|
|
-+#define TARGET_CALLEE_COPIES ubicom32_callee_copies
|
|
|
-+
|
|
|
-+#undef TARGET_RETURN_IN_MEMORY
|
|
|
-+#define TARGET_RETURN_IN_MEMORY ubicom32_return_in_memory
|
|
|
-+
|
|
|
-+#undef TARGET_INIT_BUILTINS
|
|
|
-+#define TARGET_INIT_BUILTINS ubicom32_init_builtins
|
|
|
-+
|
|
|
-+#undef TARGET_EXPAND_BUILTIN
|
|
|
-+#define TARGET_EXPAND_BUILTIN ubicom32_expand_builtin
|
|
|
-+
|
|
|
-+#undef TARGET_FOLD_BUILTIN
|
|
|
-+#define TARGET_FOLD_BUILTIN ubicom32_fold_builtin
|
|
|
-+
|
|
|
-+#undef TARGET_CANNOT_FORCE_CONST_MEM
|
|
|
-+#define TARGET_CANNOT_FORCE_CONST_MEM ubicom32_cannot_force_const_mem
|
|
|
-+
|
|
|
-+struct gcc_target targetm = TARGET_INITIALIZER;
|
|
|
-+
|
|
|
-+static char save_regs[FIRST_PSEUDO_REGISTER];
|
|
|
-+static int nregs;
|
|
|
-+static int frame_size;
|
|
|
-+int ubicom32_stack_size = 0; /* size of allocated stack (including frame) */
|
|
|
-+int ubicom32_can_use_calli_to_ret;
|
|
|
-+
|
|
|
-+#define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
|
|
|
-+#define ROUND_CALL_BLOCK_SIZE(BYTES) \
|
|
|
-+ (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
|
|
|
-+
|
|
|
-+/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
|
|
|
-+ must report the mode of the memory reference from PRINT_OPERAND to
|
|
|
-+ PRINT_OPERAND_ADDRESS. */
|
|
|
-+enum machine_mode output_memory_reference_mode;
|
|
|
-+
|
|
|
-+/* Flag for some split insns from the ubicom32.md. */
|
|
|
-+int ubicom32_reorg_completed;
|
|
|
-+
|
|
|
-+enum reg_class const ubicom32_regclass_map[FIRST_PSEUDO_REGISTER] =
|
|
|
-+{
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ FDPIC_REG,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ACC_REGS,
|
|
|
-+ ACC_LO_REGS,
|
|
|
-+ ACC_REGS,
|
|
|
-+ ACC_LO_REGS,
|
|
|
-+ SOURCE3_REG,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ NO_REGS, /* CC_REG must be NO_REGS */
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ SPECIAL_REGS
|
|
|
-+};
|
|
|
-+
|
|
|
-+rtx ubicom32_compare_op0;
|
|
|
-+rtx ubicom32_compare_op1;
|
|
|
-+
|
|
|
-+/* Handle command line option overrides. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_override_options (void)
|
|
|
-+{
|
|
|
-+ flag_pic = 0;
|
|
|
-+
|
|
|
-+ if (strcmp (ubicom32_arch_name, "ubicom32v1") == 0) {
|
|
|
-+ /* If we have a version 1 architecture then we want to avoid using jump
|
|
|
-+ tables. */
|
|
|
-+ ubicom32_case_values_threshold = 30000;
|
|
|
-+ ubicom32_v3 = 0;
|
|
|
-+ ubicom32_v4 = 0;
|
|
|
-+ } else if (strcmp (ubicom32_arch_name, "ubicom32v2") == 0) {
|
|
|
-+ ubicom32_v3 = 0;
|
|
|
-+ ubicom32_v4 = 0;
|
|
|
-+ } else if (strcmp (ubicom32_arch_name, "ubicom32v3") == 0) {
|
|
|
-+ ubicom32_v3 = 1;
|
|
|
-+ ubicom32_v4 = 0;
|
|
|
-+ } else if (strcmp (ubicom32_arch_name, "ubicom32v4") == 0) {
|
|
|
-+ ubicom32_v3 = 1;
|
|
|
-+ ubicom32_v4 = 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* There is no single unaligned SI op for PIC code. Sometimes we
|
|
|
-+ need to use ".4byte" and sometimes we need to use ".picptr".
|
|
|
-+ See ubicom32_assemble_integer for details. */
|
|
|
-+ if (TARGET_FDPIC)
|
|
|
-+ targetm.asm_out.unaligned_op.si = 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_conditional_register_usage (void)
|
|
|
-+{
|
|
|
-+ /* If we're using the old ipOS ABI we need to make D10 through D13
|
|
|
-+ caller-clobbered. */
|
|
|
-+ if (TARGET_IPOS_ABI)
|
|
|
-+ {
|
|
|
-+ call_used_regs[D10_REGNUM] = 1;
|
|
|
-+ call_used_regs[D11_REGNUM] = 1;
|
|
|
-+ call_used_regs[D12_REGNUM] = 1;
|
|
|
-+ call_used_regs[D13_REGNUM] = 1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* We have some number of optimizations that don't really work for the Ubicom32
|
|
|
-+ architecture so we deal with them here. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_optimization_options (int level ATTRIBUTE_UNUSED,
|
|
|
-+ int size ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ /* The tree IVOPTs pass seems to do really bad things for the Ubicom32
|
|
|
-+ architecture - it tends to turn things that would happily use pre/post
|
|
|
-+ increment/decrement into operations involving unecessary loop
|
|
|
-+ indicies. */
|
|
|
-+ flag_ivopts = 0;
|
|
|
-+
|
|
|
-+ /* We have problems where DSE at the RTL level misses partial stores
|
|
|
-+ to the stack. For now we disable it to avoid this. */
|
|
|
-+ flag_dse = 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Print operand X using operand code CODE to assembly language output file
|
|
|
-+ FILE. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_print_operand (FILE *file, rtx x, int code)
|
|
|
-+{
|
|
|
-+ switch (code)
|
|
|
-+ {
|
|
|
-+ case 'A':
|
|
|
-+ /* Identify the correct accumulator to use. */
|
|
|
-+ if (REGNO (x) == ACC0_HI_REGNUM || REGNO (x) == ACC0_LO_REGNUM)
|
|
|
-+ fprintf (file, "acc0");
|
|
|
-+ else if (REGNO (x) == ACC1_HI_REGNUM || REGNO (x) == ACC1_LO_REGNUM)
|
|
|
-+ fprintf (file, "acc1");
|
|
|
-+ else
|
|
|
-+ abort ();
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case 'b':
|
|
|
-+ case 'B':
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode;
|
|
|
-+
|
|
|
-+ mode = GET_MODE (XEXP (x, 0));
|
|
|
-+
|
|
|
-+ /* These are normal and reversed branches. */
|
|
|
-+ switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
|
|
|
-+ {
|
|
|
-+ case NE:
|
|
|
-+ fprintf (file, "ne");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case EQ:
|
|
|
-+ fprintf (file, "eq");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case GE:
|
|
|
-+ if (mode == CCSZNmode || mode == CCWZNmode)
|
|
|
-+ fprintf (file, "pl");
|
|
|
-+ else
|
|
|
-+ fprintf (file, "ge");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case GT:
|
|
|
-+ fprintf (file, "gt");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case LE:
|
|
|
-+ fprintf (file, "le");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case LT:
|
|
|
-+ if (mode == CCSZNmode || mode == CCWZNmode)
|
|
|
-+ fprintf (file, "mi");
|
|
|
-+ else
|
|
|
-+ fprintf (file, "lt");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case GEU:
|
|
|
-+ fprintf (file, "cs");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case GTU:
|
|
|
-+ fprintf (file, "hi");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case LEU:
|
|
|
-+ fprintf (file, "ls");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case LTU:
|
|
|
-+ fprintf (file, "cc");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case 'C':
|
|
|
-+ /* This is used for the operand to a call instruction;
|
|
|
-+ if it's a REG, enclose it in parens, else output
|
|
|
-+ the operand normally. */
|
|
|
-+ if (REG_P (x))
|
|
|
-+ {
|
|
|
-+ fputc ('(', file);
|
|
|
-+ ubicom32_print_operand (file, x, 0);
|
|
|
-+ fputc (')', file);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ ubicom32_print_operand (file, x, 0);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case 'd':
|
|
|
-+ /* Bit operations we need bit numbers. */
|
|
|
-+ fprintf (file, "%d", exact_log2 (INTVAL (x)));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case 'D':
|
|
|
-+ /* Bit operations we need bit numbers. */
|
|
|
-+ fprintf (file, "%d", exact_log2 (~ INTVAL (x)));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case 'E':
|
|
|
-+ /* For lea, which we use to add address registers.
|
|
|
-+ We don't want the '#' on a constant. */
|
|
|
-+ if (CONST_INT_P (x))
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%ld", INTVAL (x));
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ /* FALL THROUGH */
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ switch (GET_CODE (x))
|
|
|
-+ {
|
|
|
-+ case MEM:
|
|
|
-+ output_memory_reference_mode = GET_MODE (x);
|
|
|
-+ output_address (XEXP (x, 0));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PLUS:
|
|
|
-+ output_address (x);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case REG:
|
|
|
-+ fprintf (file, "%s", reg_names[REGNO (x)]);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case SUBREG:
|
|
|
-+ fprintf (file, "%s", reg_names[subreg_regno (x)]);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* This will only be single precision.... */
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ {
|
|
|
-+ unsigned long val;
|
|
|
-+ REAL_VALUE_TYPE rv;
|
|
|
-+
|
|
|
-+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
|
|
|
-+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
|
|
|
-+ fprintf (file, "0x%lx", val);
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ case CONST_INT:
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ case CONST:
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case CODE_LABEL:
|
|
|
-+ case LO_SUM:
|
|
|
-+ ubicom32_print_operand_address (file, x);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case HIGH:
|
|
|
-+ fprintf (file, "#%%hi(");
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (x, 0));
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case UNSPEC:
|
|
|
-+ switch (XINT (x, 1))
|
|
|
-+ {
|
|
|
-+ case UNSPEC_FDPIC_GOT:
|
|
|
-+ fprintf (file, "#%%got_lo(");
|
|
|
-+ ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case UNSPEC_FDPIC_GOT_FUNCDESC:
|
|
|
-+ fprintf (file, "#%%got_funcdesc_lo(");
|
|
|
-+ ubicom32_print_operand_address (file, XVECEXP (x, 0, 0));
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Output assembly language output for the address ADDR to FILE. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_print_operand_address (FILE *file, rtx addr)
|
|
|
-+{
|
|
|
-+ switch (GET_CODE (addr))
|
|
|
-+ {
|
|
|
-+ case POST_INC:
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "%d++", GET_MODE_SIZE (output_memory_reference_mode));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PRE_INC:
|
|
|
-+ fprintf (file, "%d", GET_MODE_SIZE (output_memory_reference_mode));
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "++");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case POST_DEC:
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "%d++", -GET_MODE_SIZE (output_memory_reference_mode));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PRE_DEC:
|
|
|
-+ fprintf (file, "%d", -GET_MODE_SIZE (output_memory_reference_mode));
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "++");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case POST_MODIFY:
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "%ld++", INTVAL (XEXP (XEXP (addr,1), 1)));
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PRE_MODIFY:
|
|
|
-+ fprintf (file, "%ld", INTVAL (XEXP (XEXP (addr,1), 1)));
|
|
|
-+ ubicom32_print_operand_address (file, XEXP (addr, 0));
|
|
|
-+ fprintf (file, "++");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case REG:
|
|
|
-+ fputc ('(', file);
|
|
|
-+ fprintf (file, "%s", reg_names[REGNO (addr)]);
|
|
|
-+ fputc (')', file);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PLUS:
|
|
|
-+ {
|
|
|
-+ rtx base = XEXP (addr, 0);
|
|
|
-+ rtx index = XEXP (addr, 1);
|
|
|
-+
|
|
|
-+ /* Switch around addresses of the form index * scaling + base. */
|
|
|
-+ if (! ubicom32_is_base_reg (base, 1))
|
|
|
-+ {
|
|
|
-+ rtx tmp = base;
|
|
|
-+ base = index;
|
|
|
-+ index = tmp;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (index))
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%ld", INTVAL (index));
|
|
|
-+ fputc ('(', file);
|
|
|
-+ fputs (reg_names[REGNO (base)], file);
|
|
|
-+ }
|
|
|
-+ else if (GET_CODE (index) == MULT
|
|
|
-+ || REG_P (index))
|
|
|
-+ {
|
|
|
-+ if (GET_CODE (index) == MULT)
|
|
|
-+ index = XEXP (index, 0);
|
|
|
-+ fputc ('(', file);
|
|
|
-+ fputs (reg_names[REGNO (base)], file);
|
|
|
-+ fputc (',', file);
|
|
|
-+ fputs (reg_names[REGNO (index)], file);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ fputc (')', file);
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ case LO_SUM:
|
|
|
-+ fprintf (file, "%%lo(");
|
|
|
-+ ubicom32_print_operand (file, XEXP (addr, 1), 'L');
|
|
|
-+ fprintf (file, ")(");
|
|
|
-+ ubicom32_print_operand (file, XEXP (addr, 0), 0);
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CONST_INT:
|
|
|
-+ fputc ('#', file);
|
|
|
-+ output_addr_const (file, addr);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ output_addr_const (file, addr);
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* X and Y are two things to compare using CODE. Emit the compare insn and
|
|
|
-+ return the rtx for the cc reg in the proper mode. */
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+ubicom32_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
|
|
|
-+{
|
|
|
-+ enum machine_mode mode = SELECT_CC_MODE (code, x, y);
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (mode, CC_REGNUM);
|
|
|
-+
|
|
|
-+ emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
|
|
|
-+ gen_rtx_COMPARE (mode, x, y)));
|
|
|
-+
|
|
|
-+ return cc_reg;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
|
|
|
-+ return the mode to be used for the comparison. */
|
|
|
-+
|
|
|
-+enum machine_mode
|
|
|
-+ubicom32_select_cc_mode (enum rtx_code op, rtx x, rtx y)
|
|
|
-+{
|
|
|
-+ /* Is this a short compare? */
|
|
|
-+ if (GET_MODE (x) == QImode
|
|
|
-+ || GET_MODE (x) == HImode
|
|
|
-+ || GET_MODE (y) == QImode
|
|
|
-+ || GET_MODE (y) == HImode)
|
|
|
-+ {
|
|
|
-+ switch (op)
|
|
|
-+ {
|
|
|
-+ case EQ :
|
|
|
-+ case NE :
|
|
|
-+ return CCSZmode;
|
|
|
-+
|
|
|
-+ case GE:
|
|
|
-+ case LT:
|
|
|
-+ if (y == const0_rtx)
|
|
|
-+ return CCSZNmode;
|
|
|
-+
|
|
|
-+ default :
|
|
|
-+ return CCSmode;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* We have a word compare. */
|
|
|
-+ switch (op)
|
|
|
-+ {
|
|
|
-+ case EQ :
|
|
|
-+ case NE :
|
|
|
-+ return CCWZmode;
|
|
|
-+
|
|
|
-+ case GE :
|
|
|
-+ case LT :
|
|
|
-+ if (y == const0_rtx)
|
|
|
-+ return CCWZNmode;
|
|
|
-+
|
|
|
-+ default :
|
|
|
-+ return CCWmode;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return TRUE or FALSE depending on whether the first SET in INSN
|
|
|
-+ has source and destination with matching CC modes, and that the
|
|
|
-+ CC mode is at least as constrained as REQ_MODE. */
|
|
|
-+bool
|
|
|
-+ubicom32_match_cc_mode (rtx insn, enum machine_mode req_mode)
|
|
|
-+{
|
|
|
-+ rtx set;
|
|
|
-+ enum machine_mode set_mode;
|
|
|
-+
|
|
|
-+ set = PATTERN (insn);
|
|
|
-+ if (GET_CODE (set) == PARALLEL)
|
|
|
-+ set = XVECEXP (set, 0, 0);
|
|
|
-+ gcc_assert (GET_CODE (set) == SET);
|
|
|
-+ gcc_assert (GET_CODE (SET_SRC (set)) == COMPARE);
|
|
|
-+
|
|
|
-+ /* SET_MODE is the mode we have in the instruction. This must either
|
|
|
-+ be the same or less restrictive that the required mode REQ_MODE. */
|
|
|
-+ set_mode = GET_MODE (SET_DEST (set));
|
|
|
-+
|
|
|
-+ switch (req_mode)
|
|
|
-+ {
|
|
|
-+ case CCSZmode:
|
|
|
-+ if (set_mode != CCSZmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CCSZNmode:
|
|
|
-+ if (set_mode != CCSZmode
|
|
|
-+ && set_mode != CCSZNmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CCSmode:
|
|
|
-+ if (set_mode != CCSmode
|
|
|
-+ && set_mode != CCSZmode
|
|
|
-+ && set_mode != CCSZNmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CCWZmode:
|
|
|
-+ if (set_mode != CCWZmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CCWZNmode:
|
|
|
-+ if (set_mode != CCWZmode
|
|
|
-+ && set_mode != CCWZNmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CCWmode:
|
|
|
-+ if (set_mode != CCWmode
|
|
|
-+ && set_mode != CCWZmode
|
|
|
-+ && set_mode != CCWZNmode)
|
|
|
-+ return 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ gcc_unreachable ();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return (GET_MODE (SET_SRC (set)) == set_mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
|
|
|
-+ that we can implement more efficiently. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
|
|
|
-+{
|
|
|
-+ /* If we have a REG and a MEM then compare the MEM with the REG and not
|
|
|
-+ the other way round. */
|
|
|
-+ if (REG_P (*op0) && MEM_P (*op1))
|
|
|
-+ {
|
|
|
-+ rtx tem = *op0;
|
|
|
-+ *op0 = *op1;
|
|
|
-+ *op1 = tem;
|
|
|
-+ *code = swap_condition (*code);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* If we have a REG and a CONST_INT then we may want to reverse things
|
|
|
-+ if the constant can be represented as an "I" constraint. */
|
|
|
-+ if (REG_P (*op0) && CONST_INT_P (*op1) && satisfies_constraint_I (*op1))
|
|
|
-+ {
|
|
|
-+ rtx tem = *op0;
|
|
|
-+ *op0 = *op1;
|
|
|
-+ *op1 = tem;
|
|
|
-+ *code = swap_condition (*code);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return the fixed registers used for condition codes. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
|
|
|
-+{
|
|
|
-+ *p1 = CC_REGNUM;
|
|
|
-+ *p2 = INVALID_REGNUM;
|
|
|
-+
|
|
|
-+ return true;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* If two condition code modes are compatible, return a condition code
|
|
|
-+ mode which is compatible with both. Otherwise, return
|
|
|
-+ VOIDmode. */
|
|
|
-+
|
|
|
-+static enum machine_mode
|
|
|
-+ubicom32_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
|
|
|
-+{
|
|
|
-+ if (m1 == m2)
|
|
|
-+ return m1;
|
|
|
-+
|
|
|
-+ if (GET_MODE_CLASS (m1) != MODE_CC || GET_MODE_CLASS (m2) != MODE_CC)
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ switch (m1)
|
|
|
-+ {
|
|
|
-+ case CCWmode:
|
|
|
-+ if (m2 == CCWZNmode || m2 == CCWZmode)
|
|
|
-+ return m1;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ case CCWZNmode:
|
|
|
-+ if (m2 == CCWmode)
|
|
|
-+ return m2;
|
|
|
-+
|
|
|
-+ if (m2 == CCWZmode)
|
|
|
-+ return m1;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ case CCWZmode:
|
|
|
-+ if (m2 == CCWmode || m2 == CCWZNmode)
|
|
|
-+ return m2;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ case CCSmode:
|
|
|
-+ if (m2 == CCSZNmode || m2 == CCSZmode)
|
|
|
-+ return m1;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ case CCSZNmode:
|
|
|
-+ if (m2 == CCSmode)
|
|
|
-+ return m2;
|
|
|
-+
|
|
|
-+ if (m2 == CCSZmode)
|
|
|
-+ return m1;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ case CCSZmode:
|
|
|
-+ if (m2 == CCSmode || m2 == CCSZNmode)
|
|
|
-+ return m2;
|
|
|
-+
|
|
|
-+ return VOIDmode;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ gcc_unreachable ();
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+ubicom32_legitimize_fdpic_address_symbol (rtx orig, rtx reg, rtx fdpic_reg)
|
|
|
-+{
|
|
|
-+ int unspec;
|
|
|
-+ rtx got_offs;
|
|
|
-+ rtx got_offs_scaled;
|
|
|
-+ rtx plus_scaled;
|
|
|
-+ rtx tmp;
|
|
|
-+ rtx new_rtx;
|
|
|
-+
|
|
|
-+ gcc_assert (reg != 0);
|
|
|
-+
|
|
|
-+ if (GET_CODE (orig) == SYMBOL_REF
|
|
|
-+ && SYMBOL_REF_FUNCTION_P (orig))
|
|
|
-+ unspec = UNSPEC_FDPIC_GOT_FUNCDESC;
|
|
|
-+ else
|
|
|
-+ unspec = UNSPEC_FDPIC_GOT;
|
|
|
-+
|
|
|
-+ got_offs = gen_reg_rtx (SImode);
|
|
|
-+ tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig), unspec);
|
|
|
-+ emit_move_insn (got_offs, tmp);
|
|
|
-+
|
|
|
-+ got_offs_scaled = gen_rtx_MULT (SImode, got_offs, GEN_INT (4));
|
|
|
-+ plus_scaled = gen_rtx_PLUS (Pmode, fdpic_reg, got_offs_scaled);
|
|
|
-+ new_rtx = gen_const_mem (Pmode, plus_scaled);
|
|
|
-+ emit_move_insn (reg, new_rtx);
|
|
|
-+
|
|
|
-+ return reg;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+ubicom32_legitimize_fdpic_address (rtx orig, rtx reg, rtx fdpic_reg)
|
|
|
-+{
|
|
|
-+ rtx addr = orig;
|
|
|
-+ rtx new_rtx = orig;
|
|
|
-+
|
|
|
-+ if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
|
|
|
-+ {
|
|
|
-+ rtx base;
|
|
|
-+
|
|
|
-+ if (GET_CODE (addr) == CONST)
|
|
|
-+ {
|
|
|
-+ addr = XEXP (addr, 0);
|
|
|
-+ gcc_assert (GET_CODE (addr) == PLUS);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ base = ubicom32_legitimize_fdpic_address_symbol (XEXP (addr, 0), reg, fdpic_reg);
|
|
|
-+ return gen_rtx_PLUS (Pmode, base, XEXP (addr, 1));
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return new_rtx;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Code generation. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_movsi (rtx *operands)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (operands[1]) == SYMBOL_REF
|
|
|
-+ || (GET_CODE (operands[1]) == CONST
|
|
|
-+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
|
|
|
-+ && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
|
|
|
-+ || CONSTANT_ADDRESS_P (operands[1]))
|
|
|
-+ {
|
|
|
-+ if (TARGET_FDPIC)
|
|
|
-+ {
|
|
|
-+ rtx tmp;
|
|
|
-+ rtx fdpic_reg;
|
|
|
-+
|
|
|
-+ gcc_assert (can_create_pseudo_p ());
|
|
|
-+ tmp = gen_reg_rtx (Pmode);
|
|
|
-+ fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
|
|
|
-+ if (GET_CODE (operands[1]) == SYMBOL_REF
|
|
|
-+ || GET_CODE (operands[1]) == LABEL_REF)
|
|
|
-+ operands[1] = ubicom32_legitimize_fdpic_address_symbol (operands[1], tmp, fdpic_reg);
|
|
|
-+ else
|
|
|
-+ operands[1] = ubicom32_legitimize_fdpic_address (operands[1], tmp, fdpic_reg);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ rtx tmp;
|
|
|
-+ enum machine_mode mode;
|
|
|
-+
|
|
|
-+ /* We want to avoid reusing operand 0 if we can because it limits
|
|
|
-+ our ability to optimize later. */
|
|
|
-+ tmp = ! can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
|
|
|
-+
|
|
|
-+ mode = GET_MODE (operands[0]);
|
|
|
-+ emit_insn (gen_rtx_SET (VOIDmode, tmp,
|
|
|
-+ gen_rtx_HIGH (mode, operands[1])));
|
|
|
-+ operands[1] = gen_rtx_LO_SUM (mode, tmp, operands[1]);
|
|
|
-+ if (can_create_pseudo_p() && ! REG_P (operands[0]))
|
|
|
-+ {
|
|
|
-+ tmp = gen_reg_rtx (mode);
|
|
|
-+ emit_insn (gen_rtx_SET (VOIDmode, tmp, operands[1]));
|
|
|
-+ operands[1] = tmp;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Emit code for addsi3. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_addsi3 (rtx *operands)
|
|
|
-+{
|
|
|
-+ rtx op, clob;
|
|
|
-+
|
|
|
-+ if (can_create_pseudo_p ())
|
|
|
-+ {
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Emit the instruction. */
|
|
|
-+
|
|
|
-+ op = gen_rtx_SET (VOIDmode, operands[0],
|
|
|
-+ gen_rtx_PLUS (SImode, operands[1], operands[2]));
|
|
|
-+
|
|
|
-+ if (! can_create_pseudo_p ())
|
|
|
-+ {
|
|
|
-+ /* Reload doesn't know about the flags register, and doesn't know that
|
|
|
-+ it doesn't want to clobber it. We can only do this with PLUS. */
|
|
|
-+ emit_insn (op);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
|
|
|
-+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Emit code for mulsi3. Return 1 if we have generated all the code
|
|
|
-+ necessary to do the multiplication. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_emit_mult_sequence (rtx *operands)
|
|
|
-+{
|
|
|
-+ if (! ubicom32_v4)
|
|
|
-+ {
|
|
|
-+ rtx a1, a1_1, a2;
|
|
|
-+ rtx b1, b1_1, b2;
|
|
|
-+ rtx mac_lo_rtx;
|
|
|
-+ rtx t1, t2, t3;
|
|
|
-+
|
|
|
-+ /* Give up if we cannot create new pseudos. */
|
|
|
-+ if (!can_create_pseudo_p())
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* Synthesize 32-bit multiplication using 16-bit operations:
|
|
|
-+
|
|
|
-+ a1 = highpart (a)
|
|
|
-+ a2 = lowpart (a)
|
|
|
-+
|
|
|
-+ b1 = highpart (b)
|
|
|
-+ b2 = lowpart (b)
|
|
|
-+
|
|
|
-+ c = (a1 * b1) << 32 + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
|
|
|
-+ = 0 + (a1 * b2) << 16 + (a2 * b1) << 16 + a2 * b2
|
|
|
-+ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^
|
|
|
-+ Signed Signed Unsigned */
|
|
|
-+
|
|
|
-+ if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
|
|
|
-+ {
|
|
|
-+ rtx op1;
|
|
|
-+
|
|
|
-+ op1 = gen_reg_rtx (SImode);
|
|
|
-+ emit_move_insn (op1, operands[1]);
|
|
|
-+ operands[1] = op1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
|
|
|
-+ {
|
|
|
-+ rtx op2;
|
|
|
-+
|
|
|
-+ op2 = gen_reg_rtx (SImode);
|
|
|
-+ emit_move_insn (op2, operands[2]);
|
|
|
-+ operands[2] = op2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* a1 = highpart (a) */
|
|
|
-+ a1 = gen_reg_rtx (HImode);
|
|
|
-+ a1_1 = gen_reg_rtx (SImode);
|
|
|
-+ emit_insn (gen_ashrsi3 (a1_1, operands[1], GEN_INT (16)));
|
|
|
-+ emit_move_insn (a1, gen_lowpart (HImode, a1_1));
|
|
|
-+
|
|
|
-+ /* a2 = lowpart (a) */
|
|
|
-+ a2 = gen_reg_rtx (HImode);
|
|
|
-+ emit_move_insn (a2, gen_lowpart (HImode, operands[1]));
|
|
|
-+
|
|
|
-+ /* b1 = highpart (b) */
|
|
|
-+ b1 = gen_reg_rtx (HImode);
|
|
|
-+ b1_1 = gen_reg_rtx (SImode);
|
|
|
-+ emit_insn (gen_ashrsi3 (b1_1, operands[2], GEN_INT (16)));
|
|
|
-+ emit_move_insn (b1, gen_lowpart (HImode, b1_1));
|
|
|
-+
|
|
|
-+ /* b2 = lowpart (b) */
|
|
|
-+ b2 = gen_reg_rtx (HImode);
|
|
|
-+ emit_move_insn (b2, gen_lowpart (HImode, operands[2]));
|
|
|
-+
|
|
|
-+ /* t1 = (a1 * b2) << 16 */
|
|
|
-+ t1 = gen_reg_rtx (SImode);
|
|
|
-+ mac_lo_rtx = gen_rtx_REG (SImode, ACC0_LO_REGNUM);
|
|
|
-+ emit_insn (gen_mulhisi3 (mac_lo_rtx, a1, b2));
|
|
|
-+ emit_insn (gen_ashlsi3 (t1, mac_lo_rtx, GEN_INT (16)));
|
|
|
-+
|
|
|
-+ /* t2 = (a2 * b1) << 16 */
|
|
|
-+ t2 = gen_reg_rtx (SImode);
|
|
|
-+ emit_insn (gen_mulhisi3 (mac_lo_rtx, a2, b1));
|
|
|
-+ emit_insn (gen_ashlsi3 (t2, mac_lo_rtx, GEN_INT (16)));
|
|
|
-+
|
|
|
-+ /* mac_lo = a2 * b2 */
|
|
|
-+ emit_insn (gen_umulhisi3 (mac_lo_rtx, a2, b2));
|
|
|
-+
|
|
|
-+ /* t3 = t1 + t2 */
|
|
|
-+ t3 = gen_reg_rtx (SImode);
|
|
|
-+ emit_insn (gen_addsi3 (t3, t1, t2));
|
|
|
-+
|
|
|
-+ /* c = t3 + mac_lo_rtx */
|
|
|
-+ emit_insn (gen_addsi3 (operands[0], mac_lo_rtx, t3));
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ rtx acc_rtx;
|
|
|
-+
|
|
|
-+ /* Give up if we cannot create new pseudos. */
|
|
|
-+ if (!can_create_pseudo_p())
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ if (!ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
|
|
|
-+ {
|
|
|
-+ rtx op1;
|
|
|
-+
|
|
|
-+ op1 = gen_reg_rtx (SImode);
|
|
|
-+ emit_move_insn (op1, operands[1]);
|
|
|
-+ operands[1] = op1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
|
|
|
-+ {
|
|
|
-+ rtx op2;
|
|
|
-+
|
|
|
-+ op2 = gen_reg_rtx (SImode);
|
|
|
-+ emit_move_insn (op2, operands[2]);
|
|
|
-+ operands[2] = op2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ acc_rtx = gen_reg_rtx (DImode);
|
|
|
-+ emit_insn (gen_umulsidi3 (acc_rtx, operands[1], operands[2]));
|
|
|
-+ emit_move_insn (operands[0], gen_lowpart (SImode, acc_rtx));
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Move the integer value VAL into OPERANDS[0]. */
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_emit_move_const_int (rtx dest, rtx imm)
|
|
|
-+{
|
|
|
-+ rtx xoperands[2];
|
|
|
-+
|
|
|
-+ xoperands[0] = dest;
|
|
|
-+ xoperands[1] = imm;
|
|
|
-+
|
|
|
-+ /* Treat mem destinations separately. Values must be explicitly sign
|
|
|
-+ extended. */
|
|
|
-+ if (MEM_P (dest))
|
|
|
-+ {
|
|
|
-+ rtx low_hword_mem;
|
|
|
-+ rtx low_hword_addr;
|
|
|
-+
|
|
|
-+ /* Emit shorter sequence for signed 7-bit quantities. */
|
|
|
-+ if (satisfies_constraint_I (imm))
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("move.4\t%0, %1", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Special case for pushing constants. */
|
|
|
-+ if (GET_CODE (XEXP (dest, 0)) == PRE_DEC
|
|
|
-+ && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* See if we can add 2 to the original address. This is only
|
|
|
-+ possible if the original address is of the form REG or
|
|
|
-+ REG+const. */
|
|
|
-+ low_hword_addr = plus_constant (XEXP (dest, 0), 2);
|
|
|
-+ if (ubicom32_legitimate_address_p (HImode, low_hword_addr, 1))
|
|
|
-+ {
|
|
|
-+ low_hword_mem = gen_rtx_MEM (HImode, low_hword_addr);
|
|
|
-+ MEM_COPY_ATTRIBUTES (low_hword_mem, dest);
|
|
|
-+ output_asm_insn ("movei\t%0, #%%hi(%E1)", xoperands);
|
|
|
-+ xoperands[0] = low_hword_mem;
|
|
|
-+ output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* The original address is too complex. We need to use a
|
|
|
-+ scratch memory by (sp) and move that to the original
|
|
|
-+ destination. */
|
|
|
-+ if (! reg_mentioned_p (stack_pointer_rtx, dest))
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Our address mentions the stack pointer so we need to
|
|
|
-+ use our scratch data register here as well as scratch
|
|
|
-+ memory. */
|
|
|
-+ output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("move.4\td15, (sp)4++", xoperands);
|
|
|
-+ output_asm_insn ("move.4\t%0, d15", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Move into registers are zero extended by default. */
|
|
|
-+ if (! REG_P (dest))
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ if (satisfies_constraint_N (imm))
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("movei\t%0, %1", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (INTVAL (xoperands[1]) >= 0xff80
|
|
|
-+ && INTVAL (xoperands[1]) < 0x10000)
|
|
|
-+ {
|
|
|
-+ xoperands[1] = GEN_INT (INTVAL (xoperands[1]) - 0x10000);
|
|
|
-+ output_asm_insn ("move.2\t%0, %1", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((REGNO_REG_CLASS (REGNO (xoperands[0])) == ADDRESS_REGS
|
|
|
-+ || REGNO_REG_CLASS (REGNO (xoperands[0])) == FDPIC_REG)
|
|
|
-+ && ((INTVAL (xoperands[1]) & 0x80000000) == 0))
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("moveai\t%0, #%%hi(%E1)", xoperands);
|
|
|
-+ if ((INTVAL (xoperands[1]) & 0x7f) != 0)
|
|
|
-+ output_asm_insn ("lea.1\t%0, %%lo(%E1)(%0)", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((INTVAL (xoperands[1]) & 0xffff0000) == 0)
|
|
|
-+ {
|
|
|
-+ output_asm_insn ("movei\t%0, #%%lo(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("move.2\t%0, %0", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* This is very expensive. The constant is so large that we
|
|
|
-+ need to use the stack to do the load. */
|
|
|
-+ output_asm_insn ("movei\t-4(sp)++, #%%hi(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("movei\t2(sp), #%%lo(%E1)", xoperands);
|
|
|
-+ output_asm_insn ("move.4\t%0, (sp)4++", xoperands);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Stack layout. Prologue/Epilogue. */
|
|
|
-+
|
|
|
-+static int save_regs_size;
|
|
|
-+
|
|
|
-+static void
|
|
|
-+ubicom32_layout_frame (void)
|
|
|
-+{
|
|
|
-+ int regno;
|
|
|
-+
|
|
|
-+ memset ((char *) &save_regs[0], 0, sizeof (save_regs));
|
|
|
-+ nregs = 0;
|
|
|
-+ frame_size = get_frame_size ();
|
|
|
-+
|
|
|
-+ if (frame_pointer_needed || df_regs_ever_live_p (FRAME_POINTER_REGNUM))
|
|
|
-+ {
|
|
|
-+ save_regs[FRAME_POINTER_REGNUM] = 1;
|
|
|
-+ ++nregs;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (current_function_is_leaf && ! df_regs_ever_live_p (LINK_REGNO))
|
|
|
-+ ubicom32_can_use_calli_to_ret = 1;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ ubicom32_can_use_calli_to_ret = 0;
|
|
|
-+ save_regs[LINK_REGNO] = 1;
|
|
|
-+ ++nregs;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Figure out which register(s) needs to be saved. */
|
|
|
-+ for (regno = 0; regno <= LAST_ADDRESS_REGNUM; regno++)
|
|
|
-+ if (df_regs_ever_live_p(regno)
|
|
|
-+ && ! call_used_regs[regno]
|
|
|
-+ && ! fixed_regs[regno]
|
|
|
-+ && ! save_regs[regno])
|
|
|
-+ {
|
|
|
-+ save_regs[regno] = 1;
|
|
|
-+ ++nregs;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ save_regs_size = 4 * nregs;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+ubicom32_emit_add_movsi (int regno, int adj)
|
|
|
-+{
|
|
|
-+ rtx x;
|
|
|
-+ rtx reg = gen_rtx_REG (SImode, regno);
|
|
|
-+
|
|
|
-+ adj += 4;
|
|
|
-+ if (adj > 8 * 4)
|
|
|
-+ {
|
|
|
-+ x = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (-adj)));
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ x = emit_move_insn (gen_rtx_MEM (SImode, stack_pointer_rtx), reg);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ rtx addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx,
|
|
|
-+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
|
|
|
-+ GEN_INT (-adj)));
|
|
|
-+ x = emit_move_insn (gen_rtx_MEM (SImode, addr), reg);
|
|
|
-+ }
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_prologue (void)
|
|
|
-+{
|
|
|
-+ rtx x;
|
|
|
-+ int regno;
|
|
|
-+ int outgoing_args_size = crtl->outgoing_args_size;
|
|
|
-+ int adj;
|
|
|
-+
|
|
|
-+ if (ubicom32_naked_function_p ())
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+ ubicom32_builtin_saveregs ();
|
|
|
-+
|
|
|
-+ ubicom32_layout_frame ();
|
|
|
-+ adj = (outgoing_args_size + get_frame_size () + save_regs_size
|
|
|
-+ + crtl->args.pretend_args_size);
|
|
|
-+
|
|
|
-+ if (!adj)
|
|
|
-+ ;
|
|
|
-+ else if (outgoing_args_size + save_regs_size < 508
|
|
|
-+ && get_frame_size () + save_regs_size > 508)
|
|
|
-+ {
|
|
|
-+ int i = 0;
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (-adj));
|
|
|
-+ x = emit_insn (x);
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+
|
|
|
-+ for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
|
|
|
-+ if (save_regs[regno] && regno != LINK_REGNO)
|
|
|
-+ {
|
|
|
-+ x = gen_rtx_MEM (SImode,
|
|
|
-+ gen_rtx_PLUS (Pmode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ GEN_INT (i * 4 + outgoing_args_size)));
|
|
|
-+ x = emit_move_insn (x, gen_rtx_REG (SImode, regno));
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ ++i;
|
|
|
-+ }
|
|
|
-+ if (save_regs[LINK_REGNO])
|
|
|
-+ {
|
|
|
-+ x = gen_rtx_MEM (SImode,
|
|
|
-+ gen_rtx_PLUS (Pmode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ GEN_INT (i * 4 + outgoing_args_size)));
|
|
|
-+ x = emit_move_insn (x, gen_rtx_REG (SImode, LINK_REGNO));
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ int regno;
|
|
|
-+ int adj = get_frame_size () + crtl->args.pretend_args_size;
|
|
|
-+ int i = 0;
|
|
|
-+
|
|
|
-+ if (save_regs[LINK_REGNO])
|
|
|
-+ {
|
|
|
-+ ubicom32_emit_add_movsi (LINK_REGNO, adj);
|
|
|
-+ ++i;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (regno = 0; regno <= LAST_ADDRESS_REGNUM; ++regno)
|
|
|
-+ if (save_regs[regno] && regno != LINK_REGNO)
|
|
|
-+ {
|
|
|
-+ if (i)
|
|
|
-+ {
|
|
|
-+ rtx mem = gen_rtx_MEM (SImode,
|
|
|
-+ gen_rtx_PRE_DEC (Pmode,
|
|
|
-+ stack_pointer_rtx));
|
|
|
-+ x = emit_move_insn (mem, gen_rtx_REG (SImode, regno));
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ ubicom32_emit_add_movsi (regno, adj);
|
|
|
-+ ++i;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (outgoing_args_size || (!i && adj))
|
|
|
-+ {
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (-outgoing_args_size - (i ? 0 : adj)));
|
|
|
-+ x = emit_insn (x);
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (frame_pointer_needed)
|
|
|
-+ {
|
|
|
-+ int fp_adj = save_regs_size + outgoing_args_size;
|
|
|
-+ x = gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (fp_adj));
|
|
|
-+ x = emit_insn (x);
|
|
|
-+ RTX_FRAME_RELATED_P (x) = 1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_epilogue (void)
|
|
|
-+{
|
|
|
-+ rtx x;
|
|
|
-+ int regno;
|
|
|
-+ int outgoing_args_size = crtl->outgoing_args_size;
|
|
|
-+ int adj;
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+ if (ubicom32_naked_function_p ())
|
|
|
-+ {
|
|
|
-+ emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode,
|
|
|
-+ LINK_REGNO)));
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (cfun->calls_alloca)
|
|
|
-+ {
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
|
|
|
-+ GEN_INT (-save_regs_size));
|
|
|
-+ emit_insn (x);
|
|
|
-+ outgoing_args_size = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (outgoing_args_size)
|
|
|
-+ {
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (outgoing_args_size));
|
|
|
-+ emit_insn (x);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ i = 0;
|
|
|
-+ for (regno = LAST_ADDRESS_REGNUM; regno >= 0; --regno)
|
|
|
-+ if (save_regs[regno] && regno != LINK_REGNO)
|
|
|
-+ {
|
|
|
-+ x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
|
|
|
-+ emit_move_insn (gen_rtx_REG (SImode, regno), x);
|
|
|
-+ ++i;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Do we have to adjust the stack after we've finished restoring regs? */
|
|
|
-+ adj = get_frame_size() + crtl->args.pretend_args_size;
|
|
|
-+ if (cfun->stdarg)
|
|
|
-+ adj += UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
|
|
|
-+
|
|
|
-+#if 0
|
|
|
-+ if (crtl->calls_eh_return && 0)
|
|
|
-+ {
|
|
|
-+ if (save_regs[LINK_REGNO])
|
|
|
-+ {
|
|
|
-+ x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
|
|
|
-+ emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (adj)
|
|
|
-+ {
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (adj));
|
|
|
-+ x = emit_insn (x);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Perform the additional bump for __throw. */
|
|
|
-+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ EH_RETURN_STACKADJ_RTX));
|
|
|
-+ emit_jump_insn (gen_eh_return_internal ());
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ if (save_regs[LINK_REGNO])
|
|
|
-+ {
|
|
|
-+ if (adj >= 4 && adj <= (6 * 4))
|
|
|
-+ {
|
|
|
-+ x = GEN_INT (adj + 4);
|
|
|
-+ emit_jump_insn (gen_return_from_post_modify_sp (x));
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (adj == 0)
|
|
|
-+ {
|
|
|
-+ x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
|
|
|
-+ emit_jump_insn (gen_return_internal (x));
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ x = gen_rtx_MEM (SImode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx));
|
|
|
-+ emit_move_insn (gen_rtx_REG (SImode, LINK_REGNO), x);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (adj)
|
|
|
-+ {
|
|
|
-+ x = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
|
-+ GEN_INT (adj));
|
|
|
-+ x = emit_insn (x);
|
|
|
-+ adj = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Given that we've just done all the hard work here we may as well use
|
|
|
-+ a calli to return. */
|
|
|
-+ ubicom32_can_use_calli_to_ret = 1;
|
|
|
-+ emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode, LINK_REGNO)));
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_call_fdpic (rtx *operands)
|
|
|
-+{
|
|
|
-+ rtx c;
|
|
|
-+ rtx addr;
|
|
|
-+ rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
|
|
|
-+
|
|
|
-+ addr = XEXP (operands[0], 0);
|
|
|
-+
|
|
|
-+ c = gen_call_fdpic (addr, operands[1], fdpic_reg);
|
|
|
-+ emit_call_insn (c);
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_call_value_fdpic (rtx *operands)
|
|
|
-+{
|
|
|
-+ rtx c;
|
|
|
-+ rtx addr;
|
|
|
-+ rtx fdpic_reg = get_hard_reg_initial_val (SImode, FDPIC_REGNUM);
|
|
|
-+
|
|
|
-+ addr = XEXP (operands[1], 0);
|
|
|
-+
|
|
|
-+ c = gen_call_value_fdpic (operands[0], addr, operands[2], fdpic_reg);
|
|
|
-+ emit_call_insn (c);
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_expand_eh_return (rtx *operands)
|
|
|
-+{
|
|
|
-+ if (REG_P (operands[0])
|
|
|
-+ || REGNO (operands[0]) != EH_RETURN_STACKADJ_REGNO)
|
|
|
-+ {
|
|
|
-+ rtx sp = EH_RETURN_STACKADJ_RTX;
|
|
|
-+ emit_move_insn (sp, operands[0]);
|
|
|
-+ operands[0] = sp;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (REG_P (operands[1])
|
|
|
-+ || REGNO (operands[1]) != EH_RETURN_HANDLER_REGNO)
|
|
|
-+ {
|
|
|
-+ rtx ra = EH_RETURN_HANDLER_RTX;
|
|
|
-+ emit_move_insn (ra, operands[1]);
|
|
|
-+ operands[1] = ra;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Compute the offsets between eliminable registers. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_initial_elimination_offset (int from, int to)
|
|
|
-+{
|
|
|
-+ ubicom32_layout_frame ();
|
|
|
-+ if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
|
|
|
-+ return save_regs_size + crtl->outgoing_args_size;
|
|
|
-+
|
|
|
-+ if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
|
|
|
-+ return get_frame_size ()/* + save_regs_size */;
|
|
|
-+
|
|
|
-+ if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
|
|
|
-+ return get_frame_size ()
|
|
|
-+ + crtl->outgoing_args_size
|
|
|
-+ + save_regs_size;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return 1 if it is appropriate to emit `ret' instructions in the
|
|
|
-+ body of a function. Do this only if the epilogue is simple, needing a
|
|
|
-+ couple of insns. Prior to reloading, we can't tell how many registers
|
|
|
-+ must be saved, so return 0 then. Return 0 if there is no frame
|
|
|
-+ marker to de-allocate.
|
|
|
-+
|
|
|
-+ If NON_SAVING_SETJMP is defined and true, then it is not possible
|
|
|
-+ for the epilogue to be simple, so return 0. This is a special case
|
|
|
-+ since NON_SAVING_SETJMP will not cause regs_ever_live to change
|
|
|
-+ until final, but jump_optimize may need to know sooner if a
|
|
|
-+ `return' is OK. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_can_use_return_insn_p (void)
|
|
|
-+{
|
|
|
-+ if (! reload_completed || frame_pointer_needed)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Attributes and CC handling. */
|
|
|
-+
|
|
|
-+/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
|
|
|
-+ struct attribute_spec.handler. */
|
|
|
-+static tree
|
|
|
-+ubicom32_handle_fndecl_attribute (tree *node, tree name,
|
|
|
-+ tree args ATTRIBUTE_UNUSED,
|
|
|
-+ int flags ATTRIBUTE_UNUSED,
|
|
|
-+ bool *no_add_attrs)
|
|
|
-+{
|
|
|
-+ if (TREE_CODE (*node) != FUNCTION_DECL)
|
|
|
-+ {
|
|
|
-+ warning ("'%s' attribute only applies to functions",
|
|
|
-+ IDENTIFIER_POINTER (name));
|
|
|
-+ *no_add_attrs = true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_TREE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* A C expression that places additional restrictions on the register class to
|
|
|
-+ use when it is necessary to copy value X into a register in class CLASS.
|
|
|
-+ The value is a register class; perhaps CLASS, or perhaps another, smaller
|
|
|
-+ class. On many machines, the following definition is safe:
|
|
|
-+
|
|
|
-+ #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
|
|
|
-+
|
|
|
-+ Sometimes returning a more restrictive class makes better code. For
|
|
|
-+ example, on the 68000, when X is an integer constant that is in range for a
|
|
|
-+ `moveq' instruction, the value of this macro is always `DATA_REGS' as long
|
|
|
-+ as CLASS includes the data registers. Requiring a data register guarantees
|
|
|
-+ that a `moveq' will be used.
|
|
|
-+
|
|
|
-+ If X is a `const_double', by returning `NO_REGS' you can force X into a
|
|
|
-+ memory constant. This is useful on certain machines where immediate
|
|
|
-+ floating values cannot be loaded into certain kinds of registers. */
|
|
|
-+
|
|
|
-+enum reg_class
|
|
|
-+ubicom32_preferred_reload_class (rtx x, enum reg_class class)
|
|
|
-+{
|
|
|
-+ /* If a symbolic constant, HIGH or a PLUS is reloaded,
|
|
|
-+ it is most likely being used as an address, so
|
|
|
-+ prefer ADDRESS_REGS. If 'class' is not a superset
|
|
|
-+ of ADDRESS_REGS, e.g. DATA_REGS, then reject this reload. */
|
|
|
-+ if (GET_CODE (x) == PLUS
|
|
|
-+ || GET_CODE (x) == HIGH
|
|
|
-+ || GET_CODE (x) == LABEL_REF
|
|
|
-+ || GET_CODE (x) == SYMBOL_REF
|
|
|
-+ || GET_CODE (x) == CONST)
|
|
|
-+ {
|
|
|
-+ if (reg_class_subset_p (ALL_ADDRESS_REGS, class))
|
|
|
-+ return ALL_ADDRESS_REGS;
|
|
|
-+
|
|
|
-+ return NO_REGS;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return class;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Function arguments and varargs. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_reg_parm_stack_space (tree fndecl)
|
|
|
-+{
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ if (fndecl
|
|
|
-+ && TYPE_ARG_TYPES (TREE_TYPE (fndecl)) != 0
|
|
|
-+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))))
|
|
|
-+ != void_type_node))
|
|
|
-+ return UBICOM32_FUNCTION_ARG_REGS * UNITS_PER_WORD;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Flush the argument registers to the stack for a stdarg function;
|
|
|
-+ return the new argument pointer. */
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+ubicom32_builtin_saveregs (void)
|
|
|
-+{
|
|
|
-+ int regno;
|
|
|
-+
|
|
|
-+ if (! cfun->stdarg)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ for (regno = UBICOM32_FUNCTION_ARG_REGS - 1; regno >= 0; --regno)
|
|
|
-+ emit_move_insn (gen_rtx_MEM (SImode,
|
|
|
-+ gen_rtx_PRE_DEC (SImode,
|
|
|
-+ stack_pointer_rtx)),
|
|
|
-+ gen_rtx_REG (SImode, regno));
|
|
|
-+
|
|
|
-+ return stack_pointer_rtx;
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_va_start (tree valist, rtx nextarg)
|
|
|
-+{
|
|
|
-+ std_expand_builtin_va_start (valist, nextarg);
|
|
|
-+}
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+ubicom32_va_arg (tree valist, tree type)
|
|
|
-+{
|
|
|
-+ HOST_WIDE_INT size, rsize;
|
|
|
-+ tree addr, incr, tmp;
|
|
|
-+ rtx addr_rtx;
|
|
|
-+ int indirect = 0;
|
|
|
-+
|
|
|
-+ /* Round up sizeof(type) to a word. */
|
|
|
-+ size = int_size_in_bytes (type);
|
|
|
-+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
|
|
|
-+
|
|
|
-+ /* Large types are passed by reference. */
|
|
|
-+ if (size > 8)
|
|
|
-+ {
|
|
|
-+ indirect = 1;
|
|
|
-+ size = rsize = UNITS_PER_WORD;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ incr = valist;
|
|
|
-+ addr = incr = save_expr (incr);
|
|
|
-+
|
|
|
-+ /* FIXME Nat's version - is it correct? */
|
|
|
-+ tmp = fold_convert (ptr_type_node, size_int (rsize));
|
|
|
-+ tmp = build2 (PLUS_EXPR, ptr_type_node, incr, tmp);
|
|
|
-+ incr = fold (tmp);
|
|
|
-+
|
|
|
-+ /* FIXME Nat's version - is it correct? */
|
|
|
-+ incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
|
|
|
-+
|
|
|
-+ TREE_SIDE_EFFECTS (incr) = 1;
|
|
|
-+ expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
|
|
-+
|
|
|
-+ addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
|
|
|
-+
|
|
|
-+ if (size < UNITS_PER_WORD)
|
|
|
-+ emit_insn (gen_addsi3 (addr_rtx, addr_rtx,
|
|
|
-+ GEN_INT (UNITS_PER_WORD - size)));
|
|
|
-+
|
|
|
-+ if (indirect)
|
|
|
-+ {
|
|
|
-+ addr_rtx = force_reg (Pmode, addr_rtx);
|
|
|
-+ addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
|
|
|
-+ set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return addr_rtx;
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
|
|
|
-+ int indirect ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ cum->nbytes = 0;
|
|
|
-+
|
|
|
-+ if (!libname)
|
|
|
-+ {
|
|
|
-+ cum->stdarg = (TYPE_ARG_TYPES (fntype) != 0
|
|
|
-+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
|
|
|
-+ != void_type_node));
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return an RTX to represent where a value in mode MODE will be passed
|
|
|
-+ to a function. If the result is 0, the argument will be pushed. */
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
|
|
|
-+ int named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ rtx result = 0;
|
|
|
-+ int size, align;
|
|
|
-+ int nregs = UBICOM32_FUNCTION_ARG_REGS;
|
|
|
-+
|
|
|
-+ /* Figure out the size of the object to be passed. */
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ size = int_size_in_bytes (type);
|
|
|
-+ else
|
|
|
-+ size = GET_MODE_SIZE (mode);
|
|
|
-+
|
|
|
-+ /* Figure out the alignment of the object to be passed. */
|
|
|
-+ align = size;
|
|
|
-+
|
|
|
-+ cum->nbytes = (cum->nbytes + 3) & ~3;
|
|
|
-+
|
|
|
-+ /* Don't pass this arg via a register if all the argument registers
|
|
|
-+ are used up. */
|
|
|
-+ if (cum->nbytes >= nregs * UNITS_PER_WORD)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* Don't pass this arg via a register if it would be split between
|
|
|
-+ registers and memory. */
|
|
|
-+ result = gen_rtx_REG (mode, cum->nbytes / UNITS_PER_WORD);
|
|
|
-+
|
|
|
-+ return result;
|
|
|
-+}
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+function_incoming_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
|
|
|
-+ int named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ if (cfun->stdarg)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ return function_arg (cum, mode, type, named);
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Implement hook TARGET_ARG_PARTIAL_BYTES.
|
|
|
-+
|
|
|
-+ Returns the number of bytes at the beginning of an argument that
|
|
|
-+ must be put in registers. The value must be zero for arguments
|
|
|
-+ that are passed entirely in registers or that are entirely pushed
|
|
|
-+ on the stack. */
|
|
|
-+static int
|
|
|
-+ubicom32_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
|
|
-+ tree type, bool named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ int size, diff;
|
|
|
-+
|
|
|
-+ int nregs = UBICOM32_FUNCTION_ARG_REGS;
|
|
|
-+
|
|
|
-+ /* round up to full word */
|
|
|
-+ cum->nbytes = (cum->nbytes + 3) & ~3;
|
|
|
-+
|
|
|
-+ if (targetm.calls.pass_by_reference (cum, mode, type, named))
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* number of bytes left in registers */
|
|
|
-+ diff = nregs*UNITS_PER_WORD - cum->nbytes;
|
|
|
-+
|
|
|
-+ /* regs all used up */
|
|
|
-+ if (diff <= 0)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* Figure out the size of the object to be passed. */
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ size = int_size_in_bytes (type);
|
|
|
-+ else
|
|
|
-+ size = GET_MODE_SIZE (mode);
|
|
|
-+
|
|
|
-+ /* enough space left in regs for size */
|
|
|
-+ if (size <= diff)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* put diff bytes in regs and rest on stack */
|
|
|
-+ return diff;
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode, const_tree type,
|
|
|
-+ bool named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ int size;
|
|
|
-+
|
|
|
-+ if (type)
|
|
|
-+ size = int_size_in_bytes (type);
|
|
|
-+ else
|
|
|
-+ size = GET_MODE_SIZE (mode);
|
|
|
-+
|
|
|
-+ return size <= 0 || size > 8;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_callee_copies (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode, const_tree type,
|
|
|
-+ bool named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ int size;
|
|
|
-+
|
|
|
-+ if (type)
|
|
|
-+ size = int_size_in_bytes (type);
|
|
|
-+ else
|
|
|
-+ size = GET_MODE_SIZE (mode);
|
|
|
-+
|
|
|
-+ return size <= 0 || size > 8;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ int size, mode;
|
|
|
-+
|
|
|
-+ if (!type)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ size = int_size_in_bytes(type);
|
|
|
-+ if (size > 8)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ mode = TYPE_MODE(type);
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return true if a given register number REGNO is acceptable for machine
|
|
|
-+ mode MODE. */
|
|
|
-+bool
|
|
|
-+ubicom32_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ /* If we're not at least a v3 ISA then ACC0_HI is only 16 bits. */
|
|
|
-+ if (! ubicom32_v3)
|
|
|
-+ {
|
|
|
-+ if (regno == ACC0_HI_REGNUM)
|
|
|
-+ return (mode == QImode || mode == HImode);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Only the flags reg can hold CCmode. */
|
|
|
-+ if (GET_MODE_CLASS (mode) == MODE_CC)
|
|
|
-+ return regno == CC_REGNUM;
|
|
|
-+
|
|
|
-+ /* We restrict the choice of DImode registers to only being address,
|
|
|
-+ data or accumulator regs. We also restrict them to only start on
|
|
|
-+ even register numbers so we never have to worry about partial
|
|
|
-+ overlaps between operands in instructions. */
|
|
|
-+ if (GET_MODE_SIZE (mode) > 4)
|
|
|
-+ {
|
|
|
-+ switch (REGNO_REG_CLASS (regno))
|
|
|
-+ {
|
|
|
-+ case ADDRESS_REGS:
|
|
|
-+ case DATA_REGS:
|
|
|
-+ case ACC_REGS:
|
|
|
-+ return (regno & 1) == 0;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return true;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
|
|
|
-+ and check its validity for a certain class.
|
|
|
-+ We have two alternate definitions for each of them.
|
|
|
-+ The usual definition accepts all pseudo regs; the other rejects
|
|
|
-+ them unless they have been allocated suitable hard regs.
|
|
|
-+ The symbol REG_OK_STRICT causes the latter definition to be used.
|
|
|
-+
|
|
|
-+ Most source files want to accept pseudo regs in the hope that
|
|
|
-+ they will get allocated to the class that the insn wants them to be in.
|
|
|
-+ Source files for reload pass need to be strict.
|
|
|
-+ After reload, it makes no difference, since pseudo regs have
|
|
|
-+ been eliminated by then.
|
|
|
-+
|
|
|
-+ These assume that REGNO is a hard or pseudo reg number.
|
|
|
-+ They give nonzero only if REGNO is a hard reg of the suitable class
|
|
|
-+ or a pseudo reg currently allocated to a suitable hard reg.
|
|
|
-+ Since they use reg_renumber, they are safe only once reg_renumber
|
|
|
-+ has been allocated, which happens in local-alloc.c. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_regno_ok_for_base_p (int regno, int strict)
|
|
|
-+{
|
|
|
-+ if ((regno >= FIRST_ADDRESS_REGNUM && regno <= STACK_POINTER_REGNUM)
|
|
|
-+ || (!strict
|
|
|
-+ && (regno >= FIRST_PSEUDO_REGISTER
|
|
|
-+ || regno == ARG_POINTER_REGNUM))
|
|
|
-+ || (strict && (reg_renumber
|
|
|
-+ && reg_renumber[regno] >= FIRST_ADDRESS_REGNUM
|
|
|
-+ && reg_renumber[regno] <= STACK_POINTER_REGNUM)))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_regno_ok_for_index_p (int regno, int strict)
|
|
|
-+{
|
|
|
-+ if ((regno >= FIRST_DATA_REGNUM && regno <= LAST_DATA_REGNUM)
|
|
|
-+ || (!strict && regno >= FIRST_PSEUDO_REGISTER)
|
|
|
-+ || (strict && (reg_renumber
|
|
|
-+ && reg_renumber[regno] >= FIRST_DATA_REGNUM
|
|
|
-+ && reg_renumber[regno] <= LAST_DATA_REGNUM)))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Returns 1 if X is a valid index register. STRICT is 1 if only hard
|
|
|
-+ registers should be accepted. Accept either REG or SUBREG where a
|
|
|
-+ register is valid. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_is_index_reg (rtx x, int strict)
|
|
|
-+{
|
|
|
-+ if ((REG_P (x) && ubicom32_regno_ok_for_index_p (REGNO (x), strict))
|
|
|
-+ || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
|
|
|
-+ && ubicom32_regno_ok_for_index_p (REGNO (SUBREG_REG (x)), strict)))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return 1 if X is a valid index for a memory address. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_is_index_expr (enum machine_mode mode, rtx x, int strict)
|
|
|
-+{
|
|
|
-+ /* Immediate index must be an unsigned 7-bit offset multiple of 1, 2
|
|
|
-+ or 4 depending on mode. */
|
|
|
-+ if (CONST_INT_P (x))
|
|
|
-+ {
|
|
|
-+ switch (mode)
|
|
|
-+ {
|
|
|
-+ case QImode:
|
|
|
-+ return satisfies_constraint_J (x);
|
|
|
-+
|
|
|
-+ case HImode:
|
|
|
-+ return satisfies_constraint_K (x);
|
|
|
-+
|
|
|
-+ case SImode:
|
|
|
-+ case SFmode:
|
|
|
-+ return satisfies_constraint_L (x);
|
|
|
-+
|
|
|
-+ case DImode:
|
|
|
-+ return satisfies_constraint_L (x)
|
|
|
-+ && satisfies_constraint_L (GEN_INT (INTVAL (x) + 4));
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (mode != SImode && mode != HImode && mode != QImode)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ /* Register index scaled by mode of operand: REG + REG * modesize.
|
|
|
-+ Valid scaled index registers are:
|
|
|
-+
|
|
|
-+ SImode (mult (dreg) 4))
|
|
|
-+ HImode (mult (dreg) 2))
|
|
|
-+ QImode (mult (dreg) 1)) */
|
|
|
-+ if (GET_CODE (x) == MULT
|
|
|
-+ && ubicom32_is_index_reg (XEXP (x, 0), strict)
|
|
|
-+ && CONST_INT_P (XEXP (x, 1))
|
|
|
-+ && INTVAL (XEXP (x, 1)) == (HOST_WIDE_INT)GET_MODE_SIZE (mode))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ /* REG + REG addressing is allowed for QImode. */
|
|
|
-+ if (ubicom32_is_index_reg (x, strict) && mode == QImode)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_is_valid_offset (enum machine_mode mode, HOST_WIDE_INT offs)
|
|
|
-+{
|
|
|
-+ if (offs < 0)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ switch (mode)
|
|
|
-+ {
|
|
|
-+ case QImode:
|
|
|
-+ return offs <= 127;
|
|
|
-+
|
|
|
-+ case HImode:
|
|
|
-+ return offs <= 254;
|
|
|
-+
|
|
|
-+ case SImode:
|
|
|
-+ case SFmode:
|
|
|
-+ return offs <= 508;
|
|
|
-+
|
|
|
-+ case DImode:
|
|
|
-+ return offs <= 504;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static int
|
|
|
-+ubicom32_get_valid_offset_mask (enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ switch (mode)
|
|
|
-+ {
|
|
|
-+ case QImode:
|
|
|
-+ return 127;
|
|
|
-+
|
|
|
-+ case HImode:
|
|
|
-+ return 255;
|
|
|
-+
|
|
|
-+ case SImode:
|
|
|
-+ case SFmode:
|
|
|
-+ return 511;
|
|
|
-+
|
|
|
-+ case DImode:
|
|
|
-+ return 255;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Returns 1 if X is a valid base register. STRICT is 1 if only hard
|
|
|
-+ registers should be accepted. Accept either REG or SUBREG where a
|
|
|
-+ register is valid. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_is_base_reg (rtx x, int strict)
|
|
|
-+{
|
|
|
-+ if ((REG_P (x) && ubicom32_regno_ok_for_base_p (REGNO (x), strict))
|
|
|
-+ || (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
|
|
|
-+ && ubicom32_regno_ok_for_base_p (REGNO (SUBREG_REG (x)), strict)))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ return TARGET_FDPIC;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Determine if X is a legitimate constant. */
|
|
|
-+
|
|
|
-+bool
|
|
|
-+ubicom32_legitimate_constant_p (rtx x)
|
|
|
-+{
|
|
|
-+ /* Among its other duties, LEGITIMATE_CONSTANT_P decides whether
|
|
|
-+ a constant can be entered into reg_equiv_constant[]. If we return true,
|
|
|
-+ reload can create new instances of the constant whenever it likes.
|
|
|
-+
|
|
|
-+ The idea is therefore to accept as many constants as possible (to give
|
|
|
-+ reload more freedom) while rejecting constants that can only be created
|
|
|
-+ at certain times. In particular, anything with a symbolic component will
|
|
|
-+ require use of the pseudo FDPIC register, which is only available before
|
|
|
-+ reload. */
|
|
|
-+ if (TARGET_FDPIC)
|
|
|
-+ {
|
|
|
-+ if (GET_CODE (x) == SYMBOL_REF
|
|
|
-+ || (GET_CODE (x) == CONST
|
|
|
-+ && GET_CODE (XEXP (x, 0)) == PLUS
|
|
|
-+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
|
|
|
-+ || CONSTANT_ADDRESS_P (x))
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* For non-PIC code anything goes! */
|
|
|
-+ return true;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Address validation. */
|
|
|
-+
|
|
|
-+bool
|
|
|
-+ubicom32_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
|
|
|
-+{
|
|
|
-+ if (TARGET_DEBUG_ADDRESS)
|
|
|
-+ {
|
|
|
-+ fprintf (stderr, "\n==> GO_IF_LEGITIMATE_ADDRESS%s\n",
|
|
|
-+ (strict) ? " (STRICT)" : "");
|
|
|
-+ debug_rtx (x);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (CONSTANT_ADDRESS_P (x))
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (ubicom32_is_base_reg (x, strict))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if ((GET_CODE (x) == POST_INC
|
|
|
-+ || GET_CODE (x) == PRE_INC
|
|
|
-+ || GET_CODE (x) == POST_DEC
|
|
|
-+ || GET_CODE (x) == PRE_DEC)
|
|
|
-+ && REG_P (XEXP (x, 0))
|
|
|
-+ && ubicom32_is_base_reg (XEXP (x, 0), strict)
|
|
|
-+ && mode != DImode)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if ((GET_CODE (x) == PRE_MODIFY || GET_CODE (x) == POST_MODIFY)
|
|
|
-+ && ubicom32_is_base_reg (XEXP (x, 0), strict)
|
|
|
-+ && GET_CODE (XEXP (x, 1)) == PLUS
|
|
|
-+ && rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0))
|
|
|
-+ && CONST_INT_P (XEXP (XEXP (x, 1), 1))
|
|
|
-+ && mode != DImode)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT disp = INTVAL (XEXP (XEXP (x, 1), 1));
|
|
|
-+ switch (mode)
|
|
|
-+ {
|
|
|
-+ case QImode:
|
|
|
-+ return disp >= -8 && disp <= 7;
|
|
|
-+
|
|
|
-+ case HImode:
|
|
|
-+ return disp >= -16 && disp <= 14 && ! (disp & 1);
|
|
|
-+
|
|
|
-+ case SImode:
|
|
|
-+ return disp >= -32 && disp <= 28 && ! (disp & 3);
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Accept base + index * scale. */
|
|
|
-+ if (GET_CODE (x) == PLUS
|
|
|
-+ && ubicom32_is_base_reg (XEXP (x, 0), strict)
|
|
|
-+ && ubicom32_is_index_expr (mode, XEXP (x, 1), strict))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ /* Accept index * scale + base. */
|
|
|
-+ if (GET_CODE (x) == PLUS
|
|
|
-+ && ubicom32_is_base_reg (XEXP (x, 1), strict)
|
|
|
-+ && ubicom32_is_index_expr (mode, XEXP (x, 0), strict))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ if (! TARGET_FDPIC)
|
|
|
-+ {
|
|
|
-+ /* Accept (lo_sum (reg) (symbol_ref)) that can be used as a mem+7bits
|
|
|
-+ displacement operand:
|
|
|
-+
|
|
|
-+ moveai a1, #%hi(SYM)
|
|
|
-+ move.4 d3, %lo(SYM)(a1) */
|
|
|
-+ if (GET_CODE (x) == LO_SUM
|
|
|
-+ && ubicom32_is_base_reg (XEXP (x, 0), strict)
|
|
|
-+ && (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
|
|
|
-+ || GET_CODE (XEXP (x, 1)) == LABEL_REF /* FIXME: wrong */)
|
|
|
-+ && mode != DImode)
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (TARGET_DEBUG_ADDRESS)
|
|
|
-+ fprintf (stderr, "\nNot a legitimate address.\n");
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+ubicom32_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ return NULL_RTX;
|
|
|
-+
|
|
|
-+ if (GET_CODE (x) == PLUS
|
|
|
-+ && REG_P (XEXP (x, 0))
|
|
|
-+ && ! REGNO_PTR_FRAME_P (REGNO (XEXP (x, 0)))
|
|
|
-+ && CONST_INT_P (XEXP (x, 1))
|
|
|
-+ && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (x, 1))))
|
|
|
-+ {
|
|
|
-+ rtx base;
|
|
|
-+ rtx plus;
|
|
|
-+ rtx new_rtx;
|
|
|
-+ HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
|
|
|
-+ HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
|
|
|
-+ HOST_WIDE_INT high = val ^ low;
|
|
|
-+
|
|
|
-+ if (val < 0)
|
|
|
-+ return NULL_RTX;
|
|
|
-+
|
|
|
-+ if (! low)
|
|
|
-+ return NULL_RTX;
|
|
|
-+
|
|
|
-+ /* Reload the high part into a base reg; leave the low part
|
|
|
-+ in the mem directly. */
|
|
|
-+ base = XEXP (x, 0);
|
|
|
-+ if (! ubicom32_is_base_reg (base, 0))
|
|
|
-+ base = copy_to_mode_reg (Pmode, base);
|
|
|
-+
|
|
|
-+ plus = expand_simple_binop (Pmode, PLUS,
|
|
|
-+ gen_int_mode (high, Pmode),
|
|
|
-+ base, NULL, 0, OPTAB_WIDEN);
|
|
|
-+ new_rtx = plus_constant (plus, low);
|
|
|
-+
|
|
|
-+ return new_rtx;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_RTX;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Try a machine-dependent way of reloading an illegitimate address AD
|
|
|
-+ operand. If we find one, push the reload and and return the new address.
|
|
|
-+
|
|
|
-+ MODE is the mode of the enclosing MEM. OPNUM is the operand number
|
|
|
-+ and TYPE is the reload type of the current reload. */
|
|
|
-+
|
|
|
-+rtx
|
|
|
-+ubicom32_legitimize_reload_address (rtx ad, enum machine_mode mode,
|
|
|
-+ int opnum, int type)
|
|
|
-+{
|
|
|
-+ /* Is this an address that we've already fixed up? If it is then
|
|
|
-+ recognize it and move on. */
|
|
|
-+ if (GET_CODE (ad) == PLUS
|
|
|
-+ && GET_CODE (XEXP (ad, 0)) == PLUS
|
|
|
-+ && REG_P (XEXP (XEXP (ad, 0), 0))
|
|
|
-+ && CONST_INT_P (XEXP (XEXP (ad, 0), 1))
|
|
|
-+ && CONST_INT_P (XEXP (ad, 1)))
|
|
|
-+ {
|
|
|
-+ push_reload (XEXP (ad, 0), NULL_RTX, &XEXP (ad, 0), NULL,
|
|
|
-+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
|
|
|
-+ opnum, (enum reload_type) type);
|
|
|
-+ return ad;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Have we got an address where the offset is simply out of range? If
|
|
|
-+ yes then reload the range as a high part and smaller offset. */
|
|
|
-+ if (GET_CODE (ad) == PLUS
|
|
|
-+ && REG_P (XEXP (ad, 0))
|
|
|
-+ && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
|
|
|
-+ && REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0)))
|
|
|
-+ && CONST_INT_P (XEXP (ad, 1))
|
|
|
-+ && ! ubicom32_is_valid_offset (mode, INTVAL (XEXP (ad, 1))))
|
|
|
-+ {
|
|
|
-+ rtx temp;
|
|
|
-+ rtx new_rtx;
|
|
|
-+
|
|
|
-+ HOST_WIDE_INT val = INTVAL (XEXP (ad, 1));
|
|
|
-+ HOST_WIDE_INT low = val & ubicom32_get_valid_offset_mask (mode);
|
|
|
-+ HOST_WIDE_INT high = val ^ low;
|
|
|
-+
|
|
|
-+ /* Reload the high part into a base reg; leave the low part
|
|
|
-+ in the mem directly. */
|
|
|
-+ temp = gen_rtx_PLUS (Pmode, XEXP (ad, 0), GEN_INT (high));
|
|
|
-+ new_rtx = gen_rtx_PLUS (Pmode, temp, GEN_INT (low));
|
|
|
-+
|
|
|
-+ push_reload (XEXP (new_rtx, 0), NULL_RTX, &XEXP (new_rtx, 0), NULL,
|
|
|
-+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
|
|
|
-+ opnum, (enum reload_type) type);
|
|
|
-+ return new_rtx;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* If we're presented with an pre/post inc/dec then we must force this
|
|
|
-+ to be done in an address register. The register allocator should
|
|
|
-+ work this out for itself but at times ends up trying to use the wrong
|
|
|
-+ class. If we get the wrong class then reload will end up generating
|
|
|
-+ at least 3 instructions whereas this way we can hopefully keep it to
|
|
|
-+ just 2. */
|
|
|
-+ if ((GET_CODE (ad) == POST_INC
|
|
|
-+ || GET_CODE (ad) == PRE_INC
|
|
|
-+ || GET_CODE (ad) == POST_DEC
|
|
|
-+ || GET_CODE (ad) == PRE_DEC)
|
|
|
-+ && REG_P (XEXP (ad, 0))
|
|
|
-+ && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
|
|
|
-+ && ! REGNO_OK_FOR_BASE_P (REGNO (XEXP (ad, 0))))
|
|
|
-+ {
|
|
|
-+ push_reload (XEXP (ad, 0), XEXP (ad, 0), &XEXP (ad, 0), &XEXP (ad, 0),
|
|
|
-+ BASE_REG_CLASS, GET_MODE (XEXP (ad, 0)), GET_MODE (XEXP (ad, 0)), 0, 0,
|
|
|
-+ opnum, RELOAD_OTHER);
|
|
|
-+ return ad;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_RTX;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Compute a (partial) cost for rtx X. Return true if the complete
|
|
|
-+ cost has been computed, and false if subexpressions should be
|
|
|
-+ scanned. In either case, *TOTAL contains the cost result. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+ubicom32_rtx_costs (rtx x, int code, int outer_code, int *total,
|
|
|
-+ bool speed ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ enum machine_mode mode = GET_MODE (x);
|
|
|
-+
|
|
|
-+ switch (code)
|
|
|
-+ {
|
|
|
-+ case CONST_INT:
|
|
|
-+ /* Very short constants often fold into instructions so
|
|
|
-+ we pretend that they don't cost anything! This is
|
|
|
-+ really important as regards zero values as otherwise
|
|
|
-+ the compiler has a nasty habit of wanting to reuse
|
|
|
-+ zeroes that are in regs but that tends to pessimize
|
|
|
-+ the code. */
|
|
|
-+ if (satisfies_constraint_I (x))
|
|
|
-+ {
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Bit clearing costs nothing */
|
|
|
-+ if (outer_code == AND
|
|
|
-+ && exact_log2 (~INTVAL (x)) != -1)
|
|
|
-+ {
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Masking the lower set of bits costs nothing. */
|
|
|
-+ if (outer_code == AND
|
|
|
-+ && exact_log2 (INTVAL (x) + 1) != -1)
|
|
|
-+ {
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Bit setting costs nothing. */
|
|
|
-+ if (outer_code == IOR
|
|
|
-+ && exact_log2 (INTVAL (x)) != -1)
|
|
|
-+ {
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Larger constants that can be loaded via movei aren't too
|
|
|
-+ bad. If we're just doing a set they cost nothing extra. */
|
|
|
-+ if (satisfies_constraint_N (x))
|
|
|
-+ {
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (2);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (5);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (3);
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ /* We don't optimize CONST_DOUBLEs well nor do we relax them well,
|
|
|
-+ so their cost is very high. */
|
|
|
-+ *total = COSTS_N_INSNS (6);
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case CONST:
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ case MEM:
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case IF_THEN_ELSE:
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case HIGH:
|
|
|
-+ case LO_SUM:
|
|
|
-+ case BSWAP:
|
|
|
-+ case PLUS:
|
|
|
-+ case MINUS:
|
|
|
-+ case AND:
|
|
|
-+ case IOR:
|
|
|
-+ case XOR:
|
|
|
-+ case ASHIFT:
|
|
|
-+ case ASHIFTRT:
|
|
|
-+ case LSHIFTRT:
|
|
|
-+ case NEG:
|
|
|
-+ case NOT:
|
|
|
-+ case SIGN_EXTEND:
|
|
|
-+ case ZERO_EXTEND:
|
|
|
-+ case ZERO_EXTRACT:
|
|
|
-+ if (outer_code == SET)
|
|
|
-+ {
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (2);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ }
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case COMPARE:
|
|
|
-+ if (outer_code == SET)
|
|
|
-+ {
|
|
|
-+ if (GET_MODE (XEXP (x, 0)) == DImode
|
|
|
-+ || GET_MODE (XEXP (x, 1)) == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (2);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ }
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case UMOD:
|
|
|
-+ case UDIV:
|
|
|
-+ case MOD:
|
|
|
-+ case DIV:
|
|
|
-+ if (outer_code == SET)
|
|
|
-+ {
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (600);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (200);
|
|
|
-+ }
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case MULT:
|
|
|
-+ if (outer_code == SET)
|
|
|
-+ {
|
|
|
-+ if (! ubicom32_v4)
|
|
|
-+ {
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (15);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (5);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ if (mode == DImode)
|
|
|
-+ *total = COSTS_N_INSNS (6);
|
|
|
-+ else
|
|
|
-+ *total = COSTS_N_INSNS (2);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ case UNSPEC:
|
|
|
-+ if (XINT (x, 1) == UNSPEC_FDPIC_GOT
|
|
|
-+ || XINT (x, 1) == UNSPEC_FDPIC_GOT_FUNCDESC)
|
|
|
-+ *total = 0;
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return 1 if ADDR can have different meanings depending on the machine
|
|
|
-+ mode of the memory reference it is used for or if the address is
|
|
|
-+ valid for some modes but not others.
|
|
|
-+
|
|
|
-+ Autoincrement and autodecrement addresses typically have
|
|
|
-+ mode-dependent effects because the amount of the increment or
|
|
|
-+ decrement is the size of the operand being addressed. Some machines
|
|
|
-+ have other mode-dependent addresses. Many RISC machines have no
|
|
|
-+ mode-dependent addresses.
|
|
|
-+
|
|
|
-+ You may assume that ADDR is a valid address for the machine. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_mode_dependent_address_p (rtx addr)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (addr) == POST_INC
|
|
|
-+ || GET_CODE (addr) == PRE_INC
|
|
|
-+ || GET_CODE (addr) == POST_DEC
|
|
|
-+ || GET_CODE (addr) == PRE_DEC
|
|
|
-+ || GET_CODE (addr) == POST_MODIFY
|
|
|
-+ || GET_CODE (addr) == PRE_MODIFY)
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+ubicom32_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ fprintf (file, "/* frame/pretend: %ld/%d save_regs: %d out_args: %d %s */\n",
|
|
|
-+ get_frame_size (), crtl->args.pretend_args_size,
|
|
|
-+ save_regs_size, crtl->outgoing_args_size,
|
|
|
-+ current_function_is_leaf ? "leaf" : "nonleaf");
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+ubicom32_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
|
|
|
-+ HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ ubicom32_reorg_completed = 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+ubicom32_machine_dependent_reorg (void)
|
|
|
-+{
|
|
|
-+#if 0 /* Commenting out this optimization until it is fixed */
|
|
|
-+ if (optimize)
|
|
|
-+ {
|
|
|
-+ compute_bb_for_insn ();
|
|
|
-+
|
|
|
-+ /* Do a very simple CSE pass over just the hard registers. */
|
|
|
-+ reload_cse_regs (get_insns ());
|
|
|
-+
|
|
|
-+ /* Reload_cse_regs can eliminate potentially-trapping MEMs.
|
|
|
-+ Remove any EH edges associated with them. */
|
|
|
-+ if (flag_non_call_exceptions)
|
|
|
-+ purge_all_dead_edges ();
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ ubicom32_reorg_completed = 1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+ubicom32_output_cond_jump (rtx insn, rtx cond, rtx target)
|
|
|
-+{
|
|
|
-+ rtx note;
|
|
|
-+ int mostly_false_jump;
|
|
|
-+ rtx xoperands[2];
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ note = find_reg_note (insn, REG_BR_PROB, 0);
|
|
|
-+ mostly_false_jump = !note || (INTVAL (XEXP (note, 0))
|
|
|
-+ <= REG_BR_PROB_BASE / 2);
|
|
|
-+
|
|
|
-+ xoperands[0] = target;
|
|
|
-+ xoperands[1] = cond;
|
|
|
-+ cc_reg = XEXP (cond, 0);
|
|
|
-+
|
|
|
-+ if (GET_MODE (cc_reg) == CCWmode
|
|
|
-+ || GET_MODE (cc_reg) == CCWZmode
|
|
|
-+ || GET_MODE (cc_reg) == CCWZNmode)
|
|
|
-+ {
|
|
|
-+ if (mostly_false_jump)
|
|
|
-+ output_asm_insn ("jmp%b1.w.f\t%0", xoperands);
|
|
|
-+ else
|
|
|
-+ output_asm_insn ("jmp%b1.w.t\t%0", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (GET_MODE (cc_reg) == CCSmode
|
|
|
-+ || GET_MODE (cc_reg) == CCSZmode
|
|
|
-+ || GET_MODE (cc_reg) == CCSZNmode)
|
|
|
-+ {
|
|
|
-+ if (mostly_false_jump)
|
|
|
-+ output_asm_insn ("jmp%b1.s.f\t%0", xoperands);
|
|
|
-+ else
|
|
|
-+ output_asm_insn ("jmp%b1.s.t\t%0", xoperands);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ abort ();
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return non-zero if FUNC is a naked function. */
|
|
|
-+
|
|
|
-+static int
|
|
|
-+ubicom32_naked_function_p (void)
|
|
|
-+{
|
|
|
-+ return lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return an RTX indicating where the return address to the
|
|
|
-+ calling function can be found. */
|
|
|
-+rtx
|
|
|
-+ubicom32_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ if (count != 0)
|
|
|
-+ return NULL_RTX;
|
|
|
-+
|
|
|
-+ return get_hard_reg_initial_val (Pmode, LINK_REGNO);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * ubicom32_readonly_data_section: This routtine handles code
|
|
|
-+ * at the start of readonly data sections
|
|
|
-+ */
|
|
|
-+static void
|
|
|
-+ubicom32_readonly_data_section (const void *data ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ static int num = 0;
|
|
|
-+ if (in_section == readonly_data_section){
|
|
|
-+ fprintf (asm_out_file, "%s", DATA_SECTION_ASM_OP);
|
|
|
-+ if (flag_data_sections){
|
|
|
-+ fprintf (asm_out_file, ".rodata%d", num);
|
|
|
-+ fprintf (asm_out_file, ",\"a\"");
|
|
|
-+ }
|
|
|
-+ fprintf (asm_out_file, "\n");
|
|
|
-+ }
|
|
|
-+ num++;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * ubicom32_text_section: not in readonly section
|
|
|
-+ */
|
|
|
-+static void
|
|
|
-+ubicom32_text_section(const void *data ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * ubicom32_data_section: not in readonly section
|
|
|
-+ */
|
|
|
-+static void
|
|
|
-+ubicom32_data_section(const void *data ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * ubicom32_asm_init_sections: This routine implements special
|
|
|
-+ * section handling
|
|
|
-+ */
|
|
|
-+static void
|
|
|
-+ubicom32_asm_init_sections(void)
|
|
|
-+{
|
|
|
-+ text_section = get_unnamed_section(SECTION_CODE, ubicom32_text_section, NULL);
|
|
|
-+
|
|
|
-+ data_section = get_unnamed_section(SECTION_WRITE, ubicom32_data_section, NULL);
|
|
|
-+
|
|
|
-+ readonly_data_section = get_unnamed_section(0, ubicom32_readonly_data_section, NULL);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * ubicom32_profiler: This routine would call
|
|
|
-+ * mcount to support prof and gprof if mcount
|
|
|
-+ * was supported. Currently, do nothing.
|
|
|
-+ */
|
|
|
-+void
|
|
|
-+ubicom32_profiler(void)
|
|
|
-+{
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Initialise the builtin functions. Start by initialising
|
|
|
-+ descriptions of different types of functions (e.g., void fn(int),
|
|
|
-+ int fn(void)), and then use these to define the builtins. */
|
|
|
-+static void
|
|
|
-+ubicom32_init_builtins (void)
|
|
|
-+{
|
|
|
-+ tree endlink;
|
|
|
-+ tree short_unsigned_endlink;
|
|
|
-+ tree unsigned_endlink;
|
|
|
-+ tree short_unsigned_ftype_short_unsigned;
|
|
|
-+ tree unsigned_ftype_unsigned;
|
|
|
-+
|
|
|
-+ endlink = void_list_node;
|
|
|
-+
|
|
|
-+ short_unsigned_endlink
|
|
|
-+ = tree_cons (NULL_TREE, short_unsigned_type_node, endlink);
|
|
|
-+
|
|
|
-+ unsigned_endlink
|
|
|
-+ = tree_cons (NULL_TREE, unsigned_type_node, endlink);
|
|
|
-+
|
|
|
-+ short_unsigned_ftype_short_unsigned
|
|
|
-+ = build_function_type (short_unsigned_type_node, short_unsigned_endlink);
|
|
|
-+
|
|
|
-+ unsigned_ftype_unsigned
|
|
|
-+ = build_function_type (unsigned_type_node, unsigned_endlink);
|
|
|
-+
|
|
|
-+ /* Initialise the byte swap function. */
|
|
|
-+ add_builtin_function ("__builtin_ubicom32_swapb_2",
|
|
|
-+ short_unsigned_ftype_short_unsigned,
|
|
|
-+ UBICOM32_BUILTIN_UBICOM32_SWAPB_2,
|
|
|
-+ BUILT_IN_MD, NULL,
|
|
|
-+ NULL_TREE);
|
|
|
-+
|
|
|
-+ /* Initialise the byte swap function. */
|
|
|
-+ add_builtin_function ("__builtin_ubicom32_swapb_4",
|
|
|
-+ unsigned_ftype_unsigned,
|
|
|
-+ UBICOM32_BUILTIN_UBICOM32_SWAPB_4,
|
|
|
-+ BUILT_IN_MD, NULL,
|
|
|
-+ NULL_TREE);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Given a builtin function taking 2 operands (i.e., target + source),
|
|
|
-+ emit the RTL for the underlying instruction. */
|
|
|
-+static rtx
|
|
|
-+ubicom32_expand_builtin_2op (enum insn_code icode, tree arglist, rtx target)
|
|
|
-+{
|
|
|
-+ tree arg0;
|
|
|
-+ rtx op0, pat;
|
|
|
-+ enum machine_mode tmode, mode0;
|
|
|
-+
|
|
|
-+ /* Grab the incoming argument and emit its RTL. */
|
|
|
-+ arg0 = TREE_VALUE (arglist);
|
|
|
-+ op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
|
|
|
-+
|
|
|
-+ /* Determine the modes of the instruction operands. */
|
|
|
-+ tmode = insn_data[icode].operand[0].mode;
|
|
|
-+ mode0 = insn_data[icode].operand[1].mode;
|
|
|
-+
|
|
|
-+ /* Ensure that the incoming argument RTL is in a register of the
|
|
|
-+ correct mode. */
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
|
|
|
-+ op0 = copy_to_mode_reg (mode0, op0);
|
|
|
-+
|
|
|
-+ /* If there isn't a suitable target, emit a target register. */
|
|
|
-+ if (target == 0
|
|
|
-+ || GET_MODE (target) != tmode
|
|
|
-+ || !(*insn_data[icode].operand[0].predicate) (target, tmode))
|
|
|
-+ target = gen_reg_rtx (tmode);
|
|
|
-+
|
|
|
-+ /* Emit and return the new instruction. */
|
|
|
-+ pat = GEN_FCN (icode) (target, op0);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Expand a call to a builtin function. */
|
|
|
-+static rtx
|
|
|
-+ubicom32_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
|
|
|
-+ tree arglist = CALL_EXPR_ARGS(exp);
|
|
|
-+ int fcode = DECL_FUNCTION_CODE (fndecl);
|
|
|
-+
|
|
|
-+ switch (fcode)
|
|
|
-+ {
|
|
|
-+ case UBICOM32_BUILTIN_UBICOM32_SWAPB_2:
|
|
|
-+ return ubicom32_expand_builtin_2op (CODE_FOR_bswaphi, arglist, target);
|
|
|
-+
|
|
|
-+ case UBICOM32_BUILTIN_UBICOM32_SWAPB_4:
|
|
|
-+ return ubicom32_expand_builtin_2op (CODE_FOR_bswapsi, arglist, target);
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ gcc_unreachable();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Should really do something sensible here. */
|
|
|
-+ return NULL_RTX;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Fold any constant argument for a swapb.2 instruction. */
|
|
|
-+static tree
|
|
|
-+ubicom32_fold_builtin_ubicom32_swapb_2 (tree fndecl, tree arglist)
|
|
|
-+{
|
|
|
-+ tree arg0;
|
|
|
-+
|
|
|
-+ arg0 = TREE_VALUE (arglist);
|
|
|
-+
|
|
|
-+ /* Optimize constant value. */
|
|
|
-+ if (TREE_CODE (arg0) == INTEGER_CST)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT v;
|
|
|
-+ HOST_WIDE_INT res;
|
|
|
-+
|
|
|
-+ v = TREE_INT_CST_LOW (arg0);
|
|
|
-+ res = ((v >> 8) & 0xff)
|
|
|
-+ | ((v & 0xff) << 8);
|
|
|
-+
|
|
|
-+ return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), res);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_TREE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Fold any constant argument for a swapb.4 instruction. */
|
|
|
-+static tree
|
|
|
-+ubicom32_fold_builtin_ubicom32_swapb_4 (tree fndecl, tree arglist)
|
|
|
-+{
|
|
|
-+ tree arg0;
|
|
|
-+
|
|
|
-+ arg0 = TREE_VALUE (arglist);
|
|
|
-+
|
|
|
-+ /* Optimize constant value. */
|
|
|
-+ if (TREE_CODE (arg0) == INTEGER_CST)
|
|
|
-+ {
|
|
|
-+ unsigned HOST_WIDE_INT v;
|
|
|
-+ unsigned HOST_WIDE_INT res;
|
|
|
-+
|
|
|
-+ v = TREE_INT_CST_LOW (arg0);
|
|
|
-+ res = ((v >> 24) & 0xff)
|
|
|
-+ | (((v >> 16) & 0xff) << 8)
|
|
|
-+ | (((v >> 8) & 0xff) << 16)
|
|
|
-+ | ((v & 0xff) << 24);
|
|
|
-+
|
|
|
-+ return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), res, 0);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_TREE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Fold any constant arguments for builtin functions. */
|
|
|
-+static tree
|
|
|
-+ubicom32_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ switch (DECL_FUNCTION_CODE (fndecl))
|
|
|
-+ {
|
|
|
-+ case UBICOM32_BUILTIN_UBICOM32_SWAPB_2:
|
|
|
-+ return ubicom32_fold_builtin_ubicom32_swapb_2 (fndecl, arglist);
|
|
|
-+
|
|
|
-+ case UBICOM32_BUILTIN_UBICOM32_SWAPB_4:
|
|
|
-+ return ubicom32_fold_builtin_ubicom32_swapb_4 (fndecl, arglist);
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return NULL;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
|
|
|
-+ tell the assembler to generate pointers to function descriptors in
|
|
|
-+ some cases. */
|
|
|
-+static bool
|
|
|
-+ubicom32_assemble_integer (rtx value, unsigned int size, int aligned_p)
|
|
|
-+{
|
|
|
-+ if (TARGET_FDPIC && size == UNITS_PER_WORD)
|
|
|
-+ {
|
|
|
-+ if (GET_CODE (value) == SYMBOL_REF
|
|
|
-+ && SYMBOL_REF_FUNCTION_P (value))
|
|
|
-+ {
|
|
|
-+ fputs ("\t.picptr\t%funcdesc(", asm_out_file);
|
|
|
-+ output_addr_const (asm_out_file, value);
|
|
|
-+ fputs (")\n", asm_out_file);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!aligned_p)
|
|
|
-+ {
|
|
|
-+ /* We've set the unaligned SI op to NULL, so we always have to
|
|
|
-+ handle the unaligned case here. */
|
|
|
-+ assemble_integer_with_op ("\t.4byte\t", value);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return default_assemble_integer (value, size, aligned_p);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* If the constant I can be constructed by shifting a source-1 immediate
|
|
|
-+ by a constant number of bits then return the bit count. If not
|
|
|
-+ return 0. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+ubicom32_shiftable_const_int (int i)
|
|
|
-+{
|
|
|
-+ int shift = 0;
|
|
|
-+
|
|
|
-+ /* Note that any constant that can be represented as an immediate to
|
|
|
-+ a movei instruction is automatically ignored here in the interests
|
|
|
-+ of the clarity of the output asm code. */
|
|
|
-+ if (i >= -32768 && i <= 32767)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* Find the number of trailing zeroes. We could use __builtin_ctz
|
|
|
-+ here but it's not obvious if this is supported on all build
|
|
|
-+ compilers so we err on the side of caution. */
|
|
|
-+ if ((i & 0xffff) == 0)
|
|
|
-+ {
|
|
|
-+ shift += 16;
|
|
|
-+ i >>= 16;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((i & 0xff) == 0)
|
|
|
-+ {
|
|
|
-+ shift += 8;
|
|
|
-+ i >>= 8;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((i & 0xf) == 0)
|
|
|
-+ {
|
|
|
-+ shift += 4;
|
|
|
-+ i >>= 4;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((i & 0x3) == 0)
|
|
|
-+ {
|
|
|
-+ shift += 2;
|
|
|
-+ i >>= 2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ((i & 0x1) == 0)
|
|
|
-+ {
|
|
|
-+ shift += 1;
|
|
|
-+ i >>= 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (i >= -128 && i <= 127)
|
|
|
-+ return shift;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32.h
|
|
|
-@@ -0,0 +1,1564 @@
|
|
|
-+/* Definitions of target machine for Ubicom32
|
|
|
-+
|
|
|
-+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
|
-+ 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GCC.
|
|
|
-+
|
|
|
-+ GCC is free software; you can redistribute it and/or modify it
|
|
|
-+ under the terms of the GNU General Public License as published
|
|
|
-+ by the Free Software Foundation; either version 3, or (at your
|
|
|
-+ option) any later version.
|
|
|
-+
|
|
|
-+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+ License for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License
|
|
|
-+ along with GCC; see the file COPYING3. If not see
|
|
|
-+ <http://www.gnu.org/licenses/>. */
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+#define OBJECT_FORMAT_ELF
|
|
|
-+
|
|
|
-+/* Run-time target specifications. */
|
|
|
-+
|
|
|
-+/* Target CPU builtins. */
|
|
|
-+#define TARGET_CPU_CPP_BUILTINS() \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ builtin_define_std ("__UBICOM32__"); \
|
|
|
-+ builtin_define_std ("__ubicom32__"); \
|
|
|
-+ \
|
|
|
-+ if (TARGET_FDPIC) \
|
|
|
-+ { \
|
|
|
-+ builtin_define ("__UBICOM32_FDPIC__"); \
|
|
|
-+ builtin_define ("__FDPIC__"); \
|
|
|
-+ } \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+
|
|
|
-+#ifndef TARGET_DEFAULT
|
|
|
-+#define TARGET_DEFAULT 0
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+extern int ubicom32_case_values_threshold;
|
|
|
-+
|
|
|
-+/* Nonzero if this chip supports the Ubicom32 v3 ISA. */
|
|
|
-+extern int ubicom32_v3;
|
|
|
-+
|
|
|
-+/* Nonzero if this chip supports the Ubicom32 v4 ISA. */
|
|
|
-+extern int ubicom32_v4;
|
|
|
-+
|
|
|
-+extern int ubicom32_stack_size;
|
|
|
-+
|
|
|
-+/* Flag for whether we can use calli instead of ret in returns. */
|
|
|
-+extern int ubicom32_can_use_calli_to_ret;
|
|
|
-+
|
|
|
-+/* This macro is a C statement to print on `stderr' a string describing the
|
|
|
-+ particular machine description choice. Every machine description should
|
|
|
-+ define `TARGET_VERSION'. */
|
|
|
-+#define TARGET_VERSION fprintf (stderr, " (UBICOM32)");
|
|
|
-+
|
|
|
-+/* We don't need a frame pointer to debug things. Doing this means
|
|
|
-+ that gcc can turn on -fomit-frame-pointer when '-O' is specified. */
|
|
|
-+#define CAN_DEBUG_WITHOUT_FP
|
|
|
-+
|
|
|
-+/* We need to handle processor-specific options. */
|
|
|
-+#define OVERRIDE_OPTIONS ubicom32_override_options ()
|
|
|
-+
|
|
|
-+#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) \
|
|
|
-+ ubicom32_optimization_options (LEVEL, SIZE)
|
|
|
-+
|
|
|
-+/* For Ubicom32 the least significant bit has the lowest bit number
|
|
|
-+ so we define this to be 0. */
|
|
|
-+#define BITS_BIG_ENDIAN 0
|
|
|
-+
|
|
|
-+/* For Ubicom32 the most significant byte in a word has the lowest
|
|
|
-+ number. */
|
|
|
-+#define BYTES_BIG_ENDIAN 1
|
|
|
-+
|
|
|
-+/* For Ubicom32, in a multiword object, the most signifant word has the
|
|
|
-+ lowest number. */
|
|
|
-+#define WORDS_BIG_ENDIAN 1
|
|
|
-+
|
|
|
-+/* Ubicom32 has 8 bits per byte. */
|
|
|
-+#define BITS_PER_UNIT 8
|
|
|
-+
|
|
|
-+/* Ubicom32 has 32 bits per word. */
|
|
|
-+#define BITS_PER_WORD 32
|
|
|
-+
|
|
|
-+/* Width of a word, in units (bytes). */
|
|
|
-+#define UNITS_PER_WORD 4
|
|
|
-+
|
|
|
-+/* Width of a pointer, in bits. */
|
|
|
-+#define POINTER_SIZE 32
|
|
|
-+
|
|
|
-+/* Alias for pointers. Ubicom32 is a 32-bit architecture so we use
|
|
|
-+ SImode. */
|
|
|
-+#define Pmode SImode
|
|
|
-+
|
|
|
-+/* Normal alignment required for function parameters on the stack, in
|
|
|
-+ bits. */
|
|
|
-+#define PARM_BOUNDARY 32
|
|
|
-+
|
|
|
-+/* We need to maintain the stack on a 32-bit boundary. */
|
|
|
-+#define STACK_BOUNDARY 32
|
|
|
-+
|
|
|
-+/* Alignment required for a function entry point, in bits. */
|
|
|
-+#define FUNCTION_BOUNDARY 32
|
|
|
-+
|
|
|
-+/* Alias for the machine mode used for memory references to functions being
|
|
|
-+ called, in `call' RTL expressions. We use byte-oriented addresses
|
|
|
-+ here. */
|
|
|
-+#define FUNCTION_MODE QImode
|
|
|
-+
|
|
|
-+/* Biggest alignment that any data type can require on this machine,
|
|
|
-+ in bits. */
|
|
|
-+#define BIGGEST_ALIGNMENT 32
|
|
|
-+
|
|
|
-+/* this default to BIGGEST_ALIGNMENT unless defined */
|
|
|
-+/* ART: What's the correct value here? Default is (((unsigned int)1<<28)*8)*/
|
|
|
-+#undef MAX_OFILE_ALIGNMENT
|
|
|
-+#define MAX_OFILE_ALIGNMENT (128 * 8)
|
|
|
-+
|
|
|
-+/* Alignment in bits to be given to a structure bit field that follows an empty
|
|
|
-+ field such as `int : 0;'. */
|
|
|
-+#define EMPTY_FIELD_BOUNDARY 32
|
|
|
-+
|
|
|
-+/* All structures must be a multiple of 32 bits in size. */
|
|
|
-+#define STRUCTURE_SIZE_BOUNDARY 32
|
|
|
-+
|
|
|
-+/* A bit-field declared as `int' forces `int' alignment for the struct. */
|
|
|
-+#define PCC_BITFIELD_TYPE_MATTERS 1
|
|
|
-+
|
|
|
-+/* For Ubicom32 we absolutely require that data be aligned with nominal
|
|
|
-+ alignment. */
|
|
|
-+#define STRICT_ALIGNMENT 1
|
|
|
-+
|
|
|
-+/* Make strcpy of constants fast. */
|
|
|
-+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
|
|
|
-+ (TREE_CODE (EXP) == STRING_CST \
|
|
|
-+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
|
|
|
-+
|
|
|
-+/* Define this macro as an expression for the alignment of a structure
|
|
|
-+ (given by STRUCT as a tree node) if the alignment computed in the
|
|
|
-+ usual way is COMPUTED and the alignment explicitly specified was
|
|
|
-+ SPECIFIED. */
|
|
|
-+#define DATA_ALIGNMENT(TYPE, ALIGN) \
|
|
|
-+ ((((ALIGN) < BITS_PER_WORD) \
|
|
|
-+ && (TREE_CODE (TYPE) == ARRAY_TYPE \
|
|
|
-+ || TREE_CODE (TYPE) == UNION_TYPE \
|
|
|
-+ || TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
|
|
|
-+
|
|
|
-+#define LOCAL_ALIGNMENT(TYPE,ALIGN) DATA_ALIGNMENT(TYPE,ALIGN)
|
|
|
-+
|
|
|
-+/* For Ubicom32 we default to unsigned chars. */
|
|
|
-+#define DEFAULT_SIGNED_CHAR 0
|
|
|
-+
|
|
|
-+/* Machine-specific data register numbers. */
|
|
|
-+#define FIRST_DATA_REGNUM 0
|
|
|
-+#define D10_REGNUM 10
|
|
|
-+#define D11_REGNUM 11
|
|
|
-+#define D12_REGNUM 12
|
|
|
-+#define D13_REGNUM 13
|
|
|
-+#define LAST_DATA_REGNUM 15
|
|
|
-+
|
|
|
-+/* Machine-specific address register numbers. */
|
|
|
-+#define FIRST_ADDRESS_REGNUM 16
|
|
|
-+#define LAST_ADDRESS_REGNUM 22
|
|
|
-+
|
|
|
-+/* Register numbers used for passing a function's static chain pointer. If
|
|
|
-+ register windows are used, the register number as seen by the called
|
|
|
-+ function is `STATIC_CHAIN_INCOMING_REGNUM', while the register number as
|
|
|
-+ seen by the calling function is `STATIC_CHAIN_REGNUM'. If these registers
|
|
|
-+ are the same, `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
|
|
|
-+
|
|
|
-+ The static chain register need not be a fixed register.
|
|
|
-+
|
|
|
-+ If the static chain is passed in memory, these macros should not be defined;
|
|
|
-+ instead, the next two macros should be defined. */
|
|
|
-+#define STATIC_CHAIN_REGNUM (FIRST_ADDRESS_REGNUM + 1)
|
|
|
-+
|
|
|
-+/* The register number of the frame pointer register, which is used to access
|
|
|
-+ automatic variables in the stack frame. We generally eliminate this anyway
|
|
|
-+ for Ubicom32 but we make it A6 by default. */
|
|
|
-+#define FRAME_POINTER_REGNUM (LAST_ADDRESS_REGNUM)
|
|
|
-+
|
|
|
-+/* The register number of the stack pointer register, which is also be a
|
|
|
-+ fixed register according to `FIXED_REGISTERS'. For Ubicom32 we don't
|
|
|
-+ have a hardware requirement about which register this is, but by convention
|
|
|
-+ we use A7. */
|
|
|
-+#define STACK_POINTER_REGNUM (LAST_ADDRESS_REGNUM + 1)
|
|
|
-+
|
|
|
-+/* Machine-specific accumulator register numbers. */
|
|
|
-+#define ACC0_HI_REGNUM 24
|
|
|
-+#define ACC0_LO_REGNUM 25
|
|
|
-+#define ACC1_HI_REGNUM 26
|
|
|
-+#define ACC1_LO_REGNUM 27
|
|
|
-+
|
|
|
-+/* source3 register number */
|
|
|
-+#define SOURCE3_REGNUM 28
|
|
|
-+
|
|
|
-+/* The register number of the arg pointer register, which is used to access the
|
|
|
-+ function's argument list. On some machines, this is the same as the frame
|
|
|
-+ pointer register. On some machines, the hardware determines which register
|
|
|
-+ this is. On other machines, you can choose any register you wish for this
|
|
|
-+ purpose. If this is not the same register as the frame pointer register,
|
|
|
-+ then you must mark it as a fixed register according to `FIXED_REGISTERS', or
|
|
|
-+ arrange to be able to eliminate it. */
|
|
|
-+#define ARG_POINTER_REGNUM 29
|
|
|
-+
|
|
|
-+/* Pseudo-reg for condition code. */
|
|
|
-+#define CC_REGNUM 30
|
|
|
-+
|
|
|
-+/* Interrupt set/clear registers. */
|
|
|
-+#define INT_SET0_REGNUM 31
|
|
|
-+#define INT_SET1_REGNUM 32
|
|
|
-+#define INT_CLR0_REGNUM 33
|
|
|
-+#define INT_CLR1_REGNUM 34
|
|
|
-+
|
|
|
-+/* Scratchpad registers. */
|
|
|
-+#define SCRATCHPAD0_REGNUM 35
|
|
|
-+#define SCRATCHPAD1_REGNUM 36
|
|
|
-+#define SCRATCHPAD2_REGNUM 37
|
|
|
-+#define SCRATCHPAD3_REGNUM 38
|
|
|
-+
|
|
|
-+/* FDPIC register. */
|
|
|
-+#define FDPIC_REGNUM 16
|
|
|
-+
|
|
|
-+/* Number of hardware registers known to the compiler. They receive numbers 0
|
|
|
-+ through `FIRST_PSEUDO_REGISTER-1'; thus, the first pseudo register's number
|
|
|
-+ really is assigned the number `FIRST_PSEUDO_REGISTER'. */
|
|
|
-+#define FIRST_PSEUDO_REGISTER 39
|
|
|
-+
|
|
|
-+/* An initializer that says which registers are used for fixed purposes all
|
|
|
-+ throughout the compiled code and are therefore not available for general
|
|
|
-+ allocation. These would include the stack pointer, the frame pointer
|
|
|
-+ (except on machines where that can be used as a general register when no
|
|
|
-+ frame pointer is needed), the program counter on machines where that is
|
|
|
-+ considered one of the addressable registers, and any other numbered register
|
|
|
-+ with a standard use.
|
|
|
-+
|
|
|
-+ This information is expressed as a sequence of numbers, separated by commas
|
|
|
-+ and surrounded by braces. The Nth number is 1 if register N is fixed, 0
|
|
|
-+ otherwise.
|
|
|
-+
|
|
|
-+ The table initialized from this macro, and the table initialized by the
|
|
|
-+ following one, may be overridden at run time either automatically, by the
|
|
|
-+ actions of the macro `CONDITIONAL_REGISTER_USAGE', or by the user with the
|
|
|
-+ command options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. */
|
|
|
-+#define FIXED_REGISTERS \
|
|
|
-+ { \
|
|
|
-+ 0, 0, 0, 0, 0, 0, 0, 0, /* d0 - d7 */ \
|
|
|
-+ 0, 0, 0, 0, 0, 0, 0, 1, /* d8 - d15 */ \
|
|
|
-+ 0, 0, 0, 0, 0, 0, 0, 1, /* a0 - a7 */ \
|
|
|
-+ 0, 0, /* acc0 hi/lo */ \
|
|
|
-+ 0, 0, /* acc1 hi/lo */ \
|
|
|
-+ 0, /* source3 */ \
|
|
|
-+ 1, /* arg */ \
|
|
|
-+ 1, /* cc */ \
|
|
|
-+ 1, 1, /* int_set[01] */ \
|
|
|
-+ 1, 1, /* int_clr[01] */ \
|
|
|
-+ 1, 1, 1, 1 /* scratchpad[0123] */ \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
|
|
|
-+ general) by function calls as well as for fixed registers. This macro
|
|
|
-+ therefore identifies the registers that are not available for general
|
|
|
-+ allocation of values that must live across function calls.
|
|
|
-+
|
|
|
-+ If a register has 0 in `CALL_USED_REGISTERS', the compiler automatically
|
|
|
-+ saves it on function entry and restores it on function exit, if the register
|
|
|
-+ is used within the function. */
|
|
|
-+#define CALL_USED_REGISTERS \
|
|
|
-+ { \
|
|
|
-+ 1, 1, 1, 1, 1, 1, 1, 1, /* d0 - d7 */ \
|
|
|
-+ 1, 1, 0, 0, 0, 0, 1, 1, /* d8 - d15 */ \
|
|
|
-+ 1, 0, 0, 1, 1, 1, 0, 1, /* a0 - a7 */ \
|
|
|
-+ 1, 1, /* acc0 hi/lo */ \
|
|
|
-+ 1, 1, /* acc1 hi/lo */ \
|
|
|
-+ 1, /* source3 */ \
|
|
|
-+ 1, /* arg */ \
|
|
|
-+ 1, /* cc */ \
|
|
|
-+ 1, 1, /* int_set[01] */ \
|
|
|
-+ 1, 1, /* int_clr[01] */ \
|
|
|
-+ 1, 1, 1, 1 /* scratchpad[0123] */ \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+/* How to refer to registers in assembler output.
|
|
|
-+ This sequence is indexed by compiler's hard-register-number (see above). */
|
|
|
-+
|
|
|
-+/* A C initializer containing the assembler's names for the machine registers,
|
|
|
-+ each one as a C string constant. This is what translates register numbers
|
|
|
-+ in the compiler into assembler language. */
|
|
|
-+#define REGISTER_NAMES \
|
|
|
-+ { \
|
|
|
-+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \
|
|
|
-+ "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", \
|
|
|
-+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \
|
|
|
-+ "acc0_hi", "acc0_lo", \
|
|
|
-+ "acc1_hi", "acc1_lo", \
|
|
|
-+ "source3", \
|
|
|
-+ "arg", \
|
|
|
-+ "cc", \
|
|
|
-+ "int_set0", "int_set1", \
|
|
|
-+ "int_clr0", "int_clr1", \
|
|
|
-+ "scratchpad0", "scratchpad1", "scratchpad2", "scratchpad3" \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+#define CONDITIONAL_REGISTER_USAGE \
|
|
|
-+ ubicom32_conditional_register_usage ();
|
|
|
-+
|
|
|
-+/* Order of allocation of registers. */
|
|
|
-+
|
|
|
-+/* If defined, an initializer for a vector of integers, containing the numbers
|
|
|
-+ of hard registers in the order in which GNU CC should prefer to use them
|
|
|
-+ (from most preferred to least).
|
|
|
-+
|
|
|
-+ For Ubicom32 we try using caller-clobbered data registers first, then
|
|
|
-+ callee-saved data registers, then caller-clobbered address registers,
|
|
|
-+ then callee-saved address registers and finally everything else.
|
|
|
-+
|
|
|
-+ The caller-clobbered registers are usually slightly cheaper to use because
|
|
|
-+ there's no need to save/restore. */
|
|
|
-+#define REG_ALLOC_ORDER \
|
|
|
-+ { \
|
|
|
-+ 0, 1, 2, 3, 4, /* d0 - d4 */ \
|
|
|
-+ 5, 6, 7, 8, 9, /* d5 - d9 */ \
|
|
|
-+ 14, /* d14 */ \
|
|
|
-+ 10, 11, 12, 13, /* d10 - d13 */ \
|
|
|
-+ 19, 20, 16, 21, /* a3, a4, a0, a5 */ \
|
|
|
-+ 17, 18, 22, /* a1, a2, a6 */ \
|
|
|
-+ 24, 25, /* acc0 hi/lo */ \
|
|
|
-+ 26, 27, /* acc0 hi/lo */ \
|
|
|
-+ 28 /* source3 */ \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+/* C expression for the number of consecutive hard registers, starting at
|
|
|
-+ register number REGNO, required to hold a value of mode MODE. */
|
|
|
-+#define HARD_REGNO_NREGS(REGNO, MODE) \
|
|
|
-+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
|
|
-+
|
|
|
-+/* Most registers can hold QImode, HImode and SImode values but we have to
|
|
|
-+ be able to indicate any hard registers that cannot hold values with some
|
|
|
-+ modes. */
|
|
|
-+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
|
|
|
-+ ubicom32_hard_regno_mode_ok(REGNO, MODE)
|
|
|
-+
|
|
|
-+/* We can rename most registers aside from the FDPIC register if we're using
|
|
|
-+ FDPIC. */
|
|
|
-+#define HARD_REGNO_RENAME_OK(from, to) (TARGET_FDPIC ? ((to) != FDPIC_REGNUM) : 1)
|
|
|
-+
|
|
|
-+/* A C expression that is nonzero if it is desirable to choose register
|
|
|
-+ allocation so as to avoid move instructions between a value of mode MODE1
|
|
|
-+ and a value of mode MODE2.
|
|
|
-+
|
|
|
-+ If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, MODE2)' are
|
|
|
-+ ever different for any R, then `MODES_TIEABLE_P (MODE1, MODE2)' must be
|
|
|
-+ zero. */
|
|
|
-+#define MODES_TIEABLE_P(MODE1, MODE2) 1
|
|
|
-+
|
|
|
-+/* An enumeral type that must be defined with all the register class names as
|
|
|
-+ enumeral values. `NO_REGS' must be first. `ALL_REGS' must be the last
|
|
|
-+ register class, followed by one more enumeral value, `LIM_REG_CLASSES',
|
|
|
-+ which is not a register class but rather tells how many classes there are.
|
|
|
-+
|
|
|
-+ Each register class has a number, which is the value of casting the class
|
|
|
-+ name to type `int'. The number serves as an index in many of the tables
|
|
|
-+ described below. */
|
|
|
-+
|
|
|
-+enum reg_class
|
|
|
-+{
|
|
|
-+ NO_REGS,
|
|
|
-+ DATA_REGS,
|
|
|
-+ FDPIC_REG,
|
|
|
-+ ADDRESS_REGS,
|
|
|
-+ ALL_ADDRESS_REGS,
|
|
|
-+ ACC_LO_REGS,
|
|
|
-+ ACC_REGS,
|
|
|
-+ CC_REG,
|
|
|
-+ DATA_ACC_REGS,
|
|
|
-+ SOURCE3_REG,
|
|
|
-+ SPECIAL_REGS,
|
|
|
-+ GENERAL_REGS,
|
|
|
-+ ALL_REGS,
|
|
|
-+ LIM_REG_CLASSES
|
|
|
-+};
|
|
|
-+
|
|
|
-+/* The number of distinct register classes. */
|
|
|
-+#define N_REG_CLASSES (int) LIM_REG_CLASSES
|
|
|
-+
|
|
|
-+/* An initializer containing the names of the register classes as C string
|
|
|
-+ constants. These names are used in writing some of the debugging dumps. */
|
|
|
-+
|
|
|
-+#define REG_CLASS_NAMES \
|
|
|
-+{ \
|
|
|
-+ "NO_REGS", \
|
|
|
-+ "DATA_REGS", \
|
|
|
-+ "FDPIC_REG", \
|
|
|
-+ "ADDRESS_REGS", \
|
|
|
-+ "ALL_ADDRESS_REGS", \
|
|
|
-+ "ACC_LO_REGS", \
|
|
|
-+ "ACC_REGS", \
|
|
|
-+ "CC_REG", \
|
|
|
-+ "DATA_ACC_REGS", \
|
|
|
-+ "SOURCE3_REG", \
|
|
|
-+ "SPECIAL_REGS", \
|
|
|
-+ "GENERAL_REGS", \
|
|
|
-+ "ALL_REGS", \
|
|
|
-+ "LIM_REGS" \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* An initializer containing the contents of the register classes, as integers
|
|
|
-+ which are bit masks. The Nth integer specifies the contents of class N.
|
|
|
-+ The way the integer MASK is interpreted is that register R is in the class
|
|
|
-+ if `MASK & (1 << R)' is 1.
|
|
|
-+
|
|
|
-+ When the machine has more than 32 registers, an integer does not suffice.
|
|
|
-+ Then the integers are replaced by sub-initializers, braced groupings
|
|
|
-+ containing several integers. Each sub-initializer must be suitable as an
|
|
|
-+ initializer for the type `HARD_REG_SET' which is defined in
|
|
|
-+ `hard-reg-set.h'. */
|
|
|
-+#define REG_CLASS_CONTENTS \
|
|
|
-+{ \
|
|
|
-+ {0x00000000, 0x00000000}, /* No regs */ \
|
|
|
-+ {0x0000ffff, 0x00000000}, /* DATA_REGS */ \
|
|
|
-+ {0x00010000, 0x00000000}, /* FDPIC_REG */ \
|
|
|
-+ {0x20fe0000, 0x00000000}, /* ADDRESS_REGS */ \
|
|
|
-+ {0x20ff0000, 0x00000000}, /* ALL_ADDRESS_REGS */ \
|
|
|
-+ {0x0a000000, 0x00000000}, /* ACC_LO_REGS */ \
|
|
|
-+ {0x0f000000, 0x00000000}, /* ACC_REGS */ \
|
|
|
-+ {0x40000000, 0x00000000}, /* CC_REG */ \
|
|
|
-+ {0x0f00ffff, 0x00000000}, /* DATA_ACC_REGS */ \
|
|
|
-+ {0x10000000, 0x00000000}, /* SOURGE3_REG */ \
|
|
|
-+ {0x80000000, 0x0000007f}, /* SPECIAL_REGS */ \
|
|
|
-+ {0xbfffffff, 0x0000007f}, /* GENERAL_REGS */ \
|
|
|
-+ {0xbfffffff, 0x0000007f} /* ALL_REGS */ \
|
|
|
-+}
|
|
|
-+
|
|
|
-+extern enum reg_class const ubicom32_regclass_map[FIRST_PSEUDO_REGISTER];
|
|
|
-+
|
|
|
-+/* A C expression whose value is a register class containing hard register
|
|
|
-+ REGNO. In general there is more than one such class; choose a class which
|
|
|
-+ is "minimal", meaning that no smaller class also contains the register. */
|
|
|
-+#define REGNO_REG_CLASS(REGNO) (ubicom32_regclass_map[REGNO])
|
|
|
-+
|
|
|
-+#define IRA_COVER_CLASSES \
|
|
|
-+{ \
|
|
|
-+ GENERAL_REGS, \
|
|
|
-+ LIM_REG_CLASSES \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Ubicom32 base registers must be address registers since addresses can
|
|
|
-+ only be reached via address registers. */
|
|
|
-+#define BASE_REG_CLASS ALL_ADDRESS_REGS
|
|
|
-+
|
|
|
-+/* Ubicom32 index registers must be data registers since we cannot add
|
|
|
-+ two address registers together to form an address. */
|
|
|
-+#define INDEX_REG_CLASS DATA_REGS
|
|
|
-+
|
|
|
-+/* A C expression which is nonzero if register number NUM is suitable for use
|
|
|
-+ as a base register in operand addresses. It may be either a suitable hard
|
|
|
-+ register or a pseudo register that has been allocated such a hard register. */
|
|
|
-+
|
|
|
-+#ifndef REG_OK_STRICT
|
|
|
-+#define REGNO_OK_FOR_BASE_P(regno) \
|
|
|
-+ ubicom32_regno_ok_for_base_p (regno, 0)
|
|
|
-+#else
|
|
|
-+#define REGNO_OK_FOR_BASE_P(regno) \
|
|
|
-+ ubicom32_regno_ok_for_base_p (regno, 1)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* A C expression which is nonzero if register number NUM is suitable for use
|
|
|
-+ as an index register in operand addresses. It may be either a suitable hard
|
|
|
-+ register or a pseudo register that has been allocated such a hard register.
|
|
|
-+
|
|
|
-+ The difference between an index register and a base register is that the
|
|
|
-+ index register may be scaled. If an address involves the sum of two
|
|
|
-+ registers, neither one of them scaled, then either one may be labeled the
|
|
|
-+ "base" and the other the "index"; but whichever labeling is used must fit
|
|
|
-+ the machine's constraints of which registers may serve in each capacity.
|
|
|
-+ The compiler will try both labelings, looking for one that is valid, and
|
|
|
-+ will reload one or both registers only if neither labeling works. */
|
|
|
-+#ifndef REG_OK_STRICT
|
|
|
-+#define REGNO_OK_FOR_INDEX_P(regno) \
|
|
|
-+ ubicom32_regno_ok_for_index_p (regno, 0)
|
|
|
-+#else
|
|
|
-+#define REGNO_OK_FOR_INDEX_P(regno) \
|
|
|
-+ ubicom32_regno_ok_for_index_p (regno, 1)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* Attempt to restrict the register class we need to copy value X intoto the
|
|
|
-+ would-be register class CLASS. Most things are fine for Ubicom32 but we
|
|
|
-+ have to restrict certain types of address loads. */
|
|
|
-+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
|
|
-+ ubicom32_preferred_reload_class (X, CLASS)
|
|
|
-+
|
|
|
-+/* A C expression for the maximum number of consecutive registers of
|
|
|
-+ class CLASS needed to hold a value of mode MODE. For Ubicom32 this
|
|
|
-+ is pretty much identical to HARD_REGNO_NREGS. */
|
|
|
-+#define CLASS_MAX_NREGS(CLASS, MODE) \
|
|
|
-+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
|
|
-+
|
|
|
-+/* For Ubicom32 the stack grows downwards when we push a word onto the stack
|
|
|
-+ - i.e. it moves to a smaller address. */
|
|
|
-+#define STACK_GROWS_DOWNWARD 1
|
|
|
-+
|
|
|
-+/* Offset from the frame pointer to the first local variable slot to
|
|
|
-+ be allocated. */
|
|
|
-+#define STARTING_FRAME_OFFSET 0
|
|
|
-+
|
|
|
-+/* Offset from the argument pointer register to the first argument's
|
|
|
-+ address. */
|
|
|
-+#define FIRST_PARM_OFFSET(FNDECL) 0
|
|
|
-+
|
|
|
-+/* A C expression whose value is RTL representing the value of the return
|
|
|
-+ address for the frame COUNT steps up from the current frame, after the
|
|
|
-+ prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
|
|
|
-+ pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
|
|
|
-+ defined.
|
|
|
-+
|
|
|
-+ The value of the expression must always be the correct address when COUNT is
|
|
|
-+ zero, but may be `NULL_RTX' if there is not way to determine the return
|
|
|
-+ address of other frames. */
|
|
|
-+#define RETURN_ADDR_RTX(COUNT, FRAME) \
|
|
|
-+ ubicom32_return_addr_rtx (COUNT, FRAME)
|
|
|
-+
|
|
|
-+/* Register That Address the Stack Frame. */
|
|
|
-+
|
|
|
-+/* We don't actually require a frame pointer in most functions with the
|
|
|
-+ Ubicom32 architecture so we allow it to be eliminated. */
|
|
|
-+#define FRAME_POINTER_REQUIRED 0
|
|
|
-+
|
|
|
-+/* Macro that defines a table of register pairs used to eliminate unecessary
|
|
|
-+ registers that point into the stack frame.
|
|
|
-+
|
|
|
-+ For Ubicom32 we don't generally need an arg pointer of a frame pointer
|
|
|
-+ so we allow the arg pointer to be replaced by either the frame pointer or
|
|
|
-+ the stack pointer. We also allow the frame pointer to be replaced by
|
|
|
-+ the stack pointer. */
|
|
|
-+#define ELIMINABLE_REGS \
|
|
|
-+{ \
|
|
|
-+ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
|
|
-+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
|
|
|
-+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Let the compiler know that we want to use the ELIMINABLE_REGS macro
|
|
|
-+ above. */
|
|
|
-+#define CAN_ELIMINATE(FROM, TO) 1
|
|
|
-+
|
|
|
-+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It specifies the
|
|
|
-+ initial difference between the specified pair of registers. This macro must
|
|
|
-+ be defined if `ELIMINABLE_REGS' is defined. */
|
|
|
-+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
|
|
|
-+ (OFFSET) = ubicom32_initial_elimination_offset (FROM, TO)
|
|
|
-+
|
|
|
-+/* If defined, the maximum amount of space required for outgoing arguments will
|
|
|
-+ be computed and placed into the variable
|
|
|
-+ `current_function_outgoing_args_size'. No space will be pushed onto the
|
|
|
-+ stack for each call; instead, the function prologue should increase the
|
|
|
-+ stack frame size by this amount.
|
|
|
-+
|
|
|
-+ Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is not
|
|
|
-+ proper. */
|
|
|
-+#define ACCUMULATE_OUTGOING_ARGS 1
|
|
|
-+
|
|
|
-+/* Define this macro if functions should assume that stack space has been
|
|
|
-+ allocated for arguments even when their values are passed in registers.
|
|
|
-+
|
|
|
-+ The value of this macro is the size, in bytes, of the area reserved for
|
|
|
-+ arguments passed in registers for the function represented by FNDECL.
|
|
|
-+
|
|
|
-+ This space can be allocated by the caller, or be a part of the
|
|
|
-+ machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says
|
|
|
-+ which. */
|
|
|
-+#define REG_PARM_STACK_SPACE(FNDECL) ubicom32_reg_parm_stack_space(FNDECL)
|
|
|
-+
|
|
|
-+/* A C expression that should indicate the number of bytes of its own arguments
|
|
|
-+ that a function pops on returning, or 0 if the function pops no arguments
|
|
|
-+ and the caller must therefore pop them all after the function returns.
|
|
|
-+
|
|
|
-+ FUNDECL is a C variable whose value is a tree node that describes the
|
|
|
-+ function in question. Normally it is a node of type `FUNCTION_DECL' that
|
|
|
-+ describes the declaration of the function. From this it is possible to
|
|
|
-+ obtain the DECL_MACHINE_ATTRIBUTES of the function.
|
|
|
-+
|
|
|
-+ FUNTYPE is a C variable whose value is a tree node that describes the
|
|
|
-+ function in question. Normally it is a node of type `FUNCTION_TYPE' that
|
|
|
-+ describes the data type of the function. From this it is possible to obtain
|
|
|
-+ the data types of the value and arguments (if known).
|
|
|
-+
|
|
|
-+ When a call to a library function is being considered, FUNTYPE will contain
|
|
|
-+ an identifier node for the library function. Thus, if you need to
|
|
|
-+ distinguish among various library functions, you can do so by their names.
|
|
|
-+ Note that "library function" in this context means a function used to
|
|
|
-+ perform arithmetic, whose name is known specially in the compiler and was
|
|
|
-+ not mentioned in the C code being compiled.
|
|
|
-+
|
|
|
-+ STACK-SIZE is the number of bytes of arguments passed on the stack. If a
|
|
|
-+ variable number of bytes is passed, it is zero, and argument popping will
|
|
|
-+ always be the responsibility of the calling function.
|
|
|
-+
|
|
|
-+ On the Vax, all functions always pop their arguments, so the definition of
|
|
|
-+ this macro is STACK-SIZE. On the 68000, using the standard calling
|
|
|
-+ convention, no functions pop their arguments, so the value of the macro is
|
|
|
-+ always 0 in this case. But an alternative calling convention is available
|
|
|
-+ in which functions that take a fixed number of arguments pop them but other
|
|
|
-+ functions (such as `printf') pop nothing (the caller pops all). When this
|
|
|
-+ convention is in use, FUNTYPE is examined to determine whether a function
|
|
|
-+ takes a fixed number of arguments. */
|
|
|
-+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
|
|
|
-+
|
|
|
-+/* A C expression that controls whether a function argument is passed in a
|
|
|
-+ register, and which register.
|
|
|
-+
|
|
|
-+ The arguments are CUM, of type CUMULATIVE_ARGS, which summarizes (in a way
|
|
|
-+ defined by INIT_CUMULATIVE_ARGS and FUNCTION_ARG_ADVANCE) all of the previous
|
|
|
-+ arguments so far passed in registers; MODE, the machine mode of the argument;
|
|
|
-+ TYPE, the data type of the argument as a tree node or 0 if that is not known
|
|
|
-+ (which happens for C support library functions); and NAMED, which is 1 for an
|
|
|
-+ ordinary argument and 0 for nameless arguments that correspond to `...' in the
|
|
|
-+ called function's prototype.
|
|
|
-+
|
|
|
-+ The value of the expression should either be a `reg' RTX for the hard
|
|
|
-+ register in which to pass the argument, or zero to pass the argument on the
|
|
|
-+ stack.
|
|
|
-+
|
|
|
-+ For machines like the Vax and 68000, where normally all arguments are
|
|
|
-+ pushed, zero suffices as a definition.
|
|
|
-+
|
|
|
-+ The usual way to make the ANSI library `stdarg.h' work on a machine where
|
|
|
-+ some arguments are usually passed in registers, is to cause nameless
|
|
|
-+ arguments to be passed on the stack instead. This is done by making
|
|
|
-+ `FUNCTION_ARG' return 0 whenever NAMED is 0.
|
|
|
-+
|
|
|
-+ You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the definition of
|
|
|
-+ this macro to determine if this argument is of a type that must be passed in
|
|
|
-+ the stack. If `REG_PARM_STACK_SPACE' is not defined and `FUNCTION_ARG'
|
|
|
-+ returns non-zero for such an argument, the compiler will abort. If
|
|
|
-+ `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the
|
|
|
-+ stack and then loaded into a register. */
|
|
|
-+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ function_arg (&CUM, MODE, TYPE, NAMED)
|
|
|
-+
|
|
|
-+#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ function_incoming_arg (&CUM, MODE, TYPE, NAMED)
|
|
|
-+
|
|
|
-+/* A C expression for the number of words, at the beginning of an argument,
|
|
|
-+ must be put in registers. The value must be zero for arguments that are
|
|
|
-+ passed entirely in registers or that are entirely pushed on the stack.
|
|
|
-+
|
|
|
-+ On some machines, certain arguments must be passed partially in registers
|
|
|
-+ and partially in memory. On these machines, typically the first N words of
|
|
|
-+ arguments are passed in registers, and the rest on the stack. If a
|
|
|
-+ multi-word argument (a `double' or a structure) crosses that boundary, its
|
|
|
-+ first few words must be passed in registers and the rest must be pushed.
|
|
|
-+ This macro tells the compiler when this occurs, and how many of the words
|
|
|
-+ should go in registers.
|
|
|
-+
|
|
|
-+ `FUNCTION_ARG' for these arguments should return the first register to be
|
|
|
-+ used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
|
|
|
-+ the called function. */
|
|
|
-+
|
|
|
-+/* A C expression that indicates when an argument must be passed by reference.
|
|
|
-+ If nonzero for an argument, a copy of that argument is made in memory and a
|
|
|
-+ pointer to the argument is passed instead of the argument itself. The
|
|
|
-+ pointer is passed in whatever way is appropriate for passing a pointer to
|
|
|
-+ that type.
|
|
|
-+
|
|
|
-+ On machines where `REG_PARM_STACK_SPACE' is not defined, a suitable
|
|
|
-+ definition of this macro might be
|
|
|
-+ #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ MUST_PASS_IN_STACK (MODE, TYPE) */
|
|
|
-+
|
|
|
-+/* If defined, a C expression that indicates when it is the called function's
|
|
|
-+ responsibility to make a copy of arguments passed by invisible reference.
|
|
|
-+ Normally, the caller makes a copy and passes the address of the copy to the
|
|
|
-+ routine being called. When FUNCTION_ARG_CALLEE_COPIES is defined and is
|
|
|
-+ nonzero, the caller does not make a copy. Instead, it passes a pointer to
|
|
|
-+ the "live" value. The called function must not modify this value. If it
|
|
|
-+ can be determined that the value won't be modified, it need not make a copy;
|
|
|
-+ otherwise a copy must be made. */
|
|
|
-+
|
|
|
-+/* A C type for declaring a variable that is used as the first argument of
|
|
|
-+ `FUNCTION_ARG' and other related values. For some target machines, the type
|
|
|
-+ `int' suffices and can hold the number of bytes of argument so far.
|
|
|
-+
|
|
|
-+ There is no need to record in `CUMULATIVE_ARGS' anything about the arguments
|
|
|
-+ that have been passed on the stack. The compiler has other variables to
|
|
|
-+ keep track of that. For target machines on which all arguments are passed
|
|
|
-+ on the stack, there is no need to store anything in `CUMULATIVE_ARGS';
|
|
|
-+ however, the data structure must exist and should not be empty, so use
|
|
|
-+ `int'. */
|
|
|
-+struct cum_arg
|
|
|
-+{
|
|
|
-+ int nbytes;
|
|
|
-+ int reg;
|
|
|
-+ int stdarg;
|
|
|
-+};
|
|
|
-+#define CUMULATIVE_ARGS struct cum_arg
|
|
|
-+
|
|
|
-+/* A C statement (sans semicolon) for initializing the variable CUM for the
|
|
|
-+ state at the beginning of the argument list. The variable has type
|
|
|
-+ `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node for the data type
|
|
|
-+ of the function which will receive the args, or 0 if the args are to a
|
|
|
-+ compiler support library function. The value of INDIRECT is nonzero when
|
|
|
-+ processing an indirect call, for example a call through a function pointer.
|
|
|
-+ The value of INDIRECT is zero for a call to an explicitly named function, a
|
|
|
-+ library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
|
|
|
-+ arguments for the function being compiled.
|
|
|
-+
|
|
|
-+ When processing a call to a compiler support library function, LIBNAME
|
|
|
-+ identifies which one. It is a `symbol_ref' rtx which contains the name of
|
|
|
-+ the function, as a string. LIBNAME is 0 when an ordinary C function call is
|
|
|
-+ being processed. Thus, each time this macro is called, either LIBNAME or
|
|
|
-+ FNTYPE is nonzero, but never both of them at once. */
|
|
|
-+
|
|
|
-+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT, NAMED_ARGS) \
|
|
|
-+ init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT);
|
|
|
-+
|
|
|
-+/* A C statement (sans semicolon) to update the summarizer variable CUM to
|
|
|
-+ advance past an argument in the argument list. The values MODE, TYPE and
|
|
|
-+ NAMED describe that argument. Once this is done, the variable CUM is
|
|
|
-+ suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
|
|
|
-+
|
|
|
-+ This macro need not do anything if the argument in question was passed on
|
|
|
-+ the stack. The compiler knows how to track the amount of stack space used
|
|
|
-+ for arguments without any special help. */
|
|
|
-+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ ((CUM).nbytes += ((MODE) != BLKmode \
|
|
|
-+ ? (GET_MODE_SIZE (MODE) + 3) & ~3 \
|
|
|
-+ : (int_size_in_bytes (TYPE) + 3) & ~3))
|
|
|
-+
|
|
|
-+/* For the Ubicom32 we define the upper function argument register here. */
|
|
|
-+#define UBICOM32_FUNCTION_ARG_REGS 10
|
|
|
-+
|
|
|
-+/* A C expression that is nonzero if REGNO is the number of a hard register in
|
|
|
-+ which function arguments are sometimes passed. This does *not* include
|
|
|
-+ implicit arguments such as the static chain and the structure-value address.
|
|
|
-+ On many machines, no registers can be used for this purpose since all
|
|
|
-+ function arguments are pushed on the stack. */
|
|
|
-+#define FUNCTION_ARG_REGNO_P(N) ((N) < UBICOM32_FUNCTION_ARG_REGS)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* How Scalar Function Values are Returned. */
|
|
|
-+
|
|
|
-+/* The number of the hard register that is used to return a scalar value from a
|
|
|
-+ function call. */
|
|
|
-+#define RETURN_VALUE_REGNUM 0
|
|
|
-+
|
|
|
-+/* A C expression to create an RTX representing the place where a function
|
|
|
-+ returns a value of data type VALTYPE. VALTYPE is a tree node representing a
|
|
|
-+ data type. Write `TYPE_MODE (VALTYPE)' to get the machine mode used to
|
|
|
-+ represent that type. On many machines, only the mode is relevant.
|
|
|
-+ (Actually, on most machines, scalar values are returned in the same place
|
|
|
-+ regardless of mode).
|
|
|
-+
|
|
|
-+ If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same promotion
|
|
|
-+ rules specified in `PROMOTE_MODE' if VALTYPE is a scalar type.
|
|
|
-+
|
|
|
-+ If the precise function being called is known, FUNC is a tree node
|
|
|
-+ (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This makes it
|
|
|
-+ possible to use a different value-returning convention for specific
|
|
|
-+ functions when all their calls are known.
|
|
|
-+
|
|
|
-+ `FUNCTION_VALUE' is not used for return vales with aggregate data types,
|
|
|
-+ because these are returned in another way. See `STRUCT_VALUE_REGNUM' and
|
|
|
-+ related macros, below. */
|
|
|
-+#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
|
|
-+ gen_rtx_REG (TYPE_MODE (VALTYPE), FIRST_DATA_REGNUM)
|
|
|
-+
|
|
|
-+/* A C expression to create an RTX representing the place where a library
|
|
|
-+ function returns a value of mode MODE.
|
|
|
-+
|
|
|
-+ Note that "library function" in this context means a compiler support
|
|
|
-+ routine, used to perform arithmetic, whose name is known specially by the
|
|
|
-+ compiler and was not mentioned in the C code being compiled.
|
|
|
-+
|
|
|
-+ The definition of `LIBRARY_VALUE' need not be concerned aggregate data
|
|
|
-+ types, because none of the library functions returns such types. */
|
|
|
-+#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, FIRST_DATA_REGNUM)
|
|
|
-+
|
|
|
-+/* A C expression that is nonzero if REGNO is the number of a hard register in
|
|
|
-+ which the values of called function may come back.
|
|
|
-+
|
|
|
-+ A register whose use for returning values is limited to serving as the
|
|
|
-+ second of a pair (for a value of type `double', say) need not be recognized
|
|
|
-+ by this macro. So for most machines, this definition suffices:
|
|
|
-+
|
|
|
-+ #define FUNCTION_VALUE_REGNO_P(N) ((N) == RETURN)
|
|
|
-+
|
|
|
-+ If the machine has register windows, so that the caller and the called
|
|
|
-+ function use different registers for the return value, this macro should
|
|
|
-+ recognize only the caller's register numbers. */
|
|
|
-+#define FUNCTION_VALUE_REGNO_P(N) ((N) == FIRST_DATA_REGNUM)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* How Large Values are Returned. */
|
|
|
-+
|
|
|
-+/* A C expression which can inhibit the returning of certain function values in
|
|
|
-+ registers, based on the type of value. A nonzero value says to return the
|
|
|
-+ function value in memory, just as large structures are always returned.
|
|
|
-+ Here TYPE will be a C expression of type `tree', representing the data type
|
|
|
-+ of the value.
|
|
|
-+
|
|
|
-+ Note that values of mode `BLKmode' must be explicitly handled by this macro.
|
|
|
-+ Also, the option `-fpcc-struct-return' takes effect regardless of this
|
|
|
-+ macro. On most systems, it is possible to leave the macro undefined; this
|
|
|
-+ causes a default definition to be used, whose value is the constant 1 for
|
|
|
-+ `BLKmode' values, and 0 otherwise.
|
|
|
-+
|
|
|
-+ Do not use this macro to indicate that structures and unions should always
|
|
|
-+ be returned in memory. You should instead use `DEFAULT_PCC_STRUCT_RETURN'
|
|
|
-+ to indicate this. */
|
|
|
-+#define RETURN_IN_MEMORY(TYPE) \
|
|
|
-+ (int_size_in_bytes (TYPE) > 8 || TYPE_MODE (TYPE) == BLKmode)
|
|
|
-+
|
|
|
-+/* Define this macro to be 1 if all structure and union return values must be
|
|
|
-+ in memory. Since this results in slower code, this should be defined only
|
|
|
-+ if needed for compatibility with other compilers or with an ABI. If you
|
|
|
-+ define this macro to be 0, then the conventions used for structure and union
|
|
|
-+ return values are decided by the `RETURN_IN_MEMORY' macro.
|
|
|
-+
|
|
|
-+ If not defined, this defaults to the value 1. */
|
|
|
-+#define DEFAULT_PCC_STRUCT_RETURN 0
|
|
|
-+
|
|
|
-+/* If the structure value address is not passed in a register, define
|
|
|
-+ `STRUCT_VALUE' as an expression returning an RTX for the place
|
|
|
-+ where the address is passed. If it returns 0, the address is
|
|
|
-+ passed as an "invisible" first argument. */
|
|
|
-+#define STRUCT_VALUE 0
|
|
|
-+
|
|
|
-+/* Define this macro as a C expression that is nonzero if the return
|
|
|
-+ instruction or the function epilogue ignores the value of the stack pointer;
|
|
|
-+ in other words, if it is safe to delete an instruction to adjust the stack
|
|
|
-+ pointer before a return from the function.
|
|
|
-+
|
|
|
-+ Note that this macro's value is relevant only for functions for which frame
|
|
|
-+ pointers are maintained. It is never safe to delete a final stack
|
|
|
-+ adjustment in a function that has no frame pointer, and the compiler knows
|
|
|
-+ this regardless of `EXIT_IGNORE_STACK'. */
|
|
|
-+#define EXIT_IGNORE_STACK 1
|
|
|
-+
|
|
|
-+/* A C statement or compound statement to output to FILE some assembler code to
|
|
|
-+ call the profiling subroutine `mcount'. Before calling, the assembler code
|
|
|
-+ must load the address of a counter variable into a register where `mcount'
|
|
|
-+ expects to find the address. The name of this variable is `LP' followed by
|
|
|
-+ the number LABELNO, so you would generate the name using `LP%d' in a
|
|
|
-+ `fprintf'.
|
|
|
-+
|
|
|
-+ The details of how the address should be passed to `mcount' are determined
|
|
|
-+ by your operating system environment, not by GNU CC. To figure them out,
|
|
|
-+ compile a small program for profiling using the system's installed C
|
|
|
-+ compiler and look at the assembler code that results.
|
|
|
-+
|
|
|
-+ This declaration must be present, but it can be an abort if profiling is
|
|
|
-+ not implemented. */
|
|
|
-+
|
|
|
-+#define FUNCTION_PROFILER(file, labelno) ubicom32_profiler(file, labelno)
|
|
|
-+
|
|
|
-+/* A C statement to output, on the stream FILE, assembler code for a block of
|
|
|
-+ data that contains the constant parts of a trampoline. This code should not
|
|
|
-+ include a label--the label is taken care of automatically. */
|
|
|
-+#if 0
|
|
|
-+#define TRAMPOLINE_TEMPLATE(FILE) \
|
|
|
-+ do { \
|
|
|
-+ fprintf (FILE, "\tadd -4,sp\n"); \
|
|
|
-+ fprintf (FILE, "\t.long 0x0004fffa\n"); \
|
|
|
-+ fprintf (FILE, "\tmov (0,sp),a0\n"); \
|
|
|
-+ fprintf (FILE, "\tadd 4,sp\n"); \
|
|
|
-+ fprintf (FILE, "\tmov (13,a0),a1\n"); \
|
|
|
-+ fprintf (FILE, "\tmov (17,a0),a0\n"); \
|
|
|
-+ fprintf (FILE, "\tjmp (a0)\n"); \
|
|
|
-+ fprintf (FILE, "\t.long 0\n"); \
|
|
|
-+ fprintf (FILE, "\t.long 0\n"); \
|
|
|
-+ } while (0)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* A C expression for the size in bytes of the trampoline, as an integer. */
|
|
|
-+#define TRAMPOLINE_SIZE 0x1b
|
|
|
-+
|
|
|
-+/* Alignment required for trampolines, in bits.
|
|
|
-+
|
|
|
-+ If you don't define this macro, the value of `BIGGEST_ALIGNMENT' is used for
|
|
|
-+ aligning trampolines. */
|
|
|
-+#define TRAMPOLINE_ALIGNMENT 32
|
|
|
-+
|
|
|
-+/* A C statement to initialize the variable parts of a trampoline. ADDR is an
|
|
|
-+ RTX for the address of the trampoline; FNADDR is an RTX for the address of
|
|
|
-+ the nested function; STATIC_CHAIN is an RTX for the static chain value that
|
|
|
-+ should be passed to the function when it is called. */
|
|
|
-+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
|
|
-+{ \
|
|
|
-+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 0x14)), \
|
|
|
-+ (CXT)); \
|
|
|
-+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant ((TRAMP), 0x18)), \
|
|
|
-+ (FNADDR)); \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Ubicom32 supports pre and post increment/decrement addressing. */
|
|
|
-+#define HAVE_POST_INCREMENT 1
|
|
|
-+#define HAVE_PRE_INCREMENT 1
|
|
|
-+#define HAVE_POST_DECREMENT 1
|
|
|
-+#define HAVE_PRE_DECREMENT 1
|
|
|
-+
|
|
|
-+/* Ubicom32 supports pre and post address side-effects with constants
|
|
|
-+ other than the size of the memory operand. */
|
|
|
-+#define HAVE_PRE_MODIFY_DISP 1
|
|
|
-+#define HAVE_POST_MODIFY_DISP 1
|
|
|
-+
|
|
|
-+/* A C expression that is 1 if the RTX X is a constant which is a valid
|
|
|
-+ address. On most machines, this can be defined as `CONSTANT_P (X)',
|
|
|
-+ but a few machines are more restrictive in which constant addresses
|
|
|
-+ are supported.
|
|
|
-+
|
|
|
-+ `CONSTANT_P' accepts integer-values expressions whose values are not
|
|
|
-+ explicitly known, such as `symbol_ref', `label_ref', and `high'
|
|
|
-+ expressions and `const' arithmetic expressions, in addition to
|
|
|
-+ `const_int' and `const_double' expressions. */
|
|
|
-+#define CONSTANT_ADDRESS_P(X) \
|
|
|
-+ (GET_CODE (X) == LABEL_REF \
|
|
|
-+ || (GET_CODE (X) == CONST \
|
|
|
-+ && GET_CODE (XEXP (X, 0)) == PLUS \
|
|
|
-+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF))
|
|
|
-+
|
|
|
-+/* Ubicom32 supports a maximum of 2 registers in a valid memory address.
|
|
|
-+ One is always an address register while a second, optional, one may be a
|
|
|
-+ data register. */
|
|
|
-+#define MAX_REGS_PER_ADDRESS 2
|
|
|
-+
|
|
|
-+/* A C compound statement with a conditional `goto LABEL;' executed if X (an
|
|
|
-+ RTX) is a legitimate memory address on the target machine for a memory
|
|
|
-+ operand of mode MODE.
|
|
|
-+
|
|
|
-+ It usually pays to define several simpler macros to serve as subroutines for
|
|
|
-+ this one. Otherwise it may be too complicated to understand.
|
|
|
-+
|
|
|
-+ This macro must exist in two variants: a strict variant and a non-strict
|
|
|
-+ one. The strict variant is used in the reload pass. It must be defined so
|
|
|
-+ that any pseudo-register that has not been allocated a hard register is
|
|
|
-+ considered a memory reference. In contexts where some kind of register is
|
|
|
-+ required, a pseudo-register with no hard register must be rejected.
|
|
|
-+
|
|
|
-+ The non-strict variant is used in other passes. It must be defined to
|
|
|
-+ accept all pseudo-registers in every context where some kind of register is
|
|
|
-+ required.
|
|
|
-+
|
|
|
-+ Compiler source files that want to use the strict variant of this macro
|
|
|
-+ define the macro `REG_OK_STRICT'. You should use an `#ifdef REG_OK_STRICT'
|
|
|
-+ conditional to define the strict variant in that case and the non-strict
|
|
|
-+ variant otherwise.
|
|
|
-+
|
|
|
-+ Subroutines to check for acceptable registers for various purposes (one for
|
|
|
-+ base registers, one for index registers, and so on) are typically among the
|
|
|
-+ subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'. Then only these
|
|
|
-+ subroutine macros need have two variants; the higher levels of macros may be
|
|
|
-+ the same whether strict or not.
|
|
|
-+
|
|
|
-+ Normally, constant addresses which are the sum of a `symbol_ref' and an
|
|
|
-+ integer are stored inside a `const' RTX to mark them as constant.
|
|
|
-+ Therefore, there is no need to recognize such sums specifically as
|
|
|
-+ legitimate addresses. Normally you would simply recognize any `const' as
|
|
|
-+ legitimate.
|
|
|
-+
|
|
|
-+ Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant sums that
|
|
|
-+ are not marked with `const'. It assumes that a naked `plus' indicates
|
|
|
-+ indexing. If so, then you *must* reject such naked constant sums as
|
|
|
-+ illegitimate addresses, so that none of them will be given to
|
|
|
-+ `PRINT_OPERAND_ADDRESS'.
|
|
|
-+
|
|
|
-+ On some machines, whether a symbolic address is legitimate depends on the
|
|
|
-+ section that the address refers to. On these machines, define the macro
|
|
|
-+ `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
|
|
|
-+ then check for it here. When you see a `const', you will have to look
|
|
|
-+ inside it to find the `symbol_ref' in order to determine the section.
|
|
|
-+
|
|
|
-+ The best way to modify the name string is by adding text to the beginning,
|
|
|
-+ with suitable punctuation to prevent any ambiguity. Allocate the new name
|
|
|
-+ in `saveable_obstack'. You will have to modify `ASM_OUTPUT_LABELREF' to
|
|
|
-+ remove and decode the added text and output the name accordingly, and define
|
|
|
-+ `STRIP_NAME_ENCODING' to access the original name string.
|
|
|
-+
|
|
|
-+ You can check the information stored here into the `symbol_ref' in the
|
|
|
-+ definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
|
|
|
-+ `PRINT_OPERAND_ADDRESS'. */
|
|
|
-+/* On the ubicom32, the value in the address register must be
|
|
|
-+ in the same memory space/segment as the effective address.
|
|
|
-+
|
|
|
-+ This is problematical for reload since it does not understand
|
|
|
-+ that base+index != index+base in a memory reference. */
|
|
|
-+
|
|
|
-+#ifdef REG_OK_STRICT
|
|
|
-+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
|
|
-+ if (ubicom32_legitimate_address_p (MODE, X, 1)) goto ADDR;
|
|
|
-+#else
|
|
|
-+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
|
|
-+ if (ubicom32_legitimate_address_p (MODE, X, 0)) goto ADDR;
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* Try machine-dependent ways of modifying an illegitimate address
|
|
|
-+ to be legitimate. If we find one, return the new, valid address.
|
|
|
-+ This macro is used in only one place: `memory_address' in explow.c.
|
|
|
-+
|
|
|
-+ OLDX is the address as it was before break_out_memory_refs was called.
|
|
|
-+ In some cases it is useful to look at this to decide what needs to be done.
|
|
|
-+
|
|
|
-+ MODE and WIN are passed so that this macro can use
|
|
|
-+ GO_IF_LEGITIMATE_ADDRESS.
|
|
|
-+
|
|
|
-+ It is always safe for this macro to do nothing. It exists to recognize
|
|
|
-+ opportunities to optimize the output.
|
|
|
-+
|
|
|
-+ On RS/6000, first check for the sum of a register with a constant
|
|
|
-+ integer that is out of range. If so, generate code to add the
|
|
|
-+ constant with the low-order 16 bits masked to the register and force
|
|
|
-+ this result into another register (this can be done with `cau').
|
|
|
-+ Then generate an address of REG+(CONST&0xffff), allowing for the
|
|
|
-+ possibility of bit 16 being a one.
|
|
|
-+
|
|
|
-+ Then check for the sum of a register and something not constant, try to
|
|
|
-+ load the other things into a register and return the sum. */
|
|
|
-+
|
|
|
-+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
|
|
|
-+{ \
|
|
|
-+ rtx result = ubicom32_legitimize_address ((X), (OLDX), (MODE)); \
|
|
|
-+ if (result != NULL_RTX) \
|
|
|
-+ { \
|
|
|
-+ (X) = result; \
|
|
|
-+ goto WIN; \
|
|
|
-+ } \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Try a machine-dependent way of reloading an illegitimate address
|
|
|
-+ operand. If we find one, push the reload and jump to WIN. This
|
|
|
-+ macro is used in only one place: `find_reloads_address' in reload.c. */
|
|
|
-+#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \
|
|
|
-+{ \
|
|
|
-+ rtx new_rtx = ubicom32_legitimize_reload_address ((AD), (MODE), (OPNUM), (int)(TYPE)); \
|
|
|
-+ if (new_rtx) \
|
|
|
-+ { \
|
|
|
-+ (AD) = new_rtx; \
|
|
|
-+ goto WIN; \
|
|
|
-+ } \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* A C statement or compound statement with a conditional `goto LABEL;'
|
|
|
-+ executed if memory address X (an RTX) can have different meanings depending
|
|
|
-+ on the machine mode of the memory reference it is used for or if the address
|
|
|
-+ is valid for some modes but not others.
|
|
|
-+
|
|
|
-+ Autoincrement and autodecrement addresses typically have mode-dependent
|
|
|
-+ effects because the amount of the increment or decrement is the size of the
|
|
|
-+ operand being addressed. Some machines have other mode-dependent addresses.
|
|
|
-+ Many RISC machines have no mode-dependent addresses.
|
|
|
-+
|
|
|
-+ You may assume that ADDR is a valid address for the machine. */
|
|
|
-+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
|
|
|
-+ if (ubicom32_mode_dependent_address_p (ADDR)) \
|
|
|
-+ goto LABEL;
|
|
|
-+
|
|
|
-+/* A C expression that is nonzero if X is a legitimate constant for an
|
|
|
-+ immediate operand on the target machine. You can assume that X
|
|
|
-+ satisfies `CONSTANT_P', so you need not check this. In fact, `1' is
|
|
|
-+ a suitable definition for this macro on machines where anything
|
|
|
-+ `CONSTANT_P' is valid. */
|
|
|
-+#define LEGITIMATE_CONSTANT_P(X) \
|
|
|
-+ ubicom32_legitimate_constant_p ((X))
|
|
|
-+
|
|
|
-+/* Moves between registers are pretty-much single instructions for
|
|
|
-+ Ubicom32. We make this the default "2" that gcc likes. */
|
|
|
-+#define REGISTER_MOVE_COST(MODE, FROM, TO) 2
|
|
|
-+
|
|
|
-+/* This is a little bit of magic from the S390 port that wins 2% on code
|
|
|
-+ size when building the Linux kernel! Unfortunately while it wins on
|
|
|
-+ that size the user-space apps built using FD-PIC don't improve and the
|
|
|
-+ performance is lower because we put more pressure on the caches. We may
|
|
|
-+ want this back on some future CPU that has higher cache performance. */
|
|
|
-+/* #define IRA_HARD_REGNO_ADD_COST_MULTIPLIER(regno) 0.5 */
|
|
|
-+
|
|
|
-+/* Moves between registers and memory are more expensive than between
|
|
|
-+ registers because we have caches and write buffers that slow things
|
|
|
-+ down! */
|
|
|
-+#define MEMORY_MOVE_COST(MODE, CLASS, IN) 2
|
|
|
-+
|
|
|
-+/* A fall-through branch is very low cost but anything that changes the PC
|
|
|
-+ incurs a major pipeline hazard. We don't make the full extent of this
|
|
|
-+ hazard visible because we hope that multiple threads will absorb much
|
|
|
-+ of the cost and so we don't want a jump being replaced with, say, 7
|
|
|
-+ instructions. */
|
|
|
-+#define BRANCH_COST(SPEED_P, PREDICTABLE_P) \
|
|
|
-+ ((PREDICTABLE_P) ? 1 : 3)
|
|
|
-+
|
|
|
-+/* Define this macro as a C expression which is nonzero if accessing less than
|
|
|
-+ a word of memory (i.e. a `char' or a `short') is no faster than accessing a
|
|
|
-+ word of memory, i.e., if such access require more than one instruction or if
|
|
|
-+ there is no difference in cost between byte and (aligned) word loads.
|
|
|
-+
|
|
|
-+ When this macro is not defined, the compiler will access a field by finding
|
|
|
-+ the smallest containing object; when it is defined, a fullword load will be
|
|
|
-+ used if alignment permits. Unless bytes accesses are faster than word
|
|
|
-+ accesses, using word accesses is preferable since it may eliminate
|
|
|
-+ subsequent memory access if subsequent accesses occur to other fields in the
|
|
|
-+ same word of the structure, but to different bytes. */
|
|
|
-+#define SLOW_BYTE_ACCESS 0
|
|
|
-+
|
|
|
-+/* The number of scalar move insns which should be generated instead of a
|
|
|
-+ string move insn or a library call. Increasing the value will always make
|
|
|
-+ code faster, but eventually incurs high cost in increased code size.
|
|
|
-+
|
|
|
-+ If you don't define this, a reasonable default is used. */
|
|
|
-+/* According to expr.c, a value of around 6 should minimize code size. */
|
|
|
-+#define MOVE_RATIO(SPEED) 6
|
|
|
-+
|
|
|
-+/* We're much better off calling a constant function address with the
|
|
|
-+ Ubicom32 architecture because we have an opcode for doing so. Don't
|
|
|
-+ let the compiler extract function addresses as common subexpressions
|
|
|
-+ into an address register. */
|
|
|
-+#define NO_FUNCTION_CSE
|
|
|
-+
|
|
|
-+#define SELECT_CC_MODE(OP, X, Y) ubicom32_select_cc_mode (OP, X, Y)
|
|
|
-+
|
|
|
-+#define REVERSIBLE_CC_MODE(MODE) 1
|
|
|
-+
|
|
|
-+/* Canonicalize a comparison from one we don't have to one we do have. */
|
|
|
-+#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
|
|
|
-+ ubicom32_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
|
|
|
-+
|
|
|
-+/* Dividing the output into sections. */
|
|
|
-+
|
|
|
-+/* A C expression whose value is a string containing the assembler operation
|
|
|
-+ that should precede instructions and read-only data. Normally `".text"' is
|
|
|
-+ right. */
|
|
|
-+#define TEXT_SECTION_ASM_OP "\t.section .text"
|
|
|
-+
|
|
|
-+/* A C expression whose value is a string containing the assembler operation to
|
|
|
-+ identify the following data as writable initialized data. Normally
|
|
|
-+ `".data"' is right. */
|
|
|
-+#define DATA_SECTION_ASM_OP "\t.section .data"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* If defined, a C expression whose value is a string containing the
|
|
|
-+ assembler operation to identify the following data as
|
|
|
-+ uninitialized global data. If not defined, and neither
|
|
|
-+ `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined,
|
|
|
-+ uninitialized global data will be output in the data section if
|
|
|
-+ `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
|
|
|
-+ used. */
|
|
|
-+#define BSS_SECTION_ASM_OP "\t.section .bss"
|
|
|
-+
|
|
|
-+/* This is how we tell the assembler that a symbol is weak. */
|
|
|
-+
|
|
|
-+#define ASM_WEAKEN_LABEL(FILE, NAME) \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ fputs ("\t.weak\t", (FILE)); \
|
|
|
-+ assemble_name ((FILE), (NAME)); \
|
|
|
-+ fputc ('\n', (FILE)); \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+
|
|
|
-+/* The Overall Framework of an Assembler File. */
|
|
|
-+
|
|
|
-+#undef SET_ASM_OP
|
|
|
-+#define SET_ASM_OP "\t.set\t"
|
|
|
-+
|
|
|
-+/* A C string constant describing how to begin a comment in the target
|
|
|
-+ assembler language. The compiler assumes that the comment will end at the
|
|
|
-+ end of the line. */
|
|
|
-+#define ASM_COMMENT_START ";"
|
|
|
-+
|
|
|
-+/* A C string constant for text to be output before each `asm' statement or
|
|
|
-+ group of consecutive ones. Normally this is `"#APP"', which is a comment
|
|
|
-+ that has no effect on most assemblers but tells the GNU assembler that it
|
|
|
-+ must check the lines that follow for all valid assembler constructs. */
|
|
|
-+#define ASM_APP_ON "#APP\n"
|
|
|
-+
|
|
|
-+/* A C string constant for text to be output after each `asm' statement or
|
|
|
-+ group of consecutive ones. Normally this is `"#NO_APP"', which tells the
|
|
|
-+ GNU assembler to resume making the time-saving assumptions that are valid
|
|
|
-+ for ordinary compiler output. */
|
|
|
-+#define ASM_APP_OFF "#NO_APP\n"
|
|
|
-+
|
|
|
-+/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a separate,
|
|
|
-+ explicit argument. If you define this macro, it is used in place of
|
|
|
-+ `ASM_OUTPUT_BSS', and gives you more flexibility in handling the required
|
|
|
-+ alignment of the variable. The alignment is specified as the number of
|
|
|
-+ bits.
|
|
|
-+
|
|
|
-+ Try to use function `asm_output_aligned_bss' defined in file `varasm.c' when
|
|
|
-+ defining this macro. */
|
|
|
-+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
|
|
|
-+ asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
|
|
|
-+
|
|
|
-+/* A C expression to assign to OUTVAR (which is a variable of type `char *') a
|
|
|
-+ newly allocated string made from the string NAME and the number NUMBER, with
|
|
|
-+ some suitable punctuation added. Use `alloca' to get space for the string.
|
|
|
-+
|
|
|
-+ The string will be used as an argument to `ASM_OUTPUT_LABELREF' to produce
|
|
|
-+ an assembler label for an internal static variable whose name is NAME.
|
|
|
-+ Therefore, the string must be such as to result in valid assembler code.
|
|
|
-+ The argument NUMBER is different each time this macro is executed; it
|
|
|
-+ prevents conflicts between similarly-named internal static variables in
|
|
|
-+ different scopes.
|
|
|
-+
|
|
|
-+ Ideally this string should not be a valid C identifier, to prevent any
|
|
|
-+ conflict with the user's own symbols. Most assemblers allow periods or
|
|
|
-+ percent signs in assembler symbols; putting at least one of these between
|
|
|
-+ the name and the number will suffice. */
|
|
|
-+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
|
|
|
-+ ((OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
|
|
|
-+ sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO)))
|
|
|
-+
|
|
|
-+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \
|
|
|
-+ sprintf (STRING, "*.%s%ld", PREFIX, (long)(NUM))
|
|
|
-+/* A C statement to store into the string STRING a label whose name
|
|
|
-+ is made from the string PREFIX and the number NUM.
|
|
|
-+
|
|
|
-+ This string, when output subsequently by `assemble_name', should
|
|
|
-+ produce the output that `(*targetm.asm_out.internal_label)' would produce
|
|
|
-+ with the same PREFIX and NUM.
|
|
|
-+
|
|
|
-+ If the string begins with `*', then `assemble_name' will output
|
|
|
-+ the rest of the string unchanged. It is often convenient for
|
|
|
-+ `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way. If the
|
|
|
-+ string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to
|
|
|
-+ output the string, and may change it. (Of course,
|
|
|
-+ `ASM_OUTPUT_LABELREF' is also part of your machine description, so
|
|
|
-+ you should know what it does on your machine.) */
|
|
|
-+
|
|
|
-+/* This says how to output assembler code to declare an
|
|
|
-+ uninitialized external linkage data object. Under SVR4,
|
|
|
-+ the linker seems to want the alignment of data objects
|
|
|
-+ to depend on their types. We do exactly that here. */
|
|
|
-+
|
|
|
-+#define COMMON_ASM_OP "\t.comm\t"
|
|
|
-+
|
|
|
-+#undef ASM_OUTPUT_COMMON
|
|
|
-+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ fprintf ((FILE), "%s", COMMON_ASM_OP); \
|
|
|
-+ assemble_name ((FILE), (NAME)); \
|
|
|
-+ fprintf ((FILE), ", %u\n", (SIZE)); \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+
|
|
|
-+/* This says how to output assembler code to declare an
|
|
|
-+ uninitialized internal linkage data object. Under SVR4,
|
|
|
-+ the linker seems to want the alignment of data objects
|
|
|
-+ to depend on their types. We do exactly that here. */
|
|
|
-+#define LOCAL_ASM_OP "\t.lcomm\t"
|
|
|
-+
|
|
|
-+#undef ASM_OUTPUT_LOCAL
|
|
|
-+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ fprintf ((FILE), "%s", LOCAL_ASM_OP); \
|
|
|
-+ assemble_name ((FILE), (NAME)); \
|
|
|
-+ fprintf ((FILE), ", %u\n", (SIZE)); \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+
|
|
|
-+/* Globalizing directive for a label. */
|
|
|
-+#define GLOBAL_ASM_OP ".global\t"
|
|
|
-+
|
|
|
-+/* Output the operand of an instruction. */
|
|
|
-+#define PRINT_OPERAND(FILE, X, CODE) \
|
|
|
-+ ubicom32_print_operand(FILE, X, CODE)
|
|
|
-+
|
|
|
-+/* Output the address of an operand. */
|
|
|
-+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
|
|
|
-+ ubicom32_print_operand_address (FILE, ADDR)
|
|
|
-+
|
|
|
-+/* A C expression to output to STREAM some assembler code which will push hard
|
|
|
-+ register number REGNO onto the stack. The code need not be optimal, since
|
|
|
-+ this macro is used only when profiling. */
|
|
|
-+#define ASM_OUTPUT_REG_PUSH(FILE, REGNO)
|
|
|
-+
|
|
|
-+/* A C expression to output to STREAM some assembler code which will pop hard
|
|
|
-+ register number REGNO off of the stack. The code need not be optimal, since
|
|
|
-+ this macro is used only when profiling. */
|
|
|
-+#define ASM_OUTPUT_REG_POP(FILE, REGNO)
|
|
|
-+
|
|
|
-+/* This macro should be provided on machines where the addresses in a dispatch
|
|
|
-+ table are relative to the table's own address.
|
|
|
-+
|
|
|
-+ The definition should be a C statement to output to the stdio stream STREAM
|
|
|
-+ an assembler pseudo-instruction to generate a difference between two labels.
|
|
|
-+ VALUE and REL are the numbers of two internal labels. The definitions of
|
|
|
-+ these labels are output using `ASM_OUTPUT_INTERNAL_LABEL', and they must be
|
|
|
-+ printed in the same way here. For example,
|
|
|
-+
|
|
|
-+ fprintf (STREAM, "\t.word L%d-L%d\n", VALUE, REL) */
|
|
|
-+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
|
|
|
-+ fprintf (FILE, "\t%s .L%d-.L%d\n", ".long", VALUE, REL)
|
|
|
-+
|
|
|
-+/* This macro should be provided on machines where the addresses in a dispatch
|
|
|
-+ table are absolute.
|
|
|
-+
|
|
|
-+ The definition should be a C statement to output to the stdio stream STREAM
|
|
|
-+ an assembler pseudo-instruction to generate a reference to a label. VALUE
|
|
|
-+ is the number of an internal label whose definition is output using
|
|
|
-+ `ASM_OUTPUT_INTERNAL_LABEL'. For example,
|
|
|
-+
|
|
|
-+ fprintf (STREAM, "\t.word L%d\n", VALUE) */
|
|
|
-+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
|
|
|
-+ fprintf (STREAM, "\t.word .L%d\n", VALUE)
|
|
|
-+
|
|
|
-+/* Switch into a generic section. */
|
|
|
-+#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
|
|
|
-+
|
|
|
-+/* Assembler Commands for Alignment. */
|
|
|
-+
|
|
|
-+#define ASM_OUTPUT_SKIP(STREAM, N) fprintf (STREAM, "\t.skip %d,0\n", N)
|
|
|
-+/* A C statement to output to the stdio stream STREAM an assembler
|
|
|
-+ instruction to advance the location counter by NBYTES bytes.
|
|
|
-+ Those bytes should be zero when loaded. NBYTES will be a C
|
|
|
-+ expression of type `int'. */
|
|
|
-+
|
|
|
-+/* A C statement to output to the stdio stream STREAM an assembler command to
|
|
|
-+ advance the location counter to a multiple of 2 to the POWER bytes. POWER
|
|
|
-+ will be a C expression of type `int'. */
|
|
|
-+#define ASM_OUTPUT_ALIGN(FILE, LOG) \
|
|
|
-+ if ((LOG) != 0) \
|
|
|
-+ fprintf (FILE, "\t.align %d\n", (LOG))
|
|
|
-+
|
|
|
-+/* A C expression that returns the DBX register number for the compiler
|
|
|
-+ register number REGNO. In simple cases, the value of this expression may be
|
|
|
-+ REGNO itself. But sometimes there are some registers that the compiler
|
|
|
-+ knows about and DBX does not, or vice versa. In such cases, some register
|
|
|
-+ may need to have one number in the compiler and another for DBX.
|
|
|
-+
|
|
|
-+ If two registers have consecutive numbers inside GNU CC, and they can be
|
|
|
-+ used as a pair to hold a multiword value, then they *must* have consecutive
|
|
|
-+ numbers after renumbering with `DBX_REGISTER_NUMBER'. Otherwise, debuggers
|
|
|
-+ will be unable to access such a pair, because they expect register pairs to
|
|
|
-+ be consecutive in their own numbering scheme.
|
|
|
-+
|
|
|
-+ If you find yourself defining `DBX_REGISTER_NUMBER' in way that does not
|
|
|
-+ preserve register pairs, then what you must do instead is redefine the
|
|
|
-+ actual register numbering scheme.
|
|
|
-+
|
|
|
-+ This declaration is required. */
|
|
|
-+#define DBX_REGISTER_NUMBER(REGNO) REGNO
|
|
|
-+
|
|
|
-+/* A C expression that returns the integer offset value for an automatic
|
|
|
-+ variable having address X (an RTL expression). The default computation
|
|
|
-+ assumes that X is based on the frame-pointer and gives the offset from the
|
|
|
-+ frame-pointer. This is required for targets that produce debugging output
|
|
|
-+ for DBX or COFF-style debugging output for SDB and allow the frame-pointer
|
|
|
-+ to be eliminated when the `-g' options is used. */
|
|
|
-+#define DEBUGGER_AUTO_OFFSET(X) \
|
|
|
-+ ((GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) \
|
|
|
-+ + (frame_pointer_needed \
|
|
|
-+ ? 0 : -initial_elimination_offset (FRAME_POINTER_REGNUM, \
|
|
|
-+ STACK_POINTER_REGNUM)))
|
|
|
-+
|
|
|
-+/* A C expression that returns the integer offset value for an argument having
|
|
|
-+ address X (an RTL expression). The nominal offset is OFFSET. */
|
|
|
-+#define DEBUGGER_ARG_OFFSET(OFFSET, X) \
|
|
|
-+ ((GET_CODE (X) == PLUS ? OFFSET : 0) \
|
|
|
-+ + (frame_pointer_needed \
|
|
|
-+ ? 0 : -initial_elimination_offset (ARG_POINTER_REGNUM, \
|
|
|
-+ STACK_POINTER_REGNUM)))
|
|
|
-+
|
|
|
-+/* A C expression that returns the type of debugging output GNU CC produces
|
|
|
-+ when the user specifies `-g' or `-ggdb'. Define this if you have arranged
|
|
|
-+ for GNU CC to support more than one format of debugging output. Currently,
|
|
|
-+ the allowable values are `DBX_DEBUG', `SDB_DEBUG', `DWARF_DEBUG',
|
|
|
-+ `DWARF2_DEBUG', and `XCOFF_DEBUG'.
|
|
|
-+
|
|
|
-+ The value of this macro only affects the default debugging output; the user
|
|
|
-+ can always get a specific type of output by using `-gstabs', `-gcoff',
|
|
|
-+ `-gdwarf-1', `-gdwarf-2', or `-gxcoff'.
|
|
|
-+
|
|
|
-+ Defined in svr4.h.
|
|
|
-+*/
|
|
|
-+#undef PREFERRED_DEBUGGING_TYPE
|
|
|
-+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
|
|
|
-+
|
|
|
-+/* Define this macro if GNU CC should produce dwarf version 2 format debugging
|
|
|
-+ output in response to the `-g' option.
|
|
|
-+
|
|
|
-+ To support optional call frame debugging information, you must also define
|
|
|
-+ `INCOMING_RETURN_ADDR_RTX' and either set `RTX_FRAME_RELATED_P' on the
|
|
|
-+ prologue insns if you use RTL for the prologue, or call `dwarf2out_def_cfa'
|
|
|
-+ and `dwarf2out_reg_save' as appropriate from `FUNCTION_PROLOGUE' if you
|
|
|
-+ don't.
|
|
|
-+
|
|
|
-+ Defined in svr4.h. */
|
|
|
-+
|
|
|
-+#define DWARF2_DEBUGGING_INFO 1
|
|
|
-+/*#define DWARF2_UNWIND_INFO 1*/
|
|
|
-+#define DWARF2_UNWIND_INFO 0
|
|
|
-+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGNO)
|
|
|
-+#define INCOMING_FRAME_SP_OFFSET 0
|
|
|
-+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGNO)
|
|
|
-+#define EH_RETURN_FIRST 9
|
|
|
-+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + EH_RETURN_FIRST : INVALID_REGNUM)
|
|
|
-+
|
|
|
-+/* The EH_RETURN_STACKADJ_RTX macro returns RTL which describes the
|
|
|
-+ location used to store the amount to ajdust the stack. This is
|
|
|
-+ usually a registers that is available from end of the function's body
|
|
|
-+ to the end of the epilogue. Thus, this cannot be a register used as a
|
|
|
-+ temporary by the epilogue.
|
|
|
-+
|
|
|
-+ This must be an integer register. */
|
|
|
-+#define EH_RETURN_STACKADJ_REGNO 11
|
|
|
-+#define EH_RETURN_STACKADJ_RTX \
|
|
|
-+ gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO)
|
|
|
-+
|
|
|
-+/* The EH_RETURN_HANDLER_RTX macro returns RTL which describes the
|
|
|
-+ location used to store the address the processor should jump to
|
|
|
-+ catch exception. This is usually a registers that is available from
|
|
|
-+ end of the function's body to the end of the epilogue. Thus, this
|
|
|
-+ cannot be a register used as a temporary by the epilogue.
|
|
|
-+
|
|
|
-+ This must be an address register. */
|
|
|
-+#define EH_RETURN_HANDLER_REGNO 18
|
|
|
-+#define EH_RETURN_HANDLER_RTX \
|
|
|
-+ gen_rtx_REG (Pmode, EH_RETURN_HANDLER_REGNO)
|
|
|
-+
|
|
|
-+/* #define DWARF2_DEBUGGING_INFO */
|
|
|
-+
|
|
|
-+/* Define this macro if GNU CC should produce dwarf version 2-style
|
|
|
-+ line numbers. This usually requires extending the assembler to
|
|
|
-+ support them, and #defining DWARF2_LINE_MIN_INSN_LENGTH in the
|
|
|
-+ assembler configuration header files. */
|
|
|
-+/* #define DWARF2_ASM_LINE_DEBUG_INFO 1 */
|
|
|
-+
|
|
|
-+
|
|
|
-+/* An alias for a machine mode name. This is the machine mode that elements
|
|
|
-+ of a jump-table have. */
|
|
|
-+#define CASE_VECTOR_MODE Pmode
|
|
|
-+
|
|
|
-+/* Smallest number of different values for which it is best to use a
|
|
|
-+ jump-table instead of a tree of conditional branches. For most Ubicom32
|
|
|
-+ targets this is quite small, but for the v1 architecture implementations
|
|
|
-+ we had very little data memory and so heavily prefer the tree approach
|
|
|
-+ rather than the jump tables. */
|
|
|
-+#define CASE_VALUES_THRESHOLD ubicom32_case_values_threshold
|
|
|
-+
|
|
|
-+/* Register operations within the Ubicom32 architecture always operate on
|
|
|
-+ the whole register word and not just the sub-bits required for the opcode
|
|
|
-+ mode size. */
|
|
|
-+#define WORD_REGISTER_OPERATIONS
|
|
|
-+
|
|
|
-+/* The maximum number of bytes that a single instruction can move quickly from
|
|
|
-+ memory to memory. */
|
|
|
-+#define MOVE_MAX 4
|
|
|
-+
|
|
|
-+/* A C expression that is nonzero if on this machine the number of bits
|
|
|
-+ actually used for the count of a shift operation is equal to the number of
|
|
|
-+ bits needed to represent the size of the object being shifted. When this
|
|
|
-+ macro is non-zero, the compiler will assume that it is safe to omit a
|
|
|
-+ sign-extend, zero-extend, and certain bitwise `and' instructions that
|
|
|
-+ truncates the count of a shift operation. On machines that have
|
|
|
-+ instructions that act on bitfields at variable positions, which may include
|
|
|
-+ `bit test' instructions, a nonzero `SHIFT_COUNT_TRUNCATED' also enables
|
|
|
-+ deletion of truncations of the values that serve as arguments to bitfield
|
|
|
-+ instructions.
|
|
|
-+
|
|
|
-+ If both types of instructions truncate the count (for shifts) and position
|
|
|
-+ (for bitfield operations), or if no variable-position bitfield instructions
|
|
|
-+ exist, you should define this macro.
|
|
|
-+
|
|
|
-+ However, on some machines, such as the 80386 and the 680x0, truncation only
|
|
|
-+ applies to shift operations and not the (real or pretended) bitfield
|
|
|
-+ operations. Define `SHIFT_COUNT_TRUNCATED' to be zero on such machines.
|
|
|
-+ Instead, add patterns to the `md' file that include the implied truncation
|
|
|
-+ of the shift instructions.
|
|
|
-+
|
|
|
-+ You need not define this macro if it would always have the value of zero. */
|
|
|
-+#define SHIFT_COUNT_TRUNCATED 1
|
|
|
-+
|
|
|
-+/* A C expression which is nonzero if on this machine it is safe to "convert"
|
|
|
-+ an integer of INPREC bits to one of OUTPREC bits (where OUTPREC is smaller
|
|
|
-+ than INPREC) by merely operating on it as if it had only OUTPREC bits.
|
|
|
-+
|
|
|
-+ On many machines, this expression can be 1.
|
|
|
-+
|
|
|
-+ When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for modes for
|
|
|
-+ which `MODES_TIEABLE_P' is 0, suboptimal code can result. If this is the
|
|
|
-+ case, making `TRULY_NOOP_TRUNCATION' return 0 in such cases may improve
|
|
|
-+ things. */
|
|
|
-+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
|
|
|
-+
|
|
|
-+/* A C string constant that tells the GNU CC driver program options to pass
|
|
|
-+ to the assembler. It can also specify how to translate options you give
|
|
|
-+ to GNU CC into options for GNU CC to pass to the assembler. See the
|
|
|
-+ file `sun3.h' for an example of this.
|
|
|
-+
|
|
|
-+ Defined in svr4.h. */
|
|
|
-+#undef ASM_SPEC
|
|
|
-+#define ASM_SPEC \
|
|
|
-+ "%{march=*:-m%*} %{!march=*:-mubicom32v4} %{mfdpic:-mfdpic}"
|
|
|
-+
|
|
|
-+#define LINK_SPEC "\
|
|
|
-+%{h*} %{v:-V} \
|
|
|
-+%{b} \
|
|
|
-+%{mfdpic:-melf32ubicom32fdpic -z text} \
|
|
|
-+%{static:-dn -Bstatic} \
|
|
|
-+%{shared:-G -Bdynamic} \
|
|
|
-+%{symbolic:-Bsymbolic} \
|
|
|
-+%{G*} \
|
|
|
-+%{YP,*} \
|
|
|
-+%{Qy:} %{!Qn:-Qy}"
|
|
|
-+
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+
|
|
|
-+/* The svr4.h LIB_SPEC with -leval and --*group tacked on */
|
|
|
-+
|
|
|
-+#undef LIB_SPEC
|
|
|
-+#define LIB_SPEC "%{!shared:%{!symbolic:--start-group -lc -leval -lgcc --end-group}}"
|
|
|
-+
|
|
|
-+#undef HAVE_GAS_SHF_MERGE
|
|
|
-+#define HAVE_GAS_SHF_MERGE 0
|
|
|
-+
|
|
|
-+#define HANDLE_SYSV_PRAGMA 1
|
|
|
-+#undef HANDLE_PRAGMA_PACK
|
|
|
-+
|
|
|
-+typedef void (*ubicom32_func_ptr) (void);
|
|
|
-+
|
|
|
-+/* Define builtins for selected special-purpose instructions. */
|
|
|
-+enum ubicom32_builtins
|
|
|
-+{
|
|
|
-+ UBICOM32_BUILTIN_UBICOM32_SWAPB_2,
|
|
|
-+ UBICOM32_BUILTIN_UBICOM32_SWAPB_4
|
|
|
-+};
|
|
|
-+
|
|
|
-+extern rtx ubicom32_compare_op0;
|
|
|
-+extern rtx ubicom32_compare_op1;
|
|
|
-+
|
|
|
-+#define TYPE_ASM_OP "\t.type\t"
|
|
|
-+#define TYPE_OPERAND_FMT "@%s"
|
|
|
-+
|
|
|
-+#ifndef ASM_DECLARE_RESULT
|
|
|
-+#define ASM_DECLARE_RESULT(FILE, RESULT)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* These macros generate the special .type and .size directives which
|
|
|
-+ are used to set the corresponding fields of the linker symbol table
|
|
|
-+ entries in an ELF object file under SVR4. These macros also output
|
|
|
-+ the starting labels for the relevant functions/objects. */
|
|
|
-+
|
|
|
-+/* Write the extra assembler code needed to declare a function properly.
|
|
|
-+ Some svr4 assemblers need to also have something extra said about the
|
|
|
-+ function's return value. We allow for that here. */
|
|
|
-+
|
|
|
-+#ifndef ASM_DECLARE_FUNCTION_NAME
|
|
|
-+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \
|
|
|
-+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
|
|
|
-+ ASM_OUTPUT_LABEL (FILE, NAME); \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+#endif
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32.md
|
|
|
-@@ -0,0 +1,3753 @@
|
|
|
-+; GCC machine description for Ubicom32
|
|
|
-+;
|
|
|
-+; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software
|
|
|
-+; Foundation, Inc.
|
|
|
-+; Contributed by Ubicom, Inc.
|
|
|
-+;
|
|
|
-+; This file is part of GCC.
|
|
|
-+;
|
|
|
-+; GCC is free software; you can redistribute it and/or modify
|
|
|
-+; it under the terms of the GNU General Public License as published by
|
|
|
-+; the Free Software Foundation; either version 3, or (at your option)
|
|
|
-+; any later version.
|
|
|
-+;
|
|
|
-+; GCC is distributed in the hope that it will be useful,
|
|
|
-+; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+; GNU General Public License for more details.
|
|
|
-+;
|
|
|
-+; You should have received a copy of the GNU General Public License
|
|
|
-+; along with GCC; see the file COPYING3. If not see
|
|
|
-+; <http://www.gnu.org/licenses/>.
|
|
|
-+
|
|
|
-+(define_constants
|
|
|
-+ [(AUX_DATA_REGNO 15)
|
|
|
-+ (LINK_REGNO 21)
|
|
|
-+ (SP_REGNO 23)
|
|
|
-+ (ACC0_HI_REGNO 24)
|
|
|
-+ (ACC1_HI_REGNO 26)
|
|
|
-+ (CC_REGNO 30)])
|
|
|
-+
|
|
|
-+(define_constants
|
|
|
-+ [(UNSPEC_FDPIC_GOT 0)
|
|
|
-+ (UNSPEC_FDPIC_GOT_FUNCDESC 1)])
|
|
|
-+
|
|
|
-+(define_constants
|
|
|
-+ [(UNSPEC_VOLATILE_LOAD_FDPIC_FUNCDESC 0)])
|
|
|
-+
|
|
|
-+;; Types of instructions (for scheduling purposes).
|
|
|
-+
|
|
|
-+(define_attr "type" "mul,addr,other"
|
|
|
-+ (const_string "other"))
|
|
|
-+
|
|
|
-+; Define instruction scheduling characteristics. We can only issue
|
|
|
-+; one instruction per clock so we don't need to define CPU units.
|
|
|
-+;
|
|
|
-+(define_automaton "ubicom32")
|
|
|
-+
|
|
|
-+(define_cpu_unit "i_pipeline" "ubicom32");
|
|
|
-+
|
|
|
-+; We have a 4 cycle hazard associated with address calculations which
|
|
|
-+; seems rather tricky to avoid so we go with a defensive assumption
|
|
|
-+; that almost anything can be used to generate addresses.
|
|
|
-+;
|
|
|
-+;(define_insn_reservation "ubicom32_other" 4
|
|
|
-+; (eq_attr "type" "other")
|
|
|
-+; "i_pipeline")
|
|
|
-+
|
|
|
-+; Some moves don't generate hazards.
|
|
|
-+;
|
|
|
-+;(define_insn_reservation "ubicom32_addr" 1
|
|
|
-+; (eq_attr "type" "addr")
|
|
|
-+; "i_pipeline")
|
|
|
-+
|
|
|
-+; We need 3 cycles between a multiply instruction and any use of the
|
|
|
-+; matching accumulator register(s).
|
|
|
-+;
|
|
|
-+(define_insn_reservation "ubicom32_mul" 4
|
|
|
-+ (eq_attr "type" "mul")
|
|
|
-+ "i_pipeline")
|
|
|
-+
|
|
|
-+(define_attr "length" ""
|
|
|
-+ (const_int 4))
|
|
|
-+
|
|
|
-+(include "predicates.md")
|
|
|
-+(include "constraints.md")
|
|
|
-+
|
|
|
-+; 8-bit move with no change to the flags reg.
|
|
|
-+;
|
|
|
-+(define_insn "movqi"
|
|
|
-+ [(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_operand:QI 1 "ubicom32_move_operand" "g"))]
|
|
|
-+ ""
|
|
|
-+ "move.1\\t%0, %1")
|
|
|
-+
|
|
|
-+; Combiner-generated 8-bit move with the zero flag set accordingly.
|
|
|
-+;
|
|
|
-+(define_insn "movqi_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:QI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:QI 1 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_dup 0))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "ext.1\\t%1, %0")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 0)
|
|
|
-+ (const_int 0)]))]
|
|
|
-+ "(GET_MODE (operands[2]) == CCSZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCSZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))]
|
|
|
-+ "(GET_MODE (operands[2]) == CCSZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCSZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; 16-bit move with no change to the flags reg.
|
|
|
-+;
|
|
|
-+(define_insn "movhi"
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_operand:HI 1 "ubicom32_move_operand" "g"))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ if (CONST_INT_P (operands[1]))
|
|
|
-+ return \"movei\\t%0, %1\";
|
|
|
-+
|
|
|
-+ return \"move.2\\t%0, %1\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Combiner-generated 16-bit move with the zero flag set accordingly.
|
|
|
-+;
|
|
|
-+(define_insn "movhi_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:HI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:HI 1 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_dup 0))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "ext.2\\t%1, %0")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 0)
|
|
|
-+ (const_int 0)]))]
|
|
|
-+ "(GET_MODE (operands[2]) == CCSZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCSZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))]
|
|
|
-+ "(GET_MODE (operands[2]) == CCSZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCSZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; 32-bit move with no change to the flags reg.
|
|
|
-+;
|
|
|
-+(define_expand "movsi"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "general_operand" ""))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ /* Convert any complexities in operand 1 into something that can just
|
|
|
-+ fall into the default expander code. */
|
|
|
-+ ubicom32_expand_movsi (operands);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "movsi_high"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_address_register_operand" "=a")
|
|
|
-+ (high:SI (match_operand:SI 1 "ubicom32_symbolic_address_operand" "s")))]
|
|
|
-+ ""
|
|
|
-+ "moveai\\t%0, #%%hi(%E1)")
|
|
|
-+
|
|
|
-+(define_insn "movsi_lo_sum"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (lo_sum:SI (match_operand:SI 1 "ubicom32_address_register_operand" "a")
|
|
|
-+ (match_operand:SI 2 "immediate_operand" "s")))]
|
|
|
-+ ""
|
|
|
-+ "lea.1\\t%0, %%lo(%E2)(%1)")
|
|
|
-+
|
|
|
-+(define_insn "movsi_internal"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_operand:SI 1 "ubicom32_move_operand" "rmnY"))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ if (CONST_INT_P (operands[1]))
|
|
|
-+ {
|
|
|
-+ ubicom32_emit_move_const_int (operands[0], operands[1]);
|
|
|
-+ return \"\";
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT i = CONST_DOUBLE_LOW (operands[1]);
|
|
|
-+
|
|
|
-+ ubicom32_emit_move_const_int (operands[0], GEN_INT (i));
|
|
|
-+ return \"\";
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (ubicom32_address_register_operand (operands[0], VOIDmode)
|
|
|
-+ && register_operand (operands[1], VOIDmode))
|
|
|
-+ {
|
|
|
-+ if (ubicom32_address_register_operand (operands[1], VOIDmode))
|
|
|
-+ return \"lea.1\\t%0, 0(%1)\";
|
|
|
-+
|
|
|
-+ /* Use movea here to utilize the hazard bypass in the >= v4 ISA. */
|
|
|
-+ if (ubicom32_v4)
|
|
|
-+ return \"movea\\t%0, %1\";
|
|
|
-+
|
|
|
-+ return \"move.4\\t%0, %1\";
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return \"move.4\\t%0, %1\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; constants of value 2^n by using a bset.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(exact_log2 (INTVAL (operands[1])) > 14
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (ior:SI (const_int 0)
|
|
|
-+ (match_dup 1)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; constants of value ~(2^n) by using a bclr.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(exact_log2 (~INTVAL (operands[1])) > 14
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (and:SI (const_int -1)
|
|
|
-+ (match_dup 1)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; For 32-bit constants that have bits 0 through 24 and bit 31 set the same
|
|
|
-+; we can use swapb.4!
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[1]) & 0xffffffff) != 0xffffffff
|
|
|
-+ && (INTVAL (operands[1]) & 0xffffffff) != 0
|
|
|
-+ && ((INTVAL (operands[1]) & 0x80ffffff) == 0
|
|
|
-+ || (INTVAL (operands[1]) & 0x80ffffff) == 0x80ffffff))"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (bswap:SI (match_dup 2)))]
|
|
|
-+ "{
|
|
|
-+ operands[2] = GEN_INT (INTVAL (operands[1]) >> 24);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If this is a write of a constant to memory look to see if we can usefully
|
|
|
-+; transform this into 2 smaller writes.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "memory_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "! satisfies_constraint_I (operands[1])
|
|
|
-+ && ubicom32_legitimate_address_p (HImode, plus_constant (XEXP (operands[0], 0), 2), 1)"
|
|
|
-+ [(set (match_dup 4) (match_dup 2))
|
|
|
-+ (set (match_dup 5) (match_dup 3))]
|
|
|
-+ "{
|
|
|
-+ rtx low_hword_addr;
|
|
|
-+
|
|
|
-+ operands[2] = gen_highpart_mode (HImode, SImode, operands[1]);
|
|
|
-+ operands[3] = gen_lowpart (HImode, operands[1]);
|
|
|
-+
|
|
|
-+ operands[4] = gen_rtx_MEM (HImode, XEXP (operands[0], 0));
|
|
|
-+ MEM_COPY_ATTRIBUTES (operands[4], operands[0]);
|
|
|
-+
|
|
|
-+ low_hword_addr = plus_constant (XEXP (operands[0], 0), 2);
|
|
|
-+ operands[5] = gen_rtx_MEM (HImode, low_hword_addr);
|
|
|
-+ MEM_COPY_ATTRIBUTES (operands[5], operands[0]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're writing memory and we've not found a better way to do this then
|
|
|
-+; try loading into a D register and then copying to memory. This will
|
|
|
-+; perform the fewest possible memory read/writes.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "d")
|
|
|
-+ (set (match_operand:SI 0 "memory_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "! satisfies_constraint_I (operands[1])"
|
|
|
-+ [(set (match_dup 2) (match_dup 1))
|
|
|
-+ (set (match_dup 0) (match_dup 2))]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; constants of value (2^n - 1) by using an lsr.4.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(exact_log2 (INTVAL (operands[1]) + 1) > 14
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (lshiftrt:SI (const_int -1)
|
|
|
-+ (match_dup 2)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[2] = GEN_INT (32 - exact_log2 (INTVAL (operands[1]) + 1));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; constants of value (2^n - 1) by using an lsr.4.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "d")
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(exact_log2 (INTVAL (operands[1]) + 1) > 14
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (lshiftrt:SI (const_int -1)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 2))]
|
|
|
-+ "{
|
|
|
-+ operands[3] = GEN_INT (32 - exact_log2 (INTVAL (operands[1]) + 1));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; some other constants by using an lsl.4 to shift 7 bits left by some
|
|
|
-+; constant.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(ubicom32_shiftable_const_int (INTVAL (operands[1]))
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (ashift:SI (match_dup 2)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ int shift = ubicom32_shiftable_const_int (INTVAL (operands[1]));
|
|
|
-+ operands[2] = GEN_INT (INTVAL (operands[1]) >> shift);
|
|
|
-+ operands[3] = GEN_INT (shift);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; some other constants by using an lsl.4 to shift 7 bits left by some
|
|
|
-+; constant.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "d")
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(ubicom32_shiftable_const_int (INTVAL (operands[1]))
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (ashift:SI (match_dup 3)
|
|
|
-+ (match_dup 4)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 2))]
|
|
|
-+ "{
|
|
|
-+ int shift = ubicom32_shiftable_const_int (INTVAL (operands[1]));
|
|
|
-+ operands[3] = GEN_INT (INTVAL (operands[1]) >> shift);
|
|
|
-+ operands[4] = GEN_INT (shift);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; For some 16-bit unsigned constants that have bit 15 set we can use
|
|
|
-+; swapb.2!
|
|
|
-+;
|
|
|
-+; Note that the movsi code emits the same sequence but by using a peephole2
|
|
|
-+; we split the pattern early enough to allow instruction scheduling to
|
|
|
-+; occur.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[1]) & 0xffff80ff) == 0x80ff)"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (zero_extend:SI (bswap:HI (match_dup 2))))]
|
|
|
-+ "{
|
|
|
-+ HOST_WIDE_INT i = INTVAL (operands[1]) >> 8;
|
|
|
-+ if (i >= 0x80)
|
|
|
-+ i -= 0x100;
|
|
|
-+ operands[2] = GEN_INT (i);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; In general for a 16-bit unsigned constant that has bit 15 set
|
|
|
-+; then we need a movei/move.2 pair unless we can represent it
|
|
|
-+; via just a move.2.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(INTVAL (operands[1]) & 0xffff8000) == 0x8000
|
|
|
-+ && (INTVAL (operands[1]) & 0xffff) < 0xff80"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 1))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (zero_extend:SI (match_dup 2)))]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_rtx_REG (HImode, REGNO (operands[0]));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; 32-bit constants that have bits 16 through 31 set to arbitrary values
|
|
|
-+; and have bits 0 through 15 set to something representable as a default
|
|
|
-+; source-1 immediate - we use movei/shmrg.2
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(((INTVAL (operands[1]) >= 0x8000
|
|
|
-+ && INTVAL (operands[1]) < 0xff80)
|
|
|
-+ || INTVAL (operands[1]) >= 0x10000
|
|
|
-+ || INTVAL (operands[1]) < -0x8000)
|
|
|
-+ && ((INTVAL (operands[1]) & 0xffff) >= 0xff80
|
|
|
-+ || (INTVAL (operands[1]) & 0xffff) < 0x80)
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (match_dup 2))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_dup 0)
|
|
|
-+ (const_int 16))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_dup 3))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_highpart_mode (HImode, SImode, operands[1]);
|
|
|
-+ operands[3] = gen_lowpart (HImode, operands[1]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Exactly the same as the peephole2 preceding except that this targets a
|
|
|
-+; general register instead of D register. Hopefully the later optimization
|
|
|
-+; passes will notice that the value ended up in a D register first here
|
|
|
-+; and eliminate away the other register!
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "d")
|
|
|
-+ (set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(((INTVAL (operands[1]) >= 0x8000
|
|
|
-+ && INTVAL (operands[1]) < 0xff80)
|
|
|
-+ || INTVAL (operands[1]) >= 0x10000
|
|
|
-+ || INTVAL (operands[1]) < -0x8000)
|
|
|
-+ && ((INTVAL (operands[1]) & 0xffff) >= 0xff80
|
|
|
-+ || (INTVAL (operands[1]) & 0xffff) < 0x80)
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 3))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_dup 2)
|
|
|
-+ (const_int 16))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_dup 4))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 2))]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_highpart_mode (HImode, SImode, operands[1]);
|
|
|
-+ operands[4] = gen_lowpart (HImode, operands[1]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we have a load of a large integer constant which does not have bit 31
|
|
|
-+; set and we have a spare A reg then construct it with a moveai/lea.1 pair
|
|
|
-+; instead. This avoids constructing it in 3 instructions on the stack.
|
|
|
-+;
|
|
|
-+; Note that we have to be careful not to match anything that matches
|
|
|
-+; something we can do in a single instruction! There aren't many such
|
|
|
-+; constants but there are some.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "a")
|
|
|
-+ (set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))]
|
|
|
-+ "(! (INTVAL (operands[1]) & 0x80000000)
|
|
|
-+ && ((INTVAL (operands[1]) >= 0x8000
|
|
|
-+ && INTVAL (operands[1]) < 0xff80)
|
|
|
-+ || INTVAL (operands[1]) >= 0x10000))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 3))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 2)
|
|
|
-+ (match_dup 4)))]
|
|
|
-+ "{
|
|
|
-+ HOST_WIDE_INT i = INTVAL (operands[1]);
|
|
|
-+ operands[3] = GEN_INT (i & 0xffffff80);
|
|
|
-+ operands[4] = GEN_INT (i & 0x7f);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; If we're not dependent on the state of the condition codes we can construct
|
|
|
-+; a 32-bit constant with a movei/movei/shmrg.2 sequence if possible.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:HI 2 "d")
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))
|
|
|
-+ (match_dup 2)]
|
|
|
-+ "(INTVAL (operands[1]) & 0x80000000
|
|
|
-+ && INTVAL (operands[1]) < -0x8000
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (match_dup 3))
|
|
|
-+ (set (match_dup 2)
|
|
|
-+ (match_dup 4))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_dup 0)
|
|
|
-+ (const_int 16))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_dup 2))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_highpart_mode (HImode, SImode, operands[1]);
|
|
|
-+ operands[4] = gen_lowpart (HImode, operands[1]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Exactly the same as the peephole2 preceding except that this targets a
|
|
|
-+; general register instead of D register. Hopefully the later optimization
|
|
|
-+; passes will notice that the value ended up in a D register first here
|
|
|
-+; and eliminate away the other register!
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(match_scratch:SI 2 "d")
|
|
|
-+ (match_scratch:HI 3 "d")
|
|
|
-+ (set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))
|
|
|
-+ (match_dup 3)]
|
|
|
-+ "(INTVAL (operands[1]) & 0x80000000
|
|
|
-+ && INTVAL (operands[1]) < -0x8000
|
|
|
-+ && peep2_regno_dead_p (0, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 4))
|
|
|
-+ (set (match_dup 3)
|
|
|
-+ (match_dup 5))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_dup 2)
|
|
|
-+ (const_int 16))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_dup 3))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 2))]
|
|
|
-+ "{
|
|
|
-+ operands[4] = gen_highpart_mode (HImode, SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (HImode, operands[1]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "movsi_fdpic_got_offset"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (match_operand:SI 1 "ubicom32_fdpic_got_offset_operand" "Y"))]
|
|
|
-+ ""
|
|
|
-+ "movei\\t%0, %1")
|
|
|
-+
|
|
|
-+; The explicit MEM inside the UNSPEC prevents the compiler from moving
|
|
|
-+; the load before a branch after a NULL test, or before a store that
|
|
|
-+; initializes a function descriptor.
|
|
|
-+
|
|
|
-+(define_insn_and_split "load_fdpic_funcdesc"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_address_register_operand" "=a")
|
|
|
-+ (unspec_volatile:SI [(mem:SI (match_operand:SI 1 "address_operand" "p"))]
|
|
|
-+ UNSPEC_VOLATILE_LOAD_FDPIC_FUNCDESC))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (mem:SI (match_dup 1)))])
|
|
|
-+
|
|
|
-+; Combiner-generated 32-bit move with the zero flag set accordingly.
|
|
|
-+;
|
|
|
-+(define_insn "movsi_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "nonimmediate_operand" "rm, d")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 1 "nonimmediate_operand" "=d,rm")
|
|
|
-+ (match_dup 0))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ lsl.4\\t%1, %0, #0
|
|
|
-+ add.4\\t%1, #0, %0")
|
|
|
-+
|
|
|
-+; Combiner-generated 32-bit move with all flags set accordingly.
|
|
|
-+;
|
|
|
-+(define_insn "movsi_ccw"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 1 "nonimmediate_operand" "=rm")
|
|
|
-+ (match_dup 0))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWmode)"
|
|
|
-+ "add.4\\t%1, #0, %0")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 0)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
|
|
|
-+ "(GET_MODE (operands[2]) == CCWZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCWZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" ""))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
|
|
|
-+ "(GET_MODE (operands[2]) == CCWZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCWZmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; Combine isn't very good at merging some types of operations so we
|
|
|
-+; have to make do with a peephole. It's not as effective but it's better
|
|
|
-+; than doing nothing.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 0)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_operand:SI 4 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_dup 0))])]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && (GET_MODE (operands[2]) == CCWZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCWZmode))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (set (match_dup 4)
|
|
|
-+ (match_dup 1))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+; Register renaming may make a general reg into a D reg in which case
|
|
|
-+; we may be able to simplify a compare.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (match_operator 3 "ubicom32_compare_operator"
|
|
|
-+ [(match_dup 0)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (clobber (match_operand:SI 4 "ubicom32_data_register_operand" ""))])]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && (GET_MODE (operands[2]) == CCWZNmode
|
|
|
-+ || GET_MODE (operands[2]) == CCWZmode))"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_op_dup 3
|
|
|
-+ [(match_dup 1)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (clobber (match_dup 4))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn_and_split "movdi"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm")
|
|
|
-+ (match_operand:DI 1 "general_operand" "rmi,ri"))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 2) (match_dup 3))
|
|
|
-+ (set (match_dup 4) (match_dup 5))]
|
|
|
-+ "{
|
|
|
-+ rtx dest_low;
|
|
|
-+ rtx src_low;
|
|
|
-+
|
|
|
-+ dest_low = gen_lowpart (SImode, operands[0]);
|
|
|
-+ src_low = gen_lowpart (SImode, operands[1]);
|
|
|
-+
|
|
|
-+ if (REG_P (operands[0])
|
|
|
-+ && REG_P (operands[1])
|
|
|
-+ && REGNO (operands[0]) < REGNO (operands[1]))
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ operands[4] = dest_low;
|
|
|
-+ operands[5] = src_low;
|
|
|
-+ }
|
|
|
-+ else if (reg_mentioned_p (dest_low, src_low))
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ operands[4] = dest_low;
|
|
|
-+ operands[5] = src_low;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ operands[2] = dest_low;
|
|
|
-+ operands[3] = src_low;
|
|
|
-+ operands[4] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ }
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+; Combiner-generated 64-bit move with all flags set accordingly.
|
|
|
-+;
|
|
|
-+(define_insn "movdi_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:DI 0 "nonimmediate_operand" "d, m, r")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:DI 1 "nonimmediate_operand" "=&rm,rm,!&rm")
|
|
|
-+ (match_dup 0))
|
|
|
-+ (clobber (match_scratch:SI 2 "=X, d, d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[1]);
|
|
|
-+
|
|
|
-+ if (ubicom32_data_register_operand (operands[0], VOIDmode))
|
|
|
-+ return \"add.4\\t%4, #0, %3\;addc\\t%6, #0, %5\";
|
|
|
-+
|
|
|
-+ return \"movei\\t%2, #0\;add.4\\t%4, %3, %2\;addc\\t%6, %5, %2\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "movdi_ccw"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:DI 0 "nonimmediate_operand" "d, m, r")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:DI 1 "nonimmediate_operand" "=&rm,rm,!&rm")
|
|
|
-+ (match_dup 0))
|
|
|
-+ (clobber (match_scratch:SI 2 "=X, d, d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWmode)"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[1]);
|
|
|
-+
|
|
|
-+ if (ubicom32_data_register_operand (operands[0], VOIDmode))
|
|
|
-+ return \"add.4\\t%4, #0, %3\;addc\\t%6, #0, %5\";
|
|
|
-+
|
|
|
-+ return \"movei\\t%2, #0\;add.4\\t%4, %3, %2\;addc\\t%6, %5, %2\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "movsf"
|
|
|
-+ [(set (match_operand:SF 0 "nonimmediate_operand" "=!d,*rm")
|
|
|
-+ (match_operand:SF 1 "ubicom32_move_operand" "rmF,rmF"))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT val;
|
|
|
-+ REAL_VALUE_TYPE rv;
|
|
|
-+
|
|
|
-+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
|
|
|
-+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
|
|
|
-+
|
|
|
-+ ubicom32_emit_move_const_int (operands[0], GEN_INT (val));
|
|
|
-+ return \"\";
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return \"move.4\\t%0, %1\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "zero_extendqihi2"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "move.1\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "zero_extendqisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "move.1\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "zero_extendqisi2_ccwz_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (zero_extend:SI (match_dup 1)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "shmrg.1\\t%0, %1, #0")
|
|
|
-+
|
|
|
-+(define_insn "zero_extendhisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "move.2\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "zero_extendhisi2_ccwz_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (zero_extend:SI (match_dup 1)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "shmrg.2\\t%0, %1, #0")
|
|
|
-+
|
|
|
-+(define_insn_and_split "zero_extendqidi2"
|
|
|
-+ [(set (match_operand:DI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (zero_extend:SI (match_dup 1)))
|
|
|
-+ (set (match_dup 3)
|
|
|
-+ (const_int 0))]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart (SImode, operands[0]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn_and_split "zero_extendhidi2"
|
|
|
-+ [(set (match_operand:DI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (zero_extend:SI (match_dup 1)))
|
|
|
-+ (set (match_dup 3)
|
|
|
-+ (const_int 0))]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart (SImode, operands[0]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn_and_split "zero_extendsidi2"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 1))
|
|
|
-+ (set (match_dup 3)
|
|
|
-+ (const_int 0))]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart (SImode, operands[0]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "extendqihi2"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "ext.1\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "extendqisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "ext.1\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "extendhisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "ext.2\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn_and_split "extendsidi2"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d")
|
|
|
-+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (match_dup 1))
|
|
|
-+ (parallel
|
|
|
-+ [(set (match_dup 3)
|
|
|
-+ (ashiftrt:SI (match_dup 2)
|
|
|
-+ (const_int 31)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart (SImode, operands[0]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "bswaphi"
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (bswap:HI (match_operand:HI 1 "ubicom32_arith_operand" "rmI")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "swapb.2\\t%0, %1");
|
|
|
-+
|
|
|
-+(define_insn "bswaphisi"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (bswap:HI (match_operand:HI 1 "ubicom32_arith_operand" "rmI"))))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "swapb.2\\t%0, %1");
|
|
|
-+
|
|
|
-+(define_insn "bswapsi"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (bswap:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "swapb.4\\t%0, %1");
|
|
|
-+
|
|
|
-+(define_insn "tstqi_ext1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:QI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "ext.1\\t#0, %0")
|
|
|
-+
|
|
|
-+(define_expand "cmpqi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:QI 0 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:QI 1 "ubicom32_data_register_operand" "")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ ubicom32_compare_op0 = operands[0];
|
|
|
-+ ubicom32_compare_op1 = operands[1];
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "sub1_ccs"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:QI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:QI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "sub.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+; If we're testing for equality we don't have to worry about reversing conditions.
|
|
|
-+;
|
|
|
-+(define_insn "sub1_ccsz_1"
|
|
|
-+ [(set (reg:CCSZ CC_REGNO)
|
|
|
-+ (compare:CCSZ (match_operand:QI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (match_operand:QI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "sub.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "sub1_ccsz_2"
|
|
|
-+ [(set (reg:CCSZ CC_REGNO)
|
|
|
-+ (compare:CCSZ (match_operand:QI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (match_operand:QI 1 "ubicom32_arith_operand" "rmI")))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "sub.1\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+; When the combiner runs it doesn't have any insight into whether or not an argument
|
|
|
-+; to a compare is spilled to the stack and therefore can't swap the comparison in
|
|
|
-+; an attempt to use sub.1 more effectively. We peephole this case here.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:QI 0 "register_operand" "")
|
|
|
-+ (match_operand:QI 1 "ubicom32_arith_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (compare (match_operand:QI 3 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_dup 0)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_operator 4 "comparison_operator"
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_operand 5 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && peep2_regno_dead_p (3, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (compare (match_dup 1)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_op_dup 6
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_dup 5))
|
|
|
-+ (pc)))]
|
|
|
-+ "{
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
|
|
|
-+ operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
|
|
|
-+ GET_MODE (operands[4]),
|
|
|
-+ cc_reg,
|
|
|
-+ const0_rtx);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "tsthi_ext2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:HI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "ext.2\\t#0, %0")
|
|
|
-+
|
|
|
-+(define_expand "cmphi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:HI 0 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:HI 1 "ubicom32_compare_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ do
|
|
|
-+ {
|
|
|
-+ /* Is this a cmpi? */
|
|
|
-+ if (CONST_INT_P (operands[1]))
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Must be a sub.2 - if necessary copy an operand into a reg. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], HImode))
|
|
|
-+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
|
|
|
-+ }
|
|
|
-+ while (0);
|
|
|
-+
|
|
|
-+ ubicom32_compare_op0 = operands[0];
|
|
|
-+ ubicom32_compare_op1 = operands[1];
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "cmpi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:HI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (match_operand 1 "const_int_operand" "N")))]
|
|
|
-+ ""
|
|
|
-+ "cmpi\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "sub2_ccs"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:HI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:HI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ ""
|
|
|
-+ "sub.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+; If we're testing for equality we don't have to worry about reversing conditions.
|
|
|
-+;
|
|
|
-+(define_insn "sub2_ccsz_1"
|
|
|
-+ [(set (reg:CCSZ CC_REGNO)
|
|
|
-+ (compare:CCSZ (match_operand:HI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (match_operand:HI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ ""
|
|
|
-+ "sub.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "sub2_ccsz_2"
|
|
|
-+ [(set (reg:CCSZ CC_REGNO)
|
|
|
-+ (compare:CCSZ (match_operand:HI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (match_operand:HI 1 "ubicom32_arith_operand" "rmI")))]
|
|
|
-+ ""
|
|
|
-+ "sub.2\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+; When the combiner runs it doesn't have any insight into whether or not an argument
|
|
|
-+; to a compare is spilled to the stack and therefore can't swap the comparison in
|
|
|
-+; an attempt to use sub.2 more effectively. We peephole this case here.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "")
|
|
|
-+ (match_operand:HI 1 "ubicom32_arith_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (compare (match_operand:HI 3 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_dup 0)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_operator 4 "comparison_operator"
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_operand 5 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && peep2_regno_dead_p (3, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (compare (match_dup 1)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_op_dup 6
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_dup 5))
|
|
|
-+ (pc)))]
|
|
|
-+ "{
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
|
|
|
-+ operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
|
|
|
-+ GET_MODE (operands[4]),
|
|
|
-+ cc_reg,
|
|
|
-+ const0_rtx);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn_and_split "tstsi_lsl4"
|
|
|
-+ [(set (match_operand 0 "ubicom32_cc_register_operand" "=r")
|
|
|
-+ (match_operator 1 "ubicom32_compare_operator"
|
|
|
-+ [(match_operand:SI 2 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)]))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "#"
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (match_op_dup 1
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)]))
|
|
|
-+ (clobber (match_dup 3))])]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_reg_rtx (SImode);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "tstsi_lsl4_d"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_operand:SI 1 "ubicom32_data_register_operand" "=d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "lsl.4\\t%1, %0, #0")
|
|
|
-+
|
|
|
-+; Comparison for equality with -1.
|
|
|
-+;
|
|
|
-+(define_insn "cmpsi_not4_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int -1)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "not.4\\t#0, %0")
|
|
|
-+
|
|
|
-+(define_expand "cmpsi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:SI 1 "ubicom32_compare_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ do
|
|
|
-+ {
|
|
|
-+ /* Is this a cmpi? We can't take a memory address as cmpi takes
|
|
|
-+ 16-bit operands. */
|
|
|
-+ if (register_operand (operands[0], SImode)
|
|
|
-+ && CONST_INT_P (operands[1])
|
|
|
-+ && satisfies_constraint_N (operands[1]))
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Must be a sub.4 - if necessary copy an operand into a reg. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], SImode))
|
|
|
-+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
|
|
|
-+ }
|
|
|
-+ while (0);
|
|
|
-+
|
|
|
-+ ubicom32_compare_op0 = operands[0];
|
|
|
-+ ubicom32_compare_op1 = operands[1];
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "cmpsi_cmpi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "register_operand" "r")
|
|
|
-+ (match_operand 1 "const_int_operand" "N")))]
|
|
|
-+ "(satisfies_constraint_N (operands[1]))"
|
|
|
-+ "cmpi\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "cmpsi_sub4"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ ""
|
|
|
-+ "sub.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+; If we're testing for equality we don't have to worry about reversing conditions.
|
|
|
-+;
|
|
|
-+(define_insn "cmpsi_sub4_ccwz_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "sub.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "cmpsi_sub4_ccwz_2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" "rm")))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "sub.4\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+; When the combiner runs it doesn't have any insight into whether or not an argument
|
|
|
-+; to a compare is spilled to the stack and therefore can't swap the comparison in
|
|
|
-+; an attempt to use sub.4 more effectively. We peephole this case here.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (compare (match_operand:SI 3 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_dup 0)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_operator 4 "comparison_operator"
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_operand 5 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && peep2_regno_dead_p (3, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (compare (match_dup 1)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_op_dup 6
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_dup 5))
|
|
|
-+ (pc)))]
|
|
|
-+ "{
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
|
|
|
-+ operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
|
|
|
-+ GET_MODE (operands[4]),
|
|
|
-+ cc_reg,
|
|
|
-+ const0_rtx);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn_and_split "tstdi_or4"
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ (match_operand:DI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ (match_dup 0)
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_dup 1))])]
|
|
|
-+ "{
|
|
|
-+ operands[1] = gen_reg_rtx (SImode);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "tstdi_or4_d"
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ (match_operand:DI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_operand:SI 1 "ubicom32_data_register_operand" "=d"))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_highpart_mode (SImode, DImode, operands[0]);
|
|
|
-+
|
|
|
-+ if (ubicom32_data_register_operand (operands[0], GET_MODE (operands[0])))
|
|
|
-+ return \"or.4\\t#0, %2, %3\";
|
|
|
-+
|
|
|
-+ return \"move.4\\t%1, %2\;or.4\\t%1, %3, %1\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_expand "cmpdi"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:DI 0 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:DI 1 "ubicom32_data_register_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_compare_op0 = operands[0];
|
|
|
-+ ubicom32_compare_op1 = operands[1];
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "cmpdi_sub4subc"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare (match_operand:DI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:DI 1 "ubicom32_data_register_operand" "d")))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[4] = gen_highpart_mode (SImode, DImode, operands[0]);
|
|
|
-+ operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+
|
|
|
-+ return \"sub.4\\t#0, %2, %3\;subc\\t#0, %4, %5\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+; When the combiner runs it doesn't have any insight into whether or not an argument
|
|
|
-+; to a compare is spilled to the stack and therefore can't swap the comparison in
|
|
|
-+; an attempt to use sub.4/subc more effectively. We peephole this case here.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:DI 0 "register_operand" "")
|
|
|
-+ (match_operand:DI 1 "ubicom32_arith_operand" ""))
|
|
|
-+ (set (match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (compare (match_operand:DI 3 "ubicom32_data_register_operand" "")
|
|
|
-+ (match_dup 0)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_operator 4 "comparison_operator"
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_operand 5 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && peep2_regno_dead_p (3, CC_REGNO))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (compare (match_dup 1)
|
|
|
-+ (match_dup 3)))
|
|
|
-+ (set (pc)
|
|
|
-+ (if_then_else (match_op_dup 6
|
|
|
-+ [(match_dup 2)
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_dup 5))
|
|
|
-+ (pc)))]
|
|
|
-+ "{
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
|
|
|
-+ operands[6] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[4])),
|
|
|
-+ GET_MODE (operands[4]),
|
|
|
-+ cc_reg,
|
|
|
-+ const0_rtx);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "btst"
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ
|
|
|
-+ (zero_extract:SI
|
|
|
-+ (match_operand:SI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (const_int 1)
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ ""
|
|
|
-+ "btst\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "bfextu_ccwz_null"
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ
|
|
|
-+ (zero_extract:SI
|
|
|
-+ (match_operand:SI 0 "nonimmediate_operand" "rm")
|
|
|
-+ (match_operand 1 "const_int_operand" "M")
|
|
|
-+ (const_int 0))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ ""
|
|
|
-+ "bfextu\\t%2, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "addqi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "")
|
|
|
-+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], QImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "addqi3_add1"
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ add.1\\t%0, %2, %1
|
|
|
-+ add.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "addqi3_add1_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (neg:QI (match_operand:QI 0 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (match_operand:QI 1 "ubicom32_arith_operand" "rmI, d")))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "@
|
|
|
-+ add.1\\t#0, %1, %0
|
|
|
-+ add.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "addhi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "")
|
|
|
-+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], HImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "addhi3_add2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ add.2\\t%0, %2, %1
|
|
|
-+ add.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "addhi3_add2_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (neg:HI (match_operand:HI 0 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (match_operand:HI 1 "ubicom32_arith_operand" "rmI, d")))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "@
|
|
|
-+ add.2\\t#0, %1, %0
|
|
|
-+ add.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "addsi3"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 2 "ubicom32_move_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_expand_addsi3 (operands);
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; We start with an instruction pattern that can do all sorts of interesting
|
|
|
-+; things but we split out any uses of lea or pdec instructions because
|
|
|
-+; those instructions don't clobber the condition codes.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "addsi3_1"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm,rm,rm,rm, rm,rm")
|
|
|
-+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%a, a, a, a, a, d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_move_operand" "L, K, J, P, d,rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ #
|
|
|
-+ #
|
|
|
-+ #
|
|
|
-+ #
|
|
|
-+ #
|
|
|
-+ add.4\\t%0, %2, %1
|
|
|
-+ add.4\\t%0, %1, %2"
|
|
|
-+ "(reload_completed
|
|
|
-+ && ubicom32_address_register_operand (operands[1], GET_MODE (operands[1])))"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "addsi3_1_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (plus:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ add.4\\t%0, %2, %1
|
|
|
-+ add.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "addsi3_1_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (neg:SI (match_operand:SI 0 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d")))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ add.4\\t#0, %1, %0
|
|
|
-+ add.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn_and_split "addsi3_2"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm,rm,rm,rm,rm")
|
|
|
-+ (plus:SI (match_operand:SI 1 "ubicom32_address_register_operand" "%a, a, a, a, a, a")
|
|
|
-+ (match_operand:SI 2 "ubicom32_move_operand" "L, K, J, P, d, n")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ lea.4\\t%0, %E2(%1)
|
|
|
-+ lea.2\\t%0, %E2(%1)
|
|
|
-+ lea.1\\t%0, %E2(%1)
|
|
|
-+ pdec\\t%0, %n2(%1)
|
|
|
-+ lea.1\\t%0, (%1,%2)
|
|
|
-+ #"
|
|
|
-+ "(reload_completed
|
|
|
-+ && ! satisfies_constraint_L (operands[2])
|
|
|
-+ && ! satisfies_constraint_K (operands[2])
|
|
|
-+ && ! satisfies_constraint_J (operands[2])
|
|
|
-+ && ! satisfies_constraint_P (operands[2])
|
|
|
-+ && ! ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))"
|
|
|
-+ [(set (reg:SI AUX_DATA_REGNO)
|
|
|
-+ (match_dup 2))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 1)
|
|
|
-+ (reg:SI AUX_DATA_REGNO)))]
|
|
|
-+ ""
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "lea_2"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (plus:SI (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 2))
|
|
|
-+ (match_operand:SI 2 "ubicom32_address_register_operand" "a")))]
|
|
|
-+ ""
|
|
|
-+ "lea.2\\t%0, (%2,%1)")
|
|
|
-+
|
|
|
-+(define_insn "lea_4"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (plus:SI (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 4))
|
|
|
-+ (match_operand:SI 2 "ubicom32_address_register_operand" "a")))]
|
|
|
-+ ""
|
|
|
-+ "lea.4\\t%0, (%2,%1)")
|
|
|
-+
|
|
|
-+(define_expand "adddi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
|
|
-+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; We construct a 64-bit add from 32-bit operations. Note that we use the
|
|
|
-+; & constraint to prevent overlapping registers being allocated. We do
|
|
|
-+; allow identical registers though as that won't break anything.
|
|
|
-+;
|
|
|
-+(define_insn "adddi3_add4addc"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,&r,rm, d, m, m")
|
|
|
-+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%d,rm, 0, 0, d,rm")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d, d,rmI,rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (ubicom32_data_register_operand (operands[2], GET_MODE (operands[2])))
|
|
|
-+ return \"add.4\\t%3, %4, %5\;addc\\t%6, %7, %8\";
|
|
|
-+
|
|
|
-+ return \"add.4\\t%3, %5, %4\;addc\\t%6, %8, %7\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "adddi3_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%d,rm, 0, 0, d,rm")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d, d,rmI,rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:DI 0 "nonimmediate_operand" "=&r,&r,rm, d, m, m")
|
|
|
-+ (plus:DI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+
|
|
|
-+ if (ubicom32_data_register_operand (operands[1], GET_MODE (operands[1])))
|
|
|
-+ {
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[2]);
|
|
|
-+ operands[8] = gen_highpart (SImode, operands[1]);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return \"add.4\\t%3, %5, %4\;addc\\t%6, %8, %7\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "adddi3_ccwz_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (neg:DI (match_operand:DI 0 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (match_operand:DI 1 "ubicom32_arith_operand" "rmI, d")))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ if (ubicom32_data_register_operand (operands[0], GET_MODE (operands[0])))
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[4] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[5] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_highpart (SImode, operands[0]);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return \"add.4\\t#0, %3, %2\;addc\\t#0, %5, %4\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_expand "subqi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "")
|
|
|
-+ (minus:QI (match_operand:QI 1 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:QI 2 "ubicom32_data_register_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], QImode))
|
|
|
-+ FAIL;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "subqi3_sub1"
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "=m")
|
|
|
-+ (minus:QI (match_operand:QI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:QI 2 "ubicom32_data_register_operand" "d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "sub.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_expand "subhi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "")
|
|
|
-+ (minus:HI (match_operand:HI 1 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:HI 2 "ubicom32_data_register_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], HImode))
|
|
|
-+ FAIL;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "subhi3_sub2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m")
|
|
|
-+ (minus:HI (match_operand:HI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:HI 2 "ubicom32_data_register_operand" "d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "sub.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "subsi3"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (minus:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_data_register_operand" "d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "sub.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "subsi3_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (minus:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_data_register_operand" "d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (minus:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "sub.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+; We construct a 64-bit add from 32-bit operations. Note that we use the
|
|
|
-+; & constraint to prevent overlapping registers being allocated. We do
|
|
|
-+; allow identical registers though as that won't break anything.
|
|
|
-+;
|
|
|
-+(define_insn "subdi3"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r, d, m")
|
|
|
-+ (minus:DI (match_operand:DI 1 "ubicom32_arith_operand" "rmI,0,rmI,rmI")
|
|
|
-+ (match_operand:DI 2 "ubicom32_data_register_operand" "d,d, 0, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart (SImode, operands[2]);
|
|
|
-+
|
|
|
-+ return \"sub.4\\t%3, %4, %5\;subc\\t%6, %7, %8\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "subdi3_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (minus:DI (match_operand:DI 1 "ubicom32_arith_operand" "rmI,rmI")
|
|
|
-+ (match_operand:DI 2 "ubicom32_data_register_operand" "d, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:DI 0 "nonimmediate_operand" "=&r, m")
|
|
|
-+ (minus:DI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart_mode (SImode, DImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart (SImode, operands[2]);
|
|
|
-+
|
|
|
-+ return \"sub.4\\t%3, %4, %5\;subc\\t%6, %7, %8\";
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+;(define_insn "negqi2"
|
|
|
-+; [(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
|
|
|
-+; (neg:QI (match_operand:QI 1 "ubicom32_data_register_operand" "d")))
|
|
|
-+; (clobber (reg:CC CC_REGNO))]
|
|
|
-+; "(ubicom32_v4)"
|
|
|
-+; "sub.1\\t%0, #0, %1")
|
|
|
-+
|
|
|
-+;(define_insn "neghi2"
|
|
|
-+; [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
|
|
-+; (neg:HI (match_operand:HI 1 "ubicom32_data_register_operand" "d")))
|
|
|
-+; (clobber (reg:CC CC_REGNO))]
|
|
|
-+; ""
|
|
|
-+; "sub.2\\t%0, #0, %1")
|
|
|
-+
|
|
|
-+(define_insn "negsi2"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (neg:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "sub.4\\t%0, #0, %1")
|
|
|
-+
|
|
|
-+(define_insn_and_split "negdi2"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&rm")
|
|
|
-+ (neg:DI (match_operand:DI 1 "ubicom32_data_register_operand" "d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(parallel [(set (match_dup 0)
|
|
|
-+ (minus:DI (const_int 0)
|
|
|
-+ (match_dup 1)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "umulhisi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_acc_lo_register_operand" "=l, l")
|
|
|
-+ (mult:SI
|
|
|
-+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (zero_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm, d"))))
|
|
|
-+ (clobber (reg:HI ACC0_HI_REGNO))
|
|
|
-+ (clobber (reg:HI ACC1_HI_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ mulu\\t%A0, %2, %1
|
|
|
-+ mulu\\t%A0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul,mul")])
|
|
|
-+
|
|
|
-+(define_insn "mulhisi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_acc_lo_register_operand" "=l, l")
|
|
|
-+ (mult:SI
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (sign_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm, d"))))
|
|
|
-+ (clobber (reg:HI ACC0_HI_REGNO))
|
|
|
-+ (clobber (reg:HI ACC1_HI_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ muls\\t%A0, %2, %1
|
|
|
-+ muls\\t%A0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul,mul")])
|
|
|
-+
|
|
|
-+(define_expand "mulsi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_acc_hi_register_operand" "")
|
|
|
-+ (mult:SI (match_operand:SI 1 "ubicom32_arith_operand" "")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (ubicom32_emit_mult_sequence (operands))
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "umulsidi3"
|
|
|
-+ [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand" "=h, h")
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm, d"))))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ mulu.4\\t%A0, %2, %1
|
|
|
-+ mulu.4\\t%A0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul,mul")])
|
|
|
-+
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_dup 0))
|
|
|
-+ (zero_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2]) + 1)
|
|
|
-+ && ! rtx_equal_p (operands[0], operands[3])"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_dup 1))
|
|
|
-+ (zero_extend:DI (match_dup 3))))]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))
|
|
|
-+ (zero_extend:DI (match_dup 0))))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2]) + 1)
|
|
|
-+ && ! rtx_equal_p (operands[0], operands[3])"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_dup 1))
|
|
|
-+ (zero_extend:DI (match_dup 3))))]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "umulsidi3_const"
|
|
|
-+ [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand" "=h")
|
|
|
-+ (mult:DI
|
|
|
-+ (zero_extend:DI (match_operand:SI 1 "ubicom32_data_register_operand" "%d"))
|
|
|
-+ (match_operand 2 "const_int_operand" "I")))]
|
|
|
-+ "(ubicom32_v4 && satisfies_constraint_I (operands[2]))"
|
|
|
-+ "mulu.4\\t%A0, %2, %1"
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+(define_insn "mulsidi3"
|
|
|
-+ [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand" "=h, h")
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%d,rm"))
|
|
|
-+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm, d"))))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ muls.4\\t%A0, %2, %1
|
|
|
-+ muls.4\\t%A0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul,mul")])
|
|
|
-+
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_dup 0))
|
|
|
-+ (sign_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2]) + 1)
|
|
|
-+ && ! rtx_equal_p (operands[0], operands[3])"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_dup 1))
|
|
|
-+ (sign_extend:DI (match_dup 3))))]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "nonimmediate_operand" ""))
|
|
|
-+ (set (match_operand:DI 2 "ubicom32_acc_hi_register_operand" "")
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_operand:SI 3 "ubicom32_data_register_operand" ""))
|
|
|
-+ (sign_extend:DI (match_dup 0))))]
|
|
|
-+ "(peep2_reg_dead_p (2, operands[0])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2])
|
|
|
-+ || REGNO (operands[0]) == REGNO (operands[2]) + 1)
|
|
|
-+ && ! rtx_equal_p (operands[0], operands[3])"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_dup 1))
|
|
|
-+ (sign_extend:DI (match_dup 3))))]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "mulsidi3_const"
|
|
|
-+ [(set (match_operand:DI 0 "ubicom32_acc_hi_register_operand" "=h")
|
|
|
-+ (mult:DI
|
|
|
-+ (sign_extend:DI (match_operand:SI 1 "ubicom32_data_register_operand" "%d"))
|
|
|
-+ (match_operand 2 "const_int_operand" "I")))]
|
|
|
-+ "(ubicom32_v4 && satisfies_constraint_I (operands[2]))"
|
|
|
-+ "muls.4\\t%A0, %2, %1"
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+(define_expand "andqi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "")
|
|
|
-+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], QImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andqi3_and1"
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ and.1\\t%0, %2, %1
|
|
|
-+ and.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andqi3_and1_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (and:QI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "@
|
|
|
-+ and.1\\t%0, %2, %1
|
|
|
-+ and.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andqi3_and1_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:QI (match_operand:QI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "@
|
|
|
-+ and.1\\t#0, %1, %0
|
|
|
-+ and.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "and1_ccszn_null_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rI"))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "and.1\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "and1_ccszn_null_2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (subreg:SI
|
|
|
-+ (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ 0))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "and.1\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "and1_ccszn_null_3"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (and:SI (subreg:SI
|
|
|
-+ (match_operand:QI 0 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "and.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "andhi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "")
|
|
|
-+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], HImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andhi3_and2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ and.2\\t%0, %2, %1
|
|
|
-+ and.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andhi3_and2_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (and:HI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "@
|
|
|
-+ and.2\\t%0, %2, %1
|
|
|
-+ and.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andhi3_and2_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:HI (match_operand:HI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "@
|
|
|
-+ and.2\\t#0, %1, %0
|
|
|
-+ and.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "and2_ccszn_null_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rI"))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "and.2\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "and2_ccszn_null_2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (and:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (subreg:SI
|
|
|
-+ (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ 0))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "and.2\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "and2_ccszn_null_3"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (and:SI (subreg:SI
|
|
|
-+ (match_operand:HI 0 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "and.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "andsi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 2 "ubicom32_and_or_si3_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ do
|
|
|
-+ {
|
|
|
-+ /* Is this a bfextu? */
|
|
|
-+ if (ubicom32_data_register_operand (operands[0], SImode)
|
|
|
-+ && CONST_INT_P (operands[2])
|
|
|
-+ && exact_log2 (INTVAL (operands[2]) + 1) != -1)
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Is this a bclr? */
|
|
|
-+ if (CONST_INT_P (operands[2])
|
|
|
-+ && exact_log2 (~INTVAL (operands[2])) != -1)
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Must be an and.4 */
|
|
|
-+ if (!ubicom32_data_register_operand (operands[1], SImode))
|
|
|
-+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
|
|
|
-+
|
|
|
-+ if (!ubicom32_arith_operand (operands[2], SImode))
|
|
|
-+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
|
|
|
-+ }
|
|
|
-+ while (0);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_bfextu"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%rm")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "O")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(satisfies_constraint_O (operands[2]))"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1));
|
|
|
-+
|
|
|
-+ return \"bfextu\\t%0, %1, %3\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_bfextu_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%rm")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "O"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (and:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "(satisfies_constraint_O (operands[2])
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCWZmode))"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2]) + 1));
|
|
|
-+
|
|
|
-+ return \"bfextu\\t%0, %1, %3\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_bfextu_ccwz_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" "O"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ "(satisfies_constraint_O (operands[1])
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCWZmode))"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = GEN_INT (exact_log2 (INTVAL (operands[1]) + 1));
|
|
|
-+
|
|
|
-+ return \"bfextu\\t%2, %0, %3\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_bclr"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (and:SI (match_operand:SI 1 "ubicom32_arith_operand" "%rmI")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "n")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(exact_log2 (~INTVAL (operands[2])) != -1)"
|
|
|
-+ "bclr\\t%0, %1, #%D2")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_and4"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ and.4\\t%0, %2, %1
|
|
|
-+ and.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_and4_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (and:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ and.4\\t%0, %2, %1
|
|
|
-+ and.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_and4_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:SI (match_operand:SI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ and.4\\t#0, %1, %0
|
|
|
-+ and.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "andsi3_lsr4_ccwz_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" "n"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ "(exact_log2 ((~(INTVAL (operands[1]))) + 1) != -1
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCWZmode))"
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ operands[3] = GEN_INT (exact_log2 ((~(INTVAL (operands[1]))) + 1));
|
|
|
-+
|
|
|
-+ return \"lsr.4\\t%2, %0, %3\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; We really would like the combiner to recognize this scenario and deal with
|
|
|
-+; it but unfortunately it tries to canonicalize zero_extract ops on MEMs
|
|
|
-+; into QImode operations and we can't match them in any useful way.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))
|
|
|
-+ (set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ
|
|
|
-+ (and:SI (match_operand:SI 2 "nonimmediate_operand" "")
|
|
|
-+ (match_dup 0))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(exact_log2 (INTVAL (operands[1])) != -1
|
|
|
-+ && peep2_reg_dead_p (2, operands[0]))"
|
|
|
-+ [(set (reg:CCWZ CC_REGNO)
|
|
|
-+ (compare:CCWZ
|
|
|
-+ (zero_extract:SI
|
|
|
-+ (match_dup 2)
|
|
|
-+ (const_int 1)
|
|
|
-+ (match_dup 3))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "{
|
|
|
-+ operands[3] = GEN_INT (exact_log2 (INTVAL (operands[1])));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "anddi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
|
|
-+ (and:DI (match_operand:DI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn_and_split "anddi3_and4"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,&r, d,rm, m, m")
|
|
|
-+ (and:DI (match_operand:DI 1 "nonimmediate_operand" "%d,rm, 0, 0, d,rm")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(parallel [(set (match_dup 3)
|
|
|
-+ (and:SI (match_dup 4)
|
|
|
-+ (match_dup 5)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (parallel [(set (match_dup 6)
|
|
|
-+ (and:SI (match_dup 7)
|
|
|
-+ (match_dup 8)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_expand "iorqi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "")
|
|
|
-+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], QImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "iorqi3_or1"
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ or.1\\t%0, %2, %1
|
|
|
-+ or.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_expand "iorhi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "")
|
|
|
-+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], HImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "iorhi3_or2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ or.2\\t%0, %2, %1
|
|
|
-+ or.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_expand "iorsi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 2 "ubicom32_and_or_si3_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ do
|
|
|
-+ {
|
|
|
-+ /* Is this a bset? */
|
|
|
-+ if (CONST_INT_P (operands[2])
|
|
|
-+ && exact_log2 (INTVAL (operands[2])) != -1)
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Must be an or.4 */
|
|
|
-+ if (!ubicom32_data_register_operand (operands[1], SImode))
|
|
|
-+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
|
|
|
-+
|
|
|
-+ if (!ubicom32_arith_operand (operands[2], SImode))
|
|
|
-+ operands[2] = copy_to_mode_reg (SImode, operands[2]);
|
|
|
-+ }
|
|
|
-+ while (0);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "iorsi3_bset"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (ior:SI (match_operand:SI 1 "ubicom32_arith_operand" "%rmI")
|
|
|
-+ (match_operand 2 "const_int_operand" "n")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(exact_log2 (INTVAL (operands[2])) != -1)"
|
|
|
-+ "bset\\t%0, %1, #%d2")
|
|
|
-+
|
|
|
-+(define_insn "iorsi3_or4"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ or.4\\t%0, %2, %1
|
|
|
-+ or.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "iorsi3_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (ior:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ or.4\\t%0, %2, %1
|
|
|
-+ or.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "iorsi3_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ior:SI (match_operand:SI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ or.4\\t#0, %1, %0
|
|
|
-+ or.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "iordi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
|
|
-+ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn_and_split "iordi3_or4"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,&r, d,rm, m, m")
|
|
|
-+ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%d,rm, 0, 0, d,rm")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(parallel [(set (match_dup 3)
|
|
|
-+ (ior:SI (match_dup 4)
|
|
|
-+ (match_dup 5)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (parallel [(set (match_dup 6)
|
|
|
-+ (ior:SI (match_dup 7)
|
|
|
-+ (match_dup 8)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_expand "xorqi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "")
|
|
|
-+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], QImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "xorqi3_xor1"
|
|
|
-+ [(set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "@
|
|
|
-+ xor.1\\t%0, %2, %1
|
|
|
-+ xor.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorqi3_xor1_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:QI 0 "memory_operand" "=m, m")
|
|
|
-+ (xor:QI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "@
|
|
|
-+ xor.1\\t%0, %2, %1
|
|
|
-+ xor.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorqi3_xor1_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:QI (match_operand:QI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:QI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "@
|
|
|
-+ xor.1\\t#0, %1, %0
|
|
|
-+ xor.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "xor1_ccszn_null_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rI"))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "xor.1\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "xor1_ccszn_null_2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (subreg:SI
|
|
|
-+ (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ 0))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "xor.1\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "xor1_ccwzn_null_3"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:QI
|
|
|
-+ (xor:SI (subreg:SI
|
|
|
-+ (match_operand:QI 0 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
|
|
|
-+ 3)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && ubicom32_match_cc_mode(insn, CCSZNmode))"
|
|
|
-+ "xor.1\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "xorhi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "")
|
|
|
-+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (!memory_operand (operands[0], HImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (HImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "xorhi3_xor2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ xor.2\\t%0, %2, %1
|
|
|
-+ xor.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorhi3_xor2_ccszn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:HI 0 "memory_operand" "=m, m")
|
|
|
-+ (xor:HI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "@
|
|
|
-+ xor.2\\t%0, %2, %1
|
|
|
-+ xor.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorhi3_xor2_ccszn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:HI (match_operand:HI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:HI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "@
|
|
|
-+ xor.2\\t#0, %1, %0
|
|
|
-+ xor.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "xor2_ccszn_null_1"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "%d")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rI"))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "xor.2\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "xor2_ccszn_null_2"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (xor:SI (match_operand:SI 0 "ubicom32_data_register_operand" "d")
|
|
|
-+ (subreg:SI
|
|
|
-+ (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ 0))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "xor.2\\t#0, %1, %0")
|
|
|
-+
|
|
|
-+(define_insn "xor2_ccszn_null_3"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (subreg:HI
|
|
|
-+ (xor:SI (subreg:SI
|
|
|
-+ (match_operand:HI 0 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 1 "ubicom32_data_register_operand" "d"))
|
|
|
-+ 2)
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCSZNmode)"
|
|
|
-+ "xor.2\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "xorsi3"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ xor.4\\t%0, %2, %1
|
|
|
-+ xor.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorsi3_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
|
|
|
-+ (xor:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ xor.4\\t%0, %2, %1
|
|
|
-+ xor.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "xorsi3_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (xor:SI (match_operand:SI 0 "nonimmediate_operand" "%d,rm")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "rmI, d"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "@
|
|
|
-+ xor.4\\t#0, %1, %0
|
|
|
-+ xor.4\\t#0, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "xordi3"
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
|
|
-+ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ /* If we have a non-data reg for operand 1 then prefer that over
|
|
|
-+ a CONST_INT in operand 2. */
|
|
|
-+ if (! ubicom32_data_register_operand (operands[1], GET_MODE (operands[1]))
|
|
|
-+ && CONST_INT_P (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+
|
|
|
-+ if (CONST_INT_P (operands[2]) && ! satisfies_constraint_I (operands[2]))
|
|
|
-+ operands[2] = copy_to_mode_reg (DImode, operands[2]);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn_and_split "xordi3_xor4"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,&r, d,rm, m, m")
|
|
|
-+ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%d,rm, 0, 0, d,rm")
|
|
|
-+ (match_operand:DI 2 "ubicom32_arith_operand" "rmI, d,rmI, d,rmI, d")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(parallel [(set (match_dup 3)
|
|
|
-+ (xor:SI (match_dup 4)
|
|
|
-+ (match_dup 5)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (parallel [(set (match_dup 6)
|
|
|
-+ (xor:SI (match_dup 7)
|
|
|
-+ (match_dup 8)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[4] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[5] = gen_lowpart (SImode, operands[2]);
|
|
|
-+ operands[6] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[7] = gen_highpart (SImode, operands[1]);
|
|
|
-+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+(define_insn "not2_2"
|
|
|
-+ [(set (match_operand:HI 0 "memory_operand" "=m")
|
|
|
-+ (subreg:HI
|
|
|
-+ (not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI"))
|
|
|
-+ 2))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "not.2\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "one_cmplsi2"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "not.4\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "one_cmplsi2_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (not:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
|
|
-+ (not:SI (match_dup 1)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "not.4\\t%0, %1")
|
|
|
-+
|
|
|
-+(define_insn "one_cmplsi2_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (not:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI"))
|
|
|
-+ (const_int 0)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "not.4\\t#0, %0")
|
|
|
-+
|
|
|
-+(define_insn_and_split "one_cmpldi2"
|
|
|
-+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&rm")
|
|
|
-+ (not:DI (match_operand:DI 1 "nonimmediate_operand" "rmI0")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel [(set (match_dup 2)
|
|
|
-+ (not:SI (match_dup 3)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])
|
|
|
-+ (parallel [(set (match_dup 4)
|
|
|
-+ (not:SI (match_dup 5)))
|
|
|
-+ (clobber (reg:CC CC_REGNO))])]
|
|
|
-+ "{
|
|
|
-+ operands[2] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[3] = gen_lowpart (SImode, operands[1]);
|
|
|
-+ operands[4] = gen_highpart (SImode, operands[0]);
|
|
|
-+ operands[5] = gen_highpart (SImode, operands[1]);
|
|
|
-+ }"
|
|
|
-+ [(set_attr "length" "8")])
|
|
|
-+
|
|
|
-+; Conditional jump instructions
|
|
|
-+
|
|
|
-+(define_expand "beq"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (eq (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (EQ, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bne"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ne (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (NE, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bgt"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (gt (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (GT, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "ble"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (le (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (LE, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bge"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ge (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (GE, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "blt"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (lt (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (LT, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bgtu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (gtu (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (GTU, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bleu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (leu (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (LEU, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bgeu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (geu (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (GEU, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "bltu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ltu (match_dup 1)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ operands[1] = ubicom32_gen_compare_reg (LTU, ubicom32_compare_op0,
|
|
|
-+ ubicom32_compare_op1);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "jcc"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (match_operator 1 "comparison_operator"
|
|
|
-+ [(match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (const_int 0)])
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ ubicom32_output_cond_jump (insn, operands[1], operands[0]);
|
|
|
-+ return \"\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Reverse branch - reverse our comparison condition so that we can
|
|
|
-+; branch in the opposite sense.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "jcc_reverse"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (match_operator 1 "comparison_operator"
|
|
|
-+ [(match_operand 2 "ubicom32_cc_register_operand" "")
|
|
|
-+ (const_int 0)])
|
|
|
-+ (pc)
|
|
|
-+ (label_ref (match_operand 0 "" ""))))]
|
|
|
-+ ""
|
|
|
-+ "#"
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (match_dup 3)
|
|
|
-+ (label_ref (match_dup 0))
|
|
|
-+ (pc)))]
|
|
|
-+ "{
|
|
|
-+ rtx cc_reg;
|
|
|
-+
|
|
|
-+ cc_reg = gen_rtx_REG (GET_MODE (operands[2]), CC_REGNO);
|
|
|
-+ operands[3] = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
|
|
|
-+ GET_MODE (operands[1]),
|
|
|
-+ cc_reg,
|
|
|
-+ const0_rtx);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "jump"
|
|
|
-+ [(set (pc)
|
|
|
-+ (label_ref (match_operand 0 "" "")))]
|
|
|
-+ ""
|
|
|
-+ "jmpt\\t%l0")
|
|
|
-+
|
|
|
-+(define_expand "indirect_jump"
|
|
|
-+ [(parallel [(set (pc)
|
|
|
-+ (match_operand:SI 0 "register_operand" ""))
|
|
|
-+ (clobber (match_dup 0))])]
|
|
|
-+ ""
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "indirect_jump_internal"
|
|
|
-+ [(set (pc)
|
|
|
-+ (match_operand:SI 0 "register_operand" "a"))
|
|
|
-+ (clobber (match_dup 0))]
|
|
|
-+ ""
|
|
|
-+ "calli\\t%0,0(%0)")
|
|
|
-+
|
|
|
-+; Program Space: The table contains instructions, typically jumps.
|
|
|
-+; CALL An,TABLE_SIZE(PC) ;An = Jump Table Base Address.
|
|
|
-+; <Jump Table is Here> ;An -> Here.
|
|
|
-+; LEA Ak, (An,Dn) ;Ak -> Table Entry
|
|
|
-+; JMP/CALL (Ak)
|
|
|
-+
|
|
|
-+(define_expand "tablejump"
|
|
|
-+ [(parallel [(set (pc)
|
|
|
-+ (match_operand:SI 0 "nonimmediate_operand" ""))
|
|
|
-+ (use (label_ref (match_operand 1 "" "")))])]
|
|
|
-+ ""
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "tablejump_internal"
|
|
|
-+ [(set (pc)
|
|
|
-+ (match_operand:SI 0 "nonimmediate_operand" "rm"))
|
|
|
-+ (use (label_ref (match_operand 1 "" "")))]
|
|
|
-+ ""
|
|
|
-+ "ret\\t%0")
|
|
|
-+
|
|
|
-+; Call subroutine with no return value.
|
|
|
-+;
|
|
|
-+(define_expand "call"
|
|
|
-+ [(call (match_operand:QI 0 "general_operand" "")
|
|
|
-+ (match_operand:SI 1 "general_operand" ""))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (TARGET_FDPIC)
|
|
|
-+ {
|
|
|
-+ ubicom32_expand_call_fdpic (operands);
|
|
|
-+ DONE;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (! ubicom32_call_address_operand (XEXP (operands[0], 0), VOIDmode))
|
|
|
-+ XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; We expand to a simple form that doesn't clobber the link register and
|
|
|
-+; then split to a form that does. This allows the RTL optimizers that
|
|
|
-+; run before the splitter to have the opportunity to eliminate the call
|
|
|
-+; without marking A5 as being clobbered and this in turn avoids saves
|
|
|
-+; and returns in a number of cases.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "call_1"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 1 "general_operand" "g,g"))]
|
|
|
-+ "! TARGET_FDPIC"
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel
|
|
|
-+ [(call (mem:QI (match_dup 0))
|
|
|
-+ (match_dup 1))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "call_slow"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 1 "general_operand" "g,g"))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "(! TARGET_FDPIC && ! TARGET_FASTCALL)"
|
|
|
-+ "@
|
|
|
-+ calli\\ta5, 0(%0)
|
|
|
-+ moveai\\ta5, #%%hi(%C0)\;calli\\ta5, %%lo(%C0)(a5)")
|
|
|
-+
|
|
|
-+(define_insn "call_fast"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 1 "general_operand" "g,g"))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "(! TARGET_FDPIC && TARGET_FASTCALL)"
|
|
|
-+ "@
|
|
|
-+ calli\\ta5, 0(%0)
|
|
|
-+ call\\ta5, %C0")
|
|
|
-+
|
|
|
-+; We expand to a simple form that doesn't clobber the link register and
|
|
|
-+; then split to a form that does. This allows the RTL optimizers that
|
|
|
-+; run before the splitter to have the opportunity to eliminate the call
|
|
|
-+; without marking A5 as being clobbered and this in turn avoids saves
|
|
|
-+; and returns in a number of cases.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "call_fdpic"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 1 "general_operand" "g,g"))
|
|
|
-+ (use (match_operand:SI 2 "ubicom32_fdpic_operand" "Z,Z"))]
|
|
|
-+ "TARGET_FDPIC"
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel
|
|
|
-+ [(call (mem:QI (match_dup 0))
|
|
|
-+ (match_dup 1))
|
|
|
-+ (use (match_dup 2))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "call_fdpic_clobber"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 1 "general_operand" "g,g"))
|
|
|
-+ (use (match_operand:SI 2 "ubicom32_fdpic_operand" "Z,Z"))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "TARGET_FDPIC"
|
|
|
-+ "@
|
|
|
-+ move.4\\ta5, 0(%0)\;move.4\\t%2, 4(%0)\;calli\\ta5, 0(a5)
|
|
|
-+ call\\ta5, %C0")
|
|
|
-+
|
|
|
-+; Call subroutine, returning value in operand 0
|
|
|
-+; (which must be a hard register).
|
|
|
-+;
|
|
|
-+(define_expand "call_value"
|
|
|
-+ [(set (match_operand 0 "" "")
|
|
|
-+ (call (match_operand:QI 1 "general_operand" "")
|
|
|
-+ (match_operand:SI 2 "general_operand" "")))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ if (TARGET_FDPIC)
|
|
|
-+ {
|
|
|
-+ ubicom32_expand_call_value_fdpic (operands);
|
|
|
-+ DONE;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (! ubicom32_call_address_operand (XEXP (operands[1], 0), VOIDmode))
|
|
|
-+ XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; We expand to a simple form that doesn't clobber the link register and
|
|
|
-+; then split to a form that does. This allows the RTL optimizers that
|
|
|
-+; run before the splitter to have the opportunity to eliminate the call
|
|
|
-+; without marking A5 as being clobbered and this in turn avoids saves
|
|
|
-+; and returns in a number of cases.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "call_value_1"
|
|
|
-+ [(set (match_operand 0 "register_operand" "=r,r")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 2 "general_operand" "g,g")))]
|
|
|
-+ "! TARGET_FDPIC"
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (call (mem:QI (match_dup 1))
|
|
|
-+ (match_dup 2)))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "call_value_slow"
|
|
|
-+ [(set (match_operand 0 "register_operand" "=r,r")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 2 "general_operand" "g,g")))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "(! TARGET_FDPIC && ! TARGET_FASTCALL)"
|
|
|
-+ "@
|
|
|
-+ calli\\ta5, 0(%1)
|
|
|
-+ moveai\\ta5, #%%hi(%C1)\;calli\\ta5, %%lo(%C1)(a5)")
|
|
|
-+
|
|
|
-+(define_insn "call_value_fast"
|
|
|
-+ [(set (match_operand 0 "register_operand" "=r,r")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 2 "general_operand" "g,g")))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "(! TARGET_FDPIC && TARGET_FASTCALL)"
|
|
|
-+ "@
|
|
|
-+ calli\\ta5, 0(%1)
|
|
|
-+ call\\ta5, %C1")
|
|
|
-+
|
|
|
-+; We expand to a simple form that doesn't clobber the link register and
|
|
|
-+; then split to a form that does. This allows the RTL optimizers that
|
|
|
-+; run before the splitter to have the opportunity to eliminate the call
|
|
|
-+; without marking A5 as being clobbered and this in turn avoids saves
|
|
|
-+; and returns in a number of cases.
|
|
|
-+;
|
|
|
-+(define_insn_and_split "call_value_fdpic"
|
|
|
-+ [(set (match_operand 0 "register_operand" "=r,r")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 2 "general_operand" "g,g")))
|
|
|
-+ (use (match_operand:SI 3 "ubicom32_fdpic_operand" "Z,Z"))]
|
|
|
-+ "TARGET_FDPIC"
|
|
|
-+ "#"
|
|
|
-+ ""
|
|
|
-+ [(parallel
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (call (mem:QI (match_dup 1))
|
|
|
-+ (match_dup 2)))
|
|
|
-+ (use (match_dup 3))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))])]
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "call_value_fdpic_clobber"
|
|
|
-+ [(set (match_operand 0 "register_operand" "=r,r")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "ubicom32_call_address_operand" "a,S"))
|
|
|
-+ (match_operand:SI 2 "general_operand" "g,g")))
|
|
|
-+ (use (match_operand:SI 3 "ubicom32_fdpic_operand" "Z,Z"))
|
|
|
-+ (clobber (reg:SI LINK_REGNO))]
|
|
|
-+ "TARGET_FDPIC"
|
|
|
-+ "@
|
|
|
-+ move.4\\ta5, 0(%1)\;move.4\\t%3, 4(%1)\;calli\\ta5, 0(a5)
|
|
|
-+ call\\ta5, %C1")
|
|
|
-+
|
|
|
-+(define_expand "untyped_call"
|
|
|
-+ [(parallel [(call (match_operand 0 "" "")
|
|
|
-+ (const_int 0))
|
|
|
-+ (match_operand 1 "" "")
|
|
|
-+ (match_operand 2 "" "")])]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+ emit_call_insn (gen_call (operands[0], const0_rtx));
|
|
|
-+
|
|
|
-+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
|
|
-+ {
|
|
|
-+ rtx set = XVECEXP (operands[2], 0, i);
|
|
|
-+ emit_move_insn (SET_DEST (set), SET_SRC (set));
|
|
|
-+ }
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "lsl1_1"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashift:SI (subreg:SI
|
|
|
-+ (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "lsl.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+; The combiner gets rather creative about left shifts of sub-word memory
|
|
|
-+; operands because it's uncertain about whether the memory is sign or
|
|
|
-+; zero extended. It only wants zero-extended behaviour and so throws
|
|
|
-+; in an extra and operation.
|
|
|
-+;
|
|
|
-+(define_insn "lsl1_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (and:SI
|
|
|
-+ (ashift:SI (subreg:SI
|
|
|
-+ (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M"))
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "n")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && INTVAL (operands[3]) == (0xff << INTVAL (operands[2])))"
|
|
|
-+ "lsl.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "lsl2_1"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashift:SI (subreg:SI
|
|
|
-+ (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "lsl.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+; The combiner gets rather creative about left shifts of sub-word memory
|
|
|
-+; operands because it's uncertain about whether the memory is sign or
|
|
|
-+; zero extended. It only wants zero-extended behaviour and so throws
|
|
|
-+; in an extra and operation.
|
|
|
-+;
|
|
|
-+(define_insn "lsl2_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (and:SI
|
|
|
-+ (ashift:SI (subreg:SI
|
|
|
-+ (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M"))
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "n")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && INTVAL (operands[3]) == (0xffff << INTVAL (operands[2])))"
|
|
|
-+ "lsl.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "ashlsi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashift:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "lsl.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "lshlsi3_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ashift:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashift:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "lsl.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "lshlsi3_ccwz_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ashift:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "lsl.4\\t%2, %0, %1")
|
|
|
-+
|
|
|
-+; The combiner finds this canonical form for what is in essence a right
|
|
|
-+; shift.
|
|
|
-+;
|
|
|
-+(define_insn "asr1_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (sign_extract:SI (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M")
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "M")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[2]) + INTVAL (operands[3]) == 8))"
|
|
|
-+ "asr.1\\t%0, %1, %3")
|
|
|
-+
|
|
|
-+; The combiner finds this canonical form for what is in essence a right
|
|
|
-+; shift.
|
|
|
-+;
|
|
|
-+(define_insn "asr2_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (sign_extract:SI (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M")
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "M")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[2]) + INTVAL (operands[3]) == 16))"
|
|
|
-+ "asr.2\\t%0, %1, %3")
|
|
|
-+
|
|
|
-+(define_insn "ashrsi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmJ")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "asr.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "ashrsi3_ccwzn"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ashiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmJ")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ashiftrt:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "asr.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "ashrsi3_ccwzn_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (ashiftrt:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmJ")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZNmode)"
|
|
|
-+ "asr.4\\t%2, %0, %1")
|
|
|
-+
|
|
|
-+(define_insn "lsr1_1"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (lshiftrt:SI (subreg:SI
|
|
|
-+ (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "lsr.1\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+; The combiner finds this canonical form for what is in essence a right
|
|
|
-+; shift.
|
|
|
-+;
|
|
|
-+(define_insn "lsr1_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (zero_extract:SI (match_operand:QI 1 "memory_operand" "m")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M")
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "M")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[2]) + INTVAL (operands[3]) == 8))"
|
|
|
-+ "lsr.1\\t%0, %1, %3")
|
|
|
-+
|
|
|
-+(define_insn "lsr2_1"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (lshiftrt:SI (subreg:SI
|
|
|
-+ (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ 0)
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4)"
|
|
|
-+ "lsr.2\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+; The combiner finds this canonical form for what is in essence a right
|
|
|
-+; shift.
|
|
|
-+;
|
|
|
-+(define_insn "lsr2_2"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (zero_extract:SI (match_operand:HI 1 "memory_operand" "m")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "M")
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "M")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ "(ubicom32_v4
|
|
|
-+ && (INTVAL (operands[2]) + INTVAL (operands[3]) == 16))"
|
|
|
-+ "lsr.2\\t%0, %1, %3")
|
|
|
-+
|
|
|
-+(define_insn "lshrsi3"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (lshiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM")))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "lsr.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "lshrsi3_ccwz"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (lshiftrt:SI (match_operand:SI 1 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 2 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (lshiftrt:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "lsr.4\\t%0, %1, %2")
|
|
|
-+
|
|
|
-+(define_insn "lshrsi3_ccwz_null"
|
|
|
-+ [(set (reg CC_REGNO)
|
|
|
-+ (compare
|
|
|
-+ (lshiftrt:SI (match_operand:SI 0 "ubicom32_arith_operand" "rmI")
|
|
|
-+ (match_operand:SI 1 "ubicom32_arith_operand" "dM"))
|
|
|
-+ (const_int 0)))
|
|
|
-+ (clobber (match_scratch:SI 2 "=d"))]
|
|
|
-+ "ubicom32_match_cc_mode(insn, CCWZmode)"
|
|
|
-+ "lsr.4\\t%2, %0, %1")
|
|
|
-+
|
|
|
-+(define_expand "prologue"
|
|
|
-+ [(const_int 0)]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_expand_prologue ();
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "epilogue"
|
|
|
-+ [(return)]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_expand_epilogue ();
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "return"
|
|
|
-+ [(return)]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_expand_epilogue ();
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_expand "_eh_return"
|
|
|
-+ [(use (match_operand:SI 0 "register_operand" "r"))
|
|
|
-+ (use (match_operand:SI 1 "register_operand" "r"))]
|
|
|
-+ ""
|
|
|
-+ "{
|
|
|
-+ ubicom32_expand_eh_return (operands);
|
|
|
-+ DONE;
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; XXX - it looks almost certain that we could make return_internal use a Dn
|
|
|
-+; register too. In that instance we'd have to use a ret instruction
|
|
|
-+; rather than a calli but it might save cycles.
|
|
|
-+;
|
|
|
-+(define_insn "return_internal"
|
|
|
-+ [(const_int 2)
|
|
|
-+ (return)
|
|
|
-+ (use (match_operand:SI 0 "ubicom32_mem_or_address_register_operand" "rm"))]
|
|
|
-+ ""
|
|
|
-+ "*
|
|
|
-+ {
|
|
|
-+ if (REG_P (operands[0]) && REGNO (operands[0]) == LINK_REGNO
|
|
|
-+ && ubicom32_can_use_calli_to_ret)
|
|
|
-+ return \"calli\\t%0, 0(%0)\";
|
|
|
-+
|
|
|
-+ return \"ret\\t%0\";
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+(define_insn "return_from_post_modify_sp"
|
|
|
-+ [(parallel
|
|
|
-+ [(const_int 2)
|
|
|
-+ (return)
|
|
|
-+ (use (mem:SI (post_modify:SI
|
|
|
-+ (reg:SI SP_REGNO)
|
|
|
-+ (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_operand:SI 0 "const_int_operand" "n")))))])]
|
|
|
-+ "INTVAL (operands[0]) >= 4 && INTVAL (operands[0]) <= 7 * 4"
|
|
|
-+ "ret\\t(sp)%E0++")
|
|
|
-+
|
|
|
-+;(define_insn "eh_return_internal"
|
|
|
-+; [(const_int 4)
|
|
|
-+; (return)
|
|
|
-+; (use (reg:SI 34))]
|
|
|
-+; ""
|
|
|
-+; "ret\\ta2")
|
|
|
-+
|
|
|
-+; No operation, needed in case the user uses -g but not -O.
|
|
|
-+(define_expand "nop"
|
|
|
-+ [(const_int 0)]
|
|
|
-+ ""
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "nop_internal"
|
|
|
-+ [(const_int 0)]
|
|
|
-+ ""
|
|
|
-+ "nop")
|
|
|
-+
|
|
|
-+; The combiner will generate this pattern given shift and add operations.
|
|
|
-+; The canonical form that the combiner wants to use appears to be multiplies
|
|
|
-+; instead of shifts even if the compiled sources use shifts.
|
|
|
-+;
|
|
|
-+(define_insn "shmrg1_add"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (plus:SI
|
|
|
-+ (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 256))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI"))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "shmrg.1\\t%0, %2, %1")
|
|
|
-+
|
|
|
-+; The combiner will generate this pattern given shift and or operations.
|
|
|
-+;
|
|
|
-+(define_insn "shmrg1_ior"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 8))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_operand:QI 2 "ubicom32_arith_operand" "rmI"))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "shmrg.1\\t%0, %2, %1")
|
|
|
-+
|
|
|
-+; The combiner will generate this pattern given shift and add operations.
|
|
|
-+; The canonical form that the combiner wants to use appears to be multiplies
|
|
|
-+; instead of shifts even if the compiled sources use shifts.
|
|
|
-+;
|
|
|
-+(define_insn "shmrg2_add"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (plus:SI
|
|
|
-+ (mult:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 65536))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI"))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "shmrg.2\\t%0, %2, %1")
|
|
|
-+
|
|
|
-+; The combiner will generate this pattern given shift and or operations.
|
|
|
-+;
|
|
|
-+(define_insn "shmrg2_ior"
|
|
|
-+ [(set (match_operand:SI 0 "ubicom32_data_register_operand" "=d")
|
|
|
-+ (ior:SI
|
|
|
-+ (ashift:SI (match_operand:SI 1 "ubicom32_data_register_operand" "d")
|
|
|
-+ (const_int 16))
|
|
|
-+ (zero_extend:SI
|
|
|
-+ (match_operand:HI 2 "ubicom32_arith_operand" "rmI"))))
|
|
|
-+ (clobber (reg:CC CC_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "shmrg.2\\t%0, %2, %1")
|
|
|
-+
|
|
|
-+; Match the case where we load a word from the stack but then discard the
|
|
|
-+; upper 16 bits. We turn this into a zero-extended load of that useful
|
|
|
-+; 16 bits direct from the stack where possible.
|
|
|
-+;
|
|
|
-+
|
|
|
-+; XXX - do these peephole2 ops actually work after the CCmode conversion?
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (mem:SI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))))
|
|
|
-+ (set (match_operand:SI 2 "nonimmediate_operand" "")
|
|
|
-+ (zero_extend:SI (match_operand:HI 3 "register_operand" "")))]
|
|
|
-+ "(INTVAL (operands[1]) <= 252
|
|
|
-+ && REGNO (operands[3]) == REGNO (operands[0])
|
|
|
-+ && ((peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && ! reg_mentioned_p (operands[0], operands[2]))
|
|
|
-+ || rtx_equal_p (operands[0], operands[2])))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (zero_extend:SI (mem:HI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_dup 4)))))]
|
|
|
-+ "{
|
|
|
-+ operands[4] = GEN_INT (INTVAL (operands[1]) + 2);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Match the case where we load a word from the stack but then discard the
|
|
|
-+; upper 16 bits. We turn this into a 16-bit load of that useful
|
|
|
-+; 16 bits direct from the stack where possible.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (mem:SI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))))
|
|
|
-+ (set (match_operand:HI 2 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 3 "register_operand" ""))]
|
|
|
-+ "(INTVAL (operands[1]) <= 252
|
|
|
-+ && REGNO (operands[3]) == REGNO (operands[0])
|
|
|
-+ && ((peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && ! reg_mentioned_p (operands[0], operands[2]))
|
|
|
-+ || rtx_equal_p (operands[0], operands[2])))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mem:HI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_dup 4))))]
|
|
|
-+ "{
|
|
|
-+ operands[4] = GEN_INT (INTVAL (operands[1]) + 2);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Match the case where we load a word from the stack but then discard the
|
|
|
-+; upper 24 bits. We turn this into a zero-extended load of that useful
|
|
|
-+; 8 bits direct from the stack where possible.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (mem:SI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))))
|
|
|
-+ (set (match_operand:SI 2 "nonimmediate_operand" "")
|
|
|
-+ (zero_extend:SI (match_operand:QI 3 "register_operand" "")))]
|
|
|
-+ "(INTVAL (operands[1]) <= 124
|
|
|
-+ && REGNO (operands[3]) == REGNO (operands[0])
|
|
|
-+ && ((peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && ! reg_mentioned_p (operands[0], operands[2]))
|
|
|
-+ || rtx_equal_p (operands[0], operands[2])))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (zero_extend:SI (mem:QI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_dup 4)))))]
|
|
|
-+ "{
|
|
|
-+ operands[4] = GEN_INT (INTVAL (operands[1]) + 3);
|
|
|
-+ }")
|
|
|
-+
|
|
|
-+; Match the case where we load a word from the stack but then discard the
|
|
|
-+; upper 24 bits. We turn this into an 8-bit load of that useful
|
|
|
-+; 8 bits direct from the stack where possible.
|
|
|
-+;
|
|
|
-+(define_peephole2
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (mem:SI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_operand:SI 1 "const_int_operand" ""))))
|
|
|
-+ (set (match_operand:QI 2 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 3 "register_operand" ""))]
|
|
|
-+ "(INTVAL (operands[1]) <= 124
|
|
|
-+ && REGNO (operands[3]) == REGNO (operands[0])
|
|
|
-+ && ((peep2_reg_dead_p (2, operands[0])
|
|
|
-+ && ! reg_mentioned_p (operands[0], operands[2]))
|
|
|
-+ || rtx_equal_p (operands[0], operands[2])))"
|
|
|
-+ [(set (match_dup 2)
|
|
|
-+ (mem:QI (plus:SI (reg:SI SP_REGNO)
|
|
|
-+ (match_dup 4))))]
|
|
|
-+ "{
|
|
|
-+ operands[4] = GEN_INT (INTVAL (operands[1]) + 3);
|
|
|
-+ }")
|
|
|
-+
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/ubicom32.opt
|
|
|
-@@ -0,0 +1,27 @@
|
|
|
-+mdebug-address
|
|
|
-+Target RejectNegative Report Undocumented Mask(DEBUG_ADDRESS)
|
|
|
-+Debug addresses
|
|
|
-+
|
|
|
-+mdebug-context
|
|
|
-+Target RejectNegative Report Undocumented Mask(DEBUG_CONTEXT)
|
|
|
-+Debug contexts
|
|
|
-+
|
|
|
-+march=
|
|
|
-+Target Report Var(ubicom32_arch_name) Init("ubicom32v4") Joined
|
|
|
-+Specify the name of the target architecture
|
|
|
-+
|
|
|
-+mfdpic
|
|
|
-+Target Report Mask(FDPIC)
|
|
|
-+Enable Function Descriptor PIC mode
|
|
|
-+
|
|
|
-+minline-plt
|
|
|
-+Target Report Mask(INLINE_PLT)
|
|
|
-+Enable inlining of PLT in function calls
|
|
|
-+
|
|
|
-+mfastcall
|
|
|
-+Target Report Mask(FASTCALL)
|
|
|
-+Enable default fast (call) calling sequence for smaller applications
|
|
|
-+
|
|
|
-+mipos-abi
|
|
|
-+Target Report Mask(IPOS_ABI)
|
|
|
-+Enable the ipOS ABI in which D10-D13 are caller-clobbered
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/uclinux.h
|
|
|
-@@ -0,0 +1,67 @@
|
|
|
-+/* Definitions of target machine for Ubicom32-uclinux
|
|
|
-+
|
|
|
-+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
|
|
-+ 2009 Free Software Foundation, Inc.
|
|
|
-+ Contributed by Ubicom, Inc.
|
|
|
-+
|
|
|
-+ This file is part of GCC.
|
|
|
-+
|
|
|
-+ GCC is free software; you can redistribute it and/or modify it
|
|
|
-+ under the terms of the GNU General Public License as published
|
|
|
-+ by the Free Software Foundation; either version 3, or (at your
|
|
|
-+ option) any later version.
|
|
|
-+
|
|
|
-+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
|
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
-+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
-+ License for more details.
|
|
|
-+
|
|
|
-+ You should have received a copy of the GNU General Public License
|
|
|
-+ along with GCC; see the file COPYING3. If not see
|
|
|
-+ <http://www.gnu.org/licenses/>. */
|
|
|
-+
|
|
|
-+/* Don't assume anything about the header files. */
|
|
|
-+#define NO_IMPLICIT_EXTERN_C
|
|
|
-+
|
|
|
-+#undef LIB_SPEC
|
|
|
-+#define LIB_SPEC \
|
|
|
-+ "%{pthread:-lpthread} " \
|
|
|
-+ "%{!shared:%{!symbolic: -lc}} "
|
|
|
-+
|
|
|
-+
|
|
|
-+#undef LINK_GCC_C_SEQUENCE_SPEC
|
|
|
-+#define LINK_GCC_C_SEQUENCE_SPEC \
|
|
|
-+ "%{!shared:--start-group} %G %L %{!shared:--end-group}%{shared:%G} "
|
|
|
-+
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#define STARTFILE_SPEC \
|
|
|
-+ "%{!shared: crt1%O%s}" \
|
|
|
-+ " crti%O%s crtbegin%O%s"
|
|
|
-+
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+#define ENDFILE_SPEC "crtend%O%s crtn%O%s"
|
|
|
-+
|
|
|
-+/* This macro applies on top of OBJECT_FORMAT_ELF and indicates that
|
|
|
-+ we want to support both flat and ELF output. */
|
|
|
-+#define OBJECT_FORMAT_FLAT
|
|
|
-+
|
|
|
-+#undef DRIVER_SELF_SPECS
|
|
|
-+#define DRIVER_SELF_SPECS \
|
|
|
-+ "%{!mno-fastcall:-mfastcall}"
|
|
|
-+
|
|
|
-+/* taken from linux.h */
|
|
|
-+/* The GNU C++ standard library requires that these macros be defined. */
|
|
|
-+#undef CPLUSPLUS_CPP_SPEC
|
|
|
-+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
|
|
|
-+
|
|
|
-+#define TARGET_OS_CPP_BUILTINS() \
|
|
|
-+ do { \
|
|
|
-+ builtin_define_std ("__UBICOM32__"); \
|
|
|
-+ builtin_define_std ("__ubicom32__"); \
|
|
|
-+ builtin_define ("__gnu_linux__"); \
|
|
|
-+ builtin_define_std ("linux"); \
|
|
|
-+ builtin_define_std ("unix"); \
|
|
|
-+ builtin_assert ("system=linux"); \
|
|
|
-+ builtin_assert ("system=unix"); \
|
|
|
-+ builtin_assert ("system=posix"); \
|
|
|
-+ } while (0)
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/ubicom32/xm-ubicom32.h
|
|
|
-@@ -0,0 +1,36 @@
|
|
|
-+/* Configuration for Ubicom's Ubicom32 architecture.
|
|
|
-+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software
|
|
|
-+ Foundation, Inc.
|
|
|
-+ Contributed by Ubicom Inc.
|
|
|
-+
|
|
|
-+This file is part of GNU CC.
|
|
|
-+
|
|
|
-+GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GNU CC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+/* #defines that need visibility everywhere. */
|
|
|
-+#define FALSE 0
|
|
|
-+#define TRUE 1
|
|
|
-+
|
|
|
-+/* This describes the machine the compiler is hosted on. */
|
|
|
-+#define HOST_BITS_PER_CHAR 8
|
|
|
-+#define HOST_BITS_PER_SHORT 16
|
|
|
-+#define HOST_BITS_PER_INT 32
|
|
|
-+#define HOST_BITS_PER_LONG 32
|
|
|
-+#define HOST_BITS_PER_LONGLONG 64
|
|
|
-+
|
|
|
-+/* Arguments to use with `exit'. */
|
|
|
-+#define SUCCESS_EXIT_CODE 0
|
|
|
-+#define FATAL_EXIT_CODE 33
|
|
|
---- a/gcc/config.gcc
|
|
|
-+++ b/gcc/config.gcc
|
|
|
-@@ -2503,6 +2503,34 @@ tilepro-*-linux*)
|
|
|
- c_target_objs="tilepro-c.o"
|
|
|
- cxx_target_objs="tilepro-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
|
|
|
-+ ;;
|
|
|
- v850*-*-*)
|
|
|
- case ${target} in
|
|
|
- v850e2v3-*-*)
|
|
|
---- a/libgcc/config.host
|
|
|
-+++ b/libgcc/config.host
|
|
|
-@@ -1098,6 +1098,15 @@ tilepro-*-linux*)
|
|
|
- tmake_file="${tmake_file} tilepro/t-crtstuff t-softfp-sfdf t-softfp tilepro/t-tilepro"
|
|
|
- md_unwind_header=tilepro/linux-unwind.h
|
|
|
- ;;
|
|
|
-+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"
|
|
|
-+ ;;
|
|
|
- v850*-*-*)
|
|
|
- tmake_file="v850/t-v850 t-fdpbit"
|
|
|
- ;;
|