From 5d6038e64dd355b12f4bdba070c5d4d3054505c5 Mon Sep 17 00:00:00 2001 From: veos-sxarr Date: Fri, 19 Feb 2021 18:34:31 +0900 Subject: [PATCH] Import gcc-ve-7.1.0-6 --- .gitattributes | 2 + README.md | 66 + config.sub | 8 + gcc/common/config/ve/ve-common.c | 41 + gcc/config.gcc | 8 + gcc/config/ve/constraints.md | 94 + gcc/config/ve/linux.h | 79 + gcc/config/ve/predicates.md | 182 + gcc/config/ve/t-ve | 7 + gcc/config/ve/ve-modes.def | 28 + gcc/config/ve/ve-opts.h | 31 + gcc/config/ve/ve-protos.h | 89 + gcc/config/ve/ve-stdint.h | 52 + gcc/config/ve/ve.c | 3004 +++++++++++++ gcc/config/ve/ve.h | 1134 +++++ gcc/config/ve/ve.md | 4438 ++++++++++++++++++++ gcc/config/ve/ve.opt | 102 + gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/loop-1.c | 2 +- gcc/testsuite/lib/file-format.exp | 5 + gcc/testsuite/lib/target-supports.exp | 5 + include/longlong.h | 7 + libgcc/config.host | 5 + libgcc/config/ve/divtf3.c | 91 + libgcc/config/ve/dso_handle.c | 27 + libgcc/config/ve/lib1funcs.S | 708 ++++ libgcc/config/ve/modti.c | 48 + libgcc/config/ve/t-ve | 15 + libgcc/config/ve/unwind-ve.c | 70 + libgfortran/configure | 13 + libstdc++-v3/configure | 9 + libstdc++-v3/configure.ac | 7 + 32 files changed, 10377 insertions(+), 2 deletions(-) create mode 100644 README.md create mode 100644 gcc/common/config/ve/ve-common.c create mode 100644 gcc/config/ve/constraints.md create mode 100644 gcc/config/ve/linux.h create mode 100644 gcc/config/ve/predicates.md create mode 100644 gcc/config/ve/t-ve create mode 100644 gcc/config/ve/ve-modes.def create mode 100644 gcc/config/ve/ve-opts.h create mode 100644 gcc/config/ve/ve-protos.h create mode 100644 gcc/config/ve/ve-stdint.h create mode 100644 gcc/config/ve/ve.c create mode 100644 gcc/config/ve/ve.h create mode 100644 gcc/config/ve/ve.md create mode 100644 gcc/config/ve/ve.opt create mode 100644 libgcc/config/ve/divtf3.c create mode 100644 libgcc/config/ve/dso_handle.c create mode 100644 libgcc/config/ve/lib1funcs.S create mode 100644 libgcc/config/ve/modti.c create mode 100644 libgcc/config/ve/t-ve create mode 100644 libgcc/config/ve/unwind-ve.c diff --git a/.gitattributes b/.gitattributes index b38d7f1b43b..3ec5e7bc28b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ *.{c,C,cc,h} whitespace=indent-with-non-tab,space-before-tab,trailing-space +.gitignore export-ignore +.gitattributes export-ignore diff --git a/README.md b/README.md new file mode 100644 index 00000000000..b6acc91253d --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ + +# gcc for VE + +gcc for VE is developed based on gcc (the GNU Compiler Collection) version 7.1.0. +User can compile a program for Vector Engine by using this software. +Please read this document carefully before use. + +##### What is VE + +VE stands for Vector Engine which is vector processors of [SX-Aurora TSUBASA](https://www.nec.com/en/global/solutions/hpc/sx/index.html). + + +## Notice + + 1. This software needs binutils for VE. It is available on the [SX-Aurora + TSUBASA yum repository including SDK runtime](https://www.hpc.nec/repos/runtime/sdk/) for free. + 2. This software can compile only C language. + - Only C compiler is available. + 3. This software can't generate vector instructions. + 4. It is required to use ncc, nc++, or nfort which are compilers for SX-Aurora + TSUBASA to link objects compiled by ncc, nc++ or nfort. + 5. This software is developed only for the purpose to build glibc for VE. + Please note that NEC verified only the functionality required for it. + 6. NEC doesn't support this software as the SX-Aurora TSUBASA product software. + Please note that NEC is not obligated to respond if user sends a bug report. + +## Known Issues + + 1. A binary may malfunction when optimize options are enabled. In such case, + use '-O0' option. + 2. Gcc for VE is installed to /opt/nec/ve/bin/gcc. + When user set /opt/nec/ve/bin in $PATH before /usr/bin, /opt/nec/ve/bin/gcc + is invoked instead of /usr/bin/gcc. + - NEC MPI setup script adds /opt/nec/ve/bin into the head of $PATH. Therefore, + a build of VH side MPI program fails. + - A command expecting /usr/bin/gcc may invoke /opt/nec/ve/bin/gcc. + +## Disclaimer + + 1. The contents of this document may change without prior notice. + 2. NEC assumes no liability for any loss, including loss of earnings, + arising from the use of this software. + 3. This software is not intended for use in medical, nuclear, aerospace, mass + transit or other applications where human life may be at stake or high + reliability is required, nor is it intended for use in controlling such + applications. We disclaim liability for any personal injury and property + damages caused by such use of this software. + +## Installation + +Please refer to [releases](https://github.com/veos-sxarr-NEC/gcc-ve/releases). + +## License + +Gcc for VE is distributed under the GNU General Public License, version 3. + +## Bug Report and Sharing of Information + +* [Issues](https://github.com/veos-sxarr-NEC/gcc-ve/issues) of this project +* [Aurora Web Forum](https://www.hpc.nec/forums/) + + + + + + diff --git a/config.sub b/config.sub index 62b82599d98..5a200657d75 100755 --- a/config.sub +++ b/config.sub @@ -24,6 +24,7 @@ timestamp='2016-12-24' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). +# Changes by NEC Corporation for the VE port, 2017-2021 # Please send patches to . # @@ -1332,6 +1333,9 @@ case $basic_machine in pmac | pmac-mpw) basic_machine=powerpc-apple ;; + ve | ve-nec) + basic_machine=ve-nec + ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; @@ -1737,6 +1741,10 @@ case $basic_machine in *-atari*) os=-mint ;; + ve-nec) + os=-linux + vendor=nec + ;; *) os=-none ;; diff --git a/gcc/common/config/ve/ve-common.c b/gcc/common/config/ve/ve-common.c new file mode 100644 index 00000000000..379c03dd153 --- /dev/null +++ b/gcc/common/config/ve/ve-common.c @@ -0,0 +1,41 @@ +/* Common hooks for NEC VE. + Copyright (C) 1998-2017 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "common/common-target.h" +#include "common/common-target-def.h" + +/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ +static const struct default_options ve_option_optimization_table[] = + { + { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, + { OPT_LEVELS_NONE, 0, NULL, 0 } + }; + +#undef TARGET_OPTION_OPTIMIZATION_TABLE +#define TARGET_OPTION_OPTIMIZATION_TABLE ve_option_optimization_table + +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info + +struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; diff --git a/gcc/config.gcc b/gcc/config.gcc index b8bb4d65825..e3b69261c02 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -17,6 +17,8 @@ #along with GCC; see the file COPYING3. If not see #. +# Changes by NEC Corporation for the VE port, 2017-2021 + # This is the GCC target-specific configuration file # where a configuration type is mapped to different system-specific # definitions and files. This is invoked by the autoconf-generated @@ -496,6 +498,9 @@ tilegx*-*-*) tilepro*-*-*) cpu_type=tilepro ;; +ve-*-*) + cpu_type=ve + ;; esac tm_file=${cpu_type}/${cpu_type}.h @@ -3043,6 +3048,9 @@ m32c-*-elf*) c_target_objs="m32c-pragma.o" cxx_target_objs="m32c-pragma.o" ;; +ve-*-*) + tm_file="${tm_file} ve/linux.h ve/ve-stdint.h" + ;; *) echo "*** Configuration ${target} not supported" 1>&2 exit 1 diff --git a/gcc/config/ve/constraints.md b/gcc/config/ve/constraints.md new file mode 100644 index 00000000000..ca978e187fa --- /dev/null +++ b/gcc/config/ve/constraints.md @@ -0,0 +1,94 @@ +;; Machine description for VE architecture. +;; Copyright (C) 2009-2016 Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; Changes by NEC Corporation for the VE port, 2017-2021 + +;; Register constraints. +;(define_register_constraint "f" "S_REGS" +; "Single precision floating point registers. Same as r.") + +(define_register_constraint "U" "QS_REGS" + "Upper quadruple floating point registers, that is, even number registers.") + +;;;; Memory constraints +(define_memory_constraint "a" + "Memory address. Replaces 'm'" + (match_code "mem")) + +;; Integer constant constraints. +(define_constraint "I" + "Integer constant in the range -64 @dots{} 63" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, -64, 63)"))) + +(define_constraint "J" + "Integer constant in the range 0 @dots{} 31" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 31)"))) + +(define_constraint "K" + "Integer constant in the range 0 @dots{} 63" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 63)"))) + +(define_constraint "L" + "Integer constant in the range 0 @dots{} 127" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 127)"))) + +(define_constraint "M" + "Integer constant of 64 bit M format" + (and (match_code "const_int") + (match_test "(ival & (ival+1)) == 0 || + (~ival & (~ival +1)) ==0"))) + +(define_constraint "N" + "Integer constant of 32 bit" + (and (match_code "const_int") + (match_test "ival >= -2147483647LL-1 + && ival <= 2147483647LL"))) + +(define_constraint "O" + "Integer constant of signed 32 bit M format" + (and (match_code "const_int") + (match_test "(ival >= -2147483647LL-1 && ival <= 2147483647LL) + && (( (ival & (ival + 1)) == 0) + || (( ( 0xffffffffLL^(0xffffffffLL&ival)) + & ((0xffffffffLL^(0xffffffffLL&ival)) +1) ) == 0))"))) + +(define_constraint "P" + "Integer constant of unsigned 32 bit M format" + (and (match_code "const_int") + (match_test "ival == 0 || ival == -1 || ival == 0xffffffff || + ((ival >= 0 && ival <= 2147483647LL) + && ( (ival & (ival + 1)) == 0)) "))) + + +;; Floating-point constant constraints. +(define_constraint "G" + "The floating point zero constant" + (and (match_code "const_double") + (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT + && op == CONST0_RTX (mode)"))) + +(define_constraint "H" + "Any floating point constant" + (and (match_code "const_double") + (match_test "1"))) + diff --git a/gcc/config/ve/linux.h b/gcc/config/ve/linux.h new file mode 100644 index 00000000000..0256fbbe571 --- /dev/null +++ b/gcc/config/ve/linux.h @@ -0,0 +1,79 @@ +/* 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 +. */ + +/* Definitions for NEC VE running Linux-based GNU systems with ELF format. + Changes by NEC Corporation for the VE port, 2018-2021 */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{pthread:-lpthread} \ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +#ifdef ENABLE_SHARED_LIBGCC +#define SHARED_LIBGCC_SPEC " \ + %{static|static-libgcc:-lgcc -lgcc_eh} \ + %{!static: \ + %{!static-libgcc: \ + %{!shared: \ + %{!shared-libgcc:-lgcc -lgcc_eh} \ + %{shared-libgcc:-lgcc_s -lgcc} \ + } \ + %{shared:-lgcc_s -lgcc} \ + } \ + } " +#else +#define SHARED_LIBGCC_SPEC " -lgcc " +#endif + +#undef REAL_LIBGCC_SPEC +#define REAL_LIBGCC_SPEC SHARED_LIBGCC_SPEC + +#undef STARTFILE_SPEC +#if defined HAVE_LD_PIE +#define STARTFILE_SPEC \ + "%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} \ + crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" +#else +#define STARTFILE_SPEC \ + "%{!shared: %{pg|p|profile:gcrt1.o%s;:crt1.o%s}} \ + crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" +#endif + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" + +/* At the officeal release, the install path is changed to '/opt/nec/ve'. */ +#define GLIBC_DYNAMIC_LINKER "/opt/nec/ve/lib/ld-linux-ve.so.1" + +#undef MUSL_DYNAMIC_LINKER +#define MUSL_DYNAMIC_LINKER "/opt/nec/ve/musl/lib/ld-musl-ve.so.1" + +#if DEFAULT_LIBC == LIBC_MUSL +#define GNU_USER_DYNAMIC_LINKER MUSL_DYNAMIC_LINKER +#else +#define GNU_USER_DYNAMIC_LINKER GLIBC_DYNAMIC_LINKER +#endif + +#undef LINK_SPEC +#define LINK_SPEC "\ + %{shared:-shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + -dynamic-linker " GNU_USER_DYNAMIC_LINKER "} \ + %{static:-static}}" diff --git a/gcc/config/ve/predicates.md b/gcc/config/ve/predicates.md new file mode 100644 index 00000000000..28565732913 --- /dev/null +++ b/gcc/config/ve/predicates.md @@ -0,0 +1,182 @@ +;; Predicate definitions for VE +;; Copyright (C) 2007-2016 Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 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, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;; Changes by NEC Corporation for the VE port, 2017-2021 + +;; Return 1 if OP is an I constant or any register. +(define_predicate "reg_or_i_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) < 64 && INTVAL (op) >= -64") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an J constant or any register. +(define_predicate "reg_or_j_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) < 32 && INTVAL (op) >= 0") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an K constant or any register. +(define_predicate "reg_or_k_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) < 64 && INTVAL (op) >= 0") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an L constant or any register. +(define_predicate "reg_or_l_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) < 128 && INTVAL (op) >= 0") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an M constant or any register. +(define_predicate "reg_or_m_operand" + (if_then_else (match_code "const_int") + (match_test " ((INTVAL(op) & (INTVAL(op)+1))==0)||((~INTVAL(op) & (~INTVAL(op)+1))==0) ") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an O constant or any register. +(define_predicate "reg_or_o_operand" + (if_then_else (match_code "const_int") + (match_test " INTVAL(op) <= 2147483647LL && INTVAL(op) >= -2147483648LL + && (((INTVAL(op) & (INTVAL(op)+1))==0) + ||(((0xffffffffLL^(0xffffffffLL & INTVAL(op))) + & ((0xffffffffLL^(0xffffffffLL &INTVAL(op)))+1))==0)) ") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is a P constant or any register. +(define_predicate "reg_or_p_operand" + (if_then_else (match_code "const_int") + (match_test " INTVAL(op) == 0 || INTVAL(op) == -1 + || INTVAL(op) == 0xffffffff || + (INTVAL(op) <= 2147483647LL && INTVAL(op) >= 0 + && ((INTVAL(op) & (INTVAL(op)+1))==0) ) ") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an N constant or any register. +(define_predicate "reg_or_in_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) <= 2147483647LL && INTVAL(op) >= -2147483648LL") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an I or M constant or any register. +(define_predicate "reg_or_im_operand" + (if_then_else (match_code "const_int") + (match_test "(INTVAL (op) < 64 && INTVAL (op) >= -64) || + ((INTVAL(op) & (INTVAL(op)+1))==0)||((~INTVAL(op) & (~INTVAL(op)+1))==0) ") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an I or O constant or any register. +(define_predicate "reg_or_io_operand" + (if_then_else (match_code "const_int") + (match_test "(INTVAL (op) < 64 && INTVAL (op) >= -64) || + ( INTVAL(op) <= 2147483647LL && INTVAL(op) >= -2147483648LL + && (((INTVAL(op) & (INTVAL(op)+1))==0) + ||(((0xffffffffLL^(0xffffffffLL&INTVAL(op))) + & ((0xffffffffLL^(0xffffffffLL&INTVAL(op)))+1))==0))) ") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is an I or P constant or any register. +(define_predicate "reg_or_ip_operand" + (if_then_else (match_code "const_int") + (match_test "(INTVAL (op) < 64 && INTVAL (op) >= -64) || + INTVAL(op) == 0 || INTVAL(op) == -1 + || INTVAL(op) == 0xffffffff || + (INTVAL(op) <= 2147483647LL && INTVAL(op) >= 0 + && ((INTVAL(op) & (INTVAL(op)+1))==0) ) ") + (match_operand 0 "register_operand"))) + +(define_predicate "reg_or_imn_operand" + (if_then_else (match_code "const_int") + (match_test "(INTVAL (op) < 64 && INTVAL (op) >= -64) || + ((INTVAL(op) & (INTVAL(op)+1))==0)||((~INTVAL(op) & (~INTVAL(op)+1))==0) || + (INTVAL (op) <= 2147483647LL && INTVAL(op) >= -2147483648LL)") + (match_operand 0 "register_operand"))) + +;; Return 1 if OP is a constant or any register. +(define_predicate "reg_or_cint_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "const_int_operand"))) + +(define_predicate "reg_or_zero_operand" + (if_then_else (match_code "const_int,const_double") + (match_test "op == CONST0_RTX (GET_MODE (op))") + (match_operand 0 "register_operand"))) + +(define_predicate "const_n_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) <= 2147483647LL && INTVAL(op) >= -2147483648LL"))) + +(define_predicate "const_zero_operand" + (and (match_code "const_int,const_double") + (match_test "op == CONST0_RTX (GET_MODE (op))"))) + +(define_predicate "sym_ref_mem_operand" + (match_code "mem") +{ + rtx t1 = XEXP(op, 0); + if(GET_CODE(t1) == SYMBOL_REF) + return 1; + return 0; +}) + + +;; Return 1 if OP is a valid VE comparison operator for "cmp" style +;; instructions. +(define_predicate "ve_signed_comparison_operator" + (match_code "eq,ne,lt,le,ge,gt")) +(define_predicate "ve_ordered_comparison_operator" + (match_code "eq,ltgt,lt,le,ge,gt,ordered")) +(define_predicate "ve_unordered_comparison_operator" + (match_code "uneq,ne,unlt,unle,unge,ungt,unordered")) + +(define_predicate "const_arith_operand" + (and (match_code "const_int") + (match_test "SMALL_OPERAND (INTVAL (op))"))) + +;; Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref, +;; possibly with an offset. + +(define_predicate "symbolic_operand" + (match_code "symbol_ref,label_ref")) + +;; Return true if OP is a symbolic operand for the TLS Global Dynamic model. + +(define_predicate "tgd_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "!TARGET_TLS_ASIS || SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_GLOBAL_DYNAMIC"))) + +;; Return true if OP is a symbolic operand for the TLS Local Dynamic model. + +(define_predicate "tld_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_DYNAMIC"))) + +;; Return true if OP is a symbolic operand for the TLS Initial Exec model. + +(define_predicate "tie_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC"))) + +;; Return true if OP is a symbolic operand for the TLS Local Exec model. + +(define_predicate "tle_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC"))) + + diff --git a/gcc/config/ve/t-ve b/gcc/config/ve/t-ve new file mode 100644 index 00000000000..14ce4d8119a --- /dev/null +++ b/gcc/config/ve/t-ve @@ -0,0 +1,7 @@ +#CC=gcc +#LIBGCC1 = libgcc1.null +#CROSS_LIBGCC1 = libgcc1.null +#T_CFLAGS = -DDONT_HAVE_SETJMP +#LIBGCC2_CFLAGS=-g -O5 $(GCC_CFLAGS) + + diff --git a/gcc/config/ve/ve-modes.def b/gcc/config/ve/ve-modes.def new file mode 100644 index 00000000000..5409284d3fe --- /dev/null +++ b/gcc/config/ve/ve-modes.def @@ -0,0 +1,28 @@ +/* Mode definitions of target machine for GNU compiler. VE version. + Copyright (C) 2007-2016 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +/* VE supports the standard quiet bit. + while SX has the same reversed quiet bit as MIPS */ +RESET_FLOAT_FORMAT (SF, ieee_single_format); +RESET_FLOAT_FORMAT (DF, ieee_double_format); + +/* TFmode: IEEE quad floating point */ +FLOAT_MODE (TF, 16, ieee_quad_format); + diff --git a/gcc/config/ve/ve-opts.h b/gcc/config/ve/ve-opts.h new file mode 100644 index 00000000000..a02b6186122 --- /dev/null +++ b/gcc/config/ve/ve-opts.h @@ -0,0 +1,31 @@ +/* Definitions for option handling for VE. + Copyright (C) 2010-2016 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +#ifndef VE_OPTS_H +#define VE_OPTS_H + +/* Enumerates the setting of the -margmem option. */ +enum ve_argmem_setting { + ARGMEM_FORCE, + ARGMEM_SAFE, + ARGMEM_OPT +}; + +#endif diff --git a/gcc/config/ve/ve-protos.h b/gcc/config/ve/ve-protos.h new file mode 100644 index 00000000000..6b78d9c7e19 --- /dev/null +++ b/gcc/config/ve/ve-protos.h @@ -0,0 +1,89 @@ +/* Function prototype definitions GNU compiler. VE version. + Copyright (C) 2007-2016 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +/* gen call instruction */ +extern const char *ve_output_call_instr(rtx *); +extern const char *ve_output_call_instr_value(rtx *); + +/* gen move sf/df/tf immediate */ +extern const char *ve_movsf_reg_immediate(rtx *); +extern const char *ve_movdf_reg_immediate(rtx *); +extern const char *ve_movtf_reg_immediate(rtx *); + +/* gen load/store instrunction */ +extern const char *ve_asm_output_ldst_unified(const char *, + int , rtx *, rtx); + +extern void ve_asm_output_function_label (FILE *file, const char *fnname, + tree decl ATTRIBUTE_UNUSED); + +extern void ve_asm_output_function_prefix(FILE *file, const char *fnname); +extern void ve_asm_output_pool_prologue(FILE *file, const char *fnname, + tree fundecl ATTRIBUTE_UNUSED, + int size ATTRIBUTE_UNUSED); + +extern bool ve_legitimate_address_p (machine_mode mode, rtx x, bool strict); +extern rtx ve_legitimize_address (rtx, rtx, machine_mode); +extern int ve_regno_mode_ok_for_base_p (int regno, machine_mode mode, bool strict_p); + +extern int ve_check_symbol(rtx x, machine_mode mode); + +extern rtx ve_force_const_mem (rtx x, bool direct_call, bool ins_call); +extern rtx ve_force_label_relative (rtx x); +extern rtx ve_indirect_addr(rtx x, bool direct_call, bool ins_call); +extern int ve_expand_move(rtx *operands, machine_mode mode); + + +/* Allocate registers appropriate to data types. doubles + require even/odd pairs of long double registers. */ + +extern int ve_hard_regno_mode_ok(unsigned int regno, machine_mode mode); +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.*/ +extern unsigned int ve_dbx_register_number (unsigned int regno); + + +extern bool ve_cannot_change_mode_class (machine_mode from, machine_mode to, + enum reg_class rclass); + +extern bool ve_modes_tieable_p (machine_mode mode1, machine_mode mode2); + +extern int ve_constant_alignment (tree, int); + +extern void ve_asm_output_anchor (rtx symbol); + +extern rtx ve_function_value (const_tree valtype, const_tree func); +extern rtx ve_libcall_value (machine_mode mode); + +extern rtx ve_addr_cut_mem(rtx operand, int n); +extern bool ve_epilogue_uses (int regno); + +extern void ve_expand_prologue(void); +extern void ve_expand_epilogue(void); + +extern void ve_asm_output_ident (const char *ident_str); +extern rtx ve_return_addr_rtx (int count, rtx frame); + +extern void ve_init_cumulative_args(CUMULATIVE_ARGS *, tree, rtx, tree); +extern bool ve_const_si_p (long long x); + +extern void ve_init_expanders (void); +extern HOST_WIDE_INT ve_initial_elimination_offset (int from, int to); +extern void ve_profile_hook (int); +extern void ve_end_function(FILE *, const char *, tree); diff --git a/gcc/config/ve/ve-stdint.h b/gcc/config/ve/ve-stdint.h new file mode 100644 index 00000000000..658ba22a198 --- /dev/null +++ b/gcc/config/ve/ve-stdint.h @@ -0,0 +1,52 @@ +/* Definitions for types on systems using VE. + Copyright (C) 2009-2016 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +#define SIG_ATOMIC_TYPE "int" + +#define INT8_TYPE "signed char" +#define INT16_TYPE "short int" +#define INT32_TYPE "int" +#define INT64_TYPE "long int" +#define UINT8_TYPE "unsigned char" +#define UINT16_TYPE "short unsigned int" +#define UINT32_TYPE "unsigned int" +#define UINT64_TYPE "long unsigned int" + +#define INT_LEAST8_TYPE "signed char" +#define INT_LEAST16_TYPE "short int" +#define INT_LEAST32_TYPE "int" +#define INT_LEAST64_TYPE "long int" +#define UINT_LEAST8_TYPE "unsigned char" +#define UINT_LEAST16_TYPE "short unsigned int" +#define UINT_LEAST32_TYPE "unsigned int" +#define UINT_LEAST64_TYPE "long unsigned int" + +#define INT_FAST8_TYPE "signed char" +#define INT_FAST16_TYPE (!TARGET_MUSL_COMPAT ? "long int" : "int" ) +#define INT_FAST32_TYPE (!TARGET_MUSL_COMPAT ? "long int" : "int" ) +#define INT_FAST64_TYPE "long int" +#define UINT_FAST8_TYPE "unsigned char" +#define UINT_FAST16_TYPE (!TARGET_MUSL_COMPAT ? "long unsigned int" : "unsigned int" ) +#define UINT_FAST32_TYPE (!TARGET_MUSL_COMPAT ? "long unsigned int" : "unsigned int" ) +#define UINT_FAST64_TYPE "long unsigned int" + +#define INTPTR_TYPE "long int" +#define UINTPTR_TYPE "long unsigned int" + diff --git a/gcc/config/ve/ve.c b/gcc/config/ve/ve.c new file mode 100644 index 00000000000..551adf91e9b --- /dev/null +++ b/gcc/config/ve/ve.c @@ -0,0 +1,3004 @@ +/* Subroutines used for VE code generation. + Copyright (C) 2007-2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" +#include "tree.h" +#include "varasm.h" +#include "stor-layout.h" +#include "calls.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "insn-attr.h" +#include "recog.h" +#include "output.h" +#include "stringpool.h" +#include "function.h" +#include "memmodel.h" +#include "emit-rtl.h" +#include "expr.h" +#include "flags.h" +#include "reload.h" +#include "tm_p.h" +#include "diagnostic-core.h" +#include "optabs.h" +#include "libfuncs.h" +#include "ggc.h" +#include "target.h" +#include "target-def.h" +#include "common/common-target.h" +#include "targhooks.h" +#include "langhooks.h" +#include "gstab.h" +#include "hashtab.h" +#include "debug.h" +#include "sched-int.h" +#include "bitmap.h" +#include "diagnostic.h" +#include "real.h" +#include "insn-flags.h" +#include "toplev.h" +#include "predict.h" +#include "basic-block.h" +#include "df.h" +#include "hash-map.h" +#include "is-a.h" +#include "plugin-api.h" +#include "ipa-ref.h" +#include "cgraph.h" +#include "builtins.h" +#include + +/* s(ARG_POINTER_REGNUM) is saved if number of args >= 9 */ +#define REG_NEEDS_SAVE(i) ( \ + ( i==VE_GOT_REGNUM || i==VE_PLT_REGNUM ) || \ + df_regs_ever_live_p(i) \ + && ( !(call_used_regs[i]) \ + || (i==VE_LINKAGE_REGNUM && ve_use_linkage))) +/* || (i==10 && !crtl->is_leaf)) */ +/* FIXME s10 is saved + if function is (!leaf [!crtl->is_leaf] + or __builtin_return_address used ) */ +/* no register is always saved */ +#define REG_ALWAYS_SAVE_BEG 17 +#define REG_ALWAYS_SAVE_END 17 +#define VE_MAX_SAVE_REGS 20 + +#define VE_BUF_SIZE 130 + +void abort_with_insn (rtx, const char *); +void oops_message(char *); +bool ve_symbolic_constant_p (rtx); +static void ve_split_const (rtx, rtx *, HOST_WIDE_INT *); +rtx ve_legitimize_address (rtx, rtx,machine_mode); +static rtx ve_struct_value_rtx (tree, int); +static bool ve_return_in_memory (const_tree, const_tree); +static bool ve_pass_by_reference (cumulative_args_t cum, + machine_mode mode, const_tree type, bool named); +static int ve_const_insns (rtx x); +static bool ve_reg_ok_for_legitimate(rtx x, bool strict); +static rtx ve_expand_mem_scratch(rtx x, int *changed); +static void ve_addr_cut_mem_internal(rtx x); +static void ve_output_addr_const_offset(FILE *file, rtx addr, + HOST_WIDE_INT offset); +static bool ve_can_eliminate (const int from, const int to); +static rtx ve_function_arg (cumulative_args_t, + machine_mode, const_tree, bool); +static rtx ve_function_arg_1 (cumulative_args_t, + machine_mode, const_tree, bool, bool); +static rtx ve_function_incoming_arg (cumulative_args_t, + machine_mode, const_tree, bool); +static unsigned int ve_function_arg_boundary (machine_mode, + const_tree); +static void ve_asm_output_ldst_unified_sub(const char *, int, + rtx, rtx ,rtx, rtx, HOST_WIDE_INT, rtx); +static void ve_extract_base_offset_sub(rtx, rtx *, + rtx *, rtx *, HOST_WIDE_INT *); +static void ve_extract_base_offset(rtx, rtx *, + rtx *, rtx *, HOST_WIDE_INT *); + +/* Table of valid machine attributes. */ + +static const struct attribute_spec ve_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, + affects_type_identity } */ +#ifdef SUBTARGET_ATTRIBUTE_TABLE + SUBTARGET_ATTRIBUTE_TABLE, +#endif + { NULL, 0, 0, false, false, false, NULL, false } +}; + +/* Initialize the GCC target structure. */ +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE ve_attribute_table + +/* Abort after printing out a specific insn. */ + +void +abort_with_insn (rtx insn, const char *reason) +{ + error (reason); + debug_rtx (insn); + abort (); +} + +void +oops_message(char *str) +{ + fputs(str,stderr); +} + +static void +ve_option_override (void) +{ + ve_const_indirect = TARGET_CONST_INDIRECT ? TRUE : FALSE; + ve_symbol_indirect = TARGET_SYMBOL_INDIRECT ? TRUE : FALSE; + + if (flag_pie) + { + error("-fpie and -fPIE not supported on this target"); + flag_pie = 0; + } +} + +/* Do anything needed before RTL is emitted for each function. */ +static int ve_use_linkage; +void +ve_init_expanders (void) +{ + if (ve_const_indirect || ve_symbol_indirect) + ve_use_linkage = true; + else + ve_use_linkage = false; +} + +/* Construct the SYMBOL_REF for GOT references. */ + +static GTY(()) rtx ve_got_symbol = NULL_RTX; + +static rtx +ve_got_sym (void) +{ + if (ve_got_symbol == NULL_RTX) + { + ve_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + SYMBOL_REF_FLAGS (ve_got_symbol) |= SYMBOL_FLAG_EXTERNAL; + } + + return ve_got_symbol; +} + +/* Return true if X is a thread-local symbol. */ + +static bool +ve_tls_symbol_p (rtx x) +{ + return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0; +} + +static rtx gen_tls_tga; + +static rtx +gen_tls_get_addr (void) +{ + if (!gen_tls_tga) + gen_tls_tga = init_one_libfunc ("__tls_get_addr"); + return gen_tls_tga; +} + +int ve_hard_regno_mode_ok(unsigned int regno, machine_mode mode) +{ + /* modes that require multiple registers we choose to + always put in an even/odd pair. This is required on + the FP side but not on the integer. We do it there anyway + just to make things easier. */ + + if(GET_MODE_SIZE(mode) > UNITS_PER_WORD && + ((regno&1) != 0)) return 0; + + if(regno >= FIRST_S_REG && regno <= LAST_S_REG) + if (mode == QImode || mode == HImode || mode == SImode || mode == DImode + || mode == CQImode || mode == CHImode || mode == CSImode || mode == CDImode + || mode == SFmode || mode == DFmode || mode == SCmode || mode == DCmode + || mode == TFmode || mode == TCmode || mode == TImode || mode == CTImode) + return 1; + + return 0; +} + +/* Map internal gcc register numbers to DWARF2 register numbers. */ +unsigned int +ve_dbx_register_number (unsigned int regno) +{ + if (GP_REG_P(regno)) + return regno; + return INVALID_REGNUM; +} + +static bool +ve_scalar_mode_supported_p (machine_mode mode) +{ + if (mode == QImode || mode == HImode || mode == SImode || mode == DImode + || mode == CQImode || mode == CHImode || mode == CSImode || mode == CDImode + || mode == SFmode || mode == DFmode || mode == SCmode || mode == DCmode + || mode == TFmode || mode == TCmode || mode == TImode || mode == CTImode) + return true; + return false; +} + +static bool +ve_vector_mode_supported_p (machine_mode mode ATTRIBUTE_UNUSED) +{ + return false; +} + +/* Return true if the registers in CLASS cannot represent the change from + modes FROM to TO. */ + +bool +ve_cannot_change_mode_class (machine_mode from, machine_mode to, + enum reg_class rclass ATTRIBUTE_UNUSED) +{ + if (from == to) + return false; + + /* Reject changes to/from complex modes. */ + if (COMPLEX_MODE_P (from) || COMPLEX_MODE_P (to)) + return true; + + if (GET_MODE_CLASS (from) == MODE_FLOAT || + GET_MODE_CLASS (to) == MODE_FLOAT) + return true; + + /* We cannot use double word registers for subreg, + since aurora double word regs (especially TFmode) are + big-endian register numbering */ + if (GET_MODE_SIZE (to) > UNITS_PER_WORD || + GET_MODE_SIZE (from) > UNITS_PER_WORD) + return true; + + if (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)) + return false; + + return false; +} + +/* Return true if MODE1 is accessible in a register that can hold MODE2 + without copying. That is, all register classes that can hold MODE2 + can also hold MODE1. */ +bool +ve_modes_tieable_p (machine_mode mode1, machine_mode mode2) +{ + if (mode1 == mode2) + return true; + + if (mode1 == TFmode || mode2 == TFmode) + return false; + + if (mode1 == TImode || mode2 == TImode) + return false; + + return true; +} +/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */ + +static bool +ve_print_operand_punct_valid_p (unsigned char code) +{ + return (code == '+' || code == '-'); +} + +void ve_print_operand(FILE *stream, rtx x, int letter) +{ + enum rtx_code code; + + switch (letter) + { + case '%': + putc('%',stream); + return; + case '+': case '-': + { + rtx x; + if (!optimize) + return; + x = find_reg_note (current_output_insn, REG_BR_PROB, 0); + if (x) + { + int pred_val = XINT (x, 0); + /* if 0.45 <= p <= 0.55 , no hint is generated */ + if (pred_val < REG_BR_PROB_BASE * 45 / 100 + || pred_val > REG_BR_PROB_BASE * 55 / 100) + { + bool taken = pred_val > REG_BR_PROB_BASE / 2; + bool cputaken + = final_forward_branch_p (current_output_insn) == 0; + + /* Emit hints in the case default branch prediction + heuristics would fail, or p is small or large enough */ + if (taken != cputaken + || pred_val <= REG_BR_PROB_BASE * (100 - ve_branch_prob) / 100 + || pred_val >= REG_BR_PROB_BASE * ve_branch_prob/ 100) + { + if ((taken && letter == '+') || (!taken && letter == '-') ) + fputs (".t",stream); + else + fputs (".nt",stream); + } + } + } + } + return; + } + + if(!x) + error("PRINT_OPERAND null pointer"); + + code = GET_CODE(x); + + switch (letter) + { + case 'C': /* conditional */ + switch(code) + { + case EQ: fputs(VE_COND_EQ,stream); break; + case NE: fputs(VE_COND_NE,stream); break; + case GT: fputs(VE_COND_GT,stream); break; + case GE: fputs(VE_COND_GE,stream); break; + case LT: fputs(VE_COND_LT,stream); break; + case LE: fputs(VE_COND_LE,stream); break; + case GTU: fputs(VE_COND_GTU,stream); break; + case GEU: fputs(VE_COND_GEU,stream); break; + case LTU: fputs(VE_COND_LTU,stream); break; + case LEU: fputs(VE_COND_LEU,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%C"); + } + break; + + case'F': /* floating conditional */ + switch(code) + { + case EQ: fputs(VE_COND_EQ,stream); break; + case NE: fputs(VE_COND_FNE,stream); break; + case GT: fputs(VE_COND_GT,stream); break; + case GE: fputs(VE_COND_GE,stream); break; + case LT: fputs(VE_COND_LT,stream); break; + case LE: fputs(VE_COND_LE,stream); break; + case GTU: fputs(VE_COND_GTU,stream); break; + case GEU: fputs(VE_COND_GEU,stream); break; + case LTU: fputs(VE_COND_LTU,stream); break; + case LEU: fputs(VE_COND_LEU,stream); break; + case UNEQ: fputs(VE_COND_UNEQ,stream); break; + case LTGT: fputs(VE_COND_LTGT,stream); break; + case UNGT: fputs(VE_COND_UNGT,stream); break; + case UNGE: fputs(VE_COND_UNGE,stream); break; + case UNLT: fputs(VE_COND_UNLT,stream); break; + case UNLE: fputs(VE_COND_UNLE,stream); break; + case UNORDERED: fputs(VE_COND_UNORDERED,stream); break; + case ORDERED: fputs(VE_COND_ORDERED,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%C"); + } + break; + + case 'N': /* negate conditional */ + switch(code) + { + case EQ: fputs(VE_COND_NE,stream); break; + case NE: fputs(VE_COND_EQ,stream); break; + case GT: fputs(VE_COND_LE,stream); break; + case GE: fputs(VE_COND_LT,stream); break; + case LT: fputs(VE_COND_GE,stream); break; + case LE: fputs(VE_COND_GT,stream); break; + case GTU: fputs(VE_COND_LEU,stream); break; + case GEU: fputs(VE_COND_LTU,stream); break; + case LTU: fputs(VE_COND_GEU,stream); break; + case LEU: fputs(VE_COND_GTU,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%N"); + } + break; + + case 'E': /* floating negate conditional */ + switch(code) + { + case EQ: fputs(VE_COND_FNE,stream); break; + case NE: fputs(VE_COND_EQ,stream); break; + case GT: fputs(VE_COND_UNLE,stream); break; + case GE: fputs(VE_COND_UNLT,stream); break; + case LT: fputs(VE_COND_UNGE,stream); break; + case LE: fputs(VE_COND_UNGT,stream); break; + case GTU: fputs(VE_COND_UNLE,stream); break; + case GEU: fputs(VE_COND_UNLT,stream); break; + case LTU: fputs(VE_COND_UNGE,stream); break; + case LEU: fputs(VE_COND_UNGT,stream); break; + case UNEQ: fputs(VE_COND_LTGT,stream); break; + case LTGT: fputs(VE_COND_UNEQ,stream); break; + case UNGT: fputs(VE_COND_LE,stream); break; + case UNGE: fputs(VE_COND_LT,stream); break; + case UNLT: fputs(VE_COND_GE,stream); break; + case UNLE: fputs(VE_COND_GT,stream); break; + case UNORDERED: fputs(VE_COND_ORDERED,stream); break; + case ORDERED: fputs(VE_COND_UNORDERED,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%N"); + } + break; + + case 'R': /* reverse (swap operand) conditional */ + switch(code) + { + case EQ: fputs(VE_COND_EQ,stream); break; + case NE: fputs(VE_COND_FNE,stream); break; + case GT: fputs(VE_COND_LT,stream); break; + case GE: fputs(VE_COND_LE,stream); break; + case LT: fputs(VE_COND_GT,stream); break; + case LE: fputs(VE_COND_GE,stream); break; + case GTU: fputs(VE_COND_LTU,stream); break; + case GEU: fputs(VE_COND_LEU,stream); break; + case LTU: fputs(VE_COND_GTU,stream); break; + case LEU: fputs(VE_COND_GEU,stream); break; + case UNEQ: fputs(VE_COND_UNEQ,stream); break; + case LTGT: fputs(VE_COND_LTGT,stream); break; + case UNGT: fputs(VE_COND_UNLT,stream); break; + case UNGE: fputs(VE_COND_UNLE,stream); break; + case UNLT: fputs(VE_COND_UNGT,stream); break; + case UNLE: fputs(VE_COND_UNGE,stream); break; + case UNORDERED: fputs(VE_COND_UNORDERED,stream); break; + case ORDERED: fputs(VE_COND_ORDERED,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%R"); + } + break; + + case 'T': /* reverse (swap operands) and negate conditional */ + switch(code) + { + case EQ: fputs(VE_COND_NE,stream); break; + case NE: fputs(VE_COND_EQ,stream); break; + case GT: fputs(VE_COND_GE,stream); break; + case GE: fputs(VE_COND_GT,stream); break; + case LT: fputs(VE_COND_LE,stream); break; + case LE: fputs(VE_COND_LT,stream); break; + case GTU: fputs(VE_COND_GEU,stream); break; + case GEU: fputs(VE_COND_GTU,stream); break; + case LTU: fputs(VE_COND_LEU,stream); break; + case LEU: fputs(VE_COND_LTU,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%T"); + } + break; + + case 'J': /* remove eq condition*/ + switch(code) + { + /*case EQ: fputs(VE_COND_NE,stream); break;*/ + /*case NE: fputs(VE_COND_NE,stream); break;*/ + case GT: fputs(VE_COND_GT,stream); break; + case GE: fputs(VE_COND_GT,stream); break; + case LT: fputs(VE_COND_LT,stream); break; + case LE: fputs(VE_COND_LT,stream); break; + case GTU: fputs(VE_COND_GTU,stream); break; + case GEU: fputs(VE_COND_GTU,stream); break; + case LTU: fputs(VE_COND_LTU,stream); break; + case LEU: fputs(VE_COND_LTU,stream); break; + default: + abort_with_insn (x, "PRINT_OPERAND, illegal insn for %%T"); + } + break; + + case 'M': /* special (n)1 or (n)0 notation */ + { + long long iv = INTVAL(x); + int m, n; + if (iv == 0) + fputs("(0)1",stream); + else if (iv == -1) + fputs("(0)0",stream); + else { + if ((iv & (iv +1)) == 0) { + n = 0; + } + else { + n = 1; + } + for (m=64; (iv&1) == 1-n && m >=0 ; iv >>= 1) m--; + fprintf(stream,"(%d)%d",m,n); + } + } + break; + + case 'O': case'P': + /* special (n)1 or (n)0 notation 32bit*/ + { + long long iv = INTVAL(x); + int m, n; + if (iv & 0x80000000) iv |= 0xffffffff00000000; + if (iv == 0) + fputs("(0)1",stream); + else if (iv == -1) + fputs("(0)0",stream); + else { + if ((iv & (iv +1)) == 0) { + n = 0; + } + else { + n = 1; + } + for (m=64; (iv&1) == 1-n && m >=0 ; iv >>= 1) m--; + fprintf(stream,"(%d)%d",m,n); + } + } + break; + + case 'S': /* print SYMBOL_REF */ + assemble_name(stream,XSTR(x,0)); + break; + + + case 'U': /* Unsigned int */ + { + unsigned long iv = (unsigned)(INTVAL(x)); + fprintf(stream,"%ld",iv); + } + break; + + case 'G': /* siGned int */ + { + long iv = INTVAL(x); + fprintf(stream,"%ld",iv); + } + break; + + case 'L': /* int low 32bit */ + { + long long iv = INTVAL(x); + int l = (int)(iv & 0xffffffff); + fprintf(stream,"%d",l ); + } + break; + + case 'H': /* int high 32bit + 1(if low 32bit <0) */ + { + long long iv = INTVAL(x); + int l = (int)(iv & 0xffffffff); + fprintf(stream,"%d",(int)(iv >> 32)+(l>=0?0:1)); + } + break; + + case 'V': /* lower 5 bit for shift SI operation */ + { + unsigned long iv = (unsigned) (INTVAL(x)); + fprintf(stream,"%d",(int)(iv & 0x1f)); + } + break; + + case 'Z': /* x >=0 ? '0' : '-1' */ + { + long iv = INTVAL(x); + if (iv >=0) + fputs("0",stream); + else + fputs("-1",stream); + } + break; + + + default: + switch (code) { + case REG: + { + int regnum = REGNO(x); + if (letter=='Q') + { + gcc_assert(regnum %2 == 0); + regnum++; + } + fputs(reg_names[regnum],stream); + } + break; + + case CONST_INT: + fprintf(stream,HOST_WIDE_INT_PRINT_DEC,INTVAL(x)); + break; + + case MEM: + if (letter == 'A') + output_address(GET_MODE(x), + plus_constant(Pmode,XEXP(x,0),UNITS_PER_WORD)); + else + output_address(GET_MODE(x), XEXP(x, 0)); + + break; + + default: + output_addr_const(stream,x); + } + } +} + +void +ve_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr) +{ + int spill = 0; + HOST_WIDE_INT offset = 0; + + if (!addr) + fatal_error (input_location, + "internal error:PRINT_OPERAND_ADDRESS, null pointer"); + + if (GET_CODE(addr) == PLUS && GET_CODE(XEXP(addr,1)) == CONST_INT) + { + offset = INTVAL(XEXP(addr,1)); + addr = XEXP(addr,0); + } + switch (GET_CODE (addr)) + { + default: + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #1"); + break; + + case REG: + fprintf (file, HOST_WIDE_INT_PRINT_DEC + "(,%s)", offset, reg_names [REGNO (addr)]); + break; + + case PLUS: + { + rtx x1 = XEXP(addr, 0); + rtx x2 = XEXP(addr, 1); + + /* try swapping */ + if (! REG_P(x1) && REG_P(x2)) + { + rtx tmp = x1; x1 = x2; x2 = tmp; + } + if (CONSTANT_P (x1) && CONSTANT_P (x2)) + { + if (GET_CODE(x1) == CONST_INT) + { + if (GET_CODE(x2) == CONST_INT) + { + offset += INTVAL(x1) + INTVAL(x2); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset); + } + else + { + offset += INTVAL(x1); + output_addr_const (file, x2); + if (offset != 0) + fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); + } + } + else if (GET_CODE(x2) == CONST_INT) + { + offset += INTVAL(x2); + output_addr_const (file, x1); + if (offset !=0) + fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); + } + else + { + output_addr_const (file, addr); + if (offset !=0) + fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); + } + break; + } + + if (REG_P(x1)) + { + if (REG_P(x2)) + { + fprintf(file, HOST_WIDE_INT_PRINT_DEC "(%s,%s)", + offset, reg_names[REGNO(x1)], + reg_names[REGNO(x2)]); + break; + } + + if (CONSTANT_P(x2)) + { + ve_output_addr_const_offset(file,x2,offset); + if (GET_CODE(x2) == LABEL_REF) + { + fprintf (file, "(%s,%s)", + reg_names [REGNO (x1)], + reg_names [VE_LINKAGE_REGNUM]); + ve_use_linkage = true; + } + else + fprintf(file, "(,%s)", reg_names[REGNO(x1)]); + break; + } + + if (GET_CODE(x2) == PLUS) + { + rtx x3 = XEXP(x2,0); + rtx x4 = XEXP(x2,1); + + if (! REG_P(x3)) + { + rtx tmp = x3; x3 = x4; x4 = tmp; + } + if (REG_P(x3) && CONSTANT_P(x4)) + { + ve_output_addr_const_offset(file,x4,offset); + fprintf(file, "(%s,%s)", + reg_names[REGNO(x1)], reg_names[REGNO(x3)]); + break; + } + else + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #1"); + } + } /* end REG_P(x1) */ + + if (GET_CODE(x1) != PLUS && GET_CODE(x2) == PLUS) + { + rtx tmp = x1; x1 = x2; x2 = tmp; + } + if (GET_CODE(x1) == PLUS) + { + rtx x3 = XEXP(x1,0); + rtx x4 = XEXP(x1,1); + + if (REG_P(x3) && REG_P(x4) && CONSTANT_P(x2)) + { + ve_output_addr_const_offset(file, x2, offset); + fprintf(file, "(%s,%s)", + reg_names[REGNO(x3)], reg_names[REGNO(x4)]); + break; + } + else + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2"); + } + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #3"); + break; + } + + case SYMBOL_REF: + ve_output_addr_const_offset (file, addr, offset); + if (!CONSTANT_POOL_ADDRESS_P(addr)) break; + addr = get_pool_constant(addr); + switch (GET_CODE(addr)) { + case SYMBOL_REF: + fprintf(file,"\t# "); + output_addr_const(file,addr); + break; + case CONST_DOUBLE: + { + char string[30]; + real_to_decimal(string, CONST_DOUBLE_REAL_VALUE(addr), + sizeof(string),0,1); + + fprintf(file,"\t# %s",string); + break; + } + default: + break; + } + break; + case LABEL_REF: + case CONST_INT: + case CONST: + ve_output_addr_const_offset (file, addr, offset); + break; + } +} + +static void +ve_output_addr_const_offset(FILE *file, rtx addr, HOST_WIDE_INT offset) +{ + gcc_assert(CONSTANT_P(addr)); + if (GET_CODE(addr) == CONST_INT) + { + offset += INTVAL(addr); + fprintf(file, HOST_WIDE_INT_PRINT_DEC, offset); + } + else + { + output_addr_const (file, addr); + if (offset !=0) + fprintf(file, "+" HOST_WIDE_INT_PRINT_DEC, offset); + } +} + +static void +ve_extract_base_offset_sub(rtx addr, rtx *sym, rtx *reg1, rtx *reg2, + HOST_WIDE_INT *offset) +{ + switch (GET_CODE (addr)) + { + case CONST: + ve_extract_base_offset_sub(XEXP(addr,0),sym,reg1,reg2,offset); + break; + + case REG: + if (*reg1 == NULL_RTX) + *reg1 = addr; + else if (*reg2 == NULL_RTX) + *reg2 = addr; + else + abort_with_insn (addr, "EXTRACT_BASE_OFFSET, invalid insn"); + break; + + case SYMBOL_REF: + case LABEL_REF: + if (*sym == NULL_RTX) + *sym = addr; + else + abort_with_insn (addr, "EXTRACT_BASE_OFFSET, invalid insn"); + break; + + case CONST_INT: + *offset += INTVAL(addr); + break; + + case PLUS: + ve_extract_base_offset_sub(XEXP(addr,0),sym,reg1,reg2,offset); + ve_extract_base_offset_sub(XEXP(addr,1),sym,reg1,reg2,offset); + break; + + case MEM: + if (*reg1 == NULL_RTX) + *reg1 = gen_rtx_REG(GET_MODE(addr),VE_SCRATCH_REGNUM); + else if (*reg2 == NULL_RTX) + *reg2 = gen_rtx_REG(GET_MODE(addr),VE_SCRATCH_REGNUM); + else + abort_with_insn (addr, "EXTRACT_BASE_OFFSET, invalid insn"); + break; + + default: + abort_with_insn (addr, "EXTRACT_BASE_OFFSET, invalid insn"); + } +} + +static void +ve_extract_base_offset(rtx addr, rtx *sym, rtx *reg1, rtx *reg2, + HOST_WIDE_INT *offset) +{ + gcc_assert (MEM_P (addr)); + addr = XEXP (addr, 0); + + *sym = NULL_RTX; + *reg1 = NULL_RTX; + *reg2 = NULL_RTX; + *offset = 0; + ve_extract_base_offset_sub(addr,sym,reg1,reg2,offset); +} + +int +ve_regno_mode_ok_for_base_p (int regno, + machine_mode mode ATTRIBUTE_UNUSED, bool strict_p) +{ + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (!strict_p) + return true; + regno = reg_renumber[regno]; + } + + if (regno == ARG_POINTER_REGNUM || regno == STACK_POINTER_REGNUM) + return true; + + return GP_REG_P(regno); +} + + +/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It + returns a nonzero value if X is a legitimate address for a memory + operand of the indicated MODE. STRICT is nonzero if this function + is called during reload. */ + +static bool +ve_reg_ok_for_legitimate(rtx x, bool strict) +{ + return strict? REG_OK_FOR_BASE_STRICT_P(x):REG_OK_FOR_BASE_NONSTRICT_P(x); +} + +bool +ve_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED , + rtx x, bool strict) +{ + /* We only accept: + (mem reg) + (mem (plus reg reg)) + (mem (plus reg SIconst)) + (mem (plus reg (plus reg SIconst))) + (mem (plus (plus reg reg) SIconst)) + (mem symbol:local) + */ + + if (REG_P(x)) + return ve_reg_ok_for_legitimate(x,strict); + + if (GET_CODE(x) == MEM) return false; + + if (GET_CODE(x) == PLUS) + { + rtx x1 = XEXP(x, 0); + rtx x2 = XEXP(x, 1); + + if (GET_CODE(x1) == MEM) return false; + if (GET_CODE(x2) == MEM) return false; + + /* try swapping */ + if (! REG_P(x1) && REG_P(x2)) + { + rtx tmp = x1; x1 = x2; x2 = tmp; + } + + if (REG_P(x1)) + { + if (!ve_reg_ok_for_legitimate(x1,strict)) return false; + + if (REG_P(x2)) + return ve_reg_ok_for_legitimate(x2,strict); + + if (GET_CODE(x2) == CONST_INT) + return true; + + if (GET_CODE(x2) == PLUS) + { + rtx x3 = XEXP(x2,0); + rtx x4 = XEXP(x2,1); + + if (GET_CODE(x3) == MEM) return false; + if (GET_CODE(x4) == MEM) return false; + + /* try swapping */ + if (! REG_P(x3)) + { + rtx tmp = x3; x3 = x4; x4 = tmp; + } + if (!REG_P(x3)) return false; + if (!ve_reg_ok_for_legitimate(x3,strict)) return false; + if (GET_CODE(x4) == CONST_INT) return true; + return false; + } + } + + if (GET_CODE(x1) != PLUS && GET_CODE(x2) == PLUS) + { + rtx tmp = x1; x1 = x2; x2 = tmp; + } + if (GET_CODE(x1) == PLUS) + { + rtx x3 = XEXP(x1,0); + rtx x4 = XEXP(x1,1); + + if (GET_CODE(x3) == MEM) return false; + if (GET_CODE(x4) == MEM) return false; + if (!REG_P(x3)) return false; + if (!ve_reg_ok_for_legitimate(x3,strict)) return false; + if (!REG_P(x4)) return false; + if (!ve_reg_ok_for_legitimate(x4,strict)) return false; + if (GET_CODE(x2) == CONST_INT) return true; + return false; + } + } + + /* pic investigation */ + if (GET_CODE(x) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P(x)) + return true; + + return false; +} + +/* return num-th appearence of mem using depth first search */ + +int gnum; +rtx grtx; + +rtx +ve_addr_cut_mem(rtx x, int num) +{ + gnum = num; + grtx = NULL_RTX; + gcc_assert(GET_CODE(x) == MEM); + ve_addr_cut_mem_internal(XEXP(x,0)); + return grtx; +} + +static void +ve_addr_cut_mem_internal(rtx x) +{ + if (gnum <= 0) return; + + if (REG_P(x)) + return; + + if (GET_CODE(x) == MEM) + { + ve_addr_cut_mem_internal(XEXP(x,0)); + if (--gnum == 0) grtx = x; + return; + } + + if (GET_CODE(x) == PLUS) + { + ve_addr_cut_mem_internal(XEXP(x,0)); + if (gnum <= 0) return; + ve_addr_cut_mem_internal(XEXP(x,1)); + return; + } + + return ; +} + +/* Determine if it's legal to put X into the constant pool. This + is not possible if X contains the address of a symbol that is + not constant (TLS) or not known at final link time (PIC). */ + +static bool +ve_cannot_force_const_mem (machine_mode mode, rtx x) +{ + switch (GET_CODE (x)) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST_VECTOR: + /* Accept all non-symbolic constants. */ + return flag_pic || !ve_const_indirect; + + case LABEL_REF: + /* Labels are OK iff we are non-PIC. */ + return flag_pic || !ve_symbol_indirect ; + + case SYMBOL_REF: + /* 'Naked' TLS symbol references are never OK, + non-TLS symbols are OK iff we are non-PIC. */ + if (SYMBOL_REF_TLS_MODEL (x)) + return true; + else + return flag_pic || !ve_symbol_indirect; + + case CONST: + case HIGH: + return ve_cannot_force_const_mem (mode, XEXP (x, 0)); + case PLUS: + case MINUS: + return ve_cannot_force_const_mem (mode, XEXP (x, 0)) + || ve_cannot_force_const_mem (mode, XEXP (x, 1)); + case LO_SUM: + return ve_cannot_force_const_mem (mode, XEXP (x, 1)); + case REG: + return false; + case UNSPEC: + return true; + default: + debug_rtx(x); + gcc_unreachable (); + } +} + +/* Return true if X is a symbolic constant that can be calculated in + the same way as a bare symbol. If it is, store the type of the + symbol in *SYMBOL_TYPE. */ + +bool +ve_symbolic_constant_p (rtx x) +{ + HOST_WIDE_INT offset; + + ve_split_const (x, &x, &offset); + + if (GET_CODE(x) == SYMBOL_REF && + CONSTANT_POOL_ADDRESS_P(x)) return true; + if (GET_CODE(x) == LABEL_REF) return true; + return false; +} + +/* Split X into a base and a constant offset, storing them in *BASE + and *OFFSET respectively. */ + +static void +ve_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset) +{ + *offset = 0; + + if (GET_CODE (x) == CONST) + { + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + *offset += INTVAL (XEXP (x, 1)); + x = XEXP (x, 0); + } + } + *base = x; +} + +/* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can + be legitimized in a way that the generic machinery might not expect, + put the new address in *XLOC and return true. MODE is the mode of + the memory being accessed. */ + +rtx +ve_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED) +{ + if (GET_CODE (x) == PLUS) + { + rtx x1 = XEXP(x,0); + rtx x2 = XEXP(x,1); + if (GET_CODE(x1) == CONST_INT) + { + rtx temp; + temp = x1; x1 = x2; x2 = temp; + } + if (GET_CODE(x1) == SYMBOL_REF + && !CONSTANT_POOL_ADDRESS_P(x1) + && GET_CODE(x2) == CONST_INT) + { + rtx tmp,tmpreg; + tmpreg = ve_indirect_addr(x1,false,false); + tmp = gen_rtx_PLUS(Pmode,tmpreg,x2); + return(tmp); + } + } + + if (GET_CODE (x) == SYMBOL_REF && + !CONSTANT_POOL_ADDRESS_P(x)) + { + rtx tmpreg; + tmpreg = ve_indirect_addr(x,false,false); + return(tmpreg); + } + + return x; +} + + +/* Likewise for constant X. */ + +static bool +ve_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + if (ve_tls_symbol_p (x)) + return false; + + return ve_const_insns (x) > 0; +} + + +static int +ve_const_insns (rtx x) +{ +#define VE_IMMEDIATE_INSTR 2 + switch (GET_CODE (x)) + { + case CONST_INT: + if (ve_const_si_p(INTVAL(x))) + return 1; + else + { +/* accept const > 32bit */ + if (flag_pic || !ve_const_indirect) + return VE_IMMEDIATE_INSTR; + return 0; + } + + case CONST_DOUBLE: + case CONST_VECTOR: + if (x == CONST0_RTX (GET_MODE(x))) + return 1; + if (GET_MODE_SIZE(GET_MODE(x)) < UNITS_PER_WORD) + return 1; + if (flag_pic || !ve_const_indirect) + return VE_IMMEDIATE_INSTR; + return 0; + case CONST: + /* See if we can refer to X directly. */ + if (ve_symbolic_constant_p (x)) + /* return ve_symbol_insns (symbol_type); */ + return VE_IMMEDIATE_INSTR; + + return 0; + + case SYMBOL_REF: +/* let optimizer do not revert indirect address */ + if (!CONSTANT_POOL_ADDRESS_P(x)) return 0; + return VE_IMMEDIATE_INSTR; + case LABEL_REF: + return VE_IMMEDIATE_INSTR; + + default: + return 0; + } +} + +/* Worker function for TARGET_REGISTER_MOVE_COST. */ + +static int +ve_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, + reg_class_t from ATTRIBUTE_UNUSED, + reg_class_t to ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* Worker function for TARGET_MEMORY_MOVE_COST. */ + +static int +ve_memory_move_cost (machine_mode mode, + reg_class_t rclass ATTRIBUTE_UNUSED, + bool in ATTRIBUTE_UNUSED) +{ + return (GET_MODE_SIZE(mode)+UNITS_PER_WORD-1)/ UNITS_PER_WORD *10; +} + +static bool +ve_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, + int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, + int *total, bool speed ATTRIBUTE_UNUSED) +{ + enum rtx_code code = GET_CODE(x); + switch (code) + { + case CONST_INT: + /* Make 6-bit integers really cheap. */ + if (IN_RANGE (INTVAL (x), -64, 63)) + { + *total = 0; + return true; + } + /* Fall through. */ + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + case CONST_DOUBLE: + *total = COSTS_N_INSNS (2); + return true; + + case PLUS: + case MINUS: + case AND: + case IOR: + case XOR: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + case NOT: + case NEG: + case COMPARE: + if (GET_MODE (x) == SImode || GET_MODE(x) == DImode) + *total = COSTS_N_INSNS (1); + else + *total = COSTS_N_INSNS (3); + return true; + + case MULT: + if (GET_MODE (x) == SImode || GET_MODE(x) == DImode) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (6); + return true; + case DIV: + case UDIV: + case MOD: + case UMOD: + *total = COSTS_N_INSNS (18); + return true; + + case MEM: + *total = COSTS_N_INSNS (10); + return true; + default: + return false; + } +} + +static void +ve_trampoline_template (FILE * file) +{ + /* Output assembler code for a block containing the constant + part of a trampoline, leaving space for the variable parts. + + On the VE, (where s63 is the static chain regnum) the trampoline + looks like: + + ld %s63,Lstatic_chain(,%s12) + ld %s12,Lfunction_address(,%s12) + b.l.t (,%s12) + Lstatic_chain: + .quad static_chain + Lfunction_address: + .quad function_address + + + On the SX, (where s121 is the static chain regnum) the trampoline + looks like: + + lds $s121,Lstatic_chain(,$s120) + lds $s120,Lfunction_address(,$s120) + be> 0,(,$s120) + Lstatic_chain: + llong static_chain + Lfunction_address: + llong function address + + */ + asm_fprintf (file, "\tld\t%s,24(,%s)\n", reg_names[STATIC_CHAIN_REGNUM], + reg_names[VE_SCRATCH_REGNUM]); + asm_fprintf (file, "\tld\t%s,32(,%s)\n", reg_names[VE_SCRATCH_REGNUM], + reg_names[VE_SCRATCH_REGNUM]); + asm_fprintf (file, "\tb.l.t\t(,%s)\n",reg_names[VE_SCRATCH_REGNUM]); + asm_fprintf (file, ASM_LONGLONG "0\n"); + asm_fprintf (file, ASM_LONGLONG "0\n"); +} + +static void +ve_trampoline_init (rtx tramp, tree fndecl, rtx chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + + emit_block_move (tramp, assemble_trampoline_template (), + GEN_INT (24), BLOCK_OP_NORMAL); + + emit_move_insn (adjust_address (tramp, DImode, 24), chain); + emit_move_insn (adjust_address (tramp, DImode, 32), fnaddr); + emit_insn (gen_flush_icache ()); + +} + +static long l32 (long l) +{ + return l & 0xffffffff; +} + +/* Generate movesf constant */ +const char * +ve_movsf_reg_immediate (rtx *operands) +{ + REAL_VALUE_TYPE d; + long l; + char buf[VE_BUF_SIZE]; + char string[30]; + + d = *CONST_DOUBLE_REAL_VALUE(operands[1]); + REAL_VALUE_TO_TARGET_SINGLE(d,l); + real_to_decimal(string, &d, sizeof(string),0,1); + + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%0,0x%08lx\t# %s", + l32(l),string); + output_asm_insn(buf,operands); + return ""; +} + +/* Generate movedf constant */ +const char * +ve_movdf_reg_immediate (rtx *operands) +{ + rtx xop[3]; + REAL_VALUE_TYPE d; + long l[2]; + int ll; + char buf[VE_BUF_SIZE]; + char string[30]; + + d = *CONST_DOUBLE_REAL_VALUE(operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE(d,l); + real_to_decimal(string, &d, sizeof(string),0,1); + + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + + ll = l32(l[WORDS_BIG_ENDIAN?1:0]); + if (ll == 0) + { + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%0,0x%08lx\t# %s", + l32(l[WORDS_BIG_ENDIAN?0:1]),string); + output_asm_insn(buf,xop); + } + else + { + snprintf(buf,VE_BUF_SIZE,"lea\t%%2,0x%08lx", + l32(l[WORDS_BIG_ENDIAN?1:0])); + output_asm_insn(buf,xop); + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%0,0x%08lx(%%2)\t# %s", + l32(l[WORDS_BIG_ENDIAN?0:1]+(ll>=0?0:1)),string); + output_asm_insn(buf,xop); + } + return ""; +} + +/* Generate movetf constant */ +const char * +ve_movtf_reg_immediate (rtx *operands) +{ + rtx xop[3]; + REAL_VALUE_TYPE d; + long l[4]; + int ll; + char buf[VE_BUF_SIZE]; + char string[30]; + + d = *CONST_DOUBLE_REAL_VALUE(operands[1]); + REAL_VALUE_TO_TARGET_LONG_DOUBLE(d,l); + real_to_decimal(string, &d, sizeof(string),0,1); + + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + + ll = l32(l[WORDS_BIG_ENDIAN?1:2]); + if (ll == 0) + { + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%0,0x%08lx", + l32(l[WORDS_BIG_ENDIAN?0:3])); + output_asm_insn(buf,xop); + } + else + { + snprintf(buf,VE_BUF_SIZE,"lea\t%%2,0x%08lx", + l32(l[WORDS_BIG_ENDIAN?1:2])); + output_asm_insn(buf,xop); + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%0,0x%08lx(%%2)", + l32(l[WORDS_BIG_ENDIAN?0:3]+(ll>=0?0:1))); + output_asm_insn(buf,xop); + } + + ll = l32(l[WORDS_BIG_ENDIAN?3:0]); + if (ll == 0) + { + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%Q0,0x%08lx\t# %s", + l32(l[WORDS_BIG_ENDIAN?2:1]),string); + output_asm_insn(buf,xop); + } + else + { + snprintf(buf,VE_BUF_SIZE,"lea\t%%2,0x%08lx", + l32(l[WORDS_BIG_ENDIAN?3:0])); + output_asm_insn(buf,xop); + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%Q0,0x%08lx(%%2)\t# %s", + l32(l[WORDS_BIG_ENDIAN?2:1]+(ll>=0?0:1)),string); + output_asm_insn(buf,xop); + } + return ""; +} + +const char* +ve_asm_output_ldst_unified(const char *ldst, int direction, rtx* operands, + rtx operand_aid) +{ + int pos=1; + rtx operand_mem; + rtx operand_reg; + rtx xop[2]; + rtx sym; + rtx base1; + rtx base2; + HOST_WIDE_INT offset; + switch (direction) + { + case VE_DIR_LOAD: case VE_DIR_QLOAD: + operand_reg = operands[0]; + operand_mem = operands[1]; + break; + case VE_DIR_STORE: case VE_DIR_QSTORE: + operand_mem = operands[0]; + operand_reg = operands[1]; + break; + case VE_DIR_PFCH: + operand_mem = operands[0]; + operand_reg = NULL_RTX; + break; + case VE_DIR_ATOMIC01: + operand_reg = operands[0]; + operand_mem = operands[1]; + break; + case VE_DIR_ATOMIC20: + operand_reg = operands[2]; + operand_mem = operands[0]; + break; + default: + gcc_unreachable(); + } + + ve_extract_base_offset(operand_mem,&sym,&base1,&base2,&offset); + switch (direction) + { + case VE_DIR_QLOAD: + ve_asm_output_ldst_unified_sub(ldst,VE_DIR_QLOAD1, + operand_reg,sym,base1,base2,offset,operand_aid) ; + ve_asm_output_ldst_unified_sub(ldst,VE_DIR_QLOAD2, + operand_reg,sym,base1,base2,offset,operand_aid) ; + break; + case VE_DIR_QSTORE: + ve_asm_output_ldst_unified_sub(ldst,VE_DIR_QSTORE1, + operand_reg,sym,base1,base2,offset,operand_aid) ; + ve_asm_output_ldst_unified_sub(ldst,VE_DIR_QSTORE2, + operand_reg,sym,base1,base2,offset,operand_aid) ; + break; + default: + ve_asm_output_ldst_unified_sub(ldst,direction, + operand_reg,sym,base1,base2,offset,operand_aid) ; + break; + } + return ""; +} + +static void +ve_asm_output_ldst_unified_sub(const char *ldst, int direction, + rtx operand_reg, rtx sym, + rtx base1, rtx base2, HOST_WIDE_INT offset, + rtx operand_aid) +{ + rtx xop[6]; + char buf[VE_BUF_SIZE]; + const char *form0; + const char *form31; + const char *form4; + switch (direction) + { + case VE_DIR_QLOAD1: + form0 = "%Q0,"; + direction = VE_DIR_LOAD; + break; + case VE_DIR_QLOAD2: + form0 = "%0,"; + offset += UNITS_PER_WORD; + direction = VE_DIR_LOAD; + break; + case VE_DIR_QSTORE1: + form0 = "%Q0,"; + direction = VE_DIR_STORE; + break; + case VE_DIR_QSTORE2: + form0 = "%0,"; + offset += UNITS_PER_WORD; + direction = VE_DIR_STORE; + break; + case VE_DIR_PFCH: + form0 = ""; + break; + default: + form0 = "%0,"; + break; + } + switch (direction) + { + case VE_DIR_ATOMIC01: case VE_DIR_ATOMIC20: + if (base1 == NULL_RTX) + { + base1 = base2; + base2 = NULL_RTX; + } + if (base1 != NULL_RTX && base2 != NULL_RTX) + { + xop[0] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[1] = base1; + xop[2] = base2; + output_asm_insn("addu.l\t%0,%1,%2",xop); + base1 = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + base2 = NULL_RTX; + } + if(base1 == NULL_RTX) + form31 = ""; + else + form31 = "(%1)"; + form4 = ",%5"; + break; + + default: + if (base2 == NULL_RTX) + { + if(base1 == NULL_RTX) + form31 = ""; + else + form31 = "(,%1)"; + } + else + { + if(base1 == NULL_RTX) + form31 = "(,%2)"; + else + form31 = "(%2,%1)"; + } + form4 = ""; + } + + if (!ve_const_si_p(offset)) + { + /* over 2GB offset */ + gcc_assert(sym == NULL_RTX); + xop[0] = operand_reg; + xop[1] = base1; + xop[2] = base2; + xop[3] = GEN_INT(offset); + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[5] = operand_aid; + + snprintf(buf,VE_BUF_SIZE,"lea.sl\t%%4,%%H3%s",form31); + output_asm_insn(buf,xop); + + snprintf(buf,VE_BUF_SIZE,"%s\t%s%%L3(,%%4)%s",ldst,form0,form4); + output_asm_insn(buf,xop); + } + else + { + /* under 2GB offset, SYMBOL_REF or LABEL_REF */ + xop[0] = operand_reg; + xop[1] = base1; + xop[2] = base2; + xop[3] = GEN_INT(offset); + xop[4] = sym; + xop[5] = operand_aid; + if (sym == NULL_RTX) + { + snprintf(buf,VE_BUF_SIZE,"%s\t%s%%3%s%s",ldst,form0,form31,form4); + } + else /* sym != NULL_RTX */ + { + const char *form3 = (offset > 0)? "+%3" + : (offset ==0)? "" + : "%3"; + snprintf(buf,VE_BUF_SIZE,"%s\t%s%%4%s%s%s", + ldst,form0,form3,form31,form4); + } + + output_asm_insn(buf,xop); + } + return; +} + +/* Woker function for TARGET_PROMOTE_FUNCTION_MODE. */ +machine_mode +ve_promote_function_mode (const_tree type, + machine_mode mode, + int *punsignedp, + const_tree fntype, + int for_return) +{ + /* for function return value, apply the same rules given + by PROMOTE_MODE */ + if (for_return !=0) + return default_promote_function_mode_always_promote(type,mode, + punsignedp,fntype,for_return); + + /* Promotion of modes smaller than DI mode to + DImode only for argment */ + + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) < 8) + { + return DImode; + } + + return mode; +} + + +const char * +ve_output_call_instr(rtx *operands) +{ + rtx xop[3]; + xop[0] = operands[0]; + xop[1] = gen_rtx_REG(DImode, VE_SCRATCH_REGNUM); + xop[2] = gen_rtx_REG(DImode, VE_RETURN_REGNUM); + + if (REGNO(operands[0]) != VE_SCRATCH_REGNUM) { + output_asm_insn("or\t%1,0,%0",xop); + } + + output_asm_insn("bsic\t%2,(%1)",xop); + + return ""; +} + +const char * +ve_output_call_instr_value(rtx *operands) +{ + ve_output_call_instr(&operands[1]); + + return ""; +} + +rtx +ve_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) +{ + machine_mode mode; + mode = TYPE_MODE(valtype); + if(TREE_CODE (valtype) == VECTOR_TYPE) + return gen_rtx_REG(mode,0); + else + return ve_libcall_value (mode); +} + +rtx +ve_libcall_value (machine_mode mode) +{ + + if (GET_MODE_CLASS(mode) == MODE_COMPLEX_FLOAT) + { + machine_mode inner = GET_MODE_INNER(mode); + if (inner == TFmode || inner == TImode) + return gen_rtx_PARALLEL + (mode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG(inner,0), + GEN_INT(0)), + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG(inner,2), + GEN_INT(GET_MODE_SIZE(inner))) + )); + else + return gen_rtx_PARALLEL + (mode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (inner,0), + GEN_INT(0)), + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (inner,1), + GEN_INT(GET_MODE_SIZE(inner))))); + } + if (GET_MODE_CLASS(mode) == MODE_COMPLEX_INT) + { + machine_mode inner = GET_MODE_INNER(mode); + return gen_rtx_PARALLEL + (mode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG(inner,0), + GEN_INT(0)), + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG(inner,1), + GEN_INT(GET_MODE_SIZE(inner))))); + } + if (mode == TFmode) + return gen_rtx_REG(mode,0); + if (mode == DFmode || mode == SFmode) + return gen_rtx_REG(mode,0) ; + + if (mode == TImode) + return gen_rtx_REG(TImode,0); + if (mode == DImode) + return gen_rtx_REG(DImode,0); + + /* mode == QImode || mode == HImode || mode == SImode */ + return gen_rtx_REG(DImode,0); +} + +static void +ve_elf_asm_constructor (rtx symbol, int priority) +{ + default_elf_init_array_asm_out_constructor (symbol,priority); +} + +static void +ve_elf_asm_destructor (rtx symbol, int priority) +{ + default_elf_fini_array_asm_out_destructor (symbol,priority); +} + +/* Worker function for TARGET_STRUCT_VALUE_RTX. */ + +static rtx +ve_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ +/* pass the address of the struct that is the function value as if it + were an extra parameter */ + return NULL_RTX; +} + +/* Worker function for TARGET_RETURN_IN_MEMORY. */ +static bool +ve_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) +{ + return (TYPE_MODE (type) == BLKmode); +} + +void +ve_asm_output_function_prefix(FILE *file ATTRIBUTE_UNUSED, + const char *fnname ATTRIBUTE_UNUSED) +{ +} + +void +ve_asm_output_ident (const char *ident_str) +{ + const char *ident_asm_op = "\t.ident\t"; + + /* If we are still in the front end, do not write out the string + to asm_out_file. Instead, add a fake top-level asm statement. + This allows the front ends to use this hook without actually + writing to asm_out_file, to handle #ident or Pragma Ident. */ + if (symtab->state == PARSING) + { + char *buf = ACONCAT ((ident_asm_op, "\"", ident_str, "\"\n", NULL)); + symtab->finalize_toplevel_asm (build_string (strlen (buf), buf)); + } + else + fprintf (asm_out_file, "%s\"%s\"\n", ident_asm_op, ident_str); +} + +void +ve_asm_output_function_label (FILE *file, const char *fnname, + tree decl ATTRIBUTE_UNUSED) +{ +/* making of linkage section */ + fputs("\t.type\t",file); + assemble_name(file,fnname); + fputs(", @function\n",file); + if (ve_use_linkage) + { + fputs("\t.using\t",file); + assemble_name(file,fnname); + fprintf(file,",%s\n",reg_names[VE_LINKAGE_REGNUM]); + } + ASM_OUTPUT_LABEL (file, fnname); +} + +static void +ve_output_function_prologue (FILE *file ATTRIBUTE_UNUSED, + HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ +} + +void +ve_expand_prologue (void) +{ + HOST_WIDE_INT size = get_frame_size (); + unsigned long long local_space; + unsigned long long total_space; + int i; + int n_regs_to_save; + long long stack_extension_size; + const char *fnname ; + rtx insn; + + /* Get the function name the same way that toplev.c does before calling + assemble_start_function. This is needed so that the name used here + exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */ + fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + n_regs_to_save = 0 ; + + for(i = FIRST_S_REG ; i <= LAST_S_REG ; i++) + { + if(REG_NEEDS_SAVE(i)) + { + n_regs_to_save++; + } + } + if (n_regs_to_save > VE_MAX_SAVE_REGS) + fatal_error(input_location, + "internal error:saving registers exceeds limit"); + fputs("\t# Function '",asm_out_file); + assemble_name(asm_out_file,fnname); + fprintf(asm_out_file,"' local:" + HOST_WIDE_INT_PRINT_DEC + " bytes, param:%d bytes, save regs:%d.\n", + size,crtl->outgoing_args_size,n_regs_to_save+2); + /* +2 = frame pointer and return address */ + + /* add max function paramlist size*/ + local_space = size + crtl->outgoing_args_size; + total_space = local_space + VE_RSA_SIZE; + + /* align to 16 bytes*/ + total_space = (total_space + 15)&(~15LL); + local_space = total_space - VE_RSA_SIZE; + + /* set stack usage info */ + if (flag_stack_usage_info) + current_function_static_stack_size = total_space; + + + /* save frame pointer */ + insn = emit_move_insn ( + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, 0)), + frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant(Pmode, stack_pointer_rtx,0)); + add_reg_note (insn, REG_CFA_OFFSET, + gen_rtx_SET( + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, 0)), + frame_pointer_rtx)); + + /* save return address registerr */ + emit_move_insn ( + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, + UNITS_PER_WORD)), + gen_rtx_REG(Pmode,VE_RETURN_REGNUM)); + + /* save registers (1) special registers */ + for(i = FIRST_S_REG ; i < VE_SMALLEST_CALLEE_SAVED_REGNUM ; i++) + { + if(REG_NEEDS_SAVE(i)) + { + emit_move_insn ( + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, + (i-14)*8+16)), + gen_rtx_REG(Pmode,i)); + } + } + + /* set Global Offset Table register */ + if (flag_pic) + { + if (df_regs_ever_live_p(VE_GOT_REGNUM)) + { + rtx p,pltreg,gotreg,x; + x = ve_got_sym(); + pltreg = gen_rtx_REG(Pmode,VE_PLT_REGNUM); + gotreg = gen_rtx_REG(Pmode,VE_GOT_REGNUM); + emit_insn (gen_ve_move_pic_pc2(gotreg,x,pltreg)); + } + } + + /* set frame pointer */ + insn = emit_move_insn ( + frame_pointer_rtx, + stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_DEF_CFA,frame_pointer_rtx); + + /* save registers (2) callee saved registers */ + for(i = VE_SMALLEST_CALLEE_SAVED_REGNUM ; i <= LAST_S_REG ; i++) + { + if(REG_NEEDS_SAVE(i)) + { + emit_move_insn ( + gen_rtx_MEM(Pmode, + plus_constant(Pmode,frame_pointer_rtx, + (i-14)*8+16)), + gen_rtx_REG(Pmode,i)); + } + } + + + /* set text section base register */ + if (ve_use_linkage) + emit_move_insn ( + gen_rtx_REG(Pmode,VE_LINKAGE_REGNUM), + gen_rtx_REG(Pmode,VE_SCRATCH_REGNUM)); + + /* extend stack area */ + /* N.B. VE allows over 2GByte local stack size. Is there any limit ? */ + stack_extension_size = (HOST_WIDE_INT)(-total_space); + + emit_insn (gen_rtx_SET ( + stack_pointer_rtx, + gen_rtx_UNSPEC_VOLATILE(Pmode, + gen_rtvec(3, + GEN_INT(stack_extension_size), + gen_rtx_REG(Pmode,VE_BEGIN_TEMP_REGNUM), + gen_rtx_REG(Pmode,VE_BEGIN_TEMP_REGNUM+1)), + UNSPEC_STACK_PROLOGUE) + )); + + if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + { + emit_insn(gen_init_program_mode()); + } + + emit_insn (gen_prologue_end ()); + emit_insn (gen_blockage ()); +} + +static bool +ve_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true); +} + +/* Initial offset from frame_pointer to stack pointer after prologue */ +HOST_WIDE_INT +ve_initial_elimination_offset (int from, int to) +{ + HOST_WIDE_INT offset; + gcc_assert(from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM); + offset = get_frame_size() + crtl->outgoing_args_size + VE_RSA_SIZE; + offset = (offset + 15) & (~15LL); + return offset; +} + + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the VE first VE_MAX_ARGS_IN_REGS are passed in register + any more args are passed in stack. */ + +static rtx +ve_function_arg_1 (cumulative_args_t cum_v, machine_mode mode, + const_tree type, bool named ATTRIBUTE_UNUSED, bool incoming_p) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + int arg_number = cum->arg_words/UNITS_PER_WORD; + int arg_number_align; + int size, numargs; + rtx loc[VE_MAX_ARGS_IN_REGS+1]; + int i; + + /* Last-argument marker. */ + if (mode == VOIDmode) + return NULL_RTX; + + size = (mode != BLKmode)? GET_MODE_SIZE(mode) + : int_size_in_bytes(type); + + arg_number_align = arg_number; + if (mode == TFmode || mode == TCmode || mode == TImode || mode == CTImode) + arg_number_align = arg_number_align + (arg_number_align & 1); + + numargs = (size+UNITS_PER_WORD-1)/UNITS_PER_WORD; + if (arg_number_align + numargs > VE_MAX_ARGS_IN_REGS) + return NULL_RTX; + + if (mode == TFmode || mode == TCmode || mode == TImode || mode == CTImode) + if (arg_number_align > arg_number) + cum->arg_words += UNITS_PER_WORD; + + if (incoming_p + || ve_argmem == ARGMEM_OPT + || ((ve_argmem == ARGMEM_SAFE + && cum->prototype) && !cum->stdarg)) + { + if (cum->stdarg) + { + return NULL_RTX; + } + else + { + return gen_rtx_REG (mode,VE_FIRST_ARG_REGNUM + arg_number_align); + } + } + + /* otherwise set arg to both memory and register + if (ve_argmem == ARGMEM_FORCE + || ve_argmem == ARGMEM_SAFE + && (!cum->prototype || cum->indirect || cum->stdarg)) + */ + switch (mode) + { + case BLKmode: + /* set 0 on the first vector means set args also on stack */ + loc[0] = gen_rtx_EXPR_LIST(VOIDmode, NULL_RTX, GEN_INT(0)); + for (i=0; i < numargs; i++) + { + loc[i+1] = gen_rtx_EXPR_LIST(VOIDmode, + gen_rtx_REG(DImode, + VE_FIRST_ARG_REGNUM + arg_number_align + i), + GEN_INT(i*UNITS_PER_WORD)); + } + return gen_rtx_PARALLEL(mode, gen_rtvec_v(numargs+1,loc)); + + case TFmode: case TCmode: case TImode: case CTImode: + /* set 0 on the first vector means set args also on stack */ + /* swap odd-even regster since register number is big endian */ + /* 0 1 2 3 -> 1 0 3 2 */ + loc[0] = gen_rtx_EXPR_LIST(VOIDmode, NULL_RTX, GEN_INT(0)); + for (i=numargs-1; i>=0; i--) + { + loc[i+1] = gen_rtx_EXPR_LIST(VOIDmode, + gen_rtx_REG(DImode, + VE_FIRST_ARG_REGNUM + arg_number_align + i), + GEN_INT((i^1)*UNITS_PER_WORD)); + } + return gen_rtx_PARALLEL(mode, gen_rtvec_v(numargs+1,loc)); + + /* mode != BLKmode, TFmode, TCmode */ + /* set 0 on the first vector means set args also on stack */ + /* See ** below. This is the mode before promotion. */ + /* If we use "mode" instead of TYPE_MODE(type), wrong conversion */ + /* ZERO_EXTEND will be generated if the argument is promoted */ + default: + return gen_rtx_PARALLEL(mode, gen_rtvec(2, + gen_rtx_EXPR_LIST(VOIDmode, + NULL_RTX, + const0_rtx), + gen_rtx_EXPR_LIST(VOIDmode, + gen_rtx_REG (type?TYPE_MODE(type):mode,//<-- ** risky + VE_FIRST_ARG_REGNUM + arg_number_align), + const0_rtx) + )); + } +} + +/* Handle the TARGET_FUNCTION_ARG target hook. */ + +static rtx +ve_function_arg (cumulative_args_t cum, machine_mode mode, + const_tree type, bool named) +{ + return ve_function_arg_1 (cum, mode, type, named, false); +} + +/* Handle the TARGET_FUNCTION_INCOMING_ARG target hook. */ + +static rtx +ve_function_incoming_arg (cumulative_args_t cum, machine_mode mode, + const_tree type, bool named) +{ + return ve_function_arg_1 (cum, mode, type, named, true); +} + +static unsigned int +ve_function_arg_boundary (machine_mode mode, const_tree type) +{ + unsigned int alignment; + + alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode); + if (alignment < PARM_BOUNDARY) + alignment = PARM_BOUNDARY; + + return alignment; +} + +/* Handle the TARGET_PASS_BY_REFERENCE target hook. + Specify whether to pass the argument by reference. */ + +static bool +ve_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, + const_tree type, + bool named ATTRIBUTE_UNUSED) +{ +/* On the VE, structures and unions are passed by registers + or paramlist smaller up to 16 byte. + There are passed by reference if the */ + return (type && AGGREGATE_TYPE_P (type) + && (HOST_WIDE_INT) int_size_in_bytes (type) + > ve_struct_by_value); +} + + +/* Update the data in CUM to advance over an argument of mode MODE and + data type TYPE. (TYPE is null for libcalls where that information + may not be available.) */ + +void +ve_init_cumulative_args(CUMULATIVE_ARGS *cum, tree fntype, + rtx libname ATTRIBUTE_UNUSED, + tree fndecl) +{ + cum->arg_words = 0; + cum->indirect = fntype && !fndecl; + cum->stdarg = stdarg_p(fntype); + cum->prototype = fntype && prototype_p (fntype); +} + +static void +ve_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, + const_tree type, + bool named ATTRIBUTE_UNUSED) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + int size; + + size = (mode != BLKmode)? GET_MODE_SIZE(mode) + : int_size_in_bytes(type); + cum->arg_words += UNITS_PER_WORD*((size+UNITS_PER_WORD-1)/UNITS_PER_WORD); +} + +/* Implement TARGET_SHIFT_TRUNCATION_MASK */ + +static unsigned HOST_WIDE_INT +ve_shift_truncation_mask (machine_mode mode) +{ + switch (mode) + { + case SImode: + return 31; + case DImode: + return 63; + default: + return 0; + } +} + +/* Implement TARGET_MODE_REP_EXTENDED. */ +static int +ve_mode_rep_extended (machine_mode mode, machine_mode mode_rep) +{ + /* SImode register values are sign-extended to DImode. */ + if (mode == SImode && mode_rep == DImode) + return SIGN_EXTEND; + if (mode == HImode && mode_rep == SImode) + return SIGN_EXTEND; + if (mode == QImode && mode_rep == HImode) + return SIGN_EXTEND; + + return UNKNOWN; +} + +void +ve_profile_hook (int labelno ATTRIBUTE_UNUSED) +{ + const char *fnname; + rtx mcount_ref, fnname_ref; + + fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + while (*fnname == '*') fnname++; + fnname_ref = gen_rtx_SYMBOL_REF (Pmode, fnname); + mcount_ref = gen_rtx_SYMBOL_REF (Pmode, "mcount"); + + emit_library_call(mcount_ref, LCT_NORMAL, + VOIDmode, 2, + fnname_ref, Pmode, + gen_rtx_MEM(Pmode, + plus_constant(Pmode, frame_pointer_rtx,8)), + Pmode); +} + + +bool +ve_epilogue_uses (int regno) +{ + machine_mode mode; + if (regno == STACK_LIMIT_REGNUM || regno == FRAME_POINTER_REGNUM + || regno == VE_RETURN_REGNUM || regno == STACK_POINTER_REGNUM + || regno == VE_GOT_REGNUM || regno == VE_PLT_REGNUM ) + return true; + if (REG_NEEDS_SAVE(regno)) + return true; + + mode = DECL_MODE(DECL_RESULT(current_function_decl)); + if (regno == 0) + if (mode == DImode || mode == SImode || mode == HImode || mode == QImode + || mode == CDImode || mode == CSImode || mode == CHImode || mode == CQImode + || mode == TImode || mode == CTImode) + return true; + if (regno == 0) + if (mode == DFmode || mode == SFmode || mode == DCmode || mode == SCmode + || mode == TFmode || mode ==TCmode) + return true; + if (regno == 1) + if (mode == DCmode || mode == CDImode || mode == TFmode || mode ==TCmode + || mode == TImode || mode == CTImode) + return true; + if (regno == 2) + if (mode ==TCmode || mode == CTImode) + return true; + if (regno == 3) + if (mode ==TCmode || mode == CTImode) + return true; + + return false; +} + +void +ve_expand_epilogue(void) +{ + int i; + rtx insn; + + emit_insn (gen_blockage ()); + emit_insn (gen_epilogue_start ()); + +/* recover saved registers (2) callee saved registers */ + for(i = VE_SMALLEST_CALLEE_SAVED_REGNUM ; i <= LAST_S_REG ; i++) { + if(REG_NEEDS_SAVE(i)) + { + insn = emit_move_insn ( + gen_rtx_REG(Pmode,i), + gen_rtx_MEM(Pmode, + plus_constant(Pmode,frame_pointer_rtx, + (i-14)*8+16))); + } + } + + /* recover stack pointer */ + insn = emit_move_insn ( + stack_pointer_rtx, + frame_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_REGISTER, + gen_rtx_SET(stack_pointer_rtx,frame_pointer_rtx)); + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant(Pmode, stack_pointer_rtx,0)); + +/* recover saved registers (1) */ + for(i = FIRST_S_REG ; i < VE_SMALLEST_CALLEE_SAVED_REGNUM ; i++) + { + if(REG_NEEDS_SAVE(i)) + { + insn = emit_move_insn ( + gen_rtx_REG(Pmode,i), + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, + (i-14)*8+16))); + } + } + + /* recover return address register */ + insn = emit_move_insn ( + gen_rtx_REG(Pmode,VE_RETURN_REGNUM), + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, + UNITS_PER_WORD))); + + /* recover frame pointer */ + emit_move_insn ( + frame_pointer_rtx, + gen_rtx_MEM(Pmode, + plus_constant(Pmode,stack_pointer_rtx, 0))); + + emit_jump_insn (ret_rtx); +} + +static void +ve_output_function_epilogue (FILE *file, + HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ + fputs("\t# End of function\n", file); +} + +/* Output the rest of the textual info surrounding the epilogue. */ +void +ve_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED) +{ + if (!flag_inhibit_size_directive) + { + fputs(SIZE_ASM_OP,file); + assemble_name(file,fnname); + fputs(",.-", file); + assemble_name(file,fnname); + fputs("\n", file); + } +} + +/* Return an RTX indicating where the return address to the + calling function can be found. */ +rtx +ve_return_addr_rtx (int count ATTRIBUTE_UNUSED, rtx frame) +{ + return gen_rtx_MEM(Pmode, plus_constant(Pmode, frame, UNITS_PER_WORD)); +} + +static section * +ve_function_section (tree decl, enum node_frequency freq, + bool startup, bool exit) +{ + /* Put functions in text section if target doesn't have named sections. */ + if (!targetm_common.have_named_sections) + return text_section; + + /* Force nested functions into the same section as the containing + function. */ + if (decl + && DECL_SECTION_NAME (decl) == NULL + && DECL_CONTEXT (decl) != NULL_TREE + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL + && DECL_SECTION_NAME (DECL_CONTEXT (decl)) == NULL) + return function_section (DECL_CONTEXT (decl)); + + /* Otherwise, use the default function section. */ + return default_function_section (decl, freq, startup, exit); +} + +/* Put constant pool in text section */ +static section * +ve_select_rtx_section (machine_mode mode, rtx x, + unsigned HOST_WIDE_INT align) +{ + return default_elf_select_rtx_section (mode, x, align); +} + +static section* +ve_select_section (tree decl, int reloc, + unsigned HOST_WIDE_INT align) +{ + return default_elf_select_section (decl, reloc, align); +} + +/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. + We need to emit DTP-relative relocations. */ + +static void +ve_output_dwarf_dtprel (FILE *file, int size, rtx x) +{ + switch (size) + { + case 4: + fputs ("\t.4byte\t", file); + break; + case 8: + fputs ("\t.8byte\t", file); + break; + default: + gcc_unreachable (); + } + output_addr_const (file, x); + fputs ("@dtpoff", file); +} + +static void +ve_file_start(void) +{ + default_file_start(); +} + +/* constant_alignment, almost the same as i386 */ +int +ve_constant_alignment (tree exp, int align) +{ + if (TREE_CODE (exp) == REAL_CST || TREE_CODE (exp) == VECTOR_CST + || TREE_CODE (exp) == INTEGER_CST) + { + if (TYPE_MODE (TREE_TYPE (exp)) == DFmode && align < 64) + return 64; + else if (TYPE_MODE (TREE_TYPE (exp)) == TFmode && align < 128) + return 128; + else if (TYPE_MODE (TREE_TYPE (exp)) == TImode && align < 128) + return 128; + } + else if (!optimize_size && TREE_CODE (exp) == STRING_CST + && TREE_STRING_LENGTH (exp) >= 31 && align < BITS_PER_WORD) + return BITS_PER_WORD; + + return align; +} + +int +ve_check_symbol(rtx x, machine_mode mode) +{ + switch (GET_CODE (x)) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST_VECTOR: + return false; + + case LABEL_REF: + return true; + + case SYMBOL_REF: + return true; + + case CONST: + return ve_check_symbol(XEXP(x,0), mode); + + case PLUS: + case MINUS: + return ve_check_symbol(XEXP(x,0), mode) + || ve_check_symbol(XEXP(x,1), mode); + + default: + return false; + } +} + +rtx +ve_force_const_mem (rtx x, bool direct_call, bool ins_call) +{ + rtx p,ret; + + if (ve_tls_symbol_p(x)) + { + rtx tmp,tp; + + if (!TARGET_TLS_ASIS) + { + /* change all tls model to be global-dynamic anyway */ + ret = gen_rtx_REG(Pmode,0); + emit_insn(gen_tgd_load_call(ret,x,gen_tls_get_addr())); + return ret; + } + + + switch (SYMBOL_REF_TLS_MODEL (x)) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + ret = gen_rtx_REG(Pmode,0); + emit_insn(gen_tgd_load_call(ret,x,gen_tls_get_addr())); + break; + + case TLS_MODEL_LOCAL_DYNAMIC: + ret = gen_reg_rtx (Pmode); + tmp = gen_rtx_REG(Pmode,0); + emit_insn(gen_tld_load_call(tmp,x,gen_tls_get_addr())); + emit_insn(gen_tld_offset_load (ret, x, tmp)); + break; + + case TLS_MODEL_INITIAL_EXEC: + tp = gen_rtx_REG(Pmode, VE_THREAD_POINTER_REGNUM); + tmp = gen_reg_rtx (Pmode); + ret = gen_reg_rtx (Pmode); + emit_insn (gen_tie_load (tmp, x)); + emit_move_insn (ret, gen_rtx_PLUS (Pmode, tp, tmp)); + break; + + case TLS_MODEL_LOCAL_EXEC: + tp = gen_rtx_REG(Pmode, VE_THREAD_POINTER_REGNUM); + ret = gen_reg_rtx (Pmode); + emit_insn (gen_tle_load (ret, x, tp)); + break; + + default: + gcc_unreachable (); + } + return ret; + + } + else if (flag_pic) + { + if (SYMBOL_REF_FUNCTION_P(x)) + { + + if (SYMBOL_REF_LOCAL_P(x)) + { + /* pic static function */ + ret = gen_reg_rtx (Pmode); + emit_insn (gen_ve_move_pic_pc(ret,x)); + return ret; + } + else if (direct_call) + { + /* pic direct external function */ + ret = gen_reg_rtx (Pmode); + emit_insn (gen_ve_move_pic_plt(ret,x)); + + crtl->uses_pic_offset_table = 1; + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + emit_use (gen_rtx_REG(Pmode,VE_PLT_REGNUM)); + return ret; + } + else + { + /* pic indirect external function */ + ret = gen_reg_rtx (Pmode); + emit_insn (gen_ve_move_pic_got(ret,x)); + + crtl->uses_pic_offset_table = 1; + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + return ret; + } + } + else + { + if (SYMBOL_REF_LOCAL_P(x)) + { + /* pic static variable */ + ret = gen_reg_rtx (Pmode); + emit_insn (gen_ve_move_pic_gotoff(ret,x)); + + crtl->uses_pic_offset_table = 1; + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + return ret; + } + else + { + /* pic external variable */ + ret = gen_reg_rtx (Pmode); + emit_insn (gen_ve_move_pic_got(ret,x)); + + crtl->uses_pic_offset_table = 1; + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + return ret; + } + } + } + else if (!ve_symbol_indirect) + { + /* notls, nopic functions or variables */ + p = x; + ret = gen_reg_rtx (Pmode); + if (SYMBOL_REF_FUNCTION_P(x) && ins_call) + emit_insn (gen_ve_move_call(ret,x)); + else + emit_insn (gen_ve_move(ret,x)); + + if (SYMBOL_REF_FUNCTION_P(x) && !SYMBOL_REF_LOCAL_P(x)) + { + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + emit_use (gen_rtx_REG(Pmode,VE_PLT_REGNUM)); + } + return ret; + } + else + { + if (SYMBOL_REF_FUNCTION_P(x) && !SYMBOL_REF_LOCAL_P(x)) + { + emit_use (gen_rtx_REG(Pmode,VE_GOT_REGNUM)); + emit_use (gen_rtx_REG(Pmode,VE_PLT_REGNUM)); + } + /* nopic force use memory */ + return force_const_mem(Pmode,x); + } + + /* VE_SCRATCH_REGISTER may be destroyed between here and bsic. + So, we do not use it + if (SYMBOL_REF_FUNCTION_P(x)) + tmpreg = gen_rtx_REG(Pmode,VE_SCRATCH_REGNUM); + else + */ +} + +rtx +ve_force_label_relative(rtx x) +{ + rtx p,tmpreg; + if (!ve_symbol_indirect) + { + p = gen_rtx_UNSPEC(Pmode,gen_rtvec(1,x), + UNSPEC_MOVE_PIC_LABEL); + } + else + p = x; + tmpreg = gen_reg_rtx(Pmode); + emit_insn (gen_rtx_SET (tmpreg, p)); + return tmpreg; +} + +rtx +ve_indirect_addr(rtx x, bool direct_call, bool ins_call) +{ + rtx ret; + rtx tmpreg; + switch (GET_CODE (x)) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST_VECTOR: + ret = x; + break; + + case LABEL_REF: + ret = ve_force_label_relative(x); + break; + + case SYMBOL_REF: + tmpreg = gen_reg_rtx(GET_MODE(x)); + emit_move_insn(tmpreg,ve_force_const_mem(x,direct_call,ins_call)); + ret = tmpreg; + break; + + case CONST: + /* remove CONST */ + ret = ve_indirect_addr(XEXP(x,0),direct_call,ins_call); + break; + + case PLUS: + ret = gen_rtx_PLUS(GET_MODE(x), + ve_indirect_addr(XEXP(x,0),direct_call,ins_call), + ve_indirect_addr(XEXP(x,1),direct_call,ins_call)); + break; + + case MINUS: + ret = gen_rtx_MINUS(GET_MODE(x), + ve_indirect_addr(XEXP(x,0),direct_call,ins_call), + ve_indirect_addr(XEXP(x,1),direct_call,ins_call)); + break; + + default: + ret = x; + } + return ret; +} + + static rtx +ve_expand_mem_scratch(rtx x, int *changed) + { + rtx tmp,tmpreg; + *changed = 0; + + if (REG_P(x)) + return x; + + if (GET_CODE(x) == SYMBOL_REF) + { + return x; + } + + if (GET_CODE(x) == MEM) + { + int c1; + tmp = ve_expand_mem_scratch(XEXP(x,0),&c1); + tmpreg = gen_rtx_REG(GET_MODE(x),VE_SCRATCH_REGNUM); + emit_move_insn(tmpreg,gen_rtx_MEM(GET_MODE(x),tmp)); + *changed = 1; + return tmpreg; + } + + if (GET_CODE(x) == PLUS) + { + int c1,c2; + rtx x1 = ve_expand_mem_scratch(XEXP(x,0),&c1); + rtx x2 = ve_expand_mem_scratch(XEXP(x,1),&c2); + if (c1 || c2) + { + x = gen_rtx_PLUS(GET_MODE(x),x1,x2); + *changed = 1 ; + } + return x; + } + + return x; + } + +int +ve_expand_move(rtx *operands, machine_mode mode) +{ + int ret; + rtx lhs,rhs; + if (lra_in_progress == 0 && reload_in_progress ==0 && reload_completed == 0) + { + if (ve_check_symbol(operands[1],mode)) + { + rhs = ve_indirect_addr(operands[1],false,false); + if (ve_check_symbol(operands[0],mode)) + { + lhs = ve_indirect_addr(operands[0],false,false); + } + else + lhs = operands[0]; + if (GET_CODE(lhs) != REG && GET_CODE(rhs) != REG) + { + rtx tmpreg = gen_reg_rtx(GET_MODE(rhs)); + emit_move_insn(tmpreg,rhs); + rhs = tmpreg; + } + emit_move_insn(lhs,rhs); + ret = 1; + } + + else if (ve_check_symbol(operands[0],mode)) + { + lhs = ve_indirect_addr(operands[0],false,false); + rhs = operands[1]; + if (GET_CODE(lhs) != REG && GET_CODE(rhs) != REG) + { + rtx tmpreg = gen_reg_rtx(GET_MODE(rhs)); + emit_move_insn(tmpreg,rhs); + rhs = tmpreg; + } + emit_move_insn(lhs,rhs); + ret = 1; + } + + else + ret = 0; + } + + else { + int c1,c2; + rtx x1,x2; + + if (GET_CODE(operands[0]) == MEM) + { + x1 = ve_expand_mem_scratch(XEXP(operands[0],0),&c1); + if (GET_CODE(operands[1]) == MEM) + { + x2 = ve_expand_mem_scratch(XEXP(operands[1],0),&c2); + if (c1 || c2) + emit_move_insn(gen_rtx_MEM(mode,x1),gen_rtx_MEM(mode,x2)); + } + else + { + x2 = ve_expand_mem_scratch(operands[1],&c2); + if (c1 || c2) + emit_move_insn(gen_rtx_MEM(mode,x1),x2); + } + } + else + { + x1 = ve_expand_mem_scratch(operands[0],&c1); + if (GET_CODE(operands[1]) == MEM) + { + x2 = ve_expand_mem_scratch(XEXP(operands[1],0),&c2); + if (c1 || c2) + emit_move_insn(x1,gen_rtx_MEM(mode,x2)); + } + else + { + x2 = ve_expand_mem_scratch(operands[1],&c2); + if (c1 || c2) + emit_move_insn(x1,x2); + } + } + ret = c1 || c2; + } + + return ret; +} + +bool ve_const_si_p(long long x) { + return x >= -2147483647LL-1 && x <= 2147483647LL; +} + +enum unwind_info_type +ve_debug_unwind_info (void) +{ + return UI_SJLJ; +} + +void +ve_asm_output_anchor (rtx symbol) +{ + char buf[VE_BUF_SIZE]; + + snprintf (buf,VE_BUF_SIZE,"$ + " HOST_WIDE_INT_PRINT_DEC, + SYMBOL_REF_BLOCK_OFFSET (symbol)); + ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buf); +} + +/* Initialize the GCC target structure. */ +#undef TARGET_ASM_ALIGNED_HI_OP +#define TARGET_ASM_ALIGNED_HI_OP "\t.short\t" +#undef TARGET_ASM_ALIGNED_SI_OP +#define TARGET_ASM_ALIGNED_SI_OP "\t.int\t" +#undef TARGET_ASM_ALIGNED_DI_OP +#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" +#undef TARGET_ASM_BYTE_OP +#define TARGET_ASM_BYTE_OP "\t.byte\t" + +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS ve_legitimize_address + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P ve_legitimate_address_p + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE ve_output_function_prologue + +#undef TARGET_ASM_FUNCTION_EPILOGUE +#define TARGET_ASM_FUNCTION_EPILOGUE ve_output_function_epilogue + +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR ve_elf_asm_constructor + +#undef TARGET_ASM_DESTRUCTOR +#define TARGET_ASM_DESTRUCTOR ve_elf_asm_destructor + +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START ve_file_start + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX ve_struct_value_rtx + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY ve_return_in_memory + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM ve_cannot_force_const_mem + +#undef TARGET_PROMOTE_FUNCTION_MODE +#define TARGET_PROMOTE_FUNCTION_MODE ve_promote_function_mode + +#undef TARGET_PRINT_OPERAND +#define TARGET_PRINT_OPERAND ve_print_operand + +#undef TARGET_PRINT_OPERAND_ADDRESS +#define TARGET_PRINT_OPERAND_ADDRESS ve_print_operand_address + +#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P ve_print_operand_punct_valid_p + +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST ve_register_move_cost +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST ve_memory_move_cost +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS ve_rtx_costs + +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P ve_legitimate_constant_p + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE ve_option_override + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE ve_can_eliminate + +#undef TARGET_FUNCTION_ARG_ADVANCE +#define TARGET_FUNCTION_ARG_ADVANCE ve_function_arg_advance +#undef TARGET_FUNCTION_ARG +#define TARGET_FUNCTION_ARG ve_function_arg + +/* VE specific */ +#undef TARGET_FUNCTION_INCOMING_ARG +#define TARGET_FUNCTION_INCOMING_ARG ve_function_incoming_arg +#undef TARGET_FUNCTION_ARG_BOUNDARY +#define TARGET_FUNCTION_ARG_BOUNDARY ve_function_arg_boundary + +/* Complex arguments to be split and treated as their individual components */ +#undef TARGET_SPLIT_COMPLEX_ARG +#define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true + +#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE +#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true + +#undef TARGET_MODE_REP_EXTENDED +#define TARGET_MODE_REP_EXTENDED ve_mode_rep_extended + +#undef TARGET_ASM_FUNCTION_SECTION +#define TARGET_ASM_FUNCTION_SECTION ve_function_section + +#undef TARGET_ASM_SELECT_RTX_SECTION +#define TARGET_ASM_SELECT_RTX_SECTION ve_select_rtx_section +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION ve_select_section + +#undef TARGET_ASM_OUTPUT_IDENT +#define TARGET_ASM_OUTPUT_IDENT ve_asm_output_ident + +#undef TARGET_ASM_OUTPUT_DWARF_DTPREL +#define TARGET_ASM_OUTPUT_DWARF_DTPREL ve_output_dwarf_dtprel + +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P ve_scalar_mode_supported_p + +#undef TARGET_VECTOR_MODE_SUPPORTED_P +#define TARGET_VECTOR_MODE_SUPPORTED_P ve_vector_mode_supported_p + +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE ve_trampoline_template + +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT ve_trampoline_init + +#undef TARGET_PASS_BY_REFERENCE +#define TARGET_PASS_BY_REFERENCE ve_pass_by_reference + +#undef TARGET_SHIFT_TRUNCATION_MASK +#define TARGET_SHIFT_TRUNCATION_MASK ve_shift_truncation_mask + +/* disable new local register allocator */ +#undef TARGET_LRA_P +#define TARGET_LRA_P hook_bool_void_false + +struct gcc_target targetm = TARGET_INITIALIZER; + +#include "gt-ve.h" diff --git a/gcc/config/ve/ve.h b/gcc/config/ve/ve.h new file mode 100644 index 00000000000..f5d5d2ca6e9 --- /dev/null +++ b/gcc/config/ve/ve.h @@ -0,0 +1,1134 @@ +/* Definitions of target machine for GNU compiler. VE version. + Copyright (C) 2007-2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +#include "config/ve/ve-opts.h" + +#define TARGET_VE 1 + +#define VE_REGSYM "%" + +/* Compiler working register, only for last resort */ +#define VE_SCRATCH_REGNUM 12 + +/* linkage and text base register */ +#define VE_LINKAGE_REGNUM 17 + +/* return address register */ +#define VE_RETURN_REGNUM 10 + +/* thread pointer */ +#define VE_THREAD_POINTER_REGNUM 14 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 11 + +/* Register indicates stack limitation */ +#define STACK_LIMIT_REGNUM 8 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 9 + +/* Smallest number of callee saved register */ +#define VE_SMALLEST_CALLEE_SAVED_REGNUM 18 + + +/* Register in which address to store a structure value + is passed to a function. + #define VE_STRUCT_VALUE_REGNUM 0 + + We do not use this since we set struct_value_rtx to NULL + which means it is passed as an extra argument +*/ + +/* start of temporary (can be freely used) registers */ +#define VE_BEGIN_TEMP_REGNUM 34 + +/* Register which holds the Global Offset Table, if any. */ +#define VE_GOT_REGNUM 15 + +/* Register which holds the Procedure Linkage Table, if any. */ +#define VE_PLT_REGNUM 16 + +/* Register which holds offset table for position-independent + data references. */ + +#define PIC_OFFSET_TABLE_REGNUM \ + (flag_pic ? VE_GOT_REGNUM : INVALID_REGNUM) + +#ifdef SINGLE_LIBC +#define OPTION_GLIBC (DEFAULT_LIBC == LIBC_GLIBC) +#define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC) +#define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC) +#undef OPTION_MUSL +#define OPTION_MUSL (DEFAULT_LIBC == LIBC_MUSL) +#else +#define OPTION_GLIBC (linux_libc == LIBC_GLIBC) +#define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC) +#define OPTION_BIONIC (linux_libc == LIBC_BIONIC) +#undef OPTION_MUSL +#define OPTION_MUSL (linux_libc == LIBC_MUSL) +#endif + +/* Target CPU builtins. */ + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__linux__"); \ + builtin_define ("__linux"); \ + builtin_define ("linux"); \ + builtin_assert ("system=linux"); \ + builtin_define ("__gnu_linux__"); \ + builtin_define ("__unix__"); \ + builtin_define ("__unix"); \ + builtin_define ("unix"); \ + builtin_assert ("system=unix"); \ + builtin_assert ("system=posix"); \ + builtin_define ("__ve__"); \ + builtin_define ("__ve"); \ + builtin_define ("__VE__"); \ + builtin_define ("__VE"); \ + builtin_assert ("cpu=ve"); \ + builtin_assert ("machine=ve"); \ +} while (0) + +/* Conditional codes for branch instrunctions. + Note: + VE "ne" operation is "not equal and not nan"; this is "ltgt" of gcc + VE "nenan" operation is "not equal or nan"; this is "ne" of gcc */ +#define VE_COND_EQ "eq" +#define VE_COND_NE "ne" +#define VE_COND_FNE "nenan" +#define VE_COND_GT "gt" +#define VE_COND_GE "ge" +#define VE_COND_LT "lt" +#define VE_COND_LE "le" +#define VE_COND_GTU "gt" +#define VE_COND_GEU "ge" +#define VE_COND_LTU "lt" +#define VE_COND_LEU "le" +#define VE_COND_UNEQ "eqnan" +#define VE_COND_LTGT "ne" +#define VE_COND_UNGT "gtnan" +#define VE_COND_UNGE "genan" +#define VE_COND_UNLT "ltnan" +#define VE_COND_UNLE "lenan" +#define VE_COND_UNORDERED "nan" +#define VE_COND_ORDERED "num" + +/* asm load store instrunction flag */ +enum { +VE_DIR_LOAD, +VE_DIR_STORE, +VE_DIR_QLOAD, +VE_DIR_QLOAD1, +VE_DIR_QLOAD2, +VE_DIR_QSTORE, +VE_DIR_QSTORE1, +VE_DIR_QSTORE2, +VE_DIR_PFCH, +VE_DIR_ATOMIC01, +VE_DIR_ATOMIC20 +}; + +/* If the assembler supports thread-local storage, assume that the + system does as well. */ +#define TARGET_HAVE_TLS true +#define TARGET_TLS 1 +#undef TARGET_GNU_TLS +#define TARGET_GNU_TLS 1 + +/* Target machine storage layout */ + +/* Define this macro to have the value 1, if most significant + bit is lowest numbered in instructions that operate on + numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this macro to have the value 1 if the most significant + byte in a word has the lowest number. */ +#define BYTES_BIG_ENDIAN 0 + +/* Define this macro to have the value 1 if, in a multiword + object, the most significant word has the lowest number. + This applies to both memory locations and registers */ +#define WORDS_BIG_ENDIAN 0 + +#define REG_WORDS_BIG_ENDIAN 1 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 64 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 8 + +/* Minimum number of units in a word. If this is undefined, the default + is UNITS_PER_WORD. Otherwise, it is the constant value that is the + smallest value that UNITS_PER_WORD can have at run-time. + + FIXME: This needs to be 4 when TARGET_64BIT is true to suppress the + building of various TImode routines in libgcc. The ve runtime + specification doesn't provide the alignment requirements and calling + conventions for TImode variables. */ +#define MIN_UNITS_PER_WORD 4 + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ +if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ +{ \ + (MODE) = DImode; \ +} + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 64 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. + It cound be 64, but support of long double arise the bug 38395 problem + PARM_BOUNDARY =64 < GET_MODE_ALIGNMENT(TFmode) */ +#define PARM_BOUNDARY 64 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +/* if we change it to 128, parameter list rounds-up to 128byte */ +#define STACK_BOUNDARY 128 + +/* Define this macro if you wish to preserve a certain alignment for + the stack pointer, greater than what the hardware enforces. The + definition is a C expression for the desired alignment (measured + in bits). This macro must evaluate to a value equal to or larger + than STACK_BOUNDARY. */ +/* This must be 128 otherwise TFmode(long double) variable does not + allocated on frame properly */ +#define PREFERRED_STACK_BOUNDARY 128 + +/* Allocation boundary (in *bits*) for the code of a function. */ +/* 128 means 16 byte align */ +#define FUNCTION_BOUNDARY 128 +#if 0 +#define FUNCTION_BOUNDARY 1024 +#endif + +/* biggest alignment of data. If we set it to 128, some optimization + makes wrong code for TF mode when expand_asignment expand TFs mode + variable to bit_fields on a litte endian mode */ +#define BIGGEST_ALIGNMENT 128 +#define BIGGEST_FIELD_ALIGNMENT 128 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + + +/* Number of bits which any structure or union's size must be a + multiple of. Each structure or union's size is rounded up to a + multiple of this. */ +/* The usage of 't' is tricky; this macro is used only once in + stor-layout.c where t is a variable of type tree */ +#define STRUCTURE_SIZE_BOUNDARY (TARGET_PADSTRUCT ? 32 : 8) + + +/* Set this non-zero if move instructions will actually fail to work + when given unaligned data.*/ + +#define STRICT_ALIGNMENT 1 + +/* If bit field type is int, don't let it cross an int, + and give entire struct the alignment of an int. */ +/* Required on the 386 since it doesn't have bit-field insns. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + +#define INT_TYPE_SIZE 32 +#define SHORT_TYPE_SIZE 16 +#define LONG_TYPE_SIZE 64 +#define LONG_LONG_TYPE_SIZE 64 +#define CHAR_TYPE_SIZE 8 +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE 128 + +/* Select _Bool size depends on compile option */ +#define BOOL_TYPE_SIZE (TARGET_FOUR_BYTE_BOOL ? INT_TYPE_SIZE : CHAR_TYPE_SIZE) + +/* Define default char to be signed. This is the same as that of x86 + but different from the sxc++ default */ +#define DEFAULT_SIGNED_CHAR 1 + +/* long double is not a fixed mode, but the idea is that, if we + support long double, we also want a 128-bit integer type. */ +#define MAX_FIXED_MODE_SIZE 64 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ +#define STORE_FLAG_VALUE 1 + +/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return + values must be in memory. */ +/* So, RETURN_IN_MEMORY is not used! When setting this to 0, struct {char c;} + is not treated as BLKmode and do not go to memory */ +#define DEFAULT_PCC_STRUCT_RETURN 1 + +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. For floating-point, CCFPmode + should be used. */ + +/* A function address in a call instruction + * is 8 byte address (all instruction length is 8 byte) */ +#define FUNCTION_MODE DImode + +/* Define this to be nonzero if shift instructions ignore all but the low-order + few bits. */ +/* Although truncations happen on the machine instructions + We do not set this macro, for the compatibility with the + the VE proprietary compiler */ +#define SHIFT_COUNT_TRUNCATED (TARGET_SHIFT_COUNT_FULL? 0 : 1) + +#define Pmode DImode + +/* On nec's ve c++ if -size_t64 is specified size_t becomes unsigned long long, + otherwize it is unsigned int */ +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ +#define EXIT_IGNORE_STACK 1 + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE DImode + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 1 + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. + We represent all SI values as sign-extended DI values in + registers. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) \ + ((INPREC) <= 32 || (OUTPREC) > 32) + +/* + * We can't load any constants as immediates. + */ + + +/* + * Since all the registers are equivalent, + * a value can be reloaded in any register of the same + * class. + */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +/* Emit rtl for profiling. */ +#define PROFILE_HOOK(LABEL) ve_profile_hook (LABEL) + +/* All the work done in PROFILE_HOOK, but still required. */ +#define FUNCTION_PROFILER(FILE, LABELNO) do { } while (0) + +/* ve uses a counter for mcount, but needs special treatment (slcomm). */ +#define NO_PROFILE_COUNTERS 1 + +/* Define this macro if the code for function profiling should come + before the function prologue. Normally, the profiling code comes + after. */ + + +/* memory copy with 64 bit words. */ +#define MOVE_MAX 8 + +#define TEXT_SECTION_ASM_OP "\t.text" +#define DATA_SECTION_ASM_OP (TARGET_ASM_ALIGN ? \ + "\t.data\n\t.align\t4" : "\t.data\n\t.balign\t16" ) +#define READONLY_DATA_SECTION_ASM_OP (TARGET_ASM_ALIGN ? \ + "\t.section\t.rodata\n\t.align\t4" : "\t.section\t.rodata\n\t.balign\t16") + +#define CTORS_SECTION_ASM_OP "\t.section\t.init_array,\"aw\",@init_array" +#define DTORS_SECTION_ASM_OP "\t.section\t.fini_array,\"aw\",@fini_array" + +#undef INIT_SECTION_ASM_OP +#undef FINI_SECTION_ASM_OP +#define INIT_ARRAY_SECTION_ASM_OP CTORS_SECTION_ASM_OP +#define FINI_ARRAY_SECTION_ASM_OP DTORS_SECTION_ASM_OP + +/* Since we use .init_array/.fini_array we don't need the markers at + the start and end of the ctors/dtors arrays. */ +#define CTOR_LIST_BEGIN asm (CTORS_SECTION_ASM_OP) +#define CTOR_LIST_END /* empty */ +#define DTOR_LIST_BEGIN asm (DTORS_SECTION_ASM_OP) +#define DTOR_LIST_END /* empty */ + + +/* Some systems use __main in a way incompatible with its use in gcc, in these + * cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to + * give the same symbol without quotes for an alternative entry point. You + * must define both, or neither. */ + + +/* Given a decl node or constant node, choose the section to output it in + and select that section. */ +/* These are from mips.h, simplified somewhat. */ + +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section + +/* Allow the use of the -frecord-gcc-switches switch via the + elf_record_gcc_switches function defined in varasm.c. */ +#undef TARGET_ASM_RECORD_GCC_SWITCHES +#define TARGET_ASM_RECORD_GCC_SWITCHES elf_record_gcc_switches + +#define ASM_APP_ON "#APP\n" +#define ASM_APP_OFF "#NO_APP\n" +#define ASM_COMMENT_START "#" +#define ASM_LONGLONG "\t.quad\t" + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* If defined, a C expression to compute the alignment given to a + constant that is being placed in memory. CONSTANT is the constant + and ALIGN is the alignment that the object would ordinarily have. + The value of this macro is used instead of that alignment to align + the object. + + If this macro is not defined, then ALIGN is used. + + The typical use of this macro is to increase alignment for string + constants to be word aligned so that `strcpy' calls that copy + constants can be done inline. */ + +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + ve_constant_alignment ((EXP), (ALIGN)) + +/* : BITS_PER_WORD) */ + +/* If defined, a C expression to compute the alignment for a static + variable. TYPE is the data type, and ALIGN is the alignment that + the object would ordinarily have. The value of this macro is used + instead of that alignment to align the object. + + If this macro is not defined, then ALIGN is used. + + One use of this macro is to increase alignment of medium-size + data to make it all fit in fewer cache lines. Another is to + cause character arrays to be word-aligned so that `strcpy' calls + that copy constants to character arrays can be done inline. */ +/* Stolen from mips.h */ + +#undef DATA_ALIGNMENT +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + ((((ALIGN) < 4) \ + && (TREE_CODE (TYPE) == UNION_TYPE \ + || TREE_CODE (TYPE) == RECORD_TYPE)) ? 4 : (ALIGN)) + +/* We need this for the same reason as DATA_ALIGNMENT, namely to cause + character arrays to be word-aligned so that `strcpy' calls that copy + constants to character arrays can be done inline, and 'strcmp' can be + optimised to use word loads. */ +#define LOCAL_ALIGNMENT(TYPE, ALIGN) \ + DATA_ALIGNMENT (TYPE, ALIGN) + + +#define ASM_OUTPUT_ALIGN(stream,val) \ +{ if (TARGET_ASM_ALIGN) \ + fprintf(stream,"\t.align\t%d\n",(int)(val)); \ + else \ + fprintf(stream,"\t.balign\t%d\n",(1<<(int)(val)));} + + +#define ASM_OUTPUT_SKIP(stream,val) \ + fprintf(stream,"\t.skip\t%d\n",(int)(val)) + + +/* + * Need to split up .ascii directives to avoid breaking + * the linker. + */ + +/* + * Nonzero value if GCC should output the constant pool + * for a function before the code for the function. + * Zero value if GCC should output the constant pool + * after the function. + */ +#define CONSTANT_POOL_BEFORE_FUNCTION 0 + +#undef ASM_OUTPUT_FUNCTION_LABEL +#define ASM_OUTPUT_FUNCTION_LABEL(file, funname, fundecl) \ + ve_asm_output_function_label (file, funname, fundecl) + +#define ASM_OUTPUT_FUNCTION_PREFIX(stream, fnname) \ + ve_asm_output_function_prefix(stream,fnname) + +/* This says how to output an assembler line + to define a global common symbol. */ + + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_ALIGNED_COMMON(stream, name, size, alignment)\ + { switch_to_section(data_section); \ + fputs("\t.comm\t",stream); assemble_name(stream,name); \ + fprintf(stream,", " HOST_WIDE_INT_PRINT_DEC ", %u\n", \ + (size),(alignment)/BITS_PER_UNIT); } + +#define ASM_OUTPUT_ALIGNED_LOCAL(stream, name, size, alignment)\ + { switch_to_section(data_section); \ + fputs("\t.local\t",stream); assemble_name(stream,name); \ + fputs("\n\t.comm\t",stream); assemble_name(stream,name); \ + fprintf(stream,", " HOST_WIDE_INT_PRINT_UNSIGNED ", %u\n", \ + (size),(alignment)/BITS_PER_UNIT); } + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" + +#undef SIZE_ASM_OP +#define SIZE_ASM_OP "\t.size\t" + +#undef TYPE_ASM_OP +#define TYPE_ASM_OP "\t.type\t" + + +#define ASM_OUTPUT_TYPE_DIRECTIVE(STREAM, NAME, TYPE) \ + do \ + { \ + fputs (TYPE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", ", STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, TYPE); \ + putc ('\n', STREAM); \ + } \ + while (0) + +/* This macro closes up a function definition for the assembler. */ +#undef ASM_DECLARE_FUNCTION_SIZE +#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \ + ve_end_function(FILE,NAME,DECL) + + +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do \ + { \ + HOST_WIDE_INT size; \ + \ + ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ + \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive \ + && (DECL) && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + size = int_size_in_bytes (TREE_TYPE (DECL)); \ + ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, size); \ + } \ + \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) + + +#define ASM_OUTPUT_LABEL(STREAM, LABEL) \ +{ assemble_name(STREAM, LABEL); fputs(":\n", STREAM); } + +/* Globalizing directive for a label. */ +#define GLOBAL_ASM_OP "\t.globl\t" + + +/* May add underscore before label */ +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ + asm_fprintf (STREAM, "%U%s", NAME) + +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, NAME) \ +{ fprintf(STREAM, "%s:\n", NAME);} + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + do { char buf[100]; \ + fputs (ASM_LONGLONG, FILE); \ + ASM_GENERATE_INTERNAL_LABEL (buf, "L", VALUE); \ + assemble_name (FILE, buf); \ + putc ('-', FILE); \ + ASM_GENERATE_INTERNAL_LABEL (buf, "L", REL); \ + assemble_name (FILE, buf); \ + putc ('\n', FILE); \ + } while (0) + + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE DImode + +/* Define as C expression which evaluates to nonzero if the tablejump + instruction expects the table to contain offsets from the address of the + table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE 1 + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf((LABEL), "%s%s%ld", LOCAL_LABEL_PREFIX, (PREFIX), (long)(NUM)) + +/* Output for declaring the name of an external symbol name + which is referenced in this compilation but not defined. + This need not be defined since it is treated as external by + as/ld default. This is to make sure of it. +*/ + +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + default_elf_asm_output_external (FILE, DECL, NAME); + +/* This is how we tell the assembler that two symbols have the same value. */ + +#undef ASM_OUTPUT_DEF +#define ASM_OUTPUT_DEF(stream, alias, name) \ + do { \ + fputs("\t.set\t", stream); \ + assemble_name(stream,alias); \ + fputs(",", stream); \ + assemble_name(stream,name); \ + fputs("\n", stream); \ + } while (0) + +/* Define this so that jump tables go in same section as + the current function */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + + We define all 64 integer/floating registers, there are no other + registers. */ + +#define FIRST_PSEUDO_REGISTER 64 + + +#define FIRST_S_REG 0 +#define LAST_S_REG 63 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + Fixed registers are s8(stack limit), s9(frame pointer), + s11(stack pointer), s14(thread pointer), + s15(global offset table), s16(procedure linkage table), + and s17(linkage-area register) */ + +/* s12(spill registers used for last resort at/after reload + when no free register is available */ + +#define FIXED_REGISTERS { \ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. + s8(stack limit), s9(frame pointer), + s11(stack pointer), s14(thread descriptor) + s15(got), s16(plt), s17(linkage/text base), + and + s0 - s7 (parameter/result reg.) + s10(return PC), s12(entry/ scratch), s13(symbol information /scratch) + s34-s63 (free regs.) */ + +#define CALL_USED_REGISTERS { \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + } + +#define REGISTER_NAMES \ +{ "%s0" , "%s1" , "%s2" , "%s3" , "%s4" , "%s5" , "%s6" , "%s7", \ + "%sl" , "%fp" , "%lr", "%sp", "%s12", "%s13", "%tp", "%got", \ + "%plt", "%s17", "%s18", "%s19", "%s20", "%s21", "%s22", "%s23", \ + "%s24", "%s25", "%s26", "%s27", "%s28", "%s29", "%s30", "%s31", \ + "%s32", "%s33", "%s34", "%s35", "%s36", "%s37", "%s38", "%s39", \ + "%s40", "%s41", "%s42", "%s43", "%s44", "%s45", "%s46", "%s47", \ + "%s48", "%s49", "%s50", "%s51", "%s52", "%s53", "%s54", "%s55", \ + "%s56", "%s57", "%s58", "%s59", "%s60", "%s61", "%s62", "%s63", \ + } + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + { "%s8", 8 } \ + , { "%s9", 9 } \ + , { "%s10", 10 } \ + , { "%s11", 11 } \ + , { "%s14", 14 } \ + , { "%s15", 15 } \ + , { "%s16", 16 } \ +} + + +/* List the order in which to allocate registers. Each register must be + listed once, even those in FIXED_REGISTERS.*/ +#define REG_ALLOC_ORDER \ + { \ + 34, 35, 36, 37, 38, 39, \ + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \ + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \ + 60, 61, 62, 63, \ + 10, \ + 7, 6, 5, 4, 3, 2, 1, 0, \ + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ + 28, 29, 30, 31, 32, 33, \ + 13, 16, 15, 14, \ + 17, 9, 11, 8, 12 } + + +/********************************************* later*/ +/* values that can go in particular registers. */ +/* q-doubles will be the only thing that will take 2 registers. */ + +#define HARD_REGNO_NREGS(regno,mode) \ + ((GET_MODE_SIZE(mode) + UNITS_PER_WORD - 1)/UNITS_PER_WORD) + +#define EPILOGUE_USES(REGNO) ve_epilogue_uses (REGNO) + +/* + * Allocate registers appropriate to data types. doubles + * require even/odd pairs of long double registers. */ + +#define HARD_REGNO_MODE_OK(regno,mode) ve_hard_regno_mode_ok(regno,mode) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ + +/* How to renumber registers for dbx and gdb. */ +#define DBX_REGISTER_NUMBER(REGNO) ve_dbx_register_number (REGNO) + +/* We use the identical numbers for the DWARF 2 CFA column numbers */ +#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) +#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (VE_RETURN_REGNUM) + + +/* Return a class of registers that cannot change FROM mode to TO mode. */ +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ + ve_cannot_change_mode_class (FROM, TO, CLASS) + + +#define MODES_TIEABLE_P(mode1, mode2) ve_modes_tieable_p(mode1,mode2) + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +enum reg_class +{ + NO_REGS, /* no registers in set */ + QS_REGS, /* scalar even number registers */ + S_REGS, /* scalar registers */ + ALL_REGS, /* all registers */ + LIM_REG_CLASSES /* max value + 1 */ +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define GENERAL_REGS S_REGS +#define GP_REG_P(REGNO) (FIRST_S_REG <= (int)(REGNO) && (int)(REGNO) <= LAST_S_REG) + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "QS_REGS", \ + "S_REGS", \ + "ALL_REGS" \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000,0x00000000 }, /* no registers */ \ + { 0x55555555,0x55555555 }, /* qs registers */ \ + { 0xffffffff,0xffffffff }, /* s registers */ \ + { 0xffffffff,0xffffffff } /* all registers */ \ +} + +#define REGNO_REG_CLASS(REGNO) ((REGNO) < FIRST_PSEUDO_REGISTER \ + ? ((REGNO % 2) ? QS_REGS : S_REGS) : NO_REGS) + +/* The class value for index registers, and the one for base regs. */ + +#define BASE_REG_CLASS S_REGS +#define INDEX_REG_CLASS S_REGS + +#define VE_FIRST_ARG_REGNUM 0 +#define VE_MAX_ARGS_IN_REGS 8 + + +/* If we use the normal load/store ops , + it will always sign-extend sub-word types. */ +#define LOAD_EXTEND_OP(mode) SIGN_EXTEND + + +/* + * Memory address stuff. + */ + + +/* Addressing modes, and classification of registers for them. */ + +/* 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 all. + 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. + Some source files that are used after register allocation + need to be strict. */ + +#ifndef REG_OK_STRICT +#define REG_MODE_OK_FOR_BASE_P(X, MODE) \ + ve_regno_mode_ok_for_base_p (REGNO (X), MODE, 0) +#else +#define REG_MODE_OK_FOR_BASE_P(X, MODE) \ + ve_regno_mode_ok_for_base_p (REGNO (X), MODE, 1) +#endif + + +#define REGNO_IN_RANGE(REGNO, MIN, MAX) \ + (IN_RANGE ((REGNO), (MIN), (MAX)) \ + || (reg_renumber != NULL \ + && reg_renumber[(REGNO)] >= (MIN) \ + && reg_renumber[(REGNO)] <= (MAX))) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + REGNO_IN_RANGE(REGNO,FIRST_S_REG,LAST_S_REG) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + REGNO_IN_RANGE(REGNO,FIRST_S_REG,LAST_S_REG) + +/* Non strict versions, pseudos are ok. */ +#define REG_OK_FOR_INDEX_NONSTRICT_P(X) 1 +#define REG_OK_FOR_BASE_NONSTRICT_P(X) 1 + +/* Strict versions, hard registers only */ +#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#ifndef REG_OK_STRICT +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P (X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P (X) + +#else +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P (X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X) +#endif + + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* 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. */ + + +/* Check for constness inline but use mips_legitimate_address_p + to check whether a constant really is an address. */ + + +/* This handles the magic '..CURRENT_FUNCTION' symbol, which means + * 'the start of the function that this code is output in'. */ + + +/* + * VE has 32 bit immediates. + */ +#define SMALL_INT(X) \ + ((HOST_WIDE_INT)INTVAL(X) >= -2147483647LL-1 && (HOST_WIDE_INT)INTVAL(X) <= 2147483647) +#define SMALL_OPERAND(VALUE) \ + ((unsigned HOST_WIDE_INT) (VALUE) + 0x8000 < 0x10000) + +#define CLASS_UNITS(mode, size) \ + ((GET_MODE_SIZE (mode) + (size) - 1) / (size)) + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (CLASS_UNITS (MODE, UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +/* #define STACK_GROWS_DOWNWARD */ + +/* Define this to nonzero if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ + +#define FRAME_GROWS_DOWNWARD 1 + +/* Register save area : fp(s9),lr(s10),and s14-s33 (22 * 8byte) */ +#define VE_RSA_SIZE 176 + +/* stack allocated variables have such offset that reserve outgoing pramlist */ +#define STARTING_FRAME_OFFSET 0 + +/* Define this if the maximum size of all the outgoing args is to be + accumulated and pushed during the prologue. The amount can be + found in the variable current_function_outgoing_args_size. */ +#define ACCUMULATE_OUTGOING_ARGS 1 + +/* reserve stack space for all argument even when their values are +passed in registers. */ +#define REG_PARM_STACK_SPACE(FNDECL) UNITS_PER_WORD + +/* Define this if it is the responsibility of the caller to + allocate the area reserved for arguments passed in registers. + If `ACCUMULATE_OUTGOING_ARGS' is also defined, the only effect + of this macro is to determine whether the space is included in + `crtl->outgoing_args_size'. */ +#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1 +#define STACK_PARMS_IN_REG_PARM_AREA + +#define STACK_POINTER_OFFSET (VE_RSA_SIZE) + +/* Eliminating the Frame Pointer and the Arg Pointer. */ +#define ELIMINABLE_REGS \ +{ \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ +} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = ve_initial_elimination_offset (FROM, TO) + + +/* Lifted from mips.h. + * If defined, a C expression that gives the alignment boundary, in + * bits, of an argument with the specified mode and type. If it is + * not defined, `PARM_BOUNDARY' is used for all arguments. + */ + + +/* incomming args are accessed from this offset with %s(ARG_POINTER_REGNUM) */ +#define FIRST_PARM_OFFSET(FNDECL) (VE_RSA_SIZE) + + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ + + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 9 + +/* Register for nested function (trampoline) */ +#define STATIC_CHAIN_REGNUM 63 + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + (ve_return_addr_rtx (COUNT, FRAME)) + +/* Before the prologue, RA lives in VE_RETURN_REGNUM */ +#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG(Pmode,VE_RETURN_REGNUM)) + +/* Before the prologue, the top of the frame is at 0(%sp). */ +#define INCOMING_FRAME_SP_OFFSET 0 + +/* Place to put static chain when calling a function that requires it. */ + + +/* Place where static chain is found upon entry to routine. */ + + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + ve_function_value(VALTYPE,FUNC) + +/* return in s0, s1, s2, or s3. */ +#define LIBCALL_VALUE(MODE) \ + ve_libcall_value(MODE) + +struct ve_args +{ + int arg_words; /* Total words the argumets take */ + int indirect; /* Function call is indirect */ + int stdarg; /* Stdarg */ + int prototype; /* Function has a prototype */ +}; + +/*typedef int CUMULATIVE_ARGS;*/ +#define CUMULATIVE_ARGS struct ve_args + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ + ve_init_cumulative_args(&CUM, FNTYPE, LIBNAME, FNDECL); + +/* + * First few (VE_MAX_ARGS_IN_REGS) args are passed in registers. + */ + +#if VE_FIRST_ARG_REGNUM == 0 +#define FUNCTION_ARG_REGNO_P(regno) \ +((regno) < VE_FIRST_ARG_REGNUM + VE_MAX_ARGS_IN_REGS) +#else +#define FUNCTION_ARG_REGNO_P(regno) \ +((regno) >= VE_FIRST_ARG_REGNUM && \ + (regno) < VE_FIRST_ARG_REGNUM + VE_MAX_ARGS_IN_REGS) +#endif + +/* + * Return value is in s0, s1, s2, or s3. + */ +#define FUNCTION_VALUE_REGNO_P(regno) \ +((regno) == 0 ||(regno) == 1 ||(regno) == 2 ||(regno) ==3) + +/* Initialize data used by insn expanders. This is called from insn_emit, + once for every function before code is generated. */ +#define INIT_EXPANDERS ve_init_expanders () + +/* + * Trampoline stuff, stolen from mips.h. + * This will need serious work. + * + */ + +/* A C expression for the size in bytes of the trampoline, as an + integer. */ + +#define TRAMPOLINE_SIZE 40 +/* 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 64 + +#undef TARGET_ELF +#define TARGET_ELF 1 + +/* Tell collect that the object format is ELF. */ +#define OBJECT_FORMAT_ELF + +/* Do not use TM clone registry as it currently doesn't work. */ +#define USE_TM_CLONE_REGISTRY 0 + +/* Definitions for debugging. */ + +/* generate embedded stabs */ + +/* Generate DWARF2 debugging information and make it the default. */ +#define DWARF2_DEBUGGING_INFO 1 + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* Use a more compact format for line information. */ +#define DWARF2_ASM_LINE_DEBUG_INFO 1 + +#define DWARF2_UNWIND_INFO 0 +#define TARGET_DEBUG_UNWIND_INFO ve_debug_unwind_info + +#undef TARGET_GAS +#define TARGET_GAS 1 + +/* gas supports weak label */ +#define SUPPORTS_WEAK 1 + +/* This is how to tell assembler that a symbol is weak */ +#undef ASM_WEAKEN_LABEL +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +/* Support for C++ templates. */ +#undef MAKE_DECL_ONE_ONLY +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) + +/* Biggest alignment supported by the object file format of this + machine. Use this macro to limit the alignment which can be + specified using the `__attribute__ ((aligned (N)))' construct. If + not defined, the default value is `BIGGEST_ALIGNMENT'. */ +#define MAX_OFILE_ALIGNMENT (32768 * 8) + + +#define TARGET_THREAD_SSP_OFFSET (0x10) + +/* Define this macro if it is as good or better to call a constant + * function address than to call an address kept in a register. */ +#define NO_FUNCTION_CSE 1 diff --git a/gcc/config/ve/ve.md b/gcc/config/ve/ve.md new file mode 100644 index 00000000000..f1c37e393b2 --- /dev/null +++ b/gcc/config/ve/ve.md @@ -0,0 +1,4438 @@ +;; Machine description for VE architecture for GCC compiler +;; Copyright (C) 2007-2017 Free Software Foundation, Inc. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. not see +;; . +;; Changes by NEC Corporation for the VE port, 2017-2021 + +(define_c_enum "unspec" [ + UNSPEC_COPYSIGN + UNSPEC_COMPARE + UNSPEC_MOVE + UNSPEC_MOVE_CALL + UNSPEC_MOVE_PIC_PLT + UNSPEC_MOVE_PIC_PC + UNSPEC_MOVE_PIC_PC2 + UNSPEC_MOVE_PIC_GOT + UNSPEC_MOVE_PIC_GOT32 + UNSPEC_MOVE_PIC_GOTOFF + UNSPEC_MOVE_PIC_LABEL + UNSPEC_TLSGD + UNSPEC_TLSLD + UNSPEC_TLSLDO + UNSPEC_TLSIE + UNSPEC_TLSLE + UNSPEC_MEMORY_BARRIER + UNSPEC_SP_SET + UNSPEC_SP_TEST +]) + +(define_c_enum "unspecv" [ + UNSPEC_BLOCKAGE ; blockage insn to prevent scheduling across an insn + UNSPEC_STACK_PROBE + UNSPEC_STACK_PROLOGUE + UNSPEC_FLUSH_ICACHE ; blockage insn for i cache flush + UNSPEC_INIT_PROGRAM_MODE ; initiallize fp mode and exception flag + UNSPEC_PROLOGUE_END + UNSPEC_EPILOGUE_START + UNSPEC_COMPARE_AND_SWAP + UNSPEC_SYNC_LOCK_TEST_AND_SET + UNSPEC_SYNC_LOCK_RELEASE + UNSPEC_SYNC_OP + UNSPEC_SYNC_NEW_OP +]) + + +;; Include constrains + (include "constraints.md") + +;; Include predicate definitions + (include "predicates.md") + +(define_attr "type" + "unknown,load,store,move,alu,branch,jump,fp,multi,ghost,misc" + (const_string "unknown")) + +(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF" + (const_string "unknown")) + +;; + +(define_mode_iterator MODEANYF [SF DF TF]) +(define_mode_iterator MODEF [SF DF]) +(define_mode_iterator MODEI [SI DI]) +(define_mode_iterator MODEIF [SI DI SF DF]) +(define_mode_iterator MODEANYI [QI HI SI DI TI]) + +(define_mode_attr suffix [(SI "w") (DI "l") + (SF "s") (DF "d") + (TF "q")]) +(define_mode_attr reg_or_o_operand [(SI "reg_or_o_operand") + (DI "reg_or_m_operand")]) +(define_mode_attr reg_or_io_operand [(SI "reg_or_io_operand") + (DI "reg_or_im_operand")]) +(define_mode_attr reg_or_ip_operand [(SI "reg_or_ip_operand") + (DI "reg_or_im_operand")]) +(define_mode_attr o_const [(SI "O") + (DI "M")]) +(define_mode_attr p_const [(SI "P") + (DI "M")]) +(define_mode_attr ext [(SI ".sx") + (DI "")]) + +;; Used for signed and unsigned widening extensions. +(define_code_iterator any_extend [sign_extend zero_extend]) +(define_code_attr ex [(sign_extend "sx") (zero_extend "zx")]) + +;; Used for logical operations +(define_code_iterator any_logic [and ior xor]) +(define_code_attr logic_insn [(and "and") (ior "ior") (xor "xor")]) +(define_code_attr logic_code [(and "and") (ior "or") (xor "xor")]) + +;; Used for shiftl operations +(define_code_iterator any_shift [ashift ashiftrt lshiftrt]) +(define_code_iterator any_ashift [ashift ashiftrt]) +(define_code_attr shift_insn_w + [(ashift "ashl") (ashiftrt "ashr")]) +(define_code_attr shift_insn_l + [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr")]) +(define_code_attr shift_code_w + [(ashift "sla.w") (ashiftrt "sra.w")]) +(define_code_attr shift_code_l + [(ashift "sla.l") (ashiftrt "sra.l") (lshiftrt "srl")]) + +;; Used for max/min operations +(define_code_iterator maxmin [smax smin]) +(define_code_attr maxmin_insn + [(smax "max") (smin "min")]) +(define_code_attr maxmin_code + [(smax "max") (smin "min")]) + +;; Used for atomic operations +(define_code_iterator atomic [and ior plus minus]) +(define_code_attr atomic_insn + [(and "and") (ior "ior") (plus "add") (minus "sub")]) +(define_code_attr atomic_set + [(and "or") (ior "or") (plus "or") (minus "subs.l")]) +(define_code_attr atomic_op + [(and "0") (ior "1") (plus "2") (minus "2")]) + + +;; Used for sign/zero extend +(define_mode_iterator MODEOVQI [HI SI DI]) +(define_mode_iterator MODEOVHI [SI DI]) + +;; attributes +(define_attr "length" "" (const_int 1)) + +;; +;; instructions +;; +(define_insn "add3" + [(set (match_operand:MODEANYF 0 "register_operand" "=r") + (plus:MODEANYF (match_operand:MODEANYF 1 "register_operand" "%r") + (match_operand:MODEANYF 2 "register_operand" "r")))] + "" + "fadd.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +(define_insn "sub3" + [(set (match_operand:MODEANYF 0 "register_operand" "=r") + (minus:MODEANYF (match_operand:MODEANYF 1 "register_operand" "r") + (match_operand:MODEANYF 2 "register_operand" "r")))] + "" + "fsub.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +(define_insn "mul3" + [(set (match_operand:MODEANYF 0 "register_operand" "=r") + (mult:MODEANYF (match_operand:MODEANYF 1 "register_operand" "%r") + (match_operand:MODEANYF 2 "register_operand" "r")))] + "" + "fmul.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +(define_insn "div3" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (div:MODEF (match_operand:MODEF 1 "register_operand" "r") + (match_operand:MODEF 2 "register_operand" "r")))] + "" + "fdiv.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +;; c = a / b +;; (1) normalize a and b; (sign=0; exp=0x3ff ) +;; (2) first approx. uses double division result +;; bh(Df) = b +;; rh = 1.0d0 / bh +;; r = rh +;; (3) second applox. appply newton method +;; r = r * (2.0q0 - b *r) +;; s = a * r +;; (4) final approx. calculate exact rounding +;; (4-1) highly accurate calc. of a - s * b +;; su = s & 0xffffffffffffffff fe00000000000000 +;; sl = s - su +;; bu = b & 0xffffffffffffffff fe00000000000000 +;; bl = b - bu +;; r = a - su * bu - su * bl - sl * bu - sl * bl +;; (4-2) get final delta +;; rh(DF) = r +;; rh = rh / bh +;; r = rh +;; s = s + r +;; (5) set proper exponet and sign bit +;; sign,expo(s) += sign,expo(a) - sign,expo(b) +;; (6) move s to c +;; This is necessary since the register allocator may +;; assign the same register for c and any temporaries +;; + + +; This pattern is not used. Why? +(define_insn "3" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (maxmin:MODEF (match_operand:MODEF 1 "register_operand" "%r") + (match_operand:MODEF 2 "register_operand" "r")))] + "" + "f.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +(define_insn "*addsi3_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (plus:SI (match_operand:SI 1 "register_operand" "%r,r,r") + (match_operand:SI 2 "reg_or_io_operand" "r,I,O"))))] + "" + "@ + adds.w.\\t%0,%1,%2 + adds.w.\\t%0,%2,%1 + adds.w.\\t%0,%1,%O2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1")]) + +(define_insn "*addsi4_r_rc" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "r") + (plus:SI (match_operand:SI 2 "register_operand" "%r") + (match_operand:SI 3 "const_n_operand" "N"))))] + "" + "lea\\t%0,%3(%1,%2)" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "*addsi4_c_rr" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "const_n_operand" "N") + (plus:SI (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r"))))] + "" + "lea\\t%0,%1(%2,%3)" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "*addsi4_rc_r" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "const_n_operand" "N")) + (match_operand:SI 3 "register_operand" "r")))] + "" + "lea\\t%0,%2(%1,%3)" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "*addsi4_rr_c" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "const_n_operand" "N")))] + "" + "lea\\t%0,%3(%1,%2)" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "*adddi4_r_rc" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "register_operand" "r,r") + (plus:DI (match_operand:DI 2 "register_operand" "%r,r") + (match_operand:DI 3 "const_int_operand" "N,i"))))] + "" + "* +{ + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"lea\\t%0,%3(%1,%2)\"; + case 1: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea.sl\\t%4,%H3(%1)\\n\\tlea\\t%0,%L3(%2,%4)\",xop); + return \"\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + +(define_insn "*adddi4_lc_rr" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "const_int_operand" "N,i") + (plus:DI (match_operand:DI 2 "register_operand" "r,r") + (match_operand:DI 3 "register_operand" "r,r"))))] + "" + "* +{ + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"lea\\t%0,%1(%2,%3)\"; + case 1: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea.sl\\t%4,%H1(%2)\\n\\tlea\\t%0,%L1(%3,%4)\",xop); + return \"\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + +(define_insn "*adddi4_rc_r" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (plus:DI (match_operand:DI 1 "register_operand" "%r,r") + (match_operand:DI 2 "const_int_operand" "N,i")) + (match_operand:DI 3 "register_operand" "r,r")))] + "" + "* +{ + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"lea\\t%0,%2(%1,%3)\"; + case 1: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea.sl\\t%4,%H2(%1)\\n\\tlea\\t%0,%L2(%3,%4)\",xop); + return \"\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + +(define_insn "*adddi4_rr_c" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (plus:DI (match_operand:DI 1 "register_operand" "r,r") + (match_operand:DI 2 "register_operand" "r,r")) + (match_operand:DI 3 "const_int_operand" "N,i")))] + "" + "* +{ + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"lea\\t%0,%3(%1,%2)\"; + case 1: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea.sl\\t%4,%H3(%1)\\n\\tlea\\t%0,%L3(%2,%4)\",xop); + return \"\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%r,r,r,r") + (match_operand:SI 2 "reg_or_in_operand" "r,I,O,N")))] + "" + "@ + adds.w.sx\\t%0,%1,%2 + adds.w.sx\\t%0,%2,%1 + adds.w.sx\\t%0,%1,%O2 + lea\\t%0,%2(,%1)" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1,1")]) + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%r,r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,I,M,N,i")))] + "" + "* +{ + rtx xop[4]; + switch(which_alternative) + { + default: + case 0: + return \"adds.l\\t%0,%1,%2\"; + case 1: + return \"adds.l\\t%0,%2,%1\"; + case 2: + return \"adds.l\\t%0,%1,%M2\"; + case 3: + return \"lea\\t%0,%2(,%1)\"; + case 4: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea\\t%3,%L2\\n\\tlea.sl\\t%0,%H2(%3,%1)\",xop); + return \"\"; + } + +}" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,1,1,1,2")]) + +(define_insn "addti3" + [(set (match_operand:TI 0 "register_operand" "=&r,&r,&r,&r") + (plus:TI (match_operand:TI 1 "register_operand" "%r,r,r,r") + (match_operand:TI 2 "reg_or_in_operand" "r,I,M,N"))) + (clobber (match_scratch:DI 3 "=&r,&r,&r,&r"))] + "" + "* +{ + rtx xop[5]; + unsigned long long c; + switch(which_alternative) + { + default: + case 0: return +\"addu.l\\t%Q0,%Q1,%Q2\\n\\ +\\tsubu.l\\t%3,-1,%Q2\\n\\ +\\tadds.l\\t%0,%1,%2\\n\\ +\\tcmpu.l\\t%3,%3,%Q1\\n\\ +\\tsrl\\t%3,%3,63\\n\\ +\\tadds.l\\t%0,%3,%0\"; + + case 1: + c = 0xffffffffffffffff; + c = c - UINTVAL(operands[2]); + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = GEN_INT(c); + output_asm_insn(\"addu.l\\t%Q0,%2,%Q1\",xop); + output_asm_insn(\"cmpu.l\\t%3,%4,%Q1\",xop); + output_asm_insn(\"srl\\t%3,%3,63\",xop); + if (INTVAL(operands[2]) >= 0) + { + output_asm_insn(\"adds.l\\t%0,%3,%1\",xop); + } + else + { + output_asm_insn(\"adds.l\\t%0,%Z2,%1\",xop); + output_asm_insn(\"adds.l\\t%0,%3,%0\",xop); + } + return \"\"; + + case 2: + c = 0xffffffffffffffff; + c = c - UINTVAL(operands[2]); + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = GEN_INT(c); + output_asm_insn(\"addu.l\\t%Q0,%Q1,%M2\",xop); + output_asm_insn(\"or\\t%3,0,%M4\",xop); + output_asm_insn(\"cmpu.l\\t%3,%3,%Q1\",xop); + output_asm_insn(\"srl\\t%3,%3,63\",xop); + if (INTVAL(operands[2]) >= 0) + { + output_asm_insn(\"adds.l\\t%0,%3,%1\",xop); + } + else + { + output_asm_insn(\"adds.l\\t%0,%Z2,%1\",xop); + output_asm_insn(\"adds.l\\t%0,%3,%0\",xop); + } + return \"\"; + + case 3: + c = 0xffffffffffffffff; + c = c - UINTVAL(operands[2]); + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = GEN_INT(c); + output_asm_insn(\"lea\\t%Q0,%2(,%Q1)\",xop); + output_asm_insn(\"lea\\t%3,%4\",xop); + output_asm_insn(\"cmpu.l\\t%3,%3,%Q1\",xop); + output_asm_insn(\"srl\\t%3,%3,63\",xop); + if (INTVAL(operands[2]) >= 0) + { + output_asm_insn(\"adds.l\\t%0,%3,%1\",xop); + } + else + { + output_asm_insn(\"adds.l\\t%0,%Z2,%1\",xop); + output_asm_insn(\"adds.l\\t%0,%3,%0\",xop); + } + return \"\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "6,5,6,6")]) + +(define_insn "sub3" + [(set (match_operand:MODEI 0 "register_operand" "=r,r,r") + (minus:MODEI + (match_operand:MODEI 1 "reg_or_i_operand" "r,I,r") + (match_operand:MODEI 2 "" "r,r,")))] + "" + "@ + subs.\\t%0,%1,%2 + subs.\\t%0,%1,%2 + subs.\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "1,1,1")]) + +(define_insn "*subsi3_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (minus:SI (match_operand:SI 1 "reg_or_i_operand" "r,I,r") + (match_operand:SI 2 "reg_or_o_operand" "r,r,O"))))] + "" + "@ + subs.w.\\t%0,%1,%2 + subs.w.\\t%0,%1,%2 + subs.w.\\t%0,%1,%O2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1")]) + +(define_insn "subti3" + [(set (match_operand:TI 0 "register_operand" "=&r,&r") + (minus:TI (match_operand:TI 1 "reg_or_i_operand" "r,I") + (match_operand:TI 2 "register_operand" "r,r"))) + (clobber (match_scratch:DI 3 "=&r,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: + case 0: return +\"subu.l\\t%Q0,%Q1,%Q2\\n\\ +\\tsubs.l\\t%0,%1,%2\\n\\ +\\tcmpu.l\\t%3,%Q1,%Q2\\n\\ +\\tsrl\\t%3,%3,63\\n\\ +\\tsubs.l\\t%0,%0,%3\"; + + case 1: return +\"subu.l\\t%Q0,%1,%Q2\\n\\ +\\tsubs.l\\t%0,%Z1,%2\\n\\ +\\tcmpu.l\\t%3,%1,%Q2\\n\\ +\\tsrl\\t%3,%3,63\\n\\ +\\tsubs.l\\t%0,%0,%3\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "5,5")]) + +;; and, ior, xor + +(define_insn "si3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (any_logic:SI (match_operand:SI 1 "register_operand" "%r,r,r") + (match_operand:SI 2 "reg_or_ip_operand" "r,I,P")))] + "" + "@ + \\t%0,%1,%2 + \\t%0,%2,%1 + \\t%0,%1,%P2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1")]) + +(define_insn "di3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_logic:DI (match_operand:DI 1 "register_operand" "%r,r,r") + (match_operand:DI 2 "reg_or_im_operand" "r,I,M")))] + "" + "@ + \\t%0,%1,%2 + \\t%0,%2,%1 + \\t%0,%1,%M2" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1,1,1")]) + +(define_insn "ti3" + [(set (match_operand:TI 0 "register_operand" "=&r") + (any_logic:TI (match_operand:TI 1 "register_operand" "%r") + (match_operand:TI 2 "register_operand" "r")))] + "" + "\\t%Q0,%Q1,%Q2\\n\\ +\\t\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +;; loading zero, population count, parity + +(define_insn "clzsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (clz:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "sll\\t%2,%1,32\\n\\tor\\t%3,%2,(32)0\\n\\tldz\\t%0,%3" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "clzdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (clz:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "ldz\\t%0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "clzti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (clz:TI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "ldz\\t%Q0,%1 +\\tbrne.l\\t%1,0,24\\n\\ +\\tldz\\t%2,%Q1\\n\\ +\\taddu.l\\t%Q0,%Q0,%2\\n\\ +\\tor\\t%0,0,(0)1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "5")]) + +(define_insn "ctzsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (ctz:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "brv\\t%2,%1\\n\\tor\\t%3,%2,(32)0\\n\\tldz\\t%0,%3" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "ctzdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (ctz:DI (match_operand:DI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "brv\\t%2,%1\\n\\tldz\\t%0,%2" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "ctzti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (ctz:TI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "brv\\t%2,%Q1\\n\\ +\\tldz\\t%Q0,%2\\n\\ +\\tbrne.l\\t%2,0,32\\n\\ +\\tbrv\\t%2,%1\\n\\ +\\tldz\\t%2,%2\\n\\ +\\taddu.l\\t%Q0,%Q0,%2\\n\\ +\\tor\\t%0,0,(0)1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "7")]) + +(define_insn "popcountsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (popcount:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "and\\t%2,%1,(32)0\\n\\tpcnt\\t%0,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "popcountdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (popcount:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "pcnt\\t%0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "popcountti2" + [(set (match_operand:TI 0 "register_operand" "=r") + (popcount:TI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "pcnt\\t%2,%Q1\\n\\ +\\tpcnt\\t%3,%1\\n\\ +\\tor\\t%0,0,(0)1\\n\\ +\\taddu.l\\t%Q0,%2,%3" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "4")]) + +(define_insn "parity2" + [(set (match_operand:MODEI 0 "register_operand" "=r") + (parity:MODEI (match_operand:MODEI 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "pcnt\\t%2,%1\\n\\tand\\t%0,1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "2")]) + +(define_insn "parityti2" + [(set (match_operand:TI 0 "register_operand" "=r") + (parity:TI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "pcnt\\t%2,%Q1\\n\\ +\\tpcnt\\t%3,%1\\n\\ +\\taddu.l\\t%2,%2,%3\\n\\ +\\tor\\t%0,0,(0)1\\n\\ +\\tand\\t%Q0,1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "5")]) + +; Byte swap +(define_insn "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (bswap:SI (match_operand:SI 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "bswp\\t%2,%1,1\\n\\tadds.w.sx\\t%0,0,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "*bswapsi2_zero_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (bswap:SI (match_operand:SI 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "bswp\\t%2,%1,1\\n\\tand\\t%0,%2,(32)0" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "*bswapsi2_sign_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (bswap:SI (match_operand:SI 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "bswp\\t%2,%1,1\\n\\tadds.w.sx\\t%0,0,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "bswapdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (bswap:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "bswp\\t%0,%1,0" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "bswapti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (bswap:TI (match_operand:TI 1 "register_operand" "r")))] + "" + "bswp\\t%0,%Q1,0\\n\\tbswp\\t%Q0,%1,0" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +;; +;; -x = 0-x +;; This is ok for integers. +;; + +;; SI, DI, and TI mode +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "subs.w.sx\\t%0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*negsi2_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (neg:SI (match_operand:SI 1 "register_operand" "r"))))] + "" + "subs.w.\\t%0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "negdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (neg:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "subs.l\\t%0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "negti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (neg:TI (match_operand:TI 1 "register_operand" "r")))] + "" + "subs.l\\t%0,-1,%1\\n\\ +\\tsubs.l\\t%Q0,0,%1\\n\\ +\\tcmov.l.eq\\t%0,%Q0,%Q1\\n\\ +\\tsubu.l\\t%Q0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "4")]) + +; allows negative zero + +(define_insn "neg2" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (neg:MODEF (match_operand:MODEF 1 "register_operand" "r")))] + "" + "xor\\t%0,%1,(1)1" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +; "fsub.\\t%0,0,%1" + +(define_insn "negtf2" + [(set (match_operand:TF 0 "register_operand" "=r,r") + (neg:TF (match_operand:TF 1 "register_operand" "0,r")))] + "" + "@ + xor\\t%0,%0,(1)1 + xor\\t%0,%1,(1)1\\n\\tor\\t%Q0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "1,2")]) + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (not:QI (match_operand:QI 1 "register_operand" "r")))] + "" + "xor\\t%0,%1,(0)0" + [(set_attr "type" "alu") + (set_attr "mode" "QI") + (set_attr "length" "1")]) +;; "xor\\t%0,%1,(56)0" + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (not:HI (match_operand:HI 1 "register_operand" "r")))] + "" + "xor\\t%0,%1,(0)0" + [(set_attr "type" "alu") + (set_attr "mode" "HI") + (set_attr "length" "1")]) +;; "xor\\t%0,%1,(48)0" + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "xor\\t%0,%1,(0)0" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) +;; "xor\\t%0,%1,(32)0" + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "xor\\t%0,%1,(0)0" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "one_cmplti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (not:TI (match_operand:TI 1 "register_operand" "r")))] + "" + "xor\\t%Q0,%Q1,(0)0\\n\\txor\\t%0,%1,(0)0" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=&r") + (abs:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "subs.w.sx\\t%0,0,%1\\n\\ +\\tcmov.w.ge\\t%0,%1,%1" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "*abssi2_any_extend" + [(set (match_operand:DI 0 "register_operand" "=&r") + (any_extend:DI + (abs:SI (match_operand:SI 1 "register_operand" "r"))))] + "" + "subs.w.sx\\t%0,0,%1\\n\\ +\\tcmov.w.ge\\t%0,%1,%1" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "absdi2" + [(set (match_operand:DI 0 "register_operand" "=&r") + (abs:DI (match_operand:DI 1 "register_operand" "r")))] + "" + "subs.l\\t%0,0,%1\\n\\ +\\tcmov.l.ge\\t%0,%1,%1" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "absti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (abs:TI (match_operand:TI 1 "register_operand" "r")))] + "" + "subs.l\\t%0,-1,%1\\n\\ +\\tsubs.l\\t%Q0,0,%1\\n\\ +\\tcmov.l.eq\\t%0,%Q0,%Q1\\n\\ +\\tsubu.l\\t%Q0,0,%Q1\\n\\ +\\tcmov.l.ge\\t%0,%1,%1\\n\\ +\\tcmov.l.ge\\t%Q0,%Q1,%1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "6")]) + +(define_insn "abs2" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (abs:MODEF (match_operand:MODEF 1 "register_operand" "r")))] + "" + "and\\t%0,%1,(1)0" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "1")]) + +(define_insn "abstf2" + [(set (match_operand:TF 0 "register_operand" "=r,r") + (abs:TF (match_operand:TF 1 "register_operand" "0,r")))] + "" + "@ + and\\t%0,%0,(1)0 + and\\t%0,%1,(1)0\\n\\tor\\t%Q0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "1,2")]) + +(define_insn "copysign3" + [(set (match_operand:MODEF 0 "register_operand" "=&r,&r") + (unspec:MODEF [ + (match_operand:MODEF 1 "register_operand" "0,r") + (match_operand:MODEF 2 "register_operand" "r,r")] + UNSPEC_COPYSIGN))] + "" + "@ + mrg\\t%0,%2,(1)1 + or\\t%0,0,%1\\n\\tmrg\\t%0,%2,(1)1" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "1,2")]) + +(define_insn "copysigntf3" + [(set (match_operand:TF 0 "register_operand" "=&r,&r") + (unspec:TF [ + (match_operand:TF 1 "register_operand" "0,r") + (match_operand:TF 2 "register_operand" "r,r")] + UNSPEC_COPYSIGN))] + "" + "@ + mrg\\t%0,%2,(1)1 + or\\t%0,0,%1\\n\\tmrg\\t%0,%2,(1)1\\n\\tor\\t%Q0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "1,3")]) + + + +;; ashlsi3 and ashrsi3 +(define_insn "si3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (any_ashift:SI (match_operand:SI 1 "reg_or_o_operand" "r,r,O") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r")))] + "" + "@ + .sx\\t%0,%1,%2 + .sx\\t%0,%1,%2 + .sx\\t%0,%O1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*si3_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (any_ashift:SI (match_operand:SI 1 "reg_or_o_operand" "r,r,O") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r"))))] + "" + "@ + .\\t%0,%1,%2 + .\\t%0,%1,%2 + .\\t%0,%O1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;;sign extension is necessary in case of zero shift + +(define_insn "*lshrsi31_addsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (const_int 31)) + (match_dup 1))) + (clobber (match_scratch:SI 2 "=&r")) + (clobber (match_scratch:SI 3 "=&r"))] + "" + "sra.w.sx\\t%2,%1,31\\n\\tsubs.w.sx\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_insn "*lshrsi_addsi4" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (plus:SI + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r,L")) + (match_operand:SI 3 "reg_or_i_operand" "r,r,I,I"))) + (clobber (match_scratch:SI 4 "=&r,&r,&r,&r")) + (clobber (match_scratch:SI 5 "=&r,&r,&r,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: case 2: + return +\"and\\t%4,%1,(32)0\\n\\ +\\tand\\t%5,%2,(59)0\\n\\ +\\tsrl\\t%5,%4,%5\\n\\ +\\tadds.w.sx\\t%0,%3,%5\"; + case 1: case 3: + if ((UINTVAL(operands[2]) & 0x1f) == 0) + return \"adds.w.sx\\t%0,%3,%1\"; + return \"and\\t%4,%1,(32)0\\n\\ +\\tsrl\\t%5,%4,%V2\\n\\ +\\tadds.w.sx\\t%0,%3,%5\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "4,3,4,3")]) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "reg_or_i_operand" "r,r,I") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r"))) + (clobber (match_scratch:SI 3 "=&r,&r,&r")) + (clobber (match_scratch:SI 4 "=&r,X,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: case 2: + return +\"and\\t%3,%1,(32)0\\n\\ +\\tand\\t%4,%2,(59)0\\n\\ +\\tsrl\\t%4,%3,%4\\n\\ +\\tadds.w.sx\\t%0,0,%4\"; + case 1: + if ((UINTVAL(operands[2]) & 0x1f) == 0) + return \"adds.w.sx\\t%0,0,%1\"; + return \"and\\t%3,%1,(32)0\\n\\tsrl\\t%0,%3,%V2\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "4,2,4")]) +; Note: no sign extension is necessary in case of non-zero const shift + +(define_insn "*lshrsi3_sign_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (sign_extend:DI + (lshiftrt:SI (match_operand:SI 1 "reg_or_i_operand" "r,r,I") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r")))) + (clobber (match_scratch:SI 3 "=&r,&r,&r")) + (clobber (match_scratch:SI 4 "=&r,X,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: case 2: + return +\"and\\t%3,%1,(32)0\\n\\ +\\tand\\t%4,%2,(59)0\\n\\ +\\tsrl\\t%4,%3,%4\\n\\ +\\tadds.w.sx\\t%0,0,%4\"; + case 1: + if ((UINTVAL(operands[2]) & 0x1f) == 0) + return \"adds.w.sx\\t%0,0,%1\"; + return \"and\\t%3,%1,(32)0\\n\\tsrl\\t%0,%3,%V2\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "4,2,4")]) + +(define_insn "*lshrsi3_zero_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (zero_extend:DI + (lshiftrt:SI (match_operand:SI 1 "reg_or_i_operand" "r,r,I") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r")))) + (clobber (match_scratch:SI 3 "=&r,&r,&r")) + (clobber (match_scratch:SI 4 "=&r,X,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: case 2: + return \"and\\t%3,%1,(32)0\\n\\tand\\t%4,%2,(59)0\\n\\tsrl\\t%0,%3,%4\"; + case 1: + if ((UINTVAL(operands[2]) & 0x1f) == 0) + return \"and\\t%0,%1,(32)0\"; + return \"and\\t%3,%1,(32)0\\n\\tsrl\\t%0,%3,%V2\"; + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "3,2,3")]) + +(define_insn "di3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_shift:DI (match_operand:DI 1 "reg_or_m_operand" "r,r,M") + (match_operand:SI 2 "reg_or_l_operand" "r,L,r")))] + "" + "@ + \\t%0,%1,%2 + \\t%0,%1,%2 + \\t%0,%M1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "lshrti3" + [(set (match_operand:TI 0 "register_operand" "=&r,&r") + (lshiftrt:TI (match_operand:TI 1 "register_operand" "r,r") + (match_operand:SI 2 "reg_or_l_operand" "r,L")))] + "" + "@ + or\\t%Q0,0,%Q1\\n\\tsrd\\t%Q0,%1,%2\\n\\tor\\t%0,0,%1\\n\\tsrd\\t%0,(0)1,%2 + or\\t%Q0,0,%Q1\\n\\tsrd\\t%Q0,%1,%2\\n\\tor\\t%0,0,%1\\n\\tsrd\\t%0,(0)1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "4,4")]) + +(define_insn "ashlti3" + [(set (match_operand:TI 0 "register_operand" "=&r,&r") + (ashift:TI (match_operand:TI 1 "register_operand" "r,r") + (match_operand:SI 2 "reg_or_l_operand" "r,L")))] + "" + "@ + or\\t%0,0,%1\\n\\tsld\\t%0,%Q1,%2\\n\\tor\\t%Q0,0,%Q1\\n\\tsld\\t%Q0,(0)1,%2 + or\\t%0,0,%1\\n\\tsld\\t%0,%Q1,%2\\n\\tor\\t%Q0,0,%Q1\\n\\tsld\\t%Q0,(0)1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "4,4")]) + +(define_insn "ashrti3" + [(set (match_operand:TI 0 "register_operand" "=&r,&r") + (ashiftrt:TI (match_operand:TI 1 "register_operand" "r,r") + (match_operand:SI 2 "reg_or_l_operand" "r,L"))) + (clobber (match_scratch:DI 3 "=&r,&r")) + (clobber (match_scratch:DI 4 "=&r,&r")) + (clobber (match_scratch:DI 5 "=&r,&r"))] + "" + "@ + sra.l\\t%3,%1,63\\n\\txor\\t%4,%1,%3\\n\\txor\\t%5,%Q1,%3\\n\\tsrd\\t%5,%4,%2\\n\\tsrd\\t%4,(0)1,%2\\n\\txor\\t%Q0,%5,%3\\n\\txor\\t%0,%4,%3 + sra.l\\t%3,%1,63\\n\\txor\\t%4,%1,%3\\n\\txor\\t%5,%Q1,%3\\n\\tsrd\\t%5,%4,%2\\n\\tsrd\\t%4,(0)1,%2\\n\\txor\\t%Q0,%5,%3\\n\\txor\\t%0,%4,%3" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "7,7")]) + +(define_insn "mul3" + [(set (match_operand:MODEI 0 "register_operand" "=r,r,r") + (mult:MODEI + (match_operand:MODEI 1 "register_operand" "%r,r,r") + (match_operand:MODEI 2 "" "r,I,")))] + "" + "@ + muls.\\t%0,%1,%2 + muls.\\t%0,%2,%1 + muls.\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*mulsi3_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (mult:SI (match_operand:SI 1 "register_operand" "%r,r,r") + (match_operand:SI 2 "reg_or_io_operand" "r,I,O"))))] + "" + "@ + muls.w.\\t%0,%1,%2 + muls.w.\\t%0,%2,%1 + muls.w.\\t%0,%1,%O2" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r,r,r")) + (sign_extend:DI (match_operand:SI 2 "reg_or_io_operand" "r,I,O"))))] + "" + "@ + muls.l.w\\t%0,%1,%2 + muls.l.w\\t%0,%2,%1 + muls.l.w\\t%0,%1,%O2" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "div3" + [(set (match_operand:MODEI 0 "register_operand" "=r,r,r") + (div:MODEI + (match_operand:MODEI 1 "reg_or_i_operand" "r,I,r") + (match_operand:MODEI 2 "" "r,r,")))] + "" + "@ + divs.\\t%0,%1,%2 + divs.\\t%0,%1,%2 + divs.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "") + (set_attr "length" "1,1,1")]) + +(define_insn "*divsi3_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (div:SI (match_operand:SI 1 "reg_or_i_operand" "r,I,r") + (match_operand:SI 2 "reg_or_o_operand" "r,r,O"))))] + "" + "@ + divs.w.\\t%0,%1,%2 + divs.w.\\t%0,%1,%2 + divs.w.\\t%0,%1,%O2" + [(set_attr "type" "fp") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1")]) + +(define_insn "udiv3" + [(set (match_operand:MODEI 0 "register_operand" "=r,r,r") + (udiv:MODEI + (match_operand:MODEI 1 "reg_or_i_operand" "r,I,r") + (match_operand:MODEI 2 "" "r,r,")))] + "" + "@ + divu.\\t%0,%1,%2 + divu.\\t%0,%1,%2 + divu.\\t%0,%1,%2" + [(set_attr "type" "fp") + (set_attr "mode" "") + (set_attr "length" "1,1,1")]) + +(define_insn "s3" + [(set (match_operand:MODEI 0 "register_operand" "=r,r,r") + (maxmin:MODEI + (match_operand:MODEI 1 "register_operand" "%r,r,r") + (match_operand:MODEI 2 "" "r,I,")))] + "" + "@ + s.\\t%0,%1,%2 + s.\\t%0,%2,%1 + s.\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*s_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (any_extend:DI + (maxmin:SI (match_operand:SI 1 "register_operand" "%r,r,r") + (match_operand:SI 2 "reg_or_io_operand" "r,I,O"))))] + "" + "@ + s.w.\\t%0,%1,%2 + s.w.\\t%0,%2,%1 + s.w.\\t%0,%1,%O2" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; +;; Conversion patterns +;; + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float:SF (match_operand:SI 1 "register_operand" "r")))] + "" + "cvt.s.w\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "1") ]) + +(define_insn "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float:SF (match_operand:DI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r"))] + "" + "cvt.d.l\\t%2,%1\\n\\ +\\tcvt.s.d\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "2") ]) + +(define_insn "floatdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float:DF (match_operand:MODEI 1 "register_operand" "r")))] + "" + "cvt.d.\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "floatsitf2" + [(set (match_operand:TF 0 "register_operand" "=r") + (float:TF (match_operand:SI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r"))] + "" + "cvt.d.w\\t%2,%1\\n\\tcvt.q.d\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "2")]) + +;; full 64bit support +(define_insn "floatditf2" + [(set (match_operand:TF 0 "register_operand" "=r") + (float:TF (match_operand:DI 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:TF 3 "=&r")) + (clobber (match_scratch:DI 4 "=&r"))] + "" + "cvt.d.l\\t%4,%1\\n\\ +\\tcvt.q.d\\t%2,%4\\n\\ +\\tcvt.l.d\\t%4,%4\\n\\ +\\tsubs.l\\t%4,%1,%4\\n\\ +\\tcvt.d.l\\t%4,%4\\n\\ +\\tcvt.q.d\\t%3,%4\\n\\ +\\tfadd.q\\t%0,%2,%3" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "7")]) + +(define_insn "floattisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float:SF (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r")) + (clobber (match_scratch:DF 3 "=&r"))] + "" + "adds.l\\t%2,1,%1\\n\\ +\\tcmov.l.ge\\t%2,%1,%Q1\\n\\ +\\tcvt.d.l\\t%2,%2\\n\\ +\\tlea.sl\\t%3,0x43f00000 # 2^64\\n\\ +\\tfmul.d\\t%2,%2,%3\\n\\ +\\tcvt.d.l\\t%3,%Q1\\n\\ +\\tfadd.d\\t%2,%2,%3\\n\\ +\\tcvt.s.d\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "8") ]) + +(define_insn "floattidf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float:DF (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r")) + (clobber (match_scratch:DF 3 "=&r"))] + "" + "adds.l\\t%2,1,%1\\n\\ +\\tcmov.l.ge\\t%2,%1,%Q1\\n\\ +\\tcvt.d.l\\t%2,%2\\n\\ +\\tlea.sl\\t%3,0x43f00000 # 2^64\\n\\ +\\tfmul.d\\t%2,%2,%3\\n\\ +\\tcvt.d.l\\t%3,%Q1\\n\\ +\\tfadd.d\\t%0,%2,%3" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "5") ]) + +(define_insn "floattitf2" + [(set (match_operand:TF 0 "register_operand" "=r") + (float:TF (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:TF 3 "=&r")) + (clobber (match_scratch:TF 4 "=&r")) + (clobber (match_scratch:TF 5 "=&r")) + (clobber (match_scratch:DI 6 "=&r"))] + "" + "adds.l\\t%3,1,%1\\n\\ +\\tcmov.l.ge\\t%3,%1,%Q1\\n\\ +\\tcvt.d.l\\t%6,%3\\n\\ +\\tcvt.q.d\\t%2,%6\\n\\ +\\tcvt.l.d\\t%6,%6\\n\\ +\\tsubs.l\\t%6,%3,%6\\n\\ +\\tcvt.d.l\\t%6,%6\\n\\ +\\tcvt.q.d\\t%3,%6\\n\\ +\\tfadd.q\\t%2,%2,%3\\n\\ +\\tlea.sl\\t%4,0x403f0000 # 2^64\\n\\ +\\tor\\t%Q4,0,(0)1\\n\\ +\\tfmul.q\\t%4,%2,%4\\n\\ +\\tcvt.d.l\\t%6,%Q1\\n\\ +\\tcvt.q.d\\t%2,%6\\n\\ +\\tcvt.l.d\\t%6,%6\\n\\ +\\tsubs.l\\t%6,%Q1,%6\\n\\ +\\tcvt.d.l\\t%6,%6\\n\\ +\\tcvt.q.d\\t%3,%6\\n\\ +\\tfadd.q\\t%2,%2,%3\\n\\ +\\tfadd.q\\t%0,%4,%2" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "20")]) + +(define_insn "floatunsdisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unsigned_float:SF (match_operand:DI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r")) + (clobber (match_scratch:DF 3 "=&r"))] + "" + "cvt.d.l\\t%2,%1\\n\\ +\\tbrge.l\\t%1,0,24\\n\\ +\\tlea.sl\\t%3,0x43f00000\\n\\ +\\tfadd.d\\t%2,%2,%3\\n\\ +\\tcvt.s.d\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "4") ]) + +(define_insn "floatunsdidf2" + [(set (match_operand:DF 0 "register_operand" "=&r") + (unsigned_float:DF (match_operand:DI 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r"))] + "" + "cvt.d.l\\t%0,%1\\n\\ +\\tbrge.l\\t%1,0,24\\n\\ +\\tlea.sl\\t%2,0x43f00000\\n\\ +\\tfadd.d\\t%0,%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "3") ]) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:SF 1 "register_operand" "r")))] + "" + "cvt.w.s.sx.rz\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "1")]) + +(define_insn "fix_truncsfdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix:DI (match_operand:SF 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r"))] + "" + "cvt.d.s\\t%2,%1\\n\\tcvt.l.d.rz\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "2")]) + + +(define_insn "*fix_truncsfsi2_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (fix:SI (match_operand:SF 1 "register_operand" "r"))))] + "" + "cvt.w.s..rz\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "1")]) + +(define_insn "fix_truncdf2" + [(set (match_operand:MODEI 0 "register_operand" "=r") + (fix:MODEI (match_operand:DF 1 "register_operand" "r")))] + "" + "cvt..d.rz\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "*fix_truncdfsi2_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (fix:SI (match_operand:DF 1 "register_operand" "r"))))] + "" + "cvt.w.d..rz\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +; To avoid rounding, we cut more than 52 bit fraction of quadruple +(define_insn "fix_trunctfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:TF 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d.sx.rz\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "4")]) + +(define_insn "*fix_trunctfsi2_any_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (any_extend:DI + (fix:SI (match_operand:TF 1 "register_operand" "r")))) + (clobber (match_scratch:TF 2 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d..rz\\t%0,%2" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "4")]) + +; To avoid rounding, we cut more than 52 bit fraction of quadruple +(define_insn "fix_trunctfdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix:DI (match_operand:TF 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:DF 3 "=&r")) + (clobber (match_scratch:DI 4 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%3,%2\\n\\ +\\tcvt.l.d.rz\\t%4,%3\\n\\ +\\tcvt.d.l\\t%3,%4\\n\\ +\\tcvt.q.d\\t%2,%3\\n\\ +\\tfsub.q\\t%2,%1,%2\\n\\ +\\tand\\t%Q2,%Q2,(4)1\\n\\ +\\tcvt.d.q\\t%3,%2\\n\\ +\\tcvt.l.d.rz\\t%3,%3\\n\\ +\\tadds.l\\t%0,%3,%4" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "11")]) + +(define_insn "fixuns_truncsfqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (unsigned_fix:QI (match_operand:SF 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.s.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "2")]) + +(define_insn "fixuns_truncsfqi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:QI (match_operand:SF 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.s.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "2")]) + +(define_insn "fixuns_truncdfqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (unsigned_fix:QI (match_operand:DF 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.d.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "2")]) + +(define_insn "fixuns_truncdfqi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:QI (match_operand:DF 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.d.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "2")]) + +(define_insn "fixuns_trunctfqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (unsigned_fix:QI (match_operand:TF 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:SI 3 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d.zx.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "5")]) + +(define_insn "fixuns_trunctfqi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:QI (match_operand:TF 1 "register_operand" "r")))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:SI 3 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d.zx.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(56)0" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "5")]) + +(define_insn "fixuns_truncsfhi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (unsigned_fix:HI (match_operand:SF 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.s.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "3")]) + +(define_insn "fixuns_truncsfhi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:HI (match_operand:SF 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.s.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "3")]) + +(define_insn "fixuns_truncdfhi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (unsigned_fix:HI (match_operand:DF 1 "register_operand" "r"))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.d.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "2")]) + +(define_insn "fixuns_truncdfhi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:HI (match_operand:DF 1 "register_operand" "r")))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "cvt.w.d.zx.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "DF") + (set_attr "length" "2")]) + +(define_insn "fixuns_trunctfhi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (unsigned_fix:HI (match_operand:TF 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:SI 3 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d.zx.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "5")]) + +(define_insn "fixuns_trunctfhi2_zero_extendsi" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (unsigned_fix:HI (match_operand:TF 1 "register_operand" "r")))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:SI 3 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.w.d.zx.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(48)0" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "5")]) + +(define_insn "fixuns_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unsigned_fix:SI (match_operand:SF 1 "register_operand" "r"))) + (clobber (match_scratch:DF 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "cvt.d.s\\t%2,%1\\n\\ +\\tcvt.l.d.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(32)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "3")]) + +(define_insn "fixuns_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unsigned_fix:SI (match_operand:DF 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "cvt.l.d.rz\\t%2,%1\\n\\ +\\tand\\t%0,%2,(32)0" + [(set_attr "type" "fp") + (set_attr "mode" "SF") + (set_attr "length" "2")]) + +(define_insn "fixuns_trunctfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unsigned_fix:SI (match_operand:TF 1 "register_operand" "r"))) + (clobber (match_scratch:TF 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r"))] + "" + "or\\t%2,0,%1\\n\\ +\\tand\\t%Q2,%Q1,(4)1\\n\\ +\\tcvt.d.q\\t%2,%2\\n\\ +\\tcvt.l.d.rz\\t%3,%2\\n\\ +\\tand\\t%0,%3,(32)0" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "5")]) + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))] + "" + "cvt.s.d\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "SF")]) + +(define_insn "trunctf2" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (float_truncate:MODEF (match_operand:TF 1 "register_operand" "r")))] + "" + "cvt..q\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "")]) + +;; +;; Assume QI, HI, and SI hold lower 64bit of S register +;; In case of sign extension of QI, HI, and SI 64bit is filled. +;; + +(define_insn "truncdisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:DI 1 "register_operand" "r")))] + "" + "adds.w.sx\\t%0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*truncdisi2_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (truncate:SI (match_operand:DI 1 "register_operand" "r"))))] + "" + "adds.w.sx\\t%0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*truncdisi2_zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (truncate:SI (match_operand:DI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(32)0" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "trunchi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:MODEOVHI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,48\\n\\tsra.l\\t%0,%2,48" + [(set_attr "type" "alu") + (set_attr "mode" "HI") + (set_attr "length" "2")]) + +(define_insn "*trunchi2_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (truncate:HI (match_operand:MODEOVHI 1 "register_operand" "r")))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,48\\n\\tsra.l\\t%0,%2,48" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "*trunchi2_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (truncate:HI (match_operand:MODEOVHI 1 "register_operand" "r")))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,48\\n\\tsra.l\\t%0,%2,48" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "*trunchi2_zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (truncate:HI (match_operand:MODEOVHI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(48)0" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "*trunchi2_zero_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (truncate:HI (match_operand:MODEOVHI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(48)0" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "truncqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,56\\n\\tsra.l\\t%0,%2,56" + [(set_attr "type" "alu") + (set_attr "mode" "QI") + (set_attr "length" "2")]) + +(define_insn "truncqi2_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r")))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,56\\n\\tsra.l\\t%0,%2,56" + [(set_attr "type" "alu") + (set_attr "mode" "HI") + (set_attr "length" "2")]) + +(define_insn "truncqi2_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r")))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,56\\n\\tsra.l\\t%0,%2,56" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "truncqi2_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r")))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,56\\n\\tsra.l\\t%0,%2,56" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "truncqi2_zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(56)0" + [(set_attr "type" "alu") + (set_attr "mode" "HI") + (set_attr "length" "1")]) + +(define_insn "truncqi2_zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(56)0" + [(set_attr "type" "alu") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "truncqi2_zero_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (truncate:QI (match_operand:MODEOVQI 1 "register_operand" "r"))))] + "" + "and\\t%0,%1,(56)0" + [(set_attr "type" "alu") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + + +(define_insn "trunctidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (truncate:DI (match_operand:TI 1 "register_operand" "r")))] + "" + "or\\t%0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*settrunctidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (subreg:DI (match_operand:TI 1 "register_operand" "r") + 0 ))] + "" + "or\\t%0,0,%Q1" + [(set_attr "type" "move") + (set_attr "mode" "DI")]) + +(define_insn "trunctisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:TI 1 "register_operand" "r")))] + "" + "adds.w.sx\\t%0,0,%Q1" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "trunctihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%Q1,48\\n\\tsra.l\\t%0,%2,48" + [(set_attr "type" "alu") + (set_attr "mode" "HI") + (set_attr "length" "2")]) + +(define_insn "trunctiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:TI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%Q1,56\\n\\tsra.l\\t%0,%2,56" + [(set_attr "type" "alu") + (set_attr "mode" "QI") + (set_attr "length" "2")]) + +(define_insn "zero_extendqi2" + [(set (match_operand:MODEOVQI 0 "register_operand" "=r,r") + (zero_extend:MODEOVQI (match_operand:QI 1 "general_operand" "r,a")))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"and\\t%0,%1,(56)0\"; + case 1: + ve_asm_output_ldst_unified(\"ld1b.zx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld1b.zx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "") + (set_attr "length" "1,1")]) + +(define_insn "zero_extendhi2" + [(set (match_operand:MODEOVHI 0 "register_operand" "=r,r") + (zero_extend:MODEOVHI (match_operand:HI 1 "general_operand" "r,a")))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"and\\t%0,%1,(48)0\"; + case 1: + ve_asm_output_ldst_unified(\"ld2b.zx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld2b.zx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "") + (set_attr "length" "1,1")]) + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:SI 1 "general_operand" "r,a")))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"and\\t%0,%1,(32)0\"; + case 1: + ve_asm_output_ldst_unified(\"ldl.zx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ldl.zx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "DI") + (set_attr "length" "1,1")]) + +(define_insn "zero_extendqiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (zero_extend:TI (match_operand:QI 1 "register_operand" "r")))] + "" + "or\\t%0,0,(0)1\\n\\tand\\t%Q0,%1,(56)0" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "zero_extendhiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (zero_extend:TI (match_operand:HI 1 "register_operand" "r")))] + "" + "or\\t%0,0,(0)1\\n\\tand\\t%Q0,%1,(48)0" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "zero_extendsiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (zero_extend:TI (match_operand:SI 1 "register_operand" "r")))] + "" + "or\\t%0,0,(0)1\\n\\tand\\t%Q0,%1,(32)0" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "zero_extendditi2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (zero_extend:TI (match_operand:DI 1 "register_operand" "r")))] + "" + "or\\t%0,0,(0)1\\n\\tor\\t%Q0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "extendqi2" + [(set (match_operand:MODEOVQI 0 "register_operand" "=r,r") + (sign_extend:MODEOVQI (match_operand:QI 1 "general_operand" "r,a"))) + (clobber (match_scratch:DI 2 "=&r,X"))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + if (!TARGET_OPT_SIGN_EXTENSION) + return \"sll\\t%2,%1,56\\n\\tsra.l\\t%0,%2,56\"; + else + return \"or\\t%0,0,%1\"; + case 1: + ve_asm_output_ldst_unified(\"ld1b.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) + { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld1b.sx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "") + (set_attr "length" "1,1")]) + +(define_insn "extendhi2" + [(set (match_operand:MODEOVHI 0 "register_operand" "=r,r") + (sign_extend:MODEOVHI (match_operand:HI 1 "general_operand" "r,a"))) + (clobber (match_scratch:DI 2 "=&r,X"))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + if (!TARGET_OPT_SIGN_EXTENSION) + return \"sll\\t%2,%1,48\\n\\tsra.l\\t%0,%2,48\"; + else + return \"or\\t%0,0,%1\"; + case 1: + ve_asm_output_ldst_unified(\"ld2b.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld2b.sx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "") + (set_attr "length" "1,1")]) + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (sign_extend:DI (match_operand:SI 1 "general_operand" "r,a")))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + if (!TARGET_OPT_SIGN_EXTENSION) + return \"adds.w.sx\\t%0,0,%1\"; + else + return \"or\\t%0,0,%1\"; + case 1: + ve_asm_output_ldst_unified(\"ldl.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ldl.sx\\t%0,%1\"; + } +}" + [(set_attr "type" "alu,load") + (set_attr "mode" "DI") + (set_attr "length" "1,1")]) + +(define_insn "extendqiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (sign_extend:TI (match_operand:QI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,56\\n\\tsra.l\\t%Q0,%2,56\\n\\tsra.l\\t%0,%Q0,63" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "3")]) + +(define_insn "extendhiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (sign_extend:TI (match_operand:HI 1 "register_operand" "r"))) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "sll\\t%2,%1,48\\n\\tsra.l\\t%Q0,%2,48\\n\\tsra.l\\t%0,%Q0,63" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "3")]) + +(define_insn "extendsiti2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (sign_extend:TI (match_operand:SI 1 "register_operand" "r")))] + "" + "adds.w.sx\\t%Q0,0,%1\\n\\tsra.l\\t%0,%Q0,63" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +(define_insn "extendditi2" + [(set (match_operand:TI 0 "register_operand" "=&r") + (sign_extend:TI (match_operand:DI 1 "register_operand" "r")))] + "" + "sra.l\\t%0,%1,63\\n\\tor\\t%Q0,0,%1" + [(set_attr "type" "alu") + (set_attr "mode" "TI") + (set_attr "length" "2")]) + +;; +; +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float_extend:DF (match_operand:SF 1 "register_operand" "r")))] + "" + "cvt.d.s\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "DF")]) + +(define_insn "extendtf2" + [(set (match_operand:TF 0 "register_operand" "=r") + (float_extend:TF (match_operand:MODEF 1 "register_operand" "r")))] + "" + "cvt.q.\\t%0,%1" + [(set_attr "type" "fp") + (set_attr "mode" "TF")]) +; +; pic code +; + +(define_insn "*movdi_label_relative" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_LABEL))] + "" + "sic\\t%0\\n\\ +\\tlea\\t%0,%1-.(,%0)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "ve_move_pic_got32" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_GOT32))] + "" + "ld\\t%0,%S1@GOT32(,%%got)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +(define_insn "ve_move_pic_pc" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_PC)) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "lea\\t%0,%S1@PC_LO(-24)\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tsic\\t%2\\n\\ +\\tlea.sl\\t%0,%S1@PC_HI(%0,%2)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "4")]) + +(define_insn "ve_move_pic_pc2" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "") + (match_operand:DI 2 "register_operand" "=&r")] + UNSPEC_MOVE_PIC_PC2))] + "" + "lea\\t%0,%S1@PC_LO(-24)\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tsic\\t%2\\n\\ +\\tlea.sl\\t%0,%S1@PC_HI(%0,%2)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "4")]) + +(define_insn "ve_move_pic_plt" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_PLT)) + (clobber (match_scratch:DI 2 "=&r"))] + "" + "lea\\t%0,%S1@PLT_LO(-24)\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tsic\\t%2\\n\\ +\\tlea.sl\\t%0,%S1@PLT_HI(%0,%2)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "4")]) + +(define_insn "ve_move_pic_got" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_GOT))] + "" + "lea\\t%0,%S1@GOT_LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@GOT_HI(%0,%%got)\\n\\ +\\tld\\t%0,0(,%0)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "4")]) + +(define_insn "ve_move_pic_gotoff" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_PIC_GOTOFF))] + "" + "lea\\t%0,%S1@GOTOFF_LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@GOTOFF_HI(%0,%%got)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + + + +(define_insn "ve_move" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE))] + "" + "lea\\t%0,%S1@LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@HI(,%0)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +(define_insn "ve_move_call" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI + [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_MOVE_CALL))] + "" + "lea\\t%0,%S1@CALL_LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@CALL_HI(,%0)" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +;; TLS Support + +(define_insn "tgd_load_call" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI + [(match_operand:DI 1 "tgd_symbolic_operand" "") + (match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_TLSGD)) + (use (reg:DI 0)) + (use (reg:DI 15)) + (use (reg:DI 16)) + (clobber (reg:DI 1)) + (clobber (reg:DI 2)) + (clobber (reg:DI 3)) + (clobber (reg:DI 4)) + (clobber (reg:DI 5)) + (clobber (reg:DI 6)) + (clobber (reg:DI 7)) + (clobber (reg:DI 10)) + (clobber (reg:DI 12)) + (clobber (reg:DI 13)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36)) + (clobber (reg:DI 37)) + (clobber (reg:DI 38)) + (clobber (reg:DI 39)) + (clobber (reg:DI 40)) + (clobber (reg:DI 41)) + (clobber (reg:DI 42)) + (clobber (reg:DI 43)) + (clobber (reg:DI 44)) + (clobber (reg:DI 45)) + (clobber (reg:DI 46)) + (clobber (reg:DI 47)) + (clobber (reg:DI 48)) + (clobber (reg:DI 49)) + (clobber (reg:DI 50)) + (clobber (reg:DI 51)) + (clobber (reg:DI 52)) + (clobber (reg:DI 53)) + (clobber (reg:DI 54)) + (clobber (reg:DI 55)) + (clobber (reg:DI 56)) + (clobber (reg:DI 57)) + (clobber (reg:DI 58)) + (clobber (reg:DI 59)) + (clobber (reg:DI 60)) + (clobber (reg:DI 61)) + (clobber (reg:DI 62)) + (clobber (reg:DI 63))] + "" + "* +{ + rtx xop[7]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = gen_rtx_REG(DImode,0); + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[5] = gen_rtx_REG(DImode,VE_RETURN_REGNUM); + output_asm_insn(\"lea\\t%3,%S1@TLS_GD_LO(-24)\",xop); + output_asm_insn(\"and\\t%3,%3,(32)0\",xop); + output_asm_insn(\"sic\\t%5\",xop); + output_asm_insn(\"lea.sl\\t%3,%S1@TLS_GD_HI(%3,%5)\",xop); + output_asm_insn(\"lea\\t%4,%S2@PLT_LO(8)\",xop); + output_asm_insn(\"and\\t%4,%4,(32)0\",xop); + output_asm_insn(\"lea.sl\\t%4,%S2@PLT_HI(%4,%5)\",xop); + output_asm_insn(\"bsic\\t%5,(,%4)\",xop); + if (REGNO(operands[0]) != 0) + output_asm_insn(\"or\\t%0,0,%3\",xop); + return \"\"; +}" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "8")]) + + +(define_insn "tld_load_call" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI + [(match_operand:DI 1 "tld_symbolic_operand" "") + (match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_TLSLD)) + (use (reg:DI 0)) + (use (reg:DI 15)) + (use (reg:DI 16)) + (clobber (reg:DI 1)) + (clobber (reg:DI 2)) + (clobber (reg:DI 3)) + (clobber (reg:DI 4)) + (clobber (reg:DI 5)) + (clobber (reg:DI 6)) + (clobber (reg:DI 7)) + (clobber (reg:DI 10)) + (clobber (reg:DI 12)) + (clobber (reg:DI 13)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36)) + (clobber (reg:DI 37)) + (clobber (reg:DI 38)) + (clobber (reg:DI 39)) + (clobber (reg:DI 40)) + (clobber (reg:DI 41)) + (clobber (reg:DI 42)) + (clobber (reg:DI 43)) + (clobber (reg:DI 44)) + (clobber (reg:DI 45)) + (clobber (reg:DI 46)) + (clobber (reg:DI 47)) + (clobber (reg:DI 48)) + (clobber (reg:DI 49)) + (clobber (reg:DI 50)) + (clobber (reg:DI 51)) + (clobber (reg:DI 52)) + (clobber (reg:DI 53)) + (clobber (reg:DI 54)) + (clobber (reg:DI 55)) + (clobber (reg:DI 56)) + (clobber (reg:DI 57)) + (clobber (reg:DI 58)) + (clobber (reg:DI 59)) + (clobber (reg:DI 60)) + (clobber (reg:DI 61)) + (clobber (reg:DI 62)) + (clobber (reg:DI 63))] + "" + "* +{ + rtx xop[7]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = gen_rtx_REG(DImode,0); + xop[4] = gen_rtx_REG(DImode,VE_GOT_REGNUM); + xop[5] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[6] = gen_rtx_REG(DImode,VE_RETURN_REGNUM); + output_asm_insn(\"lea\\t%3,%S1@TLS_LD_LO\",xop); + output_asm_insn(\"and\\t%3,%3,(32)0\",xop); + output_asm_insn(\"lea.sl\\t%3,%S1@TLS_LD_HI(%4,%3)\",xop); + output_asm_insn(\"lea\\t%5,%S2@PLT_LO(-24)\",xop); + output_asm_insn(\"and\\t%5,%5,(32)0\",xop); + output_asm_insn(\"sic\\t%6\",xop); + output_asm_insn(\"lea.sl\\t%5,%S2@PLT_HI(%5,%6)\",xop); + output_asm_insn(\"bsic\\t%6,(,%5)\",xop); + if (REGNO(operands[0]) != 0) + output_asm_insn(\"or\\t%0,0,%3\",xop); + return \"\"; +}" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "8")]) + +(define_insn "tld_offset_load" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (unspec:DI [(match_operand 1 "tld_symbolic_operand" "")] + UNSPEC_TLSLDO) + (match_operand:DI 2 "register_operand" "r")))] + "" + "lea\\t%0,%S1@DTPOFF(,%2)" + [(set_attr "type" "move") + (set_attr "length" "1")]) + +(define_insn "tie_load" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI [(match_operand 1 "tie_symbolic_operand" "")] + UNSPEC_TLSIE)) + (use (reg:DI 15))] + "" + "lea\\t%0,%S1@TLS_IE_LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@TLS_IE_HI(,%0)\\n\\ +\\tld\\t%0,0(%%got,%0)" + [(set_attr "type" "move") + (set_attr "length" "3")]) + +(define_insn "tle_load" + [(set (match_operand:DI 0 "register_operand" "=&r") + (plus:DI (unspec:DI [(match_operand 1 "tle_symbolic_operand" "")] + UNSPEC_TLSLE) + (match_operand:DI 2 "register_operand" "r")))] + "" + "lea\\t%0,%S1@TPOFF_LO\\n\\ +\\tand\\t%0,%0,(32)0\\n\\ +\\tlea.sl\\t%0,%S1@TPOFF_HI(%2,%0)" + [(set_attr "type" "move") + (set_attr "length" "3")]) + + +;; +;; move instructions: +;; mem-reg, reg-mem, imm-reg +;; +;; The standard "movsi" pattern for RTL generation. It +;; makes sure one of the operands is in a register, but +;; avoids trying to do this later during compilation when +;; the register allocation is complete. +;; +;; This pattern was lifted almost verbatim from the MIPS machine +;; description. +;; + + + + +;; ve_expand_move(operands,DImode); +;; + +;; reload may generate constant > 32bit (case 3)! + +(define_expand "mov" + [(set (match_operand:MODEANYI 0 "nonimmediate_operand" "") + (match_operand:MODEANYI 1 "general_operand" ""))] + "" + " +{ + if (ve_expand_move(operands,mode)) { + DONE; + } +}") + + +(define_insn "movti_general" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,r,&r,r,a,r") + (match_operand:TI 1 "general_operand" "I,M,N,i,a,r,r"))] + "" + "* + +{ + int pos=1; + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"or\\t%0,%Z1,(0)1\\n\\tor\\t%Q0,%G1,(0)1\"; + case 1: + return \"or\\t%0,%Z1,(0)1\\n\\tor\\t%Q0,0,%M1\"; + case 2: + return \"or\\t%0,%Z1,(0)1\\n\\tlea\\t%Q0,%1\"; + case 3: + if(GET_CODE(operands[1]) == CONST_INT) { + if ((INTVAL(operands[1]) & 0xffffffff) == 0) + { + return \"or\\t%0,%Z1,(0)1\\n\\tlea.sl\\t%Q0,%H1\"; + } + else + { + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn( + \"or\\t%0,%Z1,(0)1\\n\\tlea\\t%2,%L1\\n\\tlea.sl\\t%Q0,%H1(%2)\",xop); + return \"\"; + } + } + else if (GET_CODE(operands[1]) == CONST_DOUBLE) + { + xop[0] = operands[0]; + xop[1] = GEN_INT(CONST_DOUBLE_HIGH(operands[1])); + xop[2] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + if (-2147483648 <= INTVAL(xop[1]) && INTVAL(xop[1]) <= 2147483647) + output_asm_insn(\"lea\\t%0,%1\",xop); + else + output_asm_insn(\"lea\\t%2,%L1\\n\\tlea.sl\\t%0,%H1(%2)\",xop); + xop[1] = GEN_INT(CONST_DOUBLE_LOW(operands[1])); + if (-2147483648 <= INTVAL(xop[1]) && INTVAL(xop[1]) <= 2147483647) + output_asm_insn(\"lea\\t%Q0,%1\",xop); + else + output_asm_insn(\"lea\\t%2,%L1\\n\\tlea.sl\\t%Q0,%H1(%2)\",xop); + return \"\"; + } + gcc_unreachable(); + case 4: + ve_asm_output_ldst_unified(\"ld\",VE_DIR_QLOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld\\t%0,%1\"; + case 5: + ve_asm_output_ldst_unified(\"st\",VE_DIR_QSTORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st\\t%1,%0\"; + case 6: + return \"or\\t%0,0,%1\\n\\tor\\t%Q0,0,%Q1\"; + } + +}" + [(set_attr "type" "move,move,move,move,load,store,move") + (set_attr "mode" "TI") + (set_attr "length" "2,2,2,3,2,2,2")]) + + +(define_insn "movdi_general" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,a,r") + (match_operand:DI 1 "general_operand" "I,M,N,i,a,r,r"))] + "" + "* + +{ + int pos=1; + rtx xop[5]; + switch(which_alternative) + { + default: + case 0: + return \"or\\t%0,%G1,(0)1\"; + case 1: + return \"or\\t%0,0,%M1\"; + case 2: + return \"lea\\t%0,%1\"; + case 3: + if(GET_CODE(operands[1]) == CONST_INT) { + if ((INTVAL(operands[1]) & 0xffffffff) == 0) + return \"lea.sl\\t%0,%H1\"; + else { + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea\\t%2,%L1\\n\\tlea.sl\\t%0,%H1(%2)\",xop); + return \"\"; + } + } + gcc_unreachable(); + case 4: + ve_asm_output_ldst_unified(\"ld\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld\\t%0,%1\"; + case 5: + ve_asm_output_ldst_unified(\"st\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st\\t%1,%0\"; + case 6: + return \"or\\t%0,0,%1\"; + } + +}" + [(set_attr "type" "move,move,move,move,load,store,move") + (set_attr "mode" "DI") + (set_attr "length" "1,1,1,2,1,1,1")]) + + +(define_insn "movsi_general" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,a,r") + (match_operand:SI 1 "general_operand" "I,P,N,a,r,r"))] + "" + "* + +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"or\\t%0,%G1,(0)1\"; + case 1: + return \"or\\t%0,0,%P1\"; + case 2: + return \"lea\\t%0,%1\"; + case 3: + ve_asm_output_ldst_unified(\"ldl.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ldl.sx\\t%0,%1\"; + case 4: + ve_asm_output_ldst_unified(\"stl\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"stl\\t%1,%0\"; + case 5: + return \"or\\t%0,0,%1\"; + } + +}" + [(set_attr "type" "move,move,move,load,store,move") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1,1,1,1")]) + + +;; +;; Move half words. +;; +(define_insn "movhi_general" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,a,r") + (match_operand:HI 1 "general_operand" "I,P,N,a,r,r"))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"or\\t%0,%G1,(0)1\"; + case 1: + return \"or\\t%0,0,%P1\"; + case 2: + return \"lea\\t%0,%1\"; + case 3: + ve_asm_output_ldst_unified(\"ld2b.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld2b.sx\\t%0,%1\"; + + case 4: + ve_asm_output_ldst_unified(\"st2b\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st2b\\t%1,%0\"; + case 5: + return \"or\\t%0,0,%1\"; + } + +}" + [(set_attr "type" "move,move,move,load,store,move") + (set_attr "mode" "HI") + (set_attr "length" "1,1,1,1,1,1")]) + +;; +;; move bytes. +;; + +(define_insn "movqi_general" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,a,r") + (match_operand:QI 1 "general_operand" "I,P,N,a,r,r"))] + "" + "* +{ + int pos=1; + rtx xop[2]; + switch(which_alternative) + { + default: + case 0: + return \"or\\t%0,%G1,(0)1\"; + case 1: + return \"or\\t%0,0,%P1\"; + case 2: + return \"lea\\t%0,%1\"; + case 3: + ve_asm_output_ldst_unified(\"ld1b.sx\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld1b.sx\\t%0,%1\"; + case 4: + ve_asm_output_ldst_unified(\"st1b\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st1b\\t%1,%0\"; + case 5: + return \"or\\t%0,0,%1\"; + } + +}" + [(set_attr "type" "move,move,move,load,store,move") + (set_attr "mode" "QI") + (set_attr "length" "1,1,1,1,1,1")]) + +;; +;; Move floats. +;; +(define_expand "mov" + [(set (match_operand:MODEANYF 0 "nonimmediate_operand" "") + (match_operand:MODEANYF 1 "general_operand" ""))] + "" + " +{ + if (ve_expand_move(operands,mode)) { + DONE; + } +}") + + +(define_insn "movsf_general" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,a,r,r,r") + (match_operand:SF 1 "general_operand" "a,r,r,G,H"))] + "" + "* +{ + int pos=1; + rtx xop[3]; + switch(which_alternative) + { + default: + case 0: + ve_asm_output_ldst_unified(\"ldu\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ldu\\t%0,%1\"; + case 1: + ve_asm_output_ldst_unified(\"stu\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"stu\\t%1,%0\"; + case 2: + return \"or\\t%0,0,%1\"; + case 3: + return \"or\\t%0,0,(0)1\"; + case 4: + return ve_movsf_reg_immediate(&operands[0]); + } + +}" + [(set_attr "type" "load,store,move,move,move") + (set_attr "mode" "SF") + (set_attr "length" "1,1,1,1,1")]) + +(define_insn "movdf_general" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,a,r,r,r") + (match_operand:DF 1 "general_operand" "a,r,r,G,H"))] + "" + "* +{ + int pos=1; + rtx xop[3]; + switch(which_alternative) + { + default: + case 0: + ve_asm_output_ldst_unified(\"ld\",VE_DIR_LOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld\\t%0,%1\"; + case 1: + ve_asm_output_ldst_unified(\"st\",VE_DIR_STORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st\\t%1,%0\"; + case 2: + return \"or\\t%0,0,%1\"; + case 3: + return \"or\\t%0,0,(0)1\"; + case 4: + return ve_movdf_reg_immediate(&operands[0]); + } + +}" + [(set_attr "type" "load,store,move,move,move") + (set_attr "mode" "DF") + (set_attr "length" "1,1,1,1,2")]) + + +(define_insn "movtf_general" + [(set (match_operand:TF 0 "nonimmediate_operand" "=r,a,r,r,r") + (match_operand:TF 1 "general_operand" "a,r,r,G,H"))] + "" + "* +{ + int pos=1; + rtx xop[3]; + switch(which_alternative) + { + default: + case 0: + ve_asm_output_ldst_unified(\"ld\",VE_DIR_QLOAD,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[1],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"ld\\t%Q0,%1\\n\\tld\\t%0,%A1\"; + case 1: + ve_asm_output_ldst_unified(\"st\",VE_DIR_QSTORE,operands,NULL_RTX); + return \"\"; + xop[1] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + while(1) { + xop[0] = ve_addr_cut_mem(operands[0],pos); + if (xop[0] == NULL_RTX) break; + output_asm_insn(\"ld\\t%1,%0\",xop); + pos++; + } + return \"st\\t%Q1,%0\\n\\tst\\t%1,%A0\"; + case 2: + return \"or\\t%0,0,%1\\n\\tor\\t%Q0,0,%Q1\"; + case 3: + return \"or\\t%0,0,(0)1\\n\\tor\\t%Q0,0,(0)1\"; + case 4: + return ve_movtf_reg_immediate(&operands[0]); + } + +}" + [(set_attr "type" "load,store,move,move,move") + (set_attr "mode" "TF") + (set_attr "length" "2,2,2,2,4")]) + + +; Used for alloca +(define_insn "allocate_stack" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")] + UNSPEC_STACK_PROBE)) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r")) + (clobber (reg:DI 11))] + "" + "* +{ + rtx xop[10]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[5] = stack_pointer_rtx; + xop[6] = gen_rtx_REG(DImode,STACK_LIMIT_REGNUM); + xop[7] = gen_rtx_CONST_INT(DImode, + VE_RSA_SIZE + crtl->outgoing_args_size); + xop[8] = gen_rtx_REG(DImode,0); + xop[9] = gen_rtx_REG(DImode,VE_THREAD_POINTER_REGNUM); + output_asm_insn(\"subu.l\\t%5,%5,%1\",xop); + output_asm_insn(\"brge.l.t\\t%5,%6,72\",xop); + output_asm_insn(\"ld\\t%3,0x18(,%9)\",xop); + output_asm_insn(\"or\\t%2,0,%8\",xop); + output_asm_insn(\"lea\\t%4,315\",xop); + output_asm_insn(\"shm.l\\t%4,0(%3)\",xop); + output_asm_insn(\"shm.l\\t%6,8(%3)\",xop); + output_asm_insn(\"shm.l\\t%5,16(%3)\",xop); + output_asm_insn(\"monc\",xop); + output_asm_insn(\"or\\t%8,0,%2\",xop); + output_asm_insn(\"lea\\t%0,%7(,%5)\",xop); + return \"\"; +}" + [(set_attr "type" "load") + (set_attr "mode" "none") + (set_attr "length" "11")]) + +(define_insn "allocate_stack_prologue" + [(set (match_operand:DI 0 "register_operand" "+&r") + (unspec_volatile:DI [(match_operand:DI 1 "const_int_operand" "i") + (match_operand:DI 2 "register_operand" "=&r") + (match_operand:DI 3 "register_operand" "=&r")] + UNSPEC_STACK_PROLOGUE))] + "" + "* +{ + rtx xop[9]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + xop[5] = stack_pointer_rtx; + xop[6] = gen_rtx_REG(DImode,STACK_LIMIT_REGNUM); + xop[7] = gen_rtx_REG(DImode,0); + xop[8] = gen_rtx_REG(DImode,VE_THREAD_POINTER_REGNUM); + if (ve_const_si_p(INTVAL(xop[1]))) + output_asm_insn(\"lea\\t%0,%1(,%0)\",xop); + else + { + output_asm_insn(\"lea.sl\\t%4,%H1(,%0)\",xop); + output_asm_insn(\"lea\\t%0,%L1(,%4)\",xop); + } + output_asm_insn(\"brge.l.t\\t%0,%6,72\",xop); + output_asm_insn(\"ld\\t%3,0x18(,%8)\",xop); + output_asm_insn(\"or\\t%2,0,%7\",xop); + output_asm_insn(\"lea\\t%4,315\",xop); + output_asm_insn(\"shm.l\\t%4,0(%3)\",xop); + output_asm_insn(\"shm.l\\t%6,8(%3)\",xop); + output_asm_insn(\"shm.l\\t%0,16(%3)\",xop); + output_asm_insn(\"monc\",xop); + output_asm_insn(\"or\\t%7,0,%2\",xop); + return \"\"; +}" + [(set_attr "type" "load") + (set_attr "mode" "none") + (set_attr "length" "10")]) + +; Stack protector instructions + +(define_expand "stack_protect_set" + [(set (match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" ""))] + "!TARGET_MUSL_COMPAT" +{ + operands[1] = gen_rtx_MEM(Pmode, + gen_rtx_PLUS(Pmode, + gen_rtx_REG(DImode,VE_THREAD_POINTER_REGNUM), + GEN_INT(TARGET_THREAD_SSP_OFFSET))); + emit_insn (gen_stack_protect_setdi(operands[0], operands[1])); + DONE; +}) + +(define_insn "stack_protect_setdi" + [(set (match_operand:DI 0 "memory_operand" "=m") + (unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET)) + (set (match_scratch:DI 2 "=&r") (const_int 0))] + "!TARGET_MUSL_COMPAT" + "ld\\t%2,%1\\n\\tst\\t%2,%0\\n\\tor\\t%2,0,(0)1" + [(set_attr "type" "store") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +(define_expand "stack_protect_test" + [(match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")] + "!TARGET_MUSL_COMPAT" +{ + rtx result, test; + + operands[1] = gen_rtx_MEM(Pmode, + gen_rtx_PLUS(Pmode, + gen_rtx_REG(DImode,VE_THREAD_POINTER_REGNUM), + GEN_INT(TARGET_THREAD_SSP_OFFSET))); + result = gen_reg_rtx(DImode); + emit_insn(gen_stack_protect_testdi(result,operands[0],operands[1])); + test = gen_rtx_EQ(VOIDmode,result,const0_rtx); + emit_jump_insn (gen_cbranchdi4(test,result,const0_rtx,operands[2])); + DONE; +}) + +(define_insn "stack_protect_testdi" + [(set (match_operand:DI 0 "register_operand" "=&r") + (unspec:DI [(match_operand:DI 1 "memory_operand" "m") + (match_operand:DI 2 "memory_operand" "m")] + UNSPEC_SP_TEST)) + (set (match_scratch:DI 3 "=&r") (const_int 0))] + "!TARGET_MUSL_COMPAT" + "ld\\t%0,%1\\n\\tld\\t%3,%2\\n\\txor\\t%0,%3,%0\\n\\tor\\t%3,0,(0)1" + [(set_attr "type" "load") + (set_attr "mode" "DI") + (set_attr "length" "4")]) + +(define_insn "prefetch" + [(prefetch (match_operand:DI 0 "general_operand" "r") + (match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" ""))] + "" + "pfch\\t0(,%0)" + [(set_attr "type" "load") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +(define_insn "flush_icache" + [(unspec_volatile [(const_int 0)] UNSPEC_FLUSH_ICACHE)] + "" + "* return \"fencec\\t2\";" + [(set_attr "type" "misc") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +; set fp_mode to round_nearest and clean all exception masks +(define_insn "init_program_mode" + [(unspec_volatile [(const_int 0)] UNSPEC_INIT_PROGRAM_MODE)] + "" + "* +{ + rtx xop[1]; + xop[0] = gen_rtx_REG(DImode,VE_SCRATCH_REGNUM); + output_asm_insn(\"lea\\t%0,0x3000\",xop); + output_asm_insn(\"lpm\\t%0\",xop); + return \"\"; +}" + [(set_attr "type" "misc") + (set_attr "mode" "none") + (set_attr "length" "2")]) + +;; Atomic operations +(define_expand "memory_barrier" + [(set (match_dup 0) + (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] + "" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*memory_barrier" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))] + "" + "fencem\\t3" + [(set_attr "type" "misc") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +(define_insn "sync_compare_and_swap" + [(parallel + [(set (match_operand:MODEI 0 "register_operand" "=r,r,&r,&r") + (match_operand:MODEI 1 "memory_operand" "+m,m,m,m")) + (set (match_dup 1) + (unspec_volatile:MODEI + [(match_dup 1) + (match_operand:MODEI 2 "reg_or_i_operand" "r,I,r,I") + (match_operand:MODEI 3 "register_operand" "0,0,r,r")] + UNSPEC_COMPARE_AND_SWAP)) ])] + "" + "* +{ + switch(which_alternative) + { + default: case 2: case 3: + output_asm_insn(\"or\\t%0,0,%3\",operands); + + case 0: case 1: + ve_asm_output_ldst_unified(\"cas.\",VE_DIR_ATOMIC01,operands, + operands[2]); + return \"\"; + } +}" + [(set_attr "type" "multi") + (set_attr "mode" "") + (set_attr "length" "1,1,2,2")]) + +(define_insn "sync_di" + [(set (match_operand:DI 0 "memory_operand" "+m") + (unspec_volatile:DI + [(atomic:DI (match_dup 0) + (match_operand:DI 1 "register_operand" "r"))] + UNSPEC_SYNC_OP)) + (clobber (match_scratch:DI 2 "=&r")) ] + "" + "* +{ + output_asm_insn(\"\\t%2,0,%1\",operands); + ve_asm_output_ldst_unified(\"atmam\",VE_DIR_ATOMIC20,operands, + gen_rtx_CONST_INT(DImode,)); + return \"\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "sync_old_di" + [(set (match_operand:DI 0 "register_operand" "=&r") + (match_operand:DI 1 "memory_operand" "+m")) + (set (match_dup 1) + (unspec_volatile:DI + [(atomic:DI (match_dup 1) + (match_operand:DI 2 "register_operand" "r")) ] + UNSPEC_SYNC_OP))] + "" + "* +{ + output_asm_insn(\"\\t%0,0,%2\",operands); + ve_asm_output_ldst_unified(\"atmam\",VE_DIR_ATOMIC01,operands, + gen_rtx_CONST_INT(DImode,)); + return \"\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_insn "sync_new_di" + [(parallel [ + (set (match_operand:DI 0 "register_operand" "=&r") + (unspec_volatile:DI + [(atomic:DI (match_operand:DI 1 "memory_operand" "+m") + (match_operand:DI 2 "register_operand" "r"))] + UNSPEC_SYNC_NEW_OP)) + (set (match_dup 1) + (unspec_volatile:DI [(match_dup 1) (match_dup 2)] + UNSPEC_SYNC_NEW_OP))])] + "" + "* +{ + output_asm_insn(\"\\t%0,0,%2\",operands); + ve_asm_output_ldst_unified(\"atmam\",VE_DIR_ATOMIC01,operands, + gen_rtx_CONST_INT(DImode,)); + output_asm_insn(\"ld\\t%0,%1\",operands); + return \"\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +(define_insn "sync_lock_test_and_setdi" + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (match_operand:DI 1 "memory_operand" "+m,m")) + (set (match_dup 1) + (unspec_volatile:DI + [(match_operand:DI 2 "register_operand" "0,r")] + UNSPEC_SYNC_LOCK_TEST_AND_SET)) + (clobber (match_scratch:DI 3 "=&r,&r")) ] + "" + "* +{ + switch(which_alternative) + { + default: case 1: + output_asm_insn(\"or\\t%0,0,%2\",operands); + + case 0: + output_asm_insn(\"or\\t%3,0,(56)0\",operands); + ve_asm_output_ldst_unified(\"ts1am.l\",VE_DIR_ATOMIC01,operands, + operands[3]); + return \"\"; + } +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +(define_insn "sync_lock_test_and_setsi" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (match_operand:SI 1 "memory_operand" "+m,m")) + (set (match_dup 1) + (unspec_volatile:SI + [(match_operand:SI 2 "register_operand" "0,r")] + UNSPEC_SYNC_LOCK_TEST_AND_SET))] + "" + "* +{ + switch(which_alternative) + { + default: case 1: + output_asm_insn(\"or\\t%0,0,%2\",operands); + + case 0: + ve_asm_output_ldst_unified(\"ts1am.w\",VE_DIR_ATOMIC01,operands, + gen_rtx_CONST_INT(DImode,15)); + return \"\"; + } +}" + [(set_attr "type" "multi") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "sync_lock_releasedi" + [(set (match_operand:DI 0 "memory_operand" "=m") + (unspec_volatile:DI + [(match_operand:DI 1 "register_operand" "r")] + UNSPEC_SYNC_LOCK_RELEASE)) + (clobber (match_scratch:DI 2 "=&r")) + (clobber (match_scratch:DI 3 "=&r")) ] + "" + "* +{ + output_asm_insn(\"or\\t%3,0,(56)0\",operands); + output_asm_insn(\"or\\t%2,0,%1\",operands); + ve_asm_output_ldst_unified(\"ts1am.l\",VE_DIR_ATOMIC20,operands, + operands[3]); + return \"\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + +(define_insn "sync_lock_releasesi" + [(set (match_operand:SI 0 "memory_operand" "=m") + (unspec_volatile:SI + [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_SYNC_LOCK_RELEASE)) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "* +{ + output_asm_insn(\"or\\t%2,0,%1\",operands); + ve_asm_output_ldst_unified(\"ts1am.w\",VE_DIR_ATOMIC20,operands, + gen_rtx_CONST_INT(DImode,15)); + return \"\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + + +;; +;; No-Op +;; + + +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "type" "alu") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +;; +;; unconditional branches and such. +;; + +(define_insn "indirect_jump" + [(set (pc) (match_operand:DI 0 "register_operand" "r"))] + "" + "b.l.t\\t(,%0)" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + if (GET_CODE (operands[0]) == LABEL_REF) + return \"br.l.t\\t%0\"; + else if (GET_CODE (operands[0]) == REG) + return \"b.l.t\\t(,%0)\"; + else + return \"br.l.t\\t%0\"; +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + + +;; +;; calls +;; + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "register_operand" "=r") + (call (match_operand 1 "sym_ref_mem_operand" "") + (match_operand 2 "const_int_operand" "i"))) + (clobber (reg:DI 9)) + (clobber (reg:DI 10)) + (clobber (reg:DI 17)) ])] + "" +{ + rtx callee; + callee = XEXP(operands[1],0); + if (GET_CODE(callee) != REG && ve_check_symbol(callee,Pmode)) + callee = ve_indirect_addr(callee,true,true); + operands[1] = gen_rtx_MEM( GET_MODE (operands[1]), + force_reg (Pmode, callee)); +}) + +(define_expand "call" + [(parallel [(call (match_operand 0 "sym_ref_mem_operand" "") + (match_operand 1 "const_int_operand" "i")) + (clobber (reg:DI 9)) + (clobber (reg:DI 10)) + (clobber (reg:DI 17)) ])] + "" +{ + rtx callee; + callee = XEXP(operands[0],0); + if (GET_CODE(callee) != REG && ve_check_symbol(callee,Pmode)) + callee = ve_indirect_addr(callee,true,true); + operands[0] = gen_rtx_MEM( GET_MODE (operands[0]), + force_reg (Pmode, callee)); +}) + +(define_insn "call_value_indirect" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "register_operand" "r")) + (match_operand 2 "const_int_operand" "i"))) + (clobber (reg:DI 9)) + (clobber (reg:DI 10)) + (clobber (reg:DI 17)) ])] + "" + "* +{ + return ve_output_call_instr_value(&operands[0]); +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_insn "call_indirect" + [(parallel [(call (mem:DI (match_operand:DI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (reg:DI 9)) + (clobber (reg:DI 10)) + (clobber (reg:DI 17)) ])] + "" + "* +{ + return ve_output_call_instr(&operands[0]); +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + + +;; Call subroutine returning any type. +;; used in __builtin_apply + +(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)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + DONE; +}) + + +;; +;; tablejump insn; used in generating code for switches. +;; + +(define_expand "tablejump" + [(parallel [(set (pc) + (match_operand:DI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))])] + "" +{ + rtx tempreg = gen_reg_rtx(DImode); + emit_move_insn(tempreg,gen_rtx_PLUS(DImode,operands[0], + gen_rtx_LABEL_REF(DImode,operands[1]))); + operands[0] = tempreg; +}) + +(define_insn "tablejump_internal" + [(parallel [(set (pc) + (match_operand:DI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))])] + "" + "b.l.t\\t(,%0)" + [(set_attr "type" "jump") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +;; +;; Floating point comparison +;; +(define_insn "cstore4" + [(set (match_operand:SI 0 "register_operand" "=&r") + (match_operator:SI 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r") + (match_operand:MODEF 3 "register_operand" "r")]))] + "" + "* +{ + if (flag_signaling_nans) + { + rtx xop[5]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(mode,VE_SCRATCH_REGNUM); + output_asm_insn(\"or\\t%0,1,(0)1\",xop); + output_asm_insn(\"fcmp.\\t%4,%2,%3\",xop); + output_asm_insn(\"br%F1.%+\\t%4,0,16\",xop); + output_asm_insn(\"or\\t%0,0,(0)1\",xop); + return \"\"; + } + output_asm_insn(\"or\\t%0,1,(0)1\",operands); + output_asm_insn(\"br%F1.%+\\t%2,%3,16\",operands); + output_asm_insn(\"or\\t%0,0,(0)1\",operands); + return \"\"; +}" + [(set_attr "type" "fp") + (set_attr "mode" "") + (set_attr "length" "3")]) + +(define_insn "cstoretf4" + [(set (match_operand:SI 0 "register_operand" "=&r") + (match_operator:SI 1 "comparison_operator" + [(match_operand:TF 2 "register_operand" "r") + (match_operand:TF 3 "register_operand" "r")])) + (clobber (match_scratch:DI 4 "=&r")) + (clobber (match_scratch:DI 5 "=&r"))] + "" + "* +{ + if (flag_signaling_nans) + { + output_asm_insn(\"or\\t%0,1,(0)1\",operands); + output_asm_insn(\"fcmp.q\\t%4,%2,%3\",operands); + output_asm_insn(\"br%F1.d%+\\t%4,0,16\",operands); + output_asm_insn(\"or\\t%0,0,(0)1\",operands); + return \"\"; + } + switch (GET_CODE(operands[1])) + { + default: + case EQ: case LTGT: case GT: case GE: case LT: case LE: + case ORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,80\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,64\",operands); + output_asm_insn(\"and\\t%5,%3,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,48\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q3,0,32\",operands); + output_asm_insn(\"fcmp.q\\t%4,%2,%3\",operands); + output_asm_insn(\"or\\t%0,1,(0)1\",operands); + output_asm_insn(\"br%F1.d%+\\t%4,0,16\",operands); + output_asm_insn(\"or\\t%0,0,(0)1\",operands); + return \"\"; + case UNEQ: case NE: case UNGT: case UNGE: case UNLT: case UNLE: + case UNORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,80\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,64\",operands); + output_asm_insn(\"and\\t%5,%3,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,48\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q3,0,32\",operands); + output_asm_insn(\"fcmp.q\\t%4,%2,%3\",operands); + output_asm_insn(\"or\\t%0,0,(0)1\",operands); + output_asm_insn(\"br%E1.d%-\\t%4,0,16\",operands); + output_asm_insn(\"or\\t%0,1,(0)1\",operands); + return \"\"; + } +}" + [(set_attr "type" "fp") + (set_attr "mode" "TF") + (set_attr "length" "13")]) + +;; +;; Conditional moves +;; + +(define_insn "movsicc_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r,r,r") + (const_int 0)]) + (match_operand:SI 3 "reg_or_o_operand" "r,O,0,0") + (match_operand:SI 4 "reg_or_o_operand" "0,0,r,O")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%0,%3,%2 + cmov..%C1\\t%0,%O3,%2 + cmov..%N1\\t%0,%4,%2 + cmov..%N1\\t%0,%O4,%2" + [(set_attr "type" "move") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1,1")]) + +(define_insn "movsicc_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r,r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G,G,G")]) + (match_operand:SI 3 "reg_or_o_operand" "r,O,0,0") + (match_operand:SI 4 "reg_or_o_operand" "0,0,r,O")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%0,%3,%2 + cmov..%F1\\t%0,%O3,%2 + cmov..%E1\\t%0,%4,%2 + cmov..%E1\\t%0,%O4,%2" + [(set_attr "type" "move") + (set_attr "mode" "SI") + (set_attr "length" "1,1,1,1")]) + + +(define_insn "movdicc_internal" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") + (if_then_else:DI (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r,r,r") + (const_int 0)]) + (match_operand:DI 3 "reg_or_m_operand" "r,M,0,0") + (match_operand:DI 4 "reg_or_m_operand" "0,0,r,M")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%0,%3,%2 + cmov..%C1\\t%0,%M3,%2 + cmov..%N1\\t%0,%4,%2 + cmov..%N1\\t%0,%M4,%2" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "1,1,1,1")]) + +(define_insn "movdicc_internal" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r,r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G,G,G")]) + (match_operand:DI 3 "reg_or_m_operand" "r,M,0,0") + (match_operand:DI 4 "reg_or_m_operand" "0,0,r,M")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%0,%3,%2 + cmov..%F1\\t%0,%M3,%2 + cmov..%E1\\t%0,%4,%2 + cmov..%E1\\t%0,%M4,%2" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "1,1,1,1")]) + +(define_insn "movticc_internal" + [(set (match_operand:TI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:TI (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r,r,r") + (const_int 0)]) + (match_operand:TI 3 "reg_or_m_operand" "r,M,0,0") + (match_operand:TI 4 "reg_or_m_operand" "0,0,r,M")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%Q0,%Q3,%2\\n\\tcmov..%C1\\t%0,%3,%2 + cmov..%C1\\t%Q0,%M3,%2\\n\\tsra.l\\t%0,%Q0,63 + cmov..%N1\\t%Q0,%Q4,%2\\n\\tcmov..%C1\\t%0,%4,%2 + cmov..%N1\\t%Q0,%M4,%2\\n\\tsra.l\\t%0,%Q0,63" + [(set_attr "type" "move") + (set_attr "mode" "TI") + (set_attr "length" "2,2,2,2")]) + +(define_insn "movticc_internal" + [(set (match_operand:TI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:TI (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r,r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G,G,G")]) + (match_operand:TI 3 "reg_or_m_operand" "r,M,0,0") + (match_operand:TI 4 "reg_or_m_operand" "0,0,r,M")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%Q0,%Q3,%2\\n\\tcmov..%F1\\t%0,%3,%2 + cmov..%F1\\t%Q0,%M3,%2\\n\\tsra.l\\t%0,%Q0,63 + cmov..%E1\\t%Q0,%Q4,%2\\n\\tcmov..%E1\\t%0,%4,%2 + cmov..%E1\\t%Q0,%M4,%2\\n\\tsra.l\\t%0,%Q0,63" + [(set_attr "type" "move") + (set_attr "mode" "TI") + (set_attr "length" "2,2,2,2")]) + +;; + +(define_insn "movsfcc_internal" + [(set (match_operand:SF 0 "register_operand" "=r,r") + (if_then_else:SF (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "r,0") + (match_operand:SF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%0,%3,%2 + cmov..%N1\\t%0,%4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SF") + (set_attr "length" "1,1")]) + +(define_insn "movsfcc_internal" + [(set (match_operand:SF 0 "register_operand" "=r,r") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G")]) + (match_operand:SF 3 "register_operand" "r,0") + (match_operand:SF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%0,%3,%2 + cmov..%E1\\t%0,%4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "SF") + (set_attr "length" "1,1")]) + +(define_insn "movdfcc_internal" + [(set (match_operand:DF 0 "register_operand" "=r,r") + (if_then_else:DF (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r") + (const_int 0)]) + (match_operand:DF 3 "register_operand" "r,0") + (match_operand:DF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%0,%3,%2 + cmov..%N1\\t%0,%4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "DF") + (set_attr "length" "1,1")]) + +(define_insn "movdfcc_internal" + [(set (match_operand:DF 0 "register_operand" "=r,r") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G")]) + (match_operand:DF 3 "register_operand" "r,0") + (match_operand:DF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%0,%3,%2 + cmov..%E1\\t%0,%4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "DF") + (set_attr "length" "1,1")]) + +(define_insn "movtfcc_internal" + [(set (match_operand:TF 0 "register_operand" "=r,r") + (if_then_else:TF (match_operator 1 "ve_signed_comparison_operator" + [(match_operand:MODEI 2 "register_operand" "r,r") + (const_int 0)]) + (match_operand:TF 3 "register_operand" "r,0") + (match_operand:TF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%C1\\t%0,%3,%2\\n\\tcmov..%C1\\t%Q0,%Q3,%2 + cmov..%N1\\t%0,%4,%2\\n\\tcmov..%N1\\t%Q0,%Q4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "2,2")]) + +(define_insn "movtfcc_internal" + [(set (match_operand:TF 0 "register_operand" "=r,r") + (if_then_else:TF (match_operator 1 "comparison_operator" + [(match_operand:MODEF 2 "register_operand" "r,r") + (match_operand:MODEF 5 "const_zero_operand" "G,G")]) + (match_operand:TF 3 "register_operand" "r,0") + (match_operand:TF 4 "register_operand" "0,r")))] + "!TARGET_NO_CMOV" + "@ + cmov..%F1\\t%0,%3,%2\\n\\tcmov..%F1\\t%Q0,%Q3,%2 + cmov..%E1\\t%0,%4,%2\\n\\tcmov..%E1\\t%Q0,%Q4,%2" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "2,2")]) + +(define_insn "movtftfcc_internal" + [(set (match_operand:TF 0 "register_operand" "=r,r") + (if_then_else:TF (match_operator 1 "comparison_operator" + [(match_operand:TF 2 "register_operand" "r,r") + (match_operand:TF 5 "register_operand" "r,r")]) + (match_operand:TF 3 "register_operand" "r,0") + (match_operand:TF 4 "register_operand" "0,r"))) + (clobber (match_scratch:DF 6 "=&r,&r"))] + "!TARGET_NO_CMOV" + "@ + fcmp.q\\t%6,%2,%5\\n\\tcmov.d.%F1\\t%0,%3,%6\\n\\tcmov.d.%F1\\t%Q0,%Q3,%6 + fcmp.q\\t%6,%2,%5\\n\\tcmov.d.%E1\\t%0,%4,%6\\n\\tcmov.d.%E1\\t%Q0,%Q4,%6" + [(set_attr "type" "alu") + (set_attr "mode" "TF") + (set_attr "length" "3,3")]) + +;; +;; No scratch registers can be used, after reload. +(define_insn "cmp3_internal" + [(set (match_operand:MODEI 0 "register_operand" "=r,r") + (unspec:MODEI + [(match_operand:MODEI 1 "register_operand" "r,r") + (match_operand:MODEI 2 "reg_or_i_operand" "r,I")] + UNSPEC_COMPARE))] + "" + "* +{ + rtx xop[4]; + switch(which_alternative) + { + default: case 0: + return \"cmps.\\t%0,%1,%2\"; + case 1: + switch(INTVAL(operands[2])) + { + case 1: case 3: case 7: case 15: case 31: case 63: + return \"cmps.\\t%0,%1,%O2\"; + default: + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = gen_rtx_REG(mode,VE_SCRATCH_REGNUM); + output_asm_insn( + \"or\\t%3,%2,(0)1\\n\\tcmps.\\t%0,%1,%3\",xop); + return \"\"; + } + } +}" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "1,2")]) + +(define_insn "cmp3_internal" + [(set (match_operand:MODEF 0 "register_operand" "=r") + (unspec:MODEF + [(match_operand:MODEF 1 "register_operand" "r") + (match_operand:MODEF 2 "register_operand" "r")] + UNSPEC_COMPARE))] + "" + "fcmp.\\t%0,%1,%2" + [(set_attr "type" "alu") + (set_attr "mode" "") + (set_attr "length" "1")]) + +(define_expand "movcc" + [(set (match_operand:MODEI 0 "register_operand" "") + (if_then_else:MODEI (match_operand 1 "ve_signed_comparison_operator" "") + (match_operand:MODEI 2 "register_operand" "") + (match_operand:MODEI 3 "register_operand" "")))] + "" +{ + enum rtx_code code = GET_CODE(operands[1]); + machine_mode mode10 = GET_MODE(XEXP(operands[1],0)); + machine_mode mode1 = GET_MODE(operands[1]); + rtx tmpreg = gen_reg_rtx(mode10); + if (XEXP(operands[1],1) != CONST0_RTX(mode10)) + { + emit_insn(gen_rtx_SET(tmpreg, + gen_rtx_UNSPEC(mode10, + gen_rtvec(2,XEXP(operands[1],0),XEXP(operands[1],1)), + UNSPEC_COMPARE))); + operands[1] = gen_rtx_fmt_ee (code,mode1,tmpreg,CONST0_RTX(mode10)); + } +}) + +(define_expand "movcc" + [(set (match_operand:MODEF 0 "register_operand" "") + (if_then_else:MODEF (match_operand 1 "comparison_operator" "") + (match_operand:MODEF 2 "register_operand" "") + (match_operand:MODEF 3 "register_operand" "")))] + "" +{ + enum rtx_code code = GET_CODE(operands[1]); + machine_mode mode10 = GET_MODE(XEXP(operands[1],0)); + machine_mode mode1 = GET_MODE(operands[1]); + rtx tmpreg = gen_reg_rtx(mode10); + if (XEXP(operands[1],1) != CONST0_RTX(mode10)) + { + emit_insn(gen_rtx_SET(tmpreg, + gen_rtx_UNSPEC(mode10, + gen_rtvec(2,XEXP(operands[1],0),XEXP(operands[1],1)), + UNSPEC_COMPARE))); + operands[1] = gen_rtx_fmt_ee (code,mode1,tmpreg,CONST0_RTX(mode10)); + } +}) + + +;;; +;;; Comparison + branches. +;;; + +(define_insn "cbranch4" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:MODEI 1 "register_operand" "r,r,r") + (match_operand:MODEI 2 "" "r,,I")]) + (label_ref (match_operand 3 "")) + (pc))) + (clobber (match_scratch:MODEI 4 "=&r,&r,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: + { enum rtx_code code = GET_CODE(operands[0]); + switch(code) + { + case GTU: case GEU: case LTU: case LEU: + return + \"cmpu.\\t%4,%1,%2\\n\\tbr%C0.%+\\t%4,0,%3\"; + default: + return \"br%C0.%+\\t%1,%2,%3\"; + } + } + case 1: + { enum rtx_code code = GET_CODE(operands[0]); + switch(code) + { + case GTU: case GEU: case LTU: case LEU: + return + \"cmpu.\\t%4,%1,%2\\n\\tbr%C0.%+\\t%4,0,%3\"; + default: + switch (INTVAL(operands[2])) + { + case 0: + return \"br%C0.%+\\t%1,0,%3\"; + default: + return + \"cmps.\\t%4,%1,%2\\n\\tbr%C0.%+\\t%4,0,%3\"; + } + } + } + case 2: + { enum rtx_code code = GET_CODE(operands[0]); + switch(code) + { + case GTU: case GEU: case LTU: case LEU: + return + \"cmpu.\\t%4,%2,%1\\n\\tbr%R0.%+\\t%4,0,%3\"; + default: + return \"br%R0.%+\\t%2,%1,%3\"; + } + } + } + +}" + + [(set_attr "type" "branch") + (set_attr "mode" "") + (set_attr "length" "1,1,1")]) + + +(define_insn "cbranchti4" + [(set (pc) + (if_then_else + (match_operator 0 "comparison_operator" + [(match_operand:TI 1 "register_operand" "r,r") + (match_operand:TI 2 "reg_or_i_operand" "r,I")]) + (label_ref (match_operand 3 "")) + (pc))) + (clobber (match_scratch:DI 4 "=&r,&r"))] + "" + "* +{ + switch(which_alternative) + { + default: case 0: + { + enum rtx_code code = GET_CODE(operands[0]); + switch(code) + { + default: case EQ: + return \"brne.l\\t%1,%2,16\\n\\tbreq.l%+\\t%Q1,%Q2,%3\"; + case NE: + return \"brne.l\\t%1,%2,%3\\n\\tbrne.l%+\\t%Q1,%Q2,%3\"; + case GT: case GE: case LT: case LE: + output_asm_insn(\"br%J0.l\\t%1,%2,%3\",operands); + output_asm_insn(\"brne.l\\t%1,%2,24\",operands); + output_asm_insn(\"cmpu.l\\t%4,%Q1,%Q2\",operands); + return \"br%C0.l%+\\t%4,0,%3\"; + case GTU: case GEU: case LTU: case LEU: + output_asm_insn(\"cmpu.l\\t%4,%1,%2\",operands); + output_asm_insn(\"br%J0.l\\t%4,0,%3\",operands); + output_asm_insn(\"brne.l\\t%4,0,24\",operands); + output_asm_insn(\"cmpu.l\\t%4,%Q1,%Q2\",operands); + return \"br%C0.l%+\\t%4,0,%3\"; + } + } + case 1: + { enum rtx_code code = GET_CODE(operands[0]); + switch(code) + { + default: case EQ: + return \"brne.l\\t%Z2,%1,16\\n\\tbr%R0.l%+\\t%2,%Q1,%3\"; + case NE: + return \"brne.l\\t%Z2,%1,%3\\n\\tbr%R0.l%+\\t%2,%Q1,%3\"; + case GT: case GE: case LT: case LE: + output_asm_insn(\"br%J0.l\\t%Z2,%1,%3\",operands); + output_asm_insn(\"brne.l\\t%Z2,%1,24\",operands); + output_asm_insn(\"cmpu.l\\t%4,%2,%Q1\",operands); + return \"br%R0.l%+\\t%4,0,%3\"; + case GTU: case GEU: case LTU: case LEU: + output_asm_insn(\"cmpu.l\\t%4,%Z2,%1\",operands); + output_asm_insn(\"br%J0.l\\t%4,0,%3\",operands); + output_asm_insn(\"brne.l\\t%4,0,24\",operands); + output_asm_insn(\"cmpu.l\\t%4,%2,%Q1\",operands); + return \"br%R0.l%+\\t%4,0,%3\"; + } + } + } + +}" + + [(set_attr "type" "branch") + (set_attr "mode" "TI") + (set_attr "length" "2,2")]) + + +(define_insn "cbranch4" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:MODEF 1 "register_operand" "r") + (match_operand:MODEF 2 "register_operand" "r")]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "* +{ + if (flag_signaling_nans) + { + rtx xop[5]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(mode,VE_SCRATCH_REGNUM); + output_asm_insn(\"fcmp.\\t%4,%1,%2\",xop); + output_asm_insn(\"br%F0.%+\\t%4,0,%3\",xop); + return \"\"; + } + return \"br%F0.%+\\t%1,%2,%3\"; +}" + [(set_attr "type" "branch") + (set_attr "mode" "") + (set_attr "length" "1")]) + +(define_insn "cbranchtf4" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:TF 1 "register_operand" "r") + (match_operand:TF 2 "register_operand" "r")]) + (label_ref (match_operand 3 "")) + (pc))) + (clobber (match_scratch:DI 4 "=&r")) + (clobber (match_scratch:DI 5 "=&r"))] + "" + "* +{ + if (flag_signaling_nans) + { + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%F0.d%+\\t%4,0,%3\",operands); + return \"\"; + } + switch (GET_CODE(operands[0])) + { + default: + case EQ: case LTGT: case GT: case GE: case LT: case LE: + case ORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%1,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,72\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q1,0,56\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,40\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,24\",operands); + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%F0.d%+\\t%4,0,%3\",operands); + return \"\"; + + case UNEQ: case NE: case UNGT: case UNGE: case UNLT: case UNLE: + case UNORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%1,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,%3\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q1,0,%3\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,%3\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,%3\",operands); + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%F0.d%+\\t%4,0,%3\",operands); + return \"\"; + } +}" + [(set_attr "type" "branch") + (set_attr "mode" "TF") + (set_attr "length" "11")]) + +(define_insn "*cbranch4_rev" + [(set (pc) + (if_then_else (match_operator 0 "ve_ordered_comparison_operator" + [(match_operand:MODEF 1 "register_operand" "r") + (match_operand:MODEF 2 "register_operand" "r")]) + (pc) + (label_ref (match_operand 3 ""))))] + "" + "* +{ + if (flag_signaling_nans) + { + rtx xop[5]; + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = operands[2]; + xop[3] = operands[3]; + xop[4] = gen_rtx_REG(mode,VE_SCRATCH_REGNUM); + output_asm_insn(\"fcmp.\\t%4,%1,%2\",xop); + output_asm_insn(\"br%E0.%-\\t%4,0,%3\",xop); + return \"\"; + } + return \"br%E0.%-\\t%1,%2,%3\"; +}" + [(set_attr "type" "branch") + (set_attr "mode" "") + (set_attr "length" "1")]) + +(define_insn "*cbranchtf4_rev" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:TF 1 "register_operand" "r") + (match_operand:TF 2 "register_operand" "r")]) + (pc) + (label_ref (match_operand 3 "")))) + (clobber (match_scratch:DI 4 "=&r")) + (clobber (match_scratch:DI 5 "=&r"))] + "" + "* +{ + if (flag_signaling_nans) + { + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%E0.d%-\\t%4,0,%3\",operands); + return \"\"; + } + switch (GET_CODE(operands[0])) + { + default: + case EQ: case LTGT: case GT: case GE: case LT: case LE: + case ORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%1,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,%3\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q1,0,%3\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,%3\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,%3\",operands); + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%E0.d%-\\t%4,0,%3\",operands); + return \"\"; + + case UNEQ: case NE: case UNGT: case UNGE: case UNLT: case UNLE: + case UNORDERED: + output_asm_insn(\"srl\\t%4,(15)1,1\",operands); + output_asm_insn(\"and\\t%5,%1,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,72\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q1,0,56\",operands); + output_asm_insn(\"and\\t%5,%2,(1)0\",operands); + output_asm_insn(\"brgt.l.nt\\t%5,%4,40\",operands); + output_asm_insn(\"brlt.l.t\\t%5,%4,16\",operands); + output_asm_insn(\"brne.l.t\\t%Q2,0,24\",operands); + output_asm_insn(\"fcmp.q\\t%4,%1,%2\",operands); + output_asm_insn(\"br%E0.d%-\\t%4,0,%3\",operands); + return \"\"; + } +}" + [(set_attr "type" "branch") + (set_attr "mode" "TF") + (set_attr "length" "11")]) + +;; +;; prologue +;; + +(define_expand "prologue" + [(const_int 0)] + "" +{ + ve_expand_prologue (); + DONE; +}) + +;; Just output comment for debugging +(define_insn "prologue_end" + [(unspec_volatile [(const_int 0)] UNSPEC_PROLOGUE_END)] + "" + "# End of function prologue" + [(set_attr "type" "misc") + (set_attr "mode" "none")]) + +;; +;; epilogue +;; + +;; Block any insns from being moved before this point, since the +;; profiling call to mcount can use various registers that are not +;; saved or used to pass arguments. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] + "" + "" + [(set_attr "type" "ghost") + (set_attr "mode" "none")]) + +(define_expand "epilogue" + [(return)] + "" +{ + ve_expand_epilogue (); + DONE; +}) + +(define_insn "epilogue_start" + [(unspec_volatile [(const_int 0)] UNSPEC_EPILOGUE_START)] + "" + "# Start of function epilogue" + [(set_attr "type" "misc") + (set_attr "mode" "none")]) + +(define_expand "return" + [(return)] + "" +{ + ve_expand_epilogue (); + DONE; +}) + +(define_insn "*return" + [(return)] + "" + "* +{ + rtx xop[1]; + xop[0] = gen_rtx_REG(DImode,VE_RETURN_REGNUM); + output_asm_insn(\"b.l.t\\t(,%0)\",xop); + return \"# End of function epilogue\"; +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +;; peephole optimizations +(define_peephole2 + [(set (match_operand:MODEI 0 "register_operand") + (plus:MODEI (match_operand:MODEI 1 "register_operand") + (match_operand:MODEI 2 "const_n_operand"))) + (set (match_operand:MODEI 3 "register_operand") + (plus:MODEI (match_dup 0) + (match_operand:MODEI 4 "register_operand")))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 3) + (plus:MODEI (match_dup 4) + (plus:MODEI (match_dup 1) (match_dup 2))))]) + +(define_peephole2 + [(set (match_operand:MODEI 0 "register_operand") + (plus:MODEI (match_operand:MODEI 1 "register_operand") + (match_operand:MODEI 2 "register_operand"))) + (set (match_operand:MODEI 3 "register_operand") + (plus:MODEI (match_dup 0) + (match_operand:MODEI 4 "const_n_operand")))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 3) + (plus:MODEI (match_dup 1) + (plus:MODEI (match_dup 2) (match_dup 4))))]) + +(define_peephole2 + [(set (match_operand:DI 0 "register_operand") + (sign_extend:DI (match_operand:SI 1 "register_operand")))] + "TARGET_OPT_SIGN_EXTENSION + && true_regnum(operands[0]) == true_regnum(operands[1])" + [(const_int 0)]) + +(define_peephole2 + [(parallel [(set (match_operand:MODEOVHI 0 "register_operand") + (sign_extend:MODEOVHI (match_operand:HI 1 "register_operand"))) + (clobber (match_scratch:DI 2 ))])] + "TARGET_OPT_SIGN_EXTENSION + && true_regnum(operands[0]) == true_regnum(operands[1])" + [(const_int 0)]) + +(define_peephole2 + [(parallel [(set (match_operand:MODEOVQI 0 "register_operand") + (sign_extend:MODEOVQI (match_operand:QI 1 "register_operand"))) + (clobber (match_scratch:DI 2 ))])] + "TARGET_OPT_SIGN_EXTENSION + && true_regnum(operands[0]) == true_regnum(operands[1])" + [(const_int 0)]) + diff --git a/gcc/config/ve/ve.opt b/gcc/config/ve/ve.opt new file mode 100644 index 00000000000..8296a7f1263 --- /dev/null +++ b/gcc/config/ve/ve.opt @@ -0,0 +1,102 @@ +; Options for the VE port of the compiler. + +; Copyright (C) 2010-2016 Free Software Foundation, Inc. +; +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 3, or (at your option) any later +; version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . +; Changes by NEC Corporation for the VE port, 2017-2021 + +HeaderInclude +config/ve/ve-opts.h + +TargetVariable +unsigned int ve_const_indirect + +TargetVariable +unsigned int ve_symbol_indirect + +; +; formatting options +; +masm-align +Target Mask(ASM_ALIGN) +Use .align instead of .balign in asm + +; +; compatibility options +; +mfour-byte-bool +Target Mask(FOUR_BYTE_BOOL) +Change _Bool size from 1 byte to 4 bytes (warning: ABI altered) + +mpadstruct +Target Mask(PADSTRUCT) +Make structs a multiple of 4 bytes (warning: ABI altered) + +mshift-count-full +Target Mask(SHIFT_COUNT_FULL) +Assume shift count is not truncated, but uses full bit. Basically the result may not change. It is *only* effective for compile time constant calculations. (Experimantal) + +mconst-indirect +Target Mask(CONST_INDIRECT) +Access large constants(>4bytes) indirectly through Linkage area rather than immediate instruction + +msymbol-indirect +Target Mask(SYMBOL_INDIRECT) +Access symbolic name indirectly through Linkage area rather than immediate instruction + +mmusl-compat +Target Mask(MUSL_COMPAT) +Generate code that is compatible with musl-libc + +; +; optimization options +; +margmem= +Target RejectNegative Joined Enum(ve_argmem_setting) Var(ve_argmem) Init(ARGMEM_SAFE) +-maregmrm=[force|safe|opt] Function caller sets arguments to memory FORCEdly, SAFEly, OPTimally + +Enum +Name(ve_argmem_setting) Type(enum ve_argmem_setting) + +EnumValue +Enum(ve_argmem_setting) String(force) Value(ARGMEM_FORCE) + +EnumValue +Enum(ve_argmem_setting) String(safe) Value(ARGMEM_SAFE) + +EnumValue +Enum(ve_argmem_setting) String(opt) Value(ARGMEM_OPT) + +mopt-sign-extension +Target Mask(OPT_SIGN_EXTENSION) +Optimize sign extension of integers when it seems not necessary. (Experimental) + +mstruct-by-value= +Target RejectNegative Joined UInteger Var(ve_struct_by_value) Init(0) +Upper limit of stucture or union argument size passed by value (default is 0) + +mno-cmov +Target Mask(NO_CMOV) +Do not use cmov instrunction, but (maybe) use branch + +mbranch-prob= +Target RejectNegative Joined UInteger Var(ve_branch_prob) Init(85) +Lower limit of branch probability with which static branch predicition(.t or .nt postfix for branch instruction) is generated. The value should be usually in the range between 55 and 100. Lower value generates much static prediction (default is 85) + +mtls-asis +Target Mask(TLS_ASIS) +Treat all tls model asis. Stop changing all to be global-dynamic diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c index a1237cf839b..bb6305a7278 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c @@ -33,4 +33,4 @@ void test55 (int x, int y) that the && should be emitted (based on BRANCH_COST). Fix this by teaching dom to look through && and register all components as true. */ -/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* s390*-*-* sh*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-* riscv*-*-*" } } } } */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* s390*-*-* sh*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-* riscv*-*-* ve-*-*" } } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c index 0193c6e52fc..b32478c9456 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c @@ -46,7 +46,7 @@ int xxx(void) /* CRIS keeps the address in a register. */ /* m68k sometimes puts the address in a register, depending on CPU and PIC. */ -/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* visium-*-* } } } */ +/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* x86_64-*-mingw* visium-*-* ve-*-* } } } */ /* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-* } } } */ /* { dg-final { scan-assembler-times "= foo" 5 { target ia64*-*-* } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*_foo" 5 { target i?86-*-mingw* i?86-*-cygwin* } } } */ diff --git a/gcc/testsuite/lib/file-format.exp b/gcc/testsuite/lib/file-format.exp index 0b39878d8e4..f3786571516 100644 --- a/gcc/testsuite/lib/file-format.exp +++ b/gcc/testsuite/lib/file-format.exp @@ -22,6 +22,8 @@ # formats. This procedure is defined in a separate file so that it can be # included by other expect library files. +# Changes by NEC Corporation for the VE port, 2018-2021 + proc gcc_target_object_format { } { global gcc_target_object_format_saved global tool @@ -41,6 +43,9 @@ proc gcc_target_object_format { } { } elseif { [istarget *-*-aix*] } { # AIX doesn't necessarily have objdump, so hand-code it. set gcc_target_object_format_saved coff + } elseif { [istarget ve-*-*] } { + # VE have objdump but the filename is nobjdump, so hand-code it. + set gcc_target_object_format_saved elf } else { set objdump_name [find_binutils_prog objdump] set open_file [open objfmtst.c w] diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 342af270ab1..1c6e16109af 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -14,6 +14,8 @@ # along with GCC; see the file COPYING3. If not see # . +# Changes by NEC Corporation for the VE port, 2018-2021 + # Please email any bugs, comments, and/or additions to this file to: # gcc-patches@gcc.gnu.org @@ -1117,6 +1119,9 @@ proc check_effective_target_shared { } { # Return 1 if -pie, -fpie and -fPIE are supported, 0 otherwise. proc check_effective_target_pie { } { + if { [istarget ve-*-*] } { + return 0; + } if { [istarget *-*-darwin\[912\]*] || [istarget *-*-dragonfly*] || [istarget *-*-freebsd*] diff --git a/include/longlong.h b/include/longlong.h index 9d3ab21be2d..7ba0e8676ab 100644 --- a/include/longlong.h +++ b/include/longlong.h @@ -25,6 +25,7 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ +/* Changes by NEC Corporation for the VE port, 2018-2021 */ /* You have to define the following before including this file: @@ -122,6 +123,12 @@ extern const UQItype __clz_tab[256] attribute_hidden; #define __AND_CLOBBER_CC , "cc" #endif /* __GNUC__ < 2 */ +#if defined (__ve__) +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X)) +#define COUNT_LEADING_ZEROS_0 32 +#endif /* __ve__ */ + #if defined (__aarch64__) #if W_TYPE_SIZE == 32 diff --git a/libgcc/config.host b/libgcc/config.host index b279a6458f9..f92175a09b3 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -17,6 +17,8 @@ #along with GCC; see the file COPYING3. If not see #. +# Changes by NEC Corporation for the VE port, 2017-2021 + # This is the libgcc host-specific configuration file # where a configuration type is mapped to different system-specific # definitions and files. This is invoked by the autoconf-generated @@ -1328,6 +1330,9 @@ nvptx-*) tmake_file="$tmake_file nvptx/t-nvptx" extra_parts="crt0.o" ;; +ve-*-*) + tmake_file="$tmake_file ve/t-ve t-slibgcc-libgcc" + ;; *) echo "*** Configuration ${host} not supported" 1>&2 exit 1 diff --git a/libgcc/config/ve/divtf3.c b/libgcc/config/ve/divtf3.c new file mode 100644 index 00000000000..f13391c8ec6 --- /dev/null +++ b/libgcc/config/ve/divtf3.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2017-2021 NEC Corporation + + 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include +long double __divtf3(long double a, long double b); +long double __divtf3(long double a, long double b) { + long double t,c, cu, cl, bu, bl; + double bh, th; + long signa, signb, signab, expa, expb; + expa = *((long *)&a+1) & 0xffff000000000000; + expb = *((long *)&b+1) & 0xffff000000000000; + signa = expa & 0x8000000000000000; + signb = expb & 0x8000000000000000; + expa = expa ^ signa; + expb = expb ^ signb; + signab = signa ^ signb; + if (__builtin_isnanl(a) || __builtin_isnanl(b)) + return __builtin_nanl(""); + if (__builtin_isinfl(b)) { + if (__builtin_isinf(a)) return __builtin_nanl(""); + else return (signab >=0)? 0.0L : -0.0L; + } + if (__builtin_isinfl(a)) { + return (signab >=0)? __builtin_infl() : -__builtin_infl(); + } + if (b == 0) { + volatile double x = 1.0/0.0; + if (a == 0) return __builtin_nanl(""); + return (signab >=0)? __builtin_infl() : -__builtin_infl(); + } + if (a == 0) { + return (signab >=0)? 0.0L : -0.0L; + } + *((long *)&a+1) = (*((long *)&a +1) & 0x0000ffffffffffff) + + 0x3fff000000000000; + *((long *)&b+1) = (*((long *)&b +1) & 0x0000ffffffffffff) + + 0x3fff000000000000; + bh = b; + th = 1.0 / bh; + t = th; + t = t * (2.0L - b * t); + c = a * t; + cu = c; + *(long *)&cu = *(long *)&cu & 0xfe00000000000000; + cl = c - cu; + bu = b; + *(long *)&bu = (*(long *)&bu) & 0xfe00000000000000; + bl = b - bu; + t = a - cu * bu - cu * bl - cl * bu - cl * bl; + th = t; + th = th / bh; + c = c + th; + *((long *)&c+1) = *((long *)&c+1) + (expa - expb); + if(expa >= expb) { + if ((*((long *)&c+1) & 0x8000000000000000L) || + ((*((long *)&c+1) & 0xffff000000000000L) + == 0x7fff000000000000L)) { + return (signab >=0)? __builtin_infl() : -__builtin_infl(); + } + } + if(expa <= expb) { + if ((*((long *)&c+1) & 0x8000000000000000L) || + ((*((long *)&c+1) & 0xffff000000000000L) + == 0x0000000000000000L)) { + return (signab >=0)? 0.0L : -0.0L; + } + } + + if (signab < 0) c = -c; + return c; +} diff --git a/libgcc/config/ve/dso_handle.c b/libgcc/config/ve/dso_handle.c new file mode 100644 index 00000000000..739c1f1a1cf --- /dev/null +++ b/libgcc/config/ve/dso_handle.c @@ -0,0 +1,27 @@ +/* __dso_handle initialization for VE. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +void *__dso_handle; + diff --git a/libgcc/config/ve/lib1funcs.S b/libgcc/config/ve/lib1funcs.S new file mode 100644 index 00000000000..9979848f4b2 --- /dev/null +++ b/libgcc/config/ve/lib1funcs.S @@ -0,0 +1,708 @@ +/* libgcc routines for the VE. + Copyright (C) 2014,2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This file 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + + .macro FUNC_START names:vararg + .text + .balign 16 + .irp name, \names + .globl __\name + .type __\name,@function + .endr + .endm + + .macro FUNC_ENTRY name +__\name: + .endm + + .macro FUNC_COMPAT namec, name + .symver \namec, \name@GCC_1.0 + .endm + + .macro RETURN + b.l.t (,%lr) + .endm + +#ifdef L_unordsf2 +FUNC_START unordsf2 +FUNC_ENTRY unordsf2 + brnan.s %s0,%s1,.L1 + or %s0,0,(0)1 + RETURN +.L1: + or %s0,1,(0)1 + RETURN +#endif + +#ifdef L_unorddf2 +FUNC_START unorddf2 +FUNC_ENTRY unorddf2 + brnan.d %s0,%s1,.L2 + or %s0,0,(0)1 + RETURN +.L2: + or %s0,1,(0)1 + RETURN +#endif + +#ifdef L_unordtf2 +FUNC_START unordtf2 +FUNC_ENTRY unordtf2 + srl %s4,(15)1,1 + and %s5,%s0,(1)0 + brgt.l %s5,%s4,.L5 + brle.l %s5,%s4,.L3 + brne.l %s1,0,.L5 +.L3: + and %s5,%s2,(1)0 + brgt.l %s5,%s4,.L5 + brlt.l %s5,%s4,.L4 + brne.l %s3,0,.L5 +.L4: + or %s0,0,(0)1 + RETURN +.L5: + or %s0,1,(0)1 + RETURN +#endif + +#__int128 dfti2(double x) { +# double t,x2; +# long u,l,k; +# __int128 ul; +# t = pow(2.0,127); +# .if (fabs(x) >= t) { +# ul = 1; +# ul = ul << 127; +# return ul; +# } +# t = pow(2.0,-96); +# k = (long) (x * t); +# t = pow(2.0,96); +# x2 = x - ((double)k) * t; +# u = k << 32; +# +# t = pow(2.0,-64); +# k = (long) (x2 * t); +# t = pow(2.0,64); +# x2 = x2 - ((double)k) * t; +# u = u + k ; +# .if (x2 <0) u--; +# +# t = pow(2.0,-32); +# k = (long) (x2 * t); +# t = pow(2.0,32); +# x2 = x2 - ((double)k) * t; +# l = k << 32 ; +# +# k = (long) x2; +# l = l + k; +# +# ul = u; +# ul = ul << 64; +# ul = ul + (unsigned long)l ; +# return ul; +#} +# register %s0:x,u %s1:l %s2:t %s3:x2, %s4:k, %s5:tmp + .macro FIX2TI_CORE + lea.sl %s2,0x39f00000 # (double)2^-96 + fmul.d %s5,%s0,%s2 + cvt.l.d.rz %s4,%s5 + lea.sl %s2,0x45f00000 # (double)2^96 + cvt.d.l %s5,%s4 + fmul.d %s5,%s5,%s2 + fsub.d %s3,%s0,%s5 + sll %s0,%s4,32 +# + lea.sl %s2,0x3bf00000 # (double)2^-64 + fmul.d %s5,%s3,%s2 + cvt.l.d.rz %s4,%s5 + lea.sl %s2,0x43f00000 # (double)2^64 + cvt.d.l %s5,%s4 + fmul.d %s5,%s5,%s2 + fsub.d %s3,%s3,%s5 + addu.l %s0,%s0,%s4 + addu.l %s5,-1,%s0 + cmov.l.lt %s0,%s5,%s3 +# + lea.sl %s2,0x3df00000 # (double)2^-32 + fmul.d %s5,%s3,%s2 + cvt.l.d.rz %s4,%s5 + lea.sl %s2,0x41f00000 # (double)2^32 + cvt.d.l %s5,%s4 + fmul.d %s5,%s5,%s2 + fsub.d %s3,%s3,%s5 + sll %s1,%s4,32 +# + cvt.l.d.rz %s4,%s3 + addu.l %s1,%s1,%s4 + RETURN + .endm + +#ifdef L_fixsfti +FUNC_START fixsfti +FUNC_ENTRY fixsfti + cvt.d.s %s0,%s0 + and %s5,%s0,(1)0 + lea.sl %s2,0x47e00000 # (double)2^127 + brlt.d %s5,%s2,.L20 + or %s0,0,(1)1 + or %s1,0,(0)1 + RETURN +.L20: + FIX2TI_CORE +#endif + +#ifdef L_fixdfti +FUNC_START fixdfti +FUNC_ENTRY fixdfti + and %s5,%s0,(1)0 + lea.sl %s2,0x47e00000 # (double)2^127 + brlt.d %s5,%s2,.L20 + or %s0,0,(1)1 + or %s1,0,(0)1 + RETURN +.L20: + FIX2TI_CORE +#endif + +#ifdef L_fixunssfti +FUNC_START fixunssfti +FUNC_ENTRY fixunssfti + cvt.d.s %s0,%s0 + lea.sl %s2,0x37f00000 # (double)2^-128 + fmul.d %s5,%s0,%s2 + cvt.l.d.rz %s4,%s5 + lea.sl %s2,0x47f00000 # (double)2^128 + cvt.d.l %s5,%s4 + fmul.d %s5,%s5,%s2 + fsub.d %s0,%s0,%s5 + FIX2TI_CORE +#endif + +#ifdef L_fixunsdfti +FUNC_START fixunsdfti +FUNC_ENTRY fixunsdfti + lea.sl %s2,0x37f00000 # (double)2^-128 + fmul.d %s5,%s0,%s2 + cvt.l.d.rz %s4,%s5 + lea.sl %s2,0x47f00000 # (double)2^128 + cvt.d.l %s5,%s4 + fmul.d %s5,%s5,%s2 + fsub.d %s0,%s0,%s5 + FIX2TI_CORE +#endif +# + .macro FIXTFTI_CORE +# register %s0:xu,u %s1:xl,l %s2:x2u %s3:x2l, %4:tmpu, %s5:tmpl, %s6:tu, %s7:tl +# %s45:k + lea.sl %s6,0x3f9f0000 # (long double)2^-96 + or %s7,0,(0)1 + fmul.q %s4,%s0,%s6 + and %s5,%s5,(4)1 # cut >52 bit to avoid rounding + cvt.d.q %s4,%s4 + cvt.l.d.rz %s45,%s4 + cvt.d.l %s4,%s45 + cvt.q.d %s4,%s4 + lea.sl %s6,0x405f0000 # (long double)2^96 + or %s7,0,(0)1 + fmul.q %s4,%s4,%s6 + fsub.q %s2,%s0,%s4 + sll %s0,%s45,32 +# + lea.sl %s6,0x3fbf0000 # (long double)2^-64 + or %s7,0,(0)1 + fmul.q %s4,%s2,%s6 + and %s5,%s5,(4)1 # cut >52 bit to avoid rounding + cvt.d.q %s4,%s4 + cvt.l.d.rz %s45,%s4 + cvt.d.l %s4,%s45 + cvt.q.d %s4,%s4 + lea.sl %s6,0x403f0000 # (long double)2^64 + or %s7,0,(0)1 + fmul.q %s4,%s4,%s6 + fsub.q %s2,%s2,%s4 + addu.l %s0,%s0,%s45 + addu.l %s4,-1,%s0 + cmov.l.lt %s0,%s4,%s2 +# + lea.sl %s6,0x3fdf0000 # (long double)2^-32 + or %s7,0,(0)1 + fmul.q %s4,%s2,%s6 + and %s5,%s5,(4)1 # cut >52 bit to avoid rounding + cvt.d.q %s4,%s4 + cvt.l.d.rz %s45,%s4 + cvt.d.l %s4,%s45 + cvt.q.d %s4,%s4 + lea.sl %s6,0x401f0000 # (long double)2^32 + or %s7,0,(0)1 + fmul.q %s4,%s4,%s6 + fsub.q %s2,%s2,%s4 + sll %s1,%s45,32 +# + and %s3,%s3,(4)1 # cut >52 bit to avoid rounding + cvt.d.q %s4,%s2 + cvt.l.d.rz %s45,%s4 + addu.l %s1,%s1,%s45 + RETURN + .endm + +#ifdef L_fixtfti +FUNC_START fixtfti +FUNC_ENTRY fixtfti +# register %s0:xu,u %s1:xl,l %s2:x2u %s3:x2l, %4:tmpu, %s5:tmpl, %s6:tu, %s7:tl +# %s45:k + and %s4,%s0,(1)0 + lea.sl %s6,0x407e0000 # (long double)2^127 + brlt.l %s4,%s6,.L22 + or %s0,0,(1)1 + or %s1,0,(0)1 + RETURN +.L22: + FIXTFTI_CORE +#endif + +#ifdef L_fixunstfti +FUNC_START fixunstfti +FUNC_ENTRY fixunstfti + lea.sl %s6,0x3f7f0000 # (long double)2^-128 + or %s7,0,(0)1 + fmul.q %s4,%s0,%s6 + and %s5,%s5,(4)1 # cut >52 bit to avoid rounding + cvt.d.q %s4,%s4 + cvt.l.d.rz %s45,%s4 + cvt.d.l %s4,%s45 + cvt.q.d %s4,%s4 + lea.sl %s6,0x407f0000 # (long double)2^128 + or %s7,0,(0)1 + fmul.q %s4,%s4,%s6 + fsub.q %s0,%s0,%s4 + FIXTFTI_CORE +#endif + +# +#__int128 mul(__int128 x, __int128 y) { +# __int128 z; +# unsigned long xu,xl,yu,yl,zu,zl; +# unsigned long xl1,xl2,yl1,yl2; +# unsigned long t; +# +# unsigned long max = 0xffffffffffffffff; +# unsigned long tt; +# xu = x >> 64; +# xl = x & 0xffffffffffffffff; +# yu = y >> 64; +# yl = y & 0xffffffffffffffff; +# zu = xu * yl; +# t = xl * yu; +# zu = zu + t; +# +# xl1 = xl >> 32; +# xl2 = xl & 0xffffffff; +# yl1 = yl >> 32; +# yl2 = yl & 0xffffffff; +# +# t = xl1 * yl1; +# zu = zu + t; +# +# t = xl2 * yl2; +# zl = t; +# +# t = xl1 * yl2; +# zu = zu + (t >> 32); +# t = t << 32; +# tt = max - t; +# .if (tt < zl) zu++; +# zl = zl + t; +# +# t = xl2 * yl1; +# zu = zu + (t >> 32); +# t = t << 32; +# tt = max - t; +# .if (tt < zl) zu++; +# zl = zl + t ; +# +# z = zu; +# z = z << 64; +# z = z + zl; +# return z; +#} +#register %s0:xu,zu %s1:xl,zl %s2:yu,yl1 %s3:yl,yl2 +# %s4:xl1,tmp %s5:xl2 %s6:t %s7:tt + +#ifdef L_multi3 +FUNC_START multi3 +FUNC_ENTRY multi3 + mulu.l %s0,%s0,%s3 + mulu.l %s4,%s1,%s2 + addu.l %s0,%s0,%s4 +# + srl %s4,%s1,32 + and %s5,%s1,(32)0 + srl %s2,%s3,32 + and %s3,%s3,(32)0 +# + mulu.l %s6,%s4,%s2 + addu.l %s0,%s0,%s6 + mulu.l %s1,%s5,%s3 +# + mulu.l %s6,%s4,%s3 + srl %s4,%s6,32 + addu.l %s0,%s0,%s4 + sll %s6,%s6,32 + subu.l %s7,-1,%s6 + cmpu.l %s7,%s7,%s1 + addu.l %s4,1,%s0 + cmov.l.lt %s0,%s4,%s7 + addu.l %s1,%s1,%s6 +# + mulu.l %s6,%s5,%s2 + srl %s4,%s6,32 + addu.l %s0,%s0,%s4 + sll %s6,%s6,32 + subu.l %s7,-1,%s6 + cmpu.l %s7,%s7,%s1 + addu.l %s4,1,%s0 + cmov.l.lt %s0,%s4,%s7 + addu.l %s1,%s1,%s6 + RETURN +#endif + +#__int128 div3(__int128 x, __int128 y, int uns) { +# __int128 z; /* z(return) = x / y */ +# unsigned long xu,xl,yu,yl,zh,zu,zl,z0; +# unsigned long y1,y2,y3,y4,yy; +# unsigned long tu,tl,t; +# unsigned long sign; +# unsigned long maxint; +# int shift=128; +# int k,i; +# +# maxint = 0xffffffffffffffff; +# +# xu = x >> 64; +# xl = x & 0xffffffffffffffff; +# yu = y >> 64; +# yl = y & 0xffffffffffffffff; +# +# .if (uns) { +# sign = 0; +# } else { +# sign = xu ^ yu; +#/*abs x*/ +# .if (((signed long)xu) < 0) { +# xu = xu ^ 0xffffffffffffffff; +# xl = -(signed long)xl; +# .if (xl == 0) xu++; +# } +#/*abs y*/ +# .if (((signed long)yu) < 0) { +# yu = yu ^ 0xffffffffffffffff; +# yl = -(signed long)yl; +# .if (yl == 0) yu++; +# } +# } +# +# .if (yu == 0 && yl == 0) { +# xu / yu; /* generate zero-div exception */ +# return 0; +# } +# +# .if ((yu > xu) || ((yu == xu ) && (yl > xl))) { +# z = 0; +# return z; +# } +# +#/* normalize y */ +# .if (yu == 0) { +# shift -= 64; +# yu = yl; yl = 0; +# } +# k = __builtin_clzl(yu); +# .if (k != 0) { +# yu = yu << k; +# t = yl >> (64 -k); +# yu = yu | t; +# yl = yl << k; +# shift -= k; +# } +# +#/* normalize x */ +# .if (xu == 0) { +# shift += 64; +# xu = xl; xl = 0; +# } +# k = __builtin_clzl(xu); +# .if (k != 0) { +# xu = xu << k; +# t = xl >> (64 -k); +# xu = xu | t; +# xl = xl << k; +# shift += k; +# } +#/* break y into (32bit) y1,y2,y3,y4 */ +# y1 = yu >> 32; +# y2 = yu & 0xffffffff; +# y3 = yl >> 32; +# y4 = yl & 0xffffffff; +# yy = y2 << 32 | y3; +# +# zh = 0; +# zu = 0; +# zl = 0; +# +#/* if x >= y then { x = x -y; zh = 1;} */ +# .if ((xu > yu) || ((xu == yu) && (xl >= yl))) { +# .if (xl < yl) xu --; +# xu = xu - yu; +# xl = xl - yl; +# zl = 1; +# } +# +# for (i=shift/32; i < 4; i++) { +# z0 = xu / y1; +# +# tu = z0 * y1; +# +# t = z0 * y2; +# tl = t << 32; +# t = t >> 32; +# tu = tu + t; +# +# t = z0 * y3; +# .if ((maxint - t) < tl) tu++; +# tl = tl + t; +# +# t = (z0 * y4) >> 32; +# .if ((maxint - t) < tl) tu++; +# tl = tl + t; +# +# while ((tu > xu) || ((tu == xu) && (tl > xl))) { +# /* t = t - (y >>32) */ +# .if (tl < yy) tu--; +# tu = tu - y1; +# tl = tl - yy; +# z0--; +# } +# /* x = x - t */ +# +# .if (xl < tl) xu--; +# xu = xu - tu; +# xl = xl - tl; +# +#/* shift x = x << 32; z = z << 32 */ +# xu = xu << 32; +# t = xl >> 32; +# xu = xu | t; +# xl = xl << 32; +# +# zh = zh <<32; +# t = zu >> 32; +# zh = zh | t; +# zu = zu << 32; +# t = zl >> 32; +# zu = zu | t; +# zl = zl <<32; +# zl = zl | z0; +# } +# +# shift = shift % 32; +# .if (shift > 0) { +# zl = zl >> shift; +# t = zu << (64 - shift); +# zl = zl | t; +# zu = zu >> shift; +# t = zh << (64 - shift); +# zu = zu | t; +# zh = zh >> shift; +# } +# +#/* set sign */ +# .if ((signed long)sign < 0) { +# zu = zu ^ 0xffffffffffffffff; +# zl = -(signed long)zl; +# .if (zl == 0) zu++; +# } +# z = zu; +# z = z << 64; +# z = z | zl; +# return z; +#} +# +# registers +# %s0:xu, %s1:xl, %s2:yu, %s3:yl, %s4:zh, %s5:zu, %s6:zl, %s7:z0 +# %s45:y1, %s46:y2, %s47:y3, %s48:y4, %s49:yy, %s50:tu, %s51:tl, %s52:t +# %s53:sign, %s54:shift, %s55:k/i, %s56:temp, %57:temp2 + .macro DIVTI3_CORE + brne.l %s2,0,.L103 # if (y == 0) + brne.l %s3,0,.L103 + divs.l %s56,%s0,%s2 # gen zero-div exception +.L102: + or %s0,0,(0)1 + or %s1,0,(0)1 + RETURN +.L103: + cmpu.l %s56,%s2,%s0 # if (y >x) return 0; + brgt.l %s56,0,.L102 + brne.l %s56,0,.L104 + cmpu.l %s56,%s3,%s1 + brgt.l %s56,0,.L102 +.L104: + adds.l %s54,1,(57)0 # shift = 128; + brne.l %s2,0,.L105 # if (yu == 0) y <<= 64; shift -=64; + adds.l %s54,%s54,(58)1 + or %s2,0,%s3 + or %s3,0,(0)1 +.L105: + ldz %s55,%s2 # y <<= (k = ldz(y)); + sld %s2,%s3,%s55 + sll %s3,%s3,%s55 + subs.l %s54,%s54,%s55 # shift -= k; + brne.l %s0,0,.L106 # if (xu == 0) x <<=64; shift +=64; + subs.l %s54,%s54,(58)1 + or %s0,0,%s1 + or %s1,0,(0)1 +.L106: + ldz %s55,%s0 # x <<= (k = ldz(x)) + sld %s0,%s1,%s55 + sll %s1,%s1,%s55 + adds.l %s54,%s54,%s55 # shift += k; + srl %s45,%s2,32 # break y into 32bit y1,y2,y3,y4 + and %s46,%s2,(32)0 + srl %s47,%s3,32 + and %s48,%s3,(32)0 + sll %s49,%s46,32 # yy = y2 << 32 | y3; + or %s49,%s49,%s47 +# + or %s4,0,(0)1 # zh = zu = zl = 0; + or %s5,0,(0)1 + or %s6,0,(0)1 + cmpu.l %s56,%s0,%s2 # if (x>=y) x -= y; zh =1; + brgt.l %s56,0,.L107 + brne.l %s56,0,.L108 + cmpu.l %s56,%s1,%s3 + brlt.l %s56,0,.L108 +.L107: + addu.l %s57,-1,%s0 + cmpu.l %s56,%s1,%s3 + cmov.l.lt %s0,%s57,%s56 + subu.l %s0,%s0,%s2 + subu.l %s1,%s1,%s3 + or %s6,1,(0)1 +.L108: + srl %s55,%s54,5 # for(i=shift/32; i<4; i++) { + brle.l 4,%s55,.L113 +.L109: + divu.l %s7,%s0,%s45 # z0 = xu / y1; + mulu.l %s50,%s7,%s45 # tu = z0 * y1; + mulu.l %s52,%s7,%s46 # t = z0 * y2; + sll %s51,%s52,32 # tl = t << 32; + srl %s52,%s52,32 # t = t >> 32; + addu.l %s50,%s50,%s52 # tu = tu + t +# + mulu.l %s52,%s7,%s47 # t = z0 * y3; + subu.l %s56,-1,%s52 # if ((maxint -t) < tl) tu++; + cmpu.l %s56,%s56,%s51 + addu.l %s57,1,%s50 + cmov.l.lt %s50,%s57,%s56 + addu.l %s51,%s51,%s52 # tl = tl + t; +# + mulu.l %s52,%s7,%s48 # t = (z0 * y4) >> 32; + srl %s52,%s52,32 + subu.l %s56,-1,%s52 # if ((maxint -t) < tl) tu++; + cmpu.l %s56,%s56,%s51 + addu.l %s57,1,%s50 + cmov.l.lt %s50,%s57,%s56 + addu.l %s51,%s51,%s52 # tl = tl + t; +.L110: + cmpu.l %s56,%s50,%s0 # while (t > x) { + brgt.l %s56,0,.L111 + brne.l %s56,0,.L112 + cmpu.l %s56,%s51,%s1 + brle.l %s56,0,.L112 +.L111: + cmpu.l %s56,%s51,%s49 # t = t - (y >>32) + addu.l %s57,-1,%s50 # if(tl>= shift; + srd %s5,%s4,%s54 + + or %s0,0,%s5 + or %s1,0,%s6 + brge.l %s53,0,.L114 + xor %s0,%s0,(0)0 + subs.l %s1,0,%s1 + addu.l %s56,1,%s0 + cmov.l.eq %s0,%s56,%s1 +.L114: + RETURN + .endm +# +#ifdef L_divti3 +FUNC_START divti3 +FUNC_ENTRY divti3 + xor %s53,%s0,%s2 # sign = x ^ y; + brge.l %s0,0,.L100 # if (x <0) x = -x; + xor %s0,%s0,(0)0 + subs.l %s1,0,%s1 + addu.l %s56,1,%s0 + cmov.l.eq %s0,%s56,%s1 +.L100: + brge.l %s2,0,.L101 # if (y<0) y = -y; + xor %s2,%s2,(0)0 + subs.l %s3,0,%s3 + addu.l %s56,1,%s2 + cmov.l.eq %s2,%s56,%s3 +.L101: + DIVTI3_CORE +#endif + +#ifdef L_udivti3 +FUNC_START udivti3 +FUNC_ENTRY udivti3 + or %s53,0,(0)1 + DIVTI3_CORE +#endif +# diff --git a/libgcc/config/ve/modti.c b/libgcc/config/ve/modti.c new file mode 100644 index 00000000000..8233f22666c --- /dev/null +++ b/libgcc/config/ve/modti.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2016,2017 Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) + any later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ +/* Changes by NEC Corporation for the VE port, 2017-2021 */ + +typedef unsigned int UTItype __attribute__ ((mode (TI))); +typedef int TItype __attribute__ ((mode (TI))); + +TItype __divti3 (TItype u, TItype v); +UTItype __udivti3 (UTItype u, UTItype v); +TItype __modti3 (TItype u, TItype v); +UTItype __umodti3 (UTItype u, UTItype v); +UTItype __udivmodti4 (UTItype u, UTItype v, UTItype *w); + +TItype __modti3 (TItype u, TItype v) +{ + return u - __divti3(u,v)*v; +} + +UTItype __umodti3 (UTItype u, UTItype v) +{ + return u - __udivti3(u,v)*v; +} + +UTItype __udivmodti4 (UTItype u, UTItype v, UTItype *w) +{ + UTItype x; + x = __udivti3(u,v); + if (w) *w = u - x*v; + return x; +} diff --git a/libgcc/config/ve/t-ve b/libgcc/config/ve/t-ve new file mode 100644 index 00000000000..be0c5d6443c --- /dev/null +++ b/libgcc/config/ve/t-ve @@ -0,0 +1,15 @@ +LIB1ASMSRC = ve/lib1funcs.S + +LIB1ASMFUNCS = _unordsf2 _unorddf2 _unordtf2 \ + _fixdfti _fixsfti _fixtfti \ + _fixunsdfti _fixunssfti _fixunstfti \ + _multi3 _divti3 _udivti3 + +LIB2ADD = $(srcdir)/config/ve/modti.c \ + $(srcdir)/config/ve/divtf3.c \ + $(srcdir)/config/ve/dso_handle.c + +LIB2ADDEH = $(srcdir)/unwind-c.c \ + $(srcdir)/unwind-dw2.c \ + $(srcdir)/unwind-sjlj.c \ + $(srcdir)/config/ve/unwind-ve.c diff --git a/libgcc/config/ve/unwind-ve.c b/libgcc/config/ve/unwind-ve.c new file mode 100644 index 00000000000..e39e21328ab --- /dev/null +++ b/libgcc/config/ve/unwind-ve.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2017-2021 NEC Corporation + + 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "libgcc_tm.h" +#include "unwind.h" +#include "gthr.h" + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exc); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_Resume_or_Rethrow (struct _Unwind_Exception *exc); + +void LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume (struct _Unwind_Exception *exc); + + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_RaiseException(struct _Unwind_Exception *exc) +{ + return _Unwind_SjLj_RaiseException(exc); +} + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument) +{ + return _Unwind_SjLj_ForcedUnwind (exc,stop,stop_argument); +} + +void LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + _Unwind_SjLj_Resume (exc); +} + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) +{ + return _Unwind_SjLj_Resume_or_Rethrow (exc); +} + diff --git a/libgfortran/configure b/libgfortran/configure index 81238fcb79c..be7aed60a39 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -12,6 +12,8 @@ ## M4sh Initialization. ## ## -------------------- ## +# Changes by NEC Corporation for the VE port, 2017-2021 + # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : @@ -16533,6 +16535,17 @@ case "${host}--x${with_newlib}" in hardwire_newlib=1;; esac +case "${host}" in + ve*) + +cat >>confdefs.h <<_ACEOF +#define HAVE_LOCALTIME_R 1 +#define HAVE_GMTIME_R 1 +_ACEOF + +esac + + # Check for library functions. if test "${hardwire_newlib:-0}" -eq 1; then # We are being configured with a cross compiler. AC_REPLACE_FUNCS diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 2406cb9d946..72dfe666ec2 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -12,6 +12,8 @@ ## M4sh Initialization. ## ## -------------------- ## +# Changes by NEC Corporation for the VE port, 2017-2021 + # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : @@ -15013,7 +15015,14 @@ fi # creating position-independent objects. This varies with the target # hardware and operating system, but is often: -DPIC -fPIC. if test "$enable_shared" = yes; then +case ${target} in +ve-*-*) + glibcxx_lt_pic_flag= + ;; +*) glibcxx_lt_pic_flag="-prefer-pic" + ;; +esac glibcxx_compiler_pic_flag="$lt_prog_compiler_pic_CXX" glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED" diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index 8e973503be0..34d9bdda98b 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -116,7 +116,14 @@ fi # creating position-independent objects. This varies with the target # hardware and operating system, but is often: -DPIC -fPIC. if test "$enable_shared" = yes; then +case ${target} in +ve-*-*) + glibcxx_lt_pic_flag= + ;; +*) glibcxx_lt_pic_flag="-prefer-pic" + ;; +esac glibcxx_compiler_pic_flag="$lt_prog_compiler_pic_CXX" glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED"