diff options
Diffstat (limited to 'contrib/gcc/config/s390')
-rw-r--r-- | contrib/gcc/config/s390/2064.md | 131 | ||||
-rw-r--r-- | contrib/gcc/config/s390/2084.md | 262 | ||||
-rw-r--r-- | contrib/gcc/config/s390/fixdfdi.h | 24 | ||||
-rw-r--r-- | contrib/gcc/config/s390/linux.h | 73 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390-modes.def | 60 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390-protos.h | 161 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390.c | 3889 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390.h | 457 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390.md | 5624 | ||||
-rw-r--r-- | contrib/gcc/config/s390/s390x.h | 25 | ||||
-rw-r--r-- | contrib/gcc/config/s390/t-tpf | 13 | ||||
-rw-r--r-- | contrib/gcc/config/s390/tpf.h | 112 |
12 files changed, 6052 insertions, 4779 deletions
diff --git a/contrib/gcc/config/s390/2064.md b/contrib/gcc/config/s390/2064.md new file mode 100644 index 0000000..143cd1b --- /dev/null +++ b/contrib/gcc/config/s390/2064.md @@ -0,0 +1,131 @@ +;; Scheduling description for z900 (cpu 2064). +;; Copyright (C) 2003 Free Software Foundation, Inc. +;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and +;; Ulrich Weigand (uweigand@de.ibm.com). + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to the Free +;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;; +;; References: +;; The microarchitecture of the IBM eServer z900 processor. +;; E.M. Schwarz et al. +;; IBM Journal of Research and Development Vol. 46 No 4/5, 2002. +;; +;; z900 (cpu 2064) pipeline +;; +;; dec +;; --> | <--- +;; LA bypass | agen | +;; | | | +;; --- c1 | Load bypass +;; | | +;; c2---- +;; | +;; e1 +;; | +;; wr + +(define_automaton "z_ipu") +(define_cpu_unit "z_e1" "z_ipu") +(define_cpu_unit "z_wr" "z_ipu") + + +(define_insn_reservation "z_la" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "la")) + "z_e1,z_wr") + +(define_insn_reservation "z_larl" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "larl")) + "z_e1,z_wr") + +(define_insn_reservation "z_load" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "load")) + "z_e1,z_wr") + +(define_insn_reservation "z_store" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "store")) + "z_e1,z_wr") + +(define_insn_reservation "z_call" 5 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "jsr")) + "z_e1*5,z_wr") + +(define_insn_reservation "z_o2" 2 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "o2")) + "z_e1*2,z_wr") + +(define_insn_reservation "z_o3" 3 + (and (eq_attr "cpu" "z900") + (eq_attr "type" "o3")) + "z_e1*3,z_wr") + +; +; Insn still not mentioned are check for +; the usage of the agen unit +; + +(define_insn_reservation "z_int" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "atype" "reg")) + "z_e1,z_wr") + +(define_insn_reservation "z_agen" 1 + (and (eq_attr "cpu" "z900") + (eq_attr "atype" "agen")) + "z_e1,z_wr") + + +;; +;; s390_agen_dep_p returns 1, if a register is set in the +;; first insn and used in the dependent insn to form a address. +;; + +;; +;; If an instruction uses a register to address memory, it needs +;; to be set 5 cycles in advance. +;; + +(define_bypass 5 "z_int,z_agen" + "z_agen,z_la,z_call,z_load,z_store" "s390_agen_dep_p") + +;; +;; A load type instruction uses a bypass to feed the result back +;; to the address generation pipeline stage. +;; + +(define_bypass 3 "z_load" + "z_agen,z_la,z_call,z_load,z_store" "s390_agen_dep_p") + +;; +;; A load address type instruction uses a bypass to feed the +;; result back to the address generation pipeline stage. +;; + +(define_bypass 2 "z_larl,z_la" + "z_agen,z_la,z_call,z_load,z_store" "s390_agen_dep_p") + + + + + diff --git a/contrib/gcc/config/s390/2084.md b/contrib/gcc/config/s390/2084.md new file mode 100644 index 0000000..a74ffbf --- /dev/null +++ b/contrib/gcc/config/s390/2084.md @@ -0,0 +1,262 @@ +;; Scheduling description for z990 (cpu 2084). +;; Copyright (C) 2003 Free Software Foundation, Inc. +;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and +;; Ulrich Weigand (uweigand@de.ibm.com). + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to the Free +;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +(define_automaton "x_ipu") + +(define_cpu_unit "x_e1_r,x_e1_s,x_e1_t" "x_ipu") +(define_cpu_unit "x_wr_r,x_wr_s,x_wr_t,x_wr_fp" "x_ipu") +(define_cpu_unit "x_s1,x_s2,x_s3,x_s4" "x_ipu") +(define_cpu_unit "x_t1,x_t2,x_t3,x_t4" "x_ipu") +(define_cpu_unit "x_f1,x_f2,x_f3,x_f4,x_f5,x_f6" "x_ipu") +(define_cpu_unit "x_store_tok" "x_ipu") +(define_cpu_unit "x_ms,x_mt" "x_ipu") + +(define_reservation "x-e1-st" "(x_e1_s | x_e1_t)") + +(define_reservation "x-e1-np" "(x_e1_r + x_e1_s + x_e1_t)") + +(absence_set "x_e1_r" "x_e1_s,x_e1_t") +(absence_set "x_e1_s" "x_e1_t") + +;; Try to avoid int <-> fp transitions. + +(define_reservation "x-x" "x_s1|x_t1,x_s2|x_t2,x_s3|x_t3,x_s4|x_t4") +(define_reservation "x-f" "x_f1,x_f2,x_f3,x_f4,x_f5,x_f6") +(define_reservation "x-wr-st" "((x_wr_s | x_wr_t),x-x)") +(define_reservation "x-wr-np" "((x_wr_r + x_wr_s + x_wr_t),x-x)") +(define_reservation "x-wr-fp" "x_wr_fp,x-f") +(define_reservation "x-mem" "x_ms|x_mt") + +(absence_set "x_wr_fp" + "x_s1,x_s2,x_s3,x_s4,x_t1,x_t2,x_t3,x_t4,x_wr_s,x_wr_t") + +(absence_set "x_e1_r,x_wr_r,x_wr_s,x_wr_t" + "x_f1,x_f2,x_f3,x_f4,x_f5,x_f6,x_wr_fp") + +;; Don't have any load type insn in same group as store + +(absence_set "x_ms,x_mt" "x_store_tok") + + +;; +;; Simple insns +;; + +(define_insn_reservation "x_lr" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "lr")) + "x-e1-st,x-wr-st") + +(define_insn_reservation "x_la" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "la")) + "x-e1-st,x-wr-st") + +(define_insn_reservation "x_larl" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "larl")) + "x-e1-st,x-wr-st") + +(define_insn_reservation "x_load" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "load")) + "x-e1-st+x-mem,x-wr-st") + +(define_insn_reservation "x_store" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "store")) + "x-e1-st+x_store_tok,x-wr-st") + +(define_insn_reservation "x_branch" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "branch")) + "x_e1_r,x_wr_r") + +(define_insn_reservation "x_call" 5 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "jsr")) + "x-e1-np*5,x-wr-np") + +;; +;; Multicycle insns +;; + +(define_insn_reservation "x_ss" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "op_type" "SS")) + "x-e1-np,x-wr-np") + +(define_insn_reservation "x_stm" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "stm")) + "(x-e1-np+x_store_tok)*10,x-wr-np") + +(define_insn_reservation "x_lm" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "lm")) + "x-e1-np*10,x-wr-np") + +(define_insn_reservation "x_nn" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "op_type" "NN")) + "x-e1-np,x-wr-np") + +(define_insn_reservation "x_o2" 2 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "o2")) + "x-e1-np*2,x-wr-np") + +(define_insn_reservation "x_o3" 3 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "o3")) + "x-e1-np*3,x-wr-np") + +;; +;; Floating point insns +;; + +(define_insn_reservation "x_fsimpd" 6 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fsimpd,fmuld")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_fsimps" 6 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fsimps,fmuls")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_fdivd" 36 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fdivd")) + "x_e1_t*30,x-wr-fp") + +(define_insn_reservation "x_fdivs" 36 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fdivs")) + "x_e1_t*30,x-wr-fp") + +(define_insn_reservation "x_floadd" 6 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "floadd")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_floads" 6 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "floads")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_fstored" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fstored")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_fstores" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "fstores")) + "x_e1_t,x-wr-fp") + +(define_insn_reservation "x_ftoi" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "ftoi")) + "x_e1_t*3,x-wr-fp") + +(define_insn_reservation "x_itof" 7 + (and (eq_attr "cpu" "z990") + (eq_attr "type" "itof")) + "x_e1_t*3,x-wr-fp") + +(define_bypass 1 "x_fsimpd" "x_fstored") + +(define_bypass 1 "x_fsimps" "x_fstores") + +(define_bypass 1 "x_floadd" "x_fsimpd,x_fstored,x_floadd") + +(define_bypass 1 "x_floads" "x_fsimps,x_fstores,x_floads") + +;; +;; Insns still not mentioned are checked for +;; the usage of the agen unit +;; + +(define_insn_reservation "x_int" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "atype" "reg")) + "x-e1-st,x-wr-st") + +(define_insn_reservation "x_agen" 1 + (and (eq_attr "cpu" "z990") + (eq_attr "atype" "agen")) + "x-e1-st+x-mem,x-wr-st") + +;; +;; s390_agen_dep_p returns 1, if a register is set in the +;; first insn and used in the dependent insn to form a address. +;; + +;; +;; If an instruction uses a register to address memory, it needs +;; to be set 5 cycles in advance. +;; + +(define_bypass 5 "x_int,x_agen,x_lr" + "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm" + "s390_agen_dep_p") + +(define_bypass 9 "x_int,x_agen,x_lr" + "x_floadd, x_floads, x_fstored, x_fstores,\ + x_fsimpd, x_fsimps, x_fdivd, x_fdivs" + "s390_agen_dep_p") +;; +;; A load type instruction uses a bypass to feed the result back +;; to the address generation pipeline stage. +;; + +(define_bypass 4 "x_load" + "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm" + "s390_agen_dep_p") + +(define_bypass 5 "x_load" + "x_floadd, x_floads, x_fstored, x_fstores,\ + x_fsimpd, x_fsimps, x_fdivd, x_fdivs" + "s390_agen_dep_p") + +;; +;; A load address type instruction uses a bypass to feed the +;; result back to the address generation pipeline stage. +;; + +(define_bypass 3 "x_larl,x_la" + "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm" + "s390_agen_dep_p") + +(define_bypass 5 "x_larl, x_la" + "x_floadd, x_floads, x_fstored, x_fstores,\ + x_fsimpd, x_fsimps, x_fdivd, x_fdivs" + "s390_agen_dep_p") + +;; +;; Operand forwarding +;; + +(define_bypass 0 "x_lr,x_la,x_load" "x_int,x_lr") + + diff --git a/contrib/gcc/config/s390/fixdfdi.h b/contrib/gcc/config/s390/fixdfdi.h index 1f82a9c..a5b9212 100644 --- a/contrib/gcc/config/s390/fixdfdi.h +++ b/contrib/gcc/config/s390/fixdfdi.h @@ -3,22 +3,22 @@ Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +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. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifdef L_fixunsdfdi #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) diff --git a/contrib/gcc/config/s390/linux.h b/contrib/gcc/config/s390/linux.h index cbb7710..9a6db9d 100644 --- a/contrib/gcc/config/s390/linux.h +++ b/contrib/gcc/config/s390/linux.h @@ -3,22 +3,22 @@ Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +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. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef _LINUX_H #define _LINUX_H @@ -53,12 +53,7 @@ Boston, MA 02111-1307, USA. */ #define TARGET_OS_CPP_BUILTINS() \ do \ { \ - builtin_define_std ("linux"); \ - builtin_define_std ("unix"); \ - builtin_assert ("system=linux"); \ - builtin_assert ("system=unix"); \ - builtin_define ("__ELF__"); \ - builtin_define ("__gnu_linux__"); \ + LINUX_TARGET_OS_CPP_BUILTINS(); \ if (flag_pic) \ { \ builtin_define ("__PIC__"); \ @@ -70,13 +65,8 @@ Boston, MA 02111-1307, USA. */ /* Target specific assembler settings. */ -#ifdef DEFAULT_TARGET_64BIT -#undef ASM_SPEC -#define ASM_SPEC "%{m31:-m31 -Aesa}" -#else #undef ASM_SPEC -#define ASM_SPEC "%{m64:-m64 -Aesame}" -#endif +#define ASM_SPEC "%{m31&m64}%{mesa&mzarch}%{march=*}" /* Target specific linker settings. */ @@ -87,41 +77,20 @@ Boston, MA 02111-1307, USA. */ #define MULTILIB_DEFAULTS { "m31" } #endif -#define LINK_ARCH31_SPEC \ - "-m elf_s390 \ - %{shared:-shared} \ - %{!shared: \ - %{static:-static} \ - %{!static: \ - %{rdynamic:-export-dynamic} \ - %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}}}" - -#define LINK_ARCH64_SPEC \ - "-m elf64_s390 \ +#undef LINK_SPEC +#define LINK_SPEC \ + "%{m31:-m elf_s390}%{m64:-m elf64_s390} \ %{shared:-shared} \ %{!shared: \ %{static:-static} \ %{!static: \ %{rdynamic:-export-dynamic} \ - %{!dynamic-linker:-dynamic-linker /lib/ld64.so.1}}}" - -#ifdef DEFAULT_TARGET_64BIT -#undef LINK_SPEC -#define LINK_SPEC "%{m31:%(link_arch31)} %{!m31:%(link_arch64)}" -#else -#undef LINK_SPEC -#define LINK_SPEC "%{m64:%(link_arch64)} %{!m64:%(link_arch31)}" -#endif - - -/* This macro defines names of additional specifications to put in the specs - that can be used in various specifications like CC1_SPEC. Its definition - is an initializer with a subgrouping for each command option. */ + %{!dynamic-linker: \ + %{m31:-dynamic-linker /lib/ld.so.1} \ + %{m64:-dynamic-linker /lib/ld64.so.1}}}}" -#define EXTRA_SPECS \ - { "link_arch31", LINK_ARCH31_SPEC }, \ - { "link_arch64", LINK_ARCH64_SPEC }, \ +#define TARGET_ASM_FILE_END file_end_indicate_exec_stack /* Do code reading to identify a signal frame, and set the frame state data appropriately. See unwind-dw2.c for the structs. */ diff --git a/contrib/gcc/config/s390/s390-modes.def b/contrib/gcc/config/s390/s390-modes.def index 9f9d526..0875955 100644 --- a/contrib/gcc/config/s390/s390-modes.def +++ b/contrib/gcc/config/s390/s390-modes.def @@ -1,38 +1,42 @@ /* Definitions of target machine for GNU compiler, for IBM S/390 - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +This file is part of GCC. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* 256-bit integer mode is needed for STACK_SAVEAREA_MODE. */ +INT_MODE (OI, 32); /* Add any extra modes needed to represent the condition code. */ -CC (CCZ) -CC (CCA) -CC (CCAP) -CC (CCAN) -CC (CCL) -CC (CCL1) -CC (CCL2) -CC (CCU) -CC (CCUR) -CC (CCS) -CC (CCSR) -CC (CCT) -CC (CCT1) -CC (CCT2) -CC (CCT3) +CC_MODE (CCZ); +CC_MODE (CCA); +CC_MODE (CCAP); +CC_MODE (CCAN); +CC_MODE (CCL); +CC_MODE (CCL1); +CC_MODE (CCL2); +CC_MODE (CCU); +CC_MODE (CCUR); +CC_MODE (CCS); +CC_MODE (CCSR); +CC_MODE (CCT); +CC_MODE (CCT1); +CC_MODE (CCT2); +CC_MODE (CCT3); diff --git a/contrib/gcc/config/s390/s390-protos.h b/contrib/gcc/config/s390/s390-protos.h index 1f8b144..90815a8 100644 --- a/contrib/gcc/config/s390/s390-protos.h +++ b/contrib/gcc/config/s390/s390-protos.h @@ -1,96 +1,105 @@ /* Definitions of target machine for GNU compiler, for IBM S/390. - Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +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. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* Declare functions in s390.c. */ -extern void optimization_options PARAMS ((int, int)); -extern void override_options PARAMS ((void)); -extern int s390_arg_frame_offset PARAMS ((void)); -extern void s390_emit_prologue PARAMS ((void)); -extern void s390_emit_epilogue PARAMS ((void)); -extern void s390_function_profiler PARAMS ((FILE *, int)); +extern void optimization_options (int, int); +extern void override_options (void); +extern HOST_WIDE_INT s390_arg_frame_offset (void); +extern void s390_load_got (int); +extern void s390_emit_prologue (void); +extern void s390_emit_epilogue (void); +extern void s390_function_profiler (FILE *, int); #ifdef RTX_CODE -extern int s390_address_cost PARAMS ((rtx)); -extern int q_constraint PARAMS ((rtx)); -extern int const0_operand PARAMS ((rtx, enum machine_mode)); -extern int consttable_operand PARAMS ((rtx, enum machine_mode)); -extern int larl_operand PARAMS ((rtx, enum machine_mode)); -extern int s_operand PARAMS ((rtx, enum machine_mode)); -extern int s_imm_operand PARAMS ((rtx, enum machine_mode)); -extern int bras_sym_operand PARAMS ((rtx, enum machine_mode)); -extern int load_multiple_operation PARAMS ((rtx, enum machine_mode)); -extern int store_multiple_operation PARAMS ((rtx, enum machine_mode)); -extern int s390_single_hi PARAMS ((rtx, enum machine_mode, int)); -extern int s390_extract_hi PARAMS ((rtx, enum machine_mode, int)); -extern int s390_single_qi PARAMS ((rtx, enum machine_mode, int)); -extern int s390_extract_qi PARAMS ((rtx, enum machine_mode, int)); -extern bool s390_split_ok_p PARAMS ((rtx, rtx, enum machine_mode, int)); -extern int tls_symbolic_operand PARAMS ((rtx)); +extern int s390_extra_constraint_str (rtx, int, const char *); +extern int s390_const_ok_for_constraint_p (HOST_WIDE_INT, int, const char *); +extern int const0_operand (rtx, enum machine_mode); +extern int consttable_operand (rtx, enum machine_mode); +extern int larl_operand (rtx, enum machine_mode); +extern int s_operand (rtx, enum machine_mode); +extern int s_imm_operand (rtx, enum machine_mode); +extern int shift_count_operand (rtx, enum machine_mode); +extern int bras_sym_operand (rtx, enum machine_mode); +extern int load_multiple_operation (rtx, enum machine_mode); +extern int store_multiple_operation (rtx, enum machine_mode); +extern int s390_single_part (rtx, enum machine_mode, enum machine_mode, int); +extern unsigned HOST_WIDE_INT s390_extract_part (rtx, enum machine_mode, int); +extern bool s390_split_ok_p (rtx, rtx, enum machine_mode, int); +extern int tls_symbolic_operand (rtx); -extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode)); -extern enum machine_mode s390_tm_ccmode PARAMS ((rtx, rtx, int)); -extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx)); -extern int symbolic_reference_mentioned_p PARAMS ((rtx)); -extern int tls_symbolic_reference_mentioned_p PARAMS ((rtx)); -extern rtx s390_tls_get_offset PARAMS ((void)); -extern int legitimate_la_operand_p PARAMS ((rtx)); -extern int preferred_la_operand_p PARAMS ((rtx)); -extern int legitimate_pic_operand_p PARAMS ((rtx)); -extern int legitimate_constant_p PARAMS ((rtx)); -extern int legitimate_reload_constant_p PARAMS ((rtx)); -extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int)); -extern rtx legitimize_pic_address PARAMS ((rtx, rtx)); -extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode)); -extern enum reg_class s390_preferred_reload_class PARAMS ((rtx, enum reg_class)); -extern enum reg_class s390_secondary_input_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx)); -extern enum reg_class s390_secondary_output_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx)); -extern int s390_plus_operand PARAMS ((rtx, enum machine_mode)); -extern void s390_expand_plus_operand PARAMS ((rtx, rtx, rtx)); -extern void emit_symbolic_move PARAMS ((rtx *)); -extern void s390_load_address PARAMS ((rtx, rtx)); -extern void s390_expand_movstr PARAMS ((rtx, rtx, rtx)); -extern void s390_expand_clrstr PARAMS ((rtx, rtx)); -extern void s390_expand_cmpstr PARAMS ((rtx, rtx, rtx, rtx)); -extern rtx s390_return_addr_rtx PARAMS ((int, rtx)); +extern int s390_match_ccmode (rtx, enum machine_mode); +extern enum machine_mode s390_tm_ccmode (rtx, rtx, int); +extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx); +extern int s390_alc_comparison (rtx op, enum machine_mode mode); +extern int s390_slb_comparison (rtx op, enum machine_mode mode); +extern int symbolic_reference_mentioned_p (rtx); +extern int tls_symbolic_reference_mentioned_p (rtx); +extern rtx s390_tls_get_offset (void); +extern int legitimate_la_operand_p (rtx); +extern int preferred_la_operand_p (rtx); +extern int legitimate_pic_operand_p (rtx); +extern int legitimate_constant_p (rtx); +extern int legitimate_reload_constant_p (rtx); +extern int legitimate_address_p (enum machine_mode, rtx, int); +extern rtx legitimize_pic_address (rtx, rtx); +extern rtx legitimize_address (rtx, rtx, enum machine_mode); +extern enum reg_class s390_preferred_reload_class (rtx, enum reg_class); +extern enum reg_class s390_secondary_input_reload_class (enum reg_class, + enum machine_mode, + rtx); +extern enum reg_class s390_secondary_output_reload_class (enum reg_class, + enum machine_mode, + rtx); +extern int s390_plus_operand (rtx, enum machine_mode); +extern void s390_expand_plus_operand (rtx, rtx, rtx); +extern void emit_symbolic_move (rtx *); +extern void s390_load_address (rtx, rtx); +extern void s390_expand_movstr (rtx, rtx, rtx); +extern void s390_expand_clrstr (rtx, rtx); +extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx); +extern rtx s390_return_addr_rtx (int, rtx); + +extern void s390_output_symbolic_const (FILE *, rtx); +extern void print_operand_address (FILE *, rtx); +extern void print_operand (FILE *, rtx, int); +extern void s390_output_constant_pool (rtx, rtx); +extern void s390_output_pool_entry (FILE *, rtx, enum machine_mode, + unsigned int); +extern void s390_trampoline_template (FILE *); +extern void s390_initialize_trampoline (rtx, rtx, rtx); +extern rtx s390_gen_rtx_const_DI (int, int); +extern void s390_output_dwarf_dtprel (FILE*, int, rtx); +extern int s390_agen_dep_p (rtx, rtx); -extern void s390_output_symbolic_const PARAMS ((FILE *, rtx)); -extern void print_operand_address PARAMS ((FILE *, rtx)); -extern void print_operand PARAMS ((FILE *, rtx, int)); -extern void s390_output_constant_pool PARAMS ((rtx, rtx)); -extern void s390_trampoline_template PARAMS ((FILE *)); -extern void s390_initialize_trampoline PARAMS ((rtx, rtx, rtx)); -extern rtx s390_gen_rtx_const_DI PARAMS ((int, int)); -extern rtx s390_simplify_dwarf_addr PARAMS ((rtx)); -extern void s390_machine_dependent_reorg PARAMS ((rtx)); #endif /* RTX_CODE */ #ifdef TREE_CODE -extern int s390_function_arg_pass_by_reference PARAMS ((enum machine_mode, tree)); -extern void s390_function_arg_advance PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); -extern tree s390_build_va_list PARAMS ((void)); +extern int s390_function_arg_pass_by_reference (enum machine_mode, tree); +extern void s390_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, + tree, int); #ifdef RTX_CODE -extern rtx s390_function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); -extern void s390_va_start PARAMS ((tree, rtx)); -extern rtx s390_va_arg PARAMS ((tree, tree)); +extern rtx s390_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); +extern rtx s390_function_value (tree, enum machine_mode); +extern void s390_va_start (tree, rtx); +extern rtx s390_va_arg (tree, tree); #endif /* RTX_CODE */ #endif /* TREE_CODE */ - diff --git a/contrib/gcc/config/s390/s390.c b/contrib/gcc/config/s390/s390.c index d6fda65..ced0bf9 100644 --- a/contrib/gcc/config/s390/s390.c +++ b/contrib/gcc/config/s390/s390.c @@ -1,27 +1,30 @@ /* Subroutines used for code generation on IBM S/390 and zSeries - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +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. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "tree.h" #include "tm_p.h" @@ -48,19 +51,34 @@ Boston, MA 02111-1307, USA. */ #include "langhooks.h" #include "optabs.h" -static bool s390_assemble_integer PARAMS ((rtx, unsigned int, int)); -static int s390_adjust_cost PARAMS ((rtx, rtx, rtx, int)); -static int s390_adjust_priority PARAMS ((rtx, int)); -static void s390_select_rtx_section PARAMS ((enum machine_mode, rtx, - unsigned HOST_WIDE_INT)); -static void s390_encode_section_info PARAMS ((tree, int)); -static const char *s390_strip_name_encoding PARAMS ((const char *)); -static bool s390_cannot_force_const_mem PARAMS ((rtx)); -static void s390_init_builtins PARAMS ((void)); -static rtx s390_expand_builtin PARAMS ((tree, rtx, rtx, - enum machine_mode, int)); -static void s390_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, - HOST_WIDE_INT, tree)); +/* Machine-specific symbol_ref flags. */ +#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0) + + +static bool s390_assemble_integer (rtx, unsigned int, int); +static void s390_select_rtx_section (enum machine_mode, rtx, + unsigned HOST_WIDE_INT); +static void s390_encode_section_info (tree, rtx, int); +static bool s390_cannot_force_const_mem (rtx); +static rtx s390_delegitimize_address (rtx); +static bool s390_return_in_memory (tree, tree); +static void s390_init_builtins (void); +static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, + HOST_WIDE_INT, tree); +static enum attr_type s390_safe_attr_type (rtx); + +static int s390_adjust_cost (rtx, rtx, rtx, int); +static int s390_adjust_priority (rtx, int); +static int s390_issue_rate (void); +static int s390_use_dfa_pipeline_interface (void); +static int s390_first_cycle_multipass_dfa_lookahead (void); +static int s390_sched_reorder2 (FILE *, int, rtx *, int *, int); +static bool s390_rtx_costs (rtx, int, int, int *); +static int s390_address_cost (rtx); +static void s390_reorg (void); +static bool s390_valid_pointer_mode (enum machine_mode); +static tree s390_build_builtin_va_list (void); #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" @@ -78,16 +96,8 @@ static void s390_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, #undef TARGET_ASM_SELECT_RTX_SECTION #define TARGET_ASM_SELECT_RTX_SECTION s390_select_rtx_section -#undef TARGET_SCHED_ADJUST_COST -#define TARGET_SCHED_ADJUST_COST s390_adjust_cost - -#undef TARGET_SCHED_ADJUST_PRIORITY -#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority - #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO s390_encode_section_info -#undef TARGET_STRIP_NAME_ENCODING -#define TARGET_STRIP_NAME_ENCODING s390_strip_name_encoding #ifdef HAVE_AS_TLS #undef TARGET_HAVE_TLS @@ -96,6 +106,12 @@ static void s390_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM s390_cannot_force_const_mem +#undef TARGET_DELEGITIMIZE_ADDRESS +#define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY s390_return_in_memory + #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS s390_init_builtins #undef TARGET_EXPAND_BUILTIN @@ -106,6 +122,33 @@ static void s390_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true +#undef TARGET_SCHED_ADJUST_COST +#define TARGET_SCHED_ADJUST_COST s390_adjust_cost +#undef TARGET_SCHED_ADJUST_PRIORITY +#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority +#undef TARGET_SCHED_ISSUE_RATE +#define TARGET_SCHED_ISSUE_RATE s390_issue_rate +#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE +#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE s390_use_dfa_pipeline_interface +#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD +#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead +#undef TARGET_SCHED_REORDER2 +#define TARGET_SCHED_REORDER2 s390_sched_reorder2 + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS s390_rtx_costs +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST s390_address_cost + +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG s390_reorg + +#undef TARGET_VALID_POINTER_MODE +#define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode + +#undef TARGET_BUILD_BUILTIN_VA_LIST +#define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list + struct gcc_target targetm = TARGET_INITIALIZER; extern int reload_completed; @@ -117,9 +160,6 @@ static int s390_sr_alias_set = 0; emitted. */ rtx s390_compare_op0, s390_compare_op1; -/* The encoding characters for the four TLS models present in ELF. */ -static char const tls_model_chars[] = " GLil"; - /* Structure used to hold the components of a S/390 memory address. A legitimate address on S/390 is of the general form @@ -137,16 +177,27 @@ struct s390_address int pointer; }; +/* Which cpu are we tuning for. */ +enum processor_type s390_tune; +enum processor_flags s390_tune_flags; +/* Which instruction set architecture to use. */ +enum processor_type s390_arch; +enum processor_flags s390_arch_flags; + +/* Strings to hold which cpu and instruction set architecture to use. */ +const char *s390_tune_string; /* for -mtune=<xxx> */ +const char *s390_arch_string; /* for -march=<xxx> */ + /* Define the structure for the machine field in struct function. */ struct machine_function GTY(()) { - /* Label of start of initial literal pool. */ - rtx literal_pool_label; - /* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */ int save_fprs_p; + /* Set if return address needs to be saved. */ + bool save_return_addr_p; + /* Number of first and last gpr to be saved, restored. */ int first_save_gpr; int first_restore_gpr; @@ -159,43 +210,47 @@ struct machine_function GTY(()) const char *some_ld_name; }; -static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode)); -static int s390_branch_condition_mask PARAMS ((rtx)); -static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int)); -static int check_mode PARAMS ((rtx, enum machine_mode *)); -static int general_s_operand PARAMS ((rtx, enum machine_mode, int)); -static int s390_decompose_address PARAMS ((rtx, struct s390_address *)); -static rtx get_thread_pointer PARAMS ((void)); -static rtx legitimize_tls_address PARAMS ((rtx, rtx)); -static const char *get_some_local_dynamic_name PARAMS ((void)); -static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *)); -static int reg_used_in_mem_p PARAMS ((int, rtx)); -static int addr_generation_dependency_p PARAMS ((rtx, rtx)); -static int s390_split_branches PARAMS ((rtx, bool *)); -static void find_constant_pool_ref PARAMS ((rtx, rtx *)); -static void replace_constant_pool_ref PARAMS ((rtx *, rtx, rtx)); -static int find_base_register_in_addr PARAMS ((struct s390_address *)); -static bool find_base_register_ref PARAMS ((rtx)); -static void replace_base_register_ref PARAMS ((rtx *, rtx)); -static void s390_optimize_prolog PARAMS ((int)); -static bool s390_fixup_clobbered_return_reg PARAMS ((rtx)); -static int find_unused_clobbered_reg PARAMS ((void)); -static void s390_frame_info PARAMS ((void)); -static rtx save_fpr PARAMS ((rtx, int, int)); -static rtx restore_fpr PARAMS ((rtx, int, int)); -static rtx save_gprs PARAMS ((rtx, int, int, int)); -static rtx restore_gprs PARAMS ((rtx, int, int, int)); -static int s390_function_arg_size PARAMS ((enum machine_mode, tree)); -static struct machine_function * s390_init_machine_status PARAMS ((void)); - +static int s390_match_ccmode_set (rtx, enum machine_mode); +static int s390_branch_condition_mask (rtx); +static const char *s390_branch_condition_mnemonic (rtx, int); +static int check_mode (rtx, enum machine_mode *); +static int general_s_operand (rtx, enum machine_mode, int); +static int s390_short_displacement (rtx); +static int s390_decompose_address (rtx, struct s390_address *); +static rtx get_thread_pointer (void); +static rtx legitimize_tls_address (rtx, rtx); +static void print_shift_count_operand (FILE *, rtx); +static const char *get_some_local_dynamic_name (void); +static int get_some_local_dynamic_name_1 (rtx *, void *); +static int reg_used_in_mem_p (int, rtx); +static int addr_generation_dependency_p (rtx, rtx); +static int s390_split_branches (void); +static void find_constant_pool_ref (rtx, rtx *); +static void replace_constant_pool_ref (rtx *, rtx, rtx); +static rtx find_ltrel_base (rtx); +static void replace_ltrel_base (rtx *, rtx); +static void s390_optimize_prolog (bool); +static int find_unused_clobbered_reg (void); +static void s390_frame_info (void); +static rtx save_fpr (rtx, int, int); +static rtx restore_fpr (rtx, int, int); +static rtx save_gprs (rtx, int, int, int); +static rtx restore_gprs (rtx, int, int, int); +static int s390_function_arg_size (enum machine_mode, tree); +static bool s390_function_arg_float (enum machine_mode, tree); +static struct machine_function * s390_init_machine_status (void); + +/* Check whether integer displacement is in range. */ +#define DISP_IN_RANGE(d) \ + (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \ + : ((d) >= 0 && (d) <= 4095)) + /* Return true if SET either doesn't set the CC register, or else - the source and destination have matching CC modes and that + the source and destination have matching CC modes and that CC mode is at least as constrained as REQ_MODE. */ - + static int -s390_match_ccmode_set (set, req_mode) - rtx set; - enum machine_mode req_mode; +s390_match_ccmode_set (rtx set, enum machine_mode req_mode) { enum machine_mode set_mode; @@ -233,23 +288,21 @@ s390_match_ccmode_set (set, req_mode) if (req_mode != CCAmode) return 0; break; - + default: abort (); } - + return (GET_MODE (SET_SRC (set)) == set_mode); } -/* Return true if every SET in INSN that sets the CC register - has source and destination with matching CC modes and that - CC mode is at least as constrained as REQ_MODE. +/* Return true if every SET in INSN that sets the CC register + has source and destination with matching CC modes and that + CC mode is at least as constrained as REQ_MODE. If REQ_MODE is VOIDmode, always return false. */ - + int -s390_match_ccmode (insn, req_mode) - rtx insn; - enum machine_mode req_mode; +s390_match_ccmode (rtx insn, enum machine_mode req_mode) { int i; @@ -272,18 +325,15 @@ s390_match_ccmode (insn, req_mode) return 1; } -/* If a test-under-mask instruction can be used to implement +/* If a test-under-mask instruction can be used to implement (compare (and ... OP1) OP2), return the CC mode required - to do that. Otherwise, return VOIDmode. + to do that. Otherwise, return VOIDmode. MIXED is true if the instruction can distinguish between CC1 and CC2 for mixed selected bits (TMxx), it is false if the instruction cannot (TM). */ enum machine_mode -s390_tm_ccmode (op1, op2, mixed) - rtx op1; - rtx op2; - int mixed; +s390_tm_ccmode (rtx op1, rtx op2, int mixed) { int bit0, bit1; @@ -311,25 +361,23 @@ s390_tm_ccmode (op1, op2, mixed) return VOIDmode; } -/* Given a comparison code OP (EQ, NE, etc.) and the operands - OP0 and OP1 of a COMPARE, return the mode to be used for the +/* Given a comparison code OP (EQ, NE, etc.) and the operands + OP0 and OP1 of a COMPARE, return the mode to be used for the comparison. */ enum machine_mode -s390_select_ccmode (code, op0, op1) - enum rtx_code code; - rtx op0; - rtx op1; +s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1) { switch (code) { case EQ: case NE: if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K')) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K")) return CCAPmode; - if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS - || GET_CODE (op1) == NEG) + if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS + || GET_CODE (op1) == NEG) + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) return CCLmode; if (GET_CODE (op0) == AND) @@ -345,11 +393,11 @@ s390_select_ccmode (code, op0, op1) } } - if (register_operand (op0, HImode) + if (register_operand (op0, HImode) && GET_CODE (op1) == CONST_INT && (INTVAL (op1) == -1 || INTVAL (op1) == 65535)) return CCT3mode; - if (register_operand (op0, QImode) + if (register_operand (op0, QImode) && GET_CODE (op1) == CONST_INT && (INTVAL (op1) == -1 || INTVAL (op1) == 255)) return CCT3mode; @@ -361,7 +409,7 @@ s390_select_ccmode (code, op0, op1) case GE: case GT: if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op0, 1)), 'K')) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K")) { if (INTVAL (XEXP((op0), 1)) < 0) return CCANmode; @@ -383,7 +431,8 @@ s390_select_ccmode (code, op0, op1) case LTU: case GEU: - if (GET_CODE (op0) == PLUS) + if (GET_CODE (op0) == PLUS + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) return CCL1mode; if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) @@ -393,7 +442,8 @@ s390_select_ccmode (code, op0, op1) case LEU: case GTU: - if (GET_CODE (op0) == MINUS) + if (GET_CODE (op0) == MINUS + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) return CCL2mode; if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) @@ -406,13 +456,96 @@ s390_select_ccmode (code, op0, op1) } } -/* Return branch condition mask to implement a branch +/* Return nonzero if OP is a valid comparison operator + for an ALC condition in mode MODE. */ + +int +s390_alc_comparison (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + if (GET_RTX_CLASS (GET_CODE (op)) != '<') + return 0; + + if (GET_CODE (XEXP (op, 0)) != REG + || REGNO (XEXP (op, 0)) != CC_REGNUM + || XEXP (op, 1) != const0_rtx) + return 0; + + switch (GET_MODE (XEXP (op, 0))) + { + case CCL1mode: + return GET_CODE (op) == LTU; + + case CCL2mode: + return GET_CODE (op) == LEU; + + case CCUmode: + return GET_CODE (op) == GTU; + + case CCURmode: + return GET_CODE (op) == LTU; + + case CCSmode: + return GET_CODE (op) == UNGT; + + case CCSRmode: + return GET_CODE (op) == UNLT; + + default: + return 0; + } +} + +/* Return nonzero if OP is a valid comparison operator + for an SLB condition in mode MODE. */ + +int +s390_slb_comparison (rtx op, enum machine_mode mode) +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + if (GET_RTX_CLASS (GET_CODE (op)) != '<') + return 0; + + if (GET_CODE (XEXP (op, 0)) != REG + || REGNO (XEXP (op, 0)) != CC_REGNUM + || XEXP (op, 1) != const0_rtx) + return 0; + + switch (GET_MODE (XEXP (op, 0))) + { + case CCL1mode: + return GET_CODE (op) == GEU; + + case CCL2mode: + return GET_CODE (op) == GTU; + + case CCUmode: + return GET_CODE (op) == LEU; + + case CCURmode: + return GET_CODE (op) == GEU; + + case CCSmode: + return GET_CODE (op) == LE; + + case CCSRmode: + return GET_CODE (op) == GE; + + default: + return 0; + } +} + +/* Return branch condition mask to implement a branch specified by CODE. */ static int -s390_branch_condition_mask (code) - rtx code; -{ +s390_branch_condition_mask (rtx code) +{ const int CC0 = 1 << 3; const int CC1 = 1 << 2; const int CC2 = 1 << 1; @@ -600,14 +733,12 @@ s390_branch_condition_mask (code) } } -/* If INV is false, return assembler mnemonic string to implement - a branch specified by CODE. If INV is true, return mnemonic +/* If INV is false, return assembler mnemonic string to implement + a branch specified by CODE. If INV is true, return mnemonic for the corresponding inverted branch. */ static const char * -s390_branch_condition_mnemonic (code, inv) - rtx code; - int inv; +s390_branch_condition_mnemonic (rtx code, int inv) { static const char *const mnemonic[16] = { @@ -628,228 +759,82 @@ s390_branch_condition_mnemonic (code, inv) return mnemonic[mask]; } -/* If OP is an integer constant of mode MODE with exactly one - HImode subpart unequal to DEF, return the number of that - subpart. As a special case, all HImode subparts of OP are - equal to DEF, return zero. Otherwise, return -1. */ +/* Return the part of op which has a value different from def. + The size of the part is determined by mode. + Use this function only if you already know that op really + contains such a part. */ -int -s390_single_hi (op, mode, def) - rtx op; - enum machine_mode mode; - int def; +unsigned HOST_WIDE_INT +s390_extract_part (rtx op, enum machine_mode mode, int def) { - if (GET_CODE (op) == CONST_INT) - { - unsigned HOST_WIDE_INT value = 0; - int n_parts = GET_MODE_SIZE (mode) / 2; - int i, part = -1; - - for (i = 0; i < n_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) INTVAL (op); - else - value >>= 16; - - if ((value & 0xffff) != (unsigned)(def & 0xffff)) - { - if (part != -1) - return -1; - else - part = i; - } - } - - return part == -1 ? 0 : (n_parts - 1 - part); - } - - else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode) - { - unsigned HOST_WIDE_INT value = 0; - int n_parts = GET_MODE_SIZE (mode) / 2; - int i, part = -1; - - for (i = 0; i < n_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); - else if (i == HOST_BITS_PER_WIDE_INT / 16) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op); - else - value >>= 16; - - if ((value & 0xffff) != (unsigned)(def & 0xffff)) - { - if (part != -1) - return -1; - else - part = i; - } - } - - return part == -1 ? 0 : (n_parts - 1 - part); - } - - return -1; -} - -/* Extract the HImode part number PART from integer - constant OP of mode MODE. */ - -int -s390_extract_hi (op, mode, part) - rtx op; - enum machine_mode mode; - int part; -{ - int n_parts = GET_MODE_SIZE (mode) / 2; - if (part < 0 || part >= n_parts) - abort(); - else - part = n_parts - 1 - part; - - if (GET_CODE (op) == CONST_INT) - { - unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op); - return ((value >> (16 * part)) & 0xffff); - } - else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode) + unsigned HOST_WIDE_INT value = 0; + int max_parts = HOST_BITS_PER_WIDE_INT / GET_MODE_BITSIZE (mode); + int part_bits = GET_MODE_BITSIZE (mode); + unsigned HOST_WIDE_INT part_mask = (1 << part_bits) - 1; + int i; + + for (i = 0; i < max_parts; i++) { - unsigned HOST_WIDE_INT value; - if (part < HOST_BITS_PER_WIDE_INT / 16) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); + if (i == 0) + value = (unsigned HOST_WIDE_INT) INTVAL (op); else - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op), - part -= HOST_BITS_PER_WIDE_INT / 16; - - return ((value >> (16 * part)) & 0xffff); + value >>= part_bits; + + if ((value & part_mask) != (def & part_mask)) + return value & part_mask; } - + abort (); } /* If OP is an integer constant of mode MODE with exactly one - QImode subpart unequal to DEF, return the number of that - subpart. As a special case, all QImode subparts of OP are - equal to DEF, return zero. Otherwise, return -1. */ + part of mode PART_MODE unequal to DEF, return the number of that + part. Otherwise, return -1. */ int -s390_single_qi (op, mode, def) - rtx op; - enum machine_mode mode; - int def; +s390_single_part (rtx op, + enum machine_mode mode, + enum machine_mode part_mode, + int def) { - if (GET_CODE (op) == CONST_INT) - { - unsigned HOST_WIDE_INT value = 0; - int n_parts = GET_MODE_SIZE (mode); - int i, part = -1; - - for (i = 0; i < n_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) INTVAL (op); - else - value >>= 8; - - if ((value & 0xff) != (unsigned)(def & 0xff)) - { - if (part != -1) - return -1; - else - part = i; - } - } - - return part == -1 ? 0 : (n_parts - 1 - part); - } - - else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode) - { - unsigned HOST_WIDE_INT value = 0; - int n_parts = GET_MODE_SIZE (mode); - int i, part = -1; - - for (i = 0; i < n_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); - else if (i == HOST_BITS_PER_WIDE_INT / 8) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op); - else - value >>= 8; + unsigned HOST_WIDE_INT value = 0; + int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode); + unsigned HOST_WIDE_INT part_mask = (1 << GET_MODE_BITSIZE (part_mode)) - 1; + int i, part = -1; - if ((value & 0xff) != (unsigned)(def & 0xff)) - { - if (part != -1) - return -1; - else - part = i; - } - } - - return part == -1 ? 0 : (n_parts - 1 - part); - } - - return -1; -} - -/* Extract the QImode part number PART from integer - constant OP of mode MODE. */ - -int -s390_extract_qi (op, mode, part) - rtx op; - enum machine_mode mode; - int part; -{ - int n_parts = GET_MODE_SIZE (mode); - if (part < 0 || part >= n_parts) - abort(); - else - part = n_parts - 1 - part; - - if (GET_CODE (op) == CONST_INT) - { - unsigned HOST_WIDE_INT value = (unsigned HOST_WIDE_INT) INTVAL (op); - return ((value >> (8 * part)) & 0xff); - } - else if (GET_CODE (op) == CONST_DOUBLE - && GET_MODE (op) == VOIDmode) + if (GET_CODE (op) != CONST_INT) + return -1; + + for (i = 0; i < n_parts; i++) { - unsigned HOST_WIDE_INT value; - if (part < HOST_BITS_PER_WIDE_INT / 8) - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op); + if (i == 0) + value = (unsigned HOST_WIDE_INT) INTVAL (op); else - value = (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (op), - part -= HOST_BITS_PER_WIDE_INT / 8; - - return ((value >> (8 * part)) & 0xff); + value >>= GET_MODE_BITSIZE (part_mode); + + if ((value & part_mask) != (def & part_mask)) + { + if (part != -1) + return -1; + else + part = i; + } } - - abort (); + return part == -1 ? -1 : n_parts - 1 - part; } -/* Check whether we can (and want to) split a double-word - move in mode MODE from SRC to DST into two single-word +/* Check whether we can (and want to) split a double-word + move in mode MODE from SRC to DST into two single-word moves, moving the subword FIRST_SUBWORD first. */ bool -s390_split_ok_p (dst, src, mode, first_subword) - rtx dst; - rtx src; - enum machine_mode mode; - int first_subword; +s390_split_ok_p (rtx dst, rtx src, enum machine_mode mode, int first_subword) { /* Floating point registers cannot be split. */ if (FP_REG_P (src) || FP_REG_P (dst)) return false; - /* We don't need to split if operands are directly accessable. */ + /* We don't need to split if operands are directly accessible. */ if (s_operand (src, mode) || s_operand (dst, mode)) return false; @@ -871,7 +856,7 @@ s390_split_ok_p (dst, src, mode, first_subword) } -/* Change optimizations to be performed, depending on the +/* Change optimizations to be performed, depending on the optimization level. LEVEL is the optimization level specified; 2 if `-O2' is @@ -880,9 +865,7 @@ s390_split_ok_p (dst, src, mode, first_subword) SIZE is nonzero if `-Os' is specified and zero otherwise. */ void -optimization_options (level, size) - int level ATTRIBUTE_UNUSED; - int size ATTRIBUTE_UNUSED; +optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED) { /* ??? There are apparently still problems with -fcaller-saves. */ flag_caller_saves = 0; @@ -893,13 +876,80 @@ optimization_options (level, size) } void -override_options () +override_options (void) { + int i; + static struct pta + { + const char *const name; /* processor name or nickname. */ + const enum processor_type processor; + const enum processor_flags flags; + } + const processor_alias_table[] = + { + {"g5", PROCESSOR_9672_G5, PF_IEEE_FLOAT}, + {"g6", PROCESSOR_9672_G6, PF_IEEE_FLOAT}, + {"z900", PROCESSOR_2064_Z900, PF_IEEE_FLOAT | PF_ZARCH}, + {"z990", PROCESSOR_2084_Z990, PF_IEEE_FLOAT | PF_ZARCH + | PF_LONG_DISPLACEMENT}, + }; + + int const pta_size = ARRAY_SIZE (processor_alias_table); + /* Acquire a unique set number for our register saves and restores. */ s390_sr_alias_set = new_alias_set (); /* Set up function hooks. */ init_machine_status = s390_init_machine_status; + + /* Architecture mode defaults according to ABI. */ + if (!(target_flags_explicit & MASK_ZARCH)) + { + if (TARGET_64BIT) + target_flags |= MASK_ZARCH; + else + target_flags &= ~MASK_ZARCH; + } + + /* Determine processor architectural level. */ + if (!s390_arch_string) + s390_arch_string = TARGET_ZARCH? "z900" : "g5"; + + for (i = 0; i < pta_size; i++) + if (! strcmp (s390_arch_string, processor_alias_table[i].name)) + { + s390_arch = processor_alias_table[i].processor; + s390_arch_flags = processor_alias_table[i].flags; + break; + } + if (i == pta_size) + error ("Unknown cpu used in -march=%s.", s390_arch_string); + + /* Determine processor to tune for. */ + if (!s390_tune_string) + { + s390_tune = s390_arch; + s390_tune_flags = s390_arch_flags; + s390_tune_string = s390_arch_string; + } + else + { + for (i = 0; i < pta_size; i++) + if (! strcmp (s390_tune_string, processor_alias_table[i].name)) + { + s390_tune = processor_alias_table[i].processor; + s390_tune_flags = processor_alias_table[i].flags; + break; + } + if (i == pta_size) + error ("Unknown cpu used in -mtune=%s.", s390_tune_string); + } + + /* Sanity checks. */ + if (TARGET_ZARCH && !(s390_arch_flags & PF_ZARCH)) + error ("z/Architecture mode not supported on %s.", s390_arch_string); + if (TARGET_64BIT && !TARGET_ZARCH) + error ("64-bit ABI not supported in ESA/390 mode."); } /* Map for smallest class containing reg regno. */ @@ -913,18 +963,26 @@ const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, - ADDR_REGS, NO_REGS, ADDR_REGS + ADDR_REGS, NO_REGS, ADDR_REGS }; +/* Return attribute type of insn. */ + +static enum attr_type +s390_safe_attr_type (rtx insn) +{ + if (recog_memoized (insn) >= 0) + return get_attr_type (insn); + else + return TYPE_NONE; +} /* Return true if OP a (const_int 0) operand. OP is the current operation. MODE is the current operation mode. */ - + int -const0_operand (op, mode) - register rtx op; - enum machine_mode mode; +const0_operand (register rtx op, enum machine_mode mode) { return op == CONST0_RTX (mode); } @@ -934,20 +992,16 @@ const0_operand (op, mode) MODE is the current operation mode. */ int -consttable_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +consttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { return CONSTANT_P (op); } /* Return true if the mode of operand OP matches MODE. - If MODE is set to VOIDmode, set it to the mode of OP. */ + If MODE is set to VOIDmode, set it to the mode of OP. */ static int -check_mode (op, mode) - register rtx op; - enum machine_mode *mode; +check_mode (register rtx op, enum machine_mode *mode) { if (*mode == VOIDmode) *mode = GET_MODE (op); @@ -964,9 +1018,7 @@ check_mode (op, mode) MODE is the current operation mode. */ int -larl_operand (op, mode) - register rtx op; - enum machine_mode mode; +larl_operand (register rtx op, enum machine_mode mode) { if (! check_mode (op, &mode)) return 0; @@ -974,44 +1026,45 @@ larl_operand (op, mode) /* Allow labels and local symbols. */ if (GET_CODE (op) == LABEL_REF) return 1; - if (GET_CODE (op) == SYMBOL_REF - && XSTR (op, 0)[0] != '@' - && !tls_symbolic_operand (op) - && (!flag_pic || SYMBOL_REF_FLAG (op) - || CONSTANT_POOL_ADDRESS_P (op))) - return 1; + if (GET_CODE (op) == SYMBOL_REF) + return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0 + && SYMBOL_REF_TLS_MODEL (op) == 0 + && (!flag_pic || SYMBOL_REF_LOCAL_P (op))); /* Everything else must have a CONST, so strip it. */ if (GET_CODE (op) != CONST) return 0; op = XEXP (op, 0); - /* Allow adding *even* constants. */ + /* Allow adding *even* in-range constants. */ if (GET_CODE (op) == PLUS) { if (GET_CODE (XEXP (op, 1)) != CONST_INT || (INTVAL (XEXP (op, 1)) & 1) != 0) return 0; +#if HOST_BITS_PER_WIDE_INT > 32 + if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32 + || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32)) + return 0; +#endif op = XEXP (op, 0); } /* Labels and local symbols allowed here as well. */ if (GET_CODE (op) == LABEL_REF) return 1; - if (GET_CODE (op) == SYMBOL_REF - && XSTR (op, 0)[0] != '@' - && !tls_symbolic_operand (op) - && (!flag_pic || SYMBOL_REF_FLAG (op) - || CONSTANT_POOL_ADDRESS_P (op))) - return 1; + if (GET_CODE (op) == SYMBOL_REF) + return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0 + && SYMBOL_REF_TLS_MODEL (op) == 0 + && (!flag_pic || SYMBOL_REF_LOCAL_P (op))); /* Now we must have a @GOTENT offset or @PLT stub or an @INDNTPOFF TLS offset. */ if (GET_CODE (op) == UNSPEC - && XINT (op, 1) == 111) + && XINT (op, 1) == UNSPEC_GOTENT) return 1; if (GET_CODE (op) == UNSPEC - && XINT (op, 1) == 113) + && XINT (op, 1) == UNSPEC_PLT) return 1; if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_INDNTPOFF) @@ -1027,10 +1080,8 @@ larl_operand (op, mode) be accepted or not. */ static int -general_s_operand (op, mode, allow_immediate) - register rtx op; - enum machine_mode mode; - int allow_immediate; +general_s_operand (register rtx op, enum machine_mode mode, + int allow_immediate) { struct s390_address addr; @@ -1041,37 +1092,37 @@ general_s_operand (op, mode, allow_immediate) /* Just like memory_operand, allow (subreg (mem ...)) after reload. */ - if (reload_completed - && GET_CODE (op) == SUBREG + if (reload_completed + && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) op = SUBREG_REG (op); switch (GET_CODE (op)) { - /* Constants that we are sure will be forced to the - literal pool in reload are OK as s-operand. Note - that we cannot call s390_preferred_reload_class here - because it might not be known yet at this point - whether the current function is a leaf or not. */ + /* Constants are OK as s-operand if ALLOW_IMMEDIATE + is true and we are still before reload. */ case CONST_INT: case CONST_DOUBLE: if (!allow_immediate || reload_completed) - break; - if (!legitimate_reload_constant_p (op)) - return 1; - if (!TARGET_64BIT) - return 1; - break; + return 0; + return 1; /* Memory operands are OK unless they already use an index register. */ case MEM: if (GET_CODE (XEXP (op, 0)) == ADDRESSOF) return 1; - if (s390_decompose_address (XEXP (op, 0), &addr) - && !addr.indx) - return 1; - break; + if (!s390_decompose_address (XEXP (op, 0), &addr)) + return 0; + if (addr.indx) + return 0; + /* Do not allow literal pool references unless ALLOW_IMMEDIATE + is true. This prevents compares between two literal pool + entries from being accepted. */ + if (!allow_immediate + && addr.base && REGNO (addr.base) == BASE_REGISTER) + return 0; + return 1; default: break; @@ -1085,54 +1136,330 @@ general_s_operand (op, mode, allow_immediate) MODE is the current operation mode. */ int -s_operand (op, mode) - register rtx op; - enum machine_mode mode; +s_operand (register rtx op, enum machine_mode mode) { return general_s_operand (op, mode, 0); } -/* Return true if OP is a valid S-type operand or an immediate - operand that can be addressed as S-type operand by forcing +/* Return true if OP is a valid S-type operand or an immediate + operand that can be addressed as S-type operand by forcing it into the literal pool. OP is the current operation. MODE is the current operation mode. */ int -s_imm_operand (op, mode) - register rtx op; - enum machine_mode mode; +s_imm_operand (register rtx op, enum machine_mode mode) { return general_s_operand (op, mode, 1); } -/* Return true if OP is a valid operand for a 'Q' constraint. - This differs from s_operand in that only memory operands - without index register are accepted, nothing else. */ +/* Return true if OP a valid shift count operand. + OP is the current operation. + MODE is the current operation mode. */ int -q_constraint (op) - register rtx op; +shift_count_operand (rtx op, enum machine_mode mode) { - struct s390_address addr; + HOST_WIDE_INT offset = 0; - if (GET_CODE (op) != MEM) + if (! check_mode (op, &mode)) return 0; - if (!s390_decompose_address (XEXP (op, 0), &addr)) + /* We can have an integer constant, an address register, + or a sum of the two. Note that reload already checks + that any register present is an address register, so + we just check for any register here. */ + if (GET_CODE (op) == CONST_INT) + { + offset = INTVAL (op); + op = NULL_RTX; + } + if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) + { + offset = INTVAL (XEXP (op, 1)); + op = XEXP (op, 0); + } + while (op && GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + if (op && GET_CODE (op) != REG) return 0; - if (addr.indx) + /* Unfortunately we have to reject constants that are invalid + for an address, or else reload will get confused. */ + if (!DISP_IN_RANGE (offset)) return 0; return 1; } -/* Return the cost of an address rtx ADDR. */ +/* Return true if DISP is a valid short displacement. */ + +static int +s390_short_displacement (rtx disp) +{ + /* No displacement is OK. */ + if (!disp) + return 1; + + /* Integer displacement in range. */ + if (GET_CODE (disp) == CONST_INT) + return INTVAL (disp) >= 0 && INTVAL (disp) < 4096; + + /* GOT offset is not OK, the GOT can be large. */ + if (GET_CODE (disp) == CONST + && GET_CODE (XEXP (disp, 0)) == UNSPEC + && XINT (XEXP (disp, 0), 1) == UNSPEC_GOT) + return 0; + + /* All other symbolic constants are literal pool references, + which are OK as the literal pool must be small. */ + if (GET_CODE (disp) == CONST) + return 1; + + return 0; +} + +/* Return true if OP is a valid operand for a C constraint. */ int -s390_address_cost (addr) - rtx addr; +s390_extra_constraint_str (rtx op, int c, const char * str) +{ + struct s390_address addr; + + if (c != str[0]) + abort (); + + switch (c) + { + case 'Q': + if (GET_CODE (op) != MEM) + return 0; + if (!s390_decompose_address (XEXP (op, 0), &addr)) + return 0; + if (addr.indx) + return 0; + + if (TARGET_LONG_DISPLACEMENT) + { + if (!s390_short_displacement (addr.disp)) + return 0; + } + break; + + case 'R': + if (GET_CODE (op) != MEM) + return 0; + + if (TARGET_LONG_DISPLACEMENT) + { + if (!s390_decompose_address (XEXP (op, 0), &addr)) + return 0; + if (!s390_short_displacement (addr.disp)) + return 0; + } + break; + + case 'S': + if (!TARGET_LONG_DISPLACEMENT) + return 0; + if (GET_CODE (op) != MEM) + return 0; + if (!s390_decompose_address (XEXP (op, 0), &addr)) + return 0; + if (addr.indx) + return 0; + if (s390_short_displacement (addr.disp)) + return 0; + break; + + case 'T': + if (!TARGET_LONG_DISPLACEMENT) + return 0; + if (GET_CODE (op) != MEM) + return 0; + /* Any invalid address here will be fixed up by reload, + so accept it for the most generic constraint. */ + if (s390_decompose_address (XEXP (op, 0), &addr) + && s390_short_displacement (addr.disp)) + return 0; + break; + + case 'U': + if (TARGET_LONG_DISPLACEMENT) + { + if (!s390_decompose_address (op, &addr)) + return 0; + if (!s390_short_displacement (addr.disp)) + return 0; + } + break; + + case 'W': + if (!TARGET_LONG_DISPLACEMENT) + return 0; + /* Any invalid address here will be fixed up by reload, + so accept it for the most generic constraint. */ + if (s390_decompose_address (op, &addr) + && s390_short_displacement (addr.disp)) + return 0; + break; + + case 'Y': + return shift_count_operand (op, VOIDmode); + + default: + return 0; + } + + return 1; +} + +/* Return true if VALUE matches the constraint STR. */ + +int +s390_const_ok_for_constraint_p (HOST_WIDE_INT value, + int c, + const char * str) +{ + enum machine_mode mode, part_mode; + int def; + unsigned char part; + + if (c != str[0]) + abort (); + + switch (str[0]) + { + case 'I': + return (unsigned int)value < 256; + + case 'J': + return (unsigned int)value < 4096; + + case 'K': + return value >= -32768 && value < 32768; + + case 'L': + return (TARGET_LONG_DISPLACEMENT ? + (value >= -524288 && value <= 524287) + : (value >= 0 && value <= 4095)); + case 'M': + return value == 2147483647; + + case 'N': + part = str[1] - '0'; + + switch (str[2]) + { + case 'H': part_mode = HImode; break; + case 'Q': part_mode = QImode; break; + default: return 0; + } + + switch (str[3]) + { + case 'H': mode = HImode; break; + case 'S': mode = SImode; break; + case 'D': mode = DImode; break; + default: return 0; + } + + switch (str[4]) + { + case '0': def = 0; break; + case 'F': def = -1; break; + default: return 0; + } + + if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode)) + return 0; + + if (s390_single_part (GEN_INT (value), mode, part_mode, def) != part) + return 0; + + break; + + default: + return 0; + } + + return 1; +} + +/* Compute a (partial) cost for rtx X. Return true if the complete + cost has been computed, and false if subexpressions should be + scanned. In either case, *TOTAL contains the cost result. */ + +static bool +s390_rtx_costs (rtx x, int code, int outer_code, int *total) +{ + switch (code) + { + case CONST: + if (GET_CODE (XEXP (x, 0)) == MINUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT) + *total = 1000; + else + *total = 0; + return true; + + case CONST_INT: + /* Force_const_mem does not work out of reload, because the + saveable_obstack is set to reload_obstack, which does not + live long enough. Because of this we cannot use force_const_mem + in addsi3. This leads to problems with gen_add2_insn with a + constant greater than a short. Because of that we give an + addition of greater constants a cost of 3 (reload1.c 10096). */ + /* ??? saveable_obstack no longer exists. */ + if (outer_code == PLUS + && (INTVAL (x) > 32767 || INTVAL (x) < -32768)) + *total = COSTS_N_INSNS (3); + else + *total = 0; + return true; + + case LABEL_REF: + case SYMBOL_REF: + case CONST_DOUBLE: + *total = 0; + return true; + + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + case PLUS: + case AND: + case IOR: + case XOR: + case MINUS: + case NEG: + case NOT: + *total = COSTS_N_INSNS (1); + return true; + + case MULT: + if (GET_MODE (XEXP (x, 0)) == DImode) + *total = COSTS_N_INSNS (40); + else + *total = COSTS_N_INSNS (7); + return true; + + case DIV: + case UDIV: + case MOD: + case UMOD: + *total = COSTS_N_INSNS (33); + return true; + + default: + return false; + } +} + +/* Return the cost of an address rtx ADDR. */ + +static int +s390_address_cost (rtx addr) { struct s390_address ad; if (!s390_decompose_address (addr, &ad)) @@ -1146,9 +1473,7 @@ s390_address_cost (addr) MODE is the current operation mode. */ int -bras_sym_operand (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +bras_sym_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { register enum rtx_code code = GET_CODE (op); @@ -1159,7 +1484,7 @@ bras_sym_operand (op, mode) /* Allow @PLT stubs. */ if (code == CONST && GET_CODE (XEXP (op, 0)) == UNSPEC - && XINT (XEXP (op, 0), 1) == 113) + && XINT (XEXP (op, 0), 1) == UNSPEC_PLT) return 1; return 0; } @@ -1168,30 +1493,22 @@ bras_sym_operand (op, mode) otherwise return 0. */ int -tls_symbolic_operand (op) - register rtx op; +tls_symbolic_operand (register rtx op) { - const char *symbol_str; - if (GET_CODE (op) != SYMBOL_REF) return 0; - symbol_str = XSTR (op, 0); - - if (symbol_str[0] != '%') - return 0; - return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars; + return SYMBOL_REF_TLS_MODEL (op); } /* Return true if OP is a load multiple operation. It is known to be a - PARALLEL and the first section will be tested. + PARALLEL and the first section will be tested. OP is the current operation. MODE is the current operation mode. */ int -load_multiple_operation (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { + enum machine_mode elt_mode; int count = XVECLEN (op, 0); unsigned int dest_regno; rtx src_addr; @@ -1207,13 +1524,14 @@ load_multiple_operation (op, mode) dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0); + elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0))); /* Check, is base, or base + displacement. */ if (GET_CODE (src_addr) == REG) off = 0; else if (GET_CODE (src_addr) == PLUS - && GET_CODE (XEXP (src_addr, 0)) == REG + && GET_CODE (XEXP (src_addr, 0)) == REG && GET_CODE (XEXP (src_addr, 1)) == CONST_INT) { off = INTVAL (XEXP (src_addr, 1)); @@ -1231,15 +1549,15 @@ load_multiple_operation (op, mode) if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != Pmode + || GET_MODE (SET_DEST (elt)) != elt_mode || REGNO (SET_DEST (elt)) != dest_regno + i || GET_CODE (SET_SRC (elt)) != MEM - || GET_MODE (SET_SRC (elt)) != Pmode + || GET_MODE (SET_SRC (elt)) != elt_mode || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) - != off + i * UNITS_PER_WORD) + != off + i * GET_MODE_SIZE (elt_mode)) return 0; } @@ -1247,15 +1565,14 @@ load_multiple_operation (op, mode) } /* Return true if OP is a store multiple operation. It is known to be a - PARALLEL and the first section will be tested. + PARALLEL and the first section will be tested. OP is the current operation. MODE is the current operation mode. */ int -store_multiple_operation (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { + enum machine_mode elt_mode; int count = XVECLEN (op, 0); unsigned int src_regno; rtx dest_addr; @@ -1270,13 +1587,14 @@ store_multiple_operation (op, mode) src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0); + elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0))); /* Check, is base, or base + displacement. */ if (GET_CODE (dest_addr) == REG) off = 0; else if (GET_CODE (dest_addr) == PLUS - && GET_CODE (XEXP (dest_addr, 0)) == REG + && GET_CODE (XEXP (dest_addr, 0)) == REG && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT) { off = INTVAL (XEXP (dest_addr, 1)); @@ -1294,15 +1612,15 @@ store_multiple_operation (op, mode) if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != Pmode + || GET_MODE (SET_SRC (elt)) != elt_mode || REGNO (SET_SRC (elt)) != src_regno + i || GET_CODE (SET_DEST (elt)) != MEM - || GET_MODE (SET_DEST (elt)) != Pmode + || GET_MODE (SET_DEST (elt)) != elt_mode || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) - != off + i * UNITS_PER_WORD) + != off + i * GET_MODE_SIZE (elt_mode)) return 0; } return 1; @@ -1312,8 +1630,7 @@ store_multiple_operation (op, mode) /* Return true if OP contains a symbol reference */ int -symbolic_reference_mentioned_p (op) - rtx op; +symbolic_reference_mentioned_p (rtx op) { register const char *fmt; register int i; @@ -1343,8 +1660,7 @@ symbolic_reference_mentioned_p (op) /* Return true if OP contains a reference to a thread-local symbol. */ int -tls_symbolic_reference_mentioned_p (op) - rtx op; +tls_symbolic_reference_mentioned_p (rtx op) { register const char *fmt; register int i; @@ -1372,19 +1688,18 @@ tls_symbolic_reference_mentioned_p (op) } -/* Return true if OP is a legitimate general operand when - generating PIC code. It is given that flag_pic is on +/* Return true if OP is a legitimate general operand when + generating PIC code. It is given that flag_pic is on and that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */ int -legitimate_pic_operand_p (op) - register rtx op; +legitimate_pic_operand_p (register rtx op) { /* Accept all non-symbolic constants. */ if (!SYMBOLIC_CONST (op)) return 1; - /* Reject everything else; must be handled + /* Reject everything else; must be handled via emit_symbolic_move. */ return 0; } @@ -1393,15 +1708,14 @@ legitimate_pic_operand_p (op) It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */ int -legitimate_constant_p (op) - register rtx op; +legitimate_constant_p (register rtx op) { /* Accept all non-symbolic constants. */ if (!SYMBOLIC_CONST (op)) return 1; /* Accept immediate LARL operands. */ - if (TARGET_64BIT && larl_operand (op, VOIDmode)) + if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode)) return 1; /* Thread-local symbols are never legal constants. This is @@ -1426,8 +1740,7 @@ legitimate_constant_p (op) not constant (TLS) or not known at final link time (PIC). */ static bool -s390_cannot_force_const_mem (x) - rtx x; +s390_cannot_force_const_mem (rtx x) { switch (GET_CODE (x)) { @@ -1459,10 +1772,10 @@ s390_cannot_force_const_mem (x) switch (XINT (x, 1)) { /* Only lt-relative or GOT-relative UNSPECs are OK. */ - case 100: - case 104: - case 112: - case 114: + case UNSPEC_LTREL_OFFSET: + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLTOFF: case UNSPEC_TLSGD: case UNSPEC_TLSLDM: case UNSPEC_NTPOFF: @@ -1482,27 +1795,31 @@ s390_cannot_force_const_mem (x) } /* Returns true if the constant value OP is a legitimate general - operand during and after reload. The difference to + operand during and after reload. The difference to legitimate_constant_p is that this function will not accept a constant that would need to be forced to the literal pool before it can be used as operand. */ int -legitimate_reload_constant_p (op) - register rtx op; +legitimate_reload_constant_p (register rtx op) { + /* Accept la(y) operands. */ + if (GET_CODE (op) == CONST_INT + && DISP_IN_RANGE (INTVAL (op))) + return 1; + /* Accept l(g)hi operands. */ if (GET_CODE (op) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', "K")) return 1; /* Accept lliXX operands. */ - if (TARGET_64BIT - && s390_single_hi (op, DImode, 0) >= 0) + if (TARGET_ZARCH + && s390_single_part (op, DImode, HImode, 0) >= 0) return 1; /* Accept larl operands. */ - if (TARGET_64BIT + if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode)) return 1; @@ -1514,9 +1831,7 @@ legitimate_reload_constant_p (op) return the class of reg to actually use. */ enum reg_class -s390_preferred_reload_class (op, class) - rtx op; - enum reg_class class; +s390_preferred_reload_class (rtx op, enum reg_class class) { /* This can happen if a floating point constant is being reloaded into an integer register. Leave well alone. */ @@ -1563,10 +1878,8 @@ s390_preferred_reload_class (op, class) is not a legitimate operand of the LOAD ADDRESS instruction. */ enum reg_class -s390_secondary_input_reload_class (class, mode, in) - enum reg_class class ATTRIBUTE_UNUSED; - enum machine_mode mode; - rtx in; +s390_secondary_input_reload_class (enum reg_class class ATTRIBUTE_UNUSED, + enum machine_mode mode, rtx in) { if (s390_plus_operand (in, mode)) return ADDR_REGS; @@ -1577,14 +1890,12 @@ s390_secondary_input_reload_class (class, mode, in) /* Return the register class of a scratch register needed to store a register of class CLASS in MODE into OUT: - We need a temporary when storing a double-word to a + We need a temporary when storing a double-word to a non-offsettable memory address. */ enum reg_class -s390_secondary_output_reload_class (class, mode, out) - enum reg_class class; - enum machine_mode mode; - rtx out; +s390_secondary_output_reload_class (enum reg_class class, + enum machine_mode mode, rtx out) { if ((TARGET_64BIT ? mode == TImode : (mode == DImode || mode == DFmode)) @@ -1598,14 +1909,12 @@ s390_secondary_output_reload_class (class, mode, out) } /* Return true if OP is a PLUS that is not a legitimate - operand for the LA instruction. + operand for the LA instruction. OP is the current operation. MODE is the current operation mode. */ int -s390_plus_operand (op, mode) - register rtx op; - enum machine_mode mode; +s390_plus_operand (register rtx op, enum machine_mode mode) { if (!check_mode (op, &mode) || mode != Pmode) return FALSE; @@ -1624,10 +1933,8 @@ s390_plus_operand (op, mode) SCRATCH may be used as scratch register. */ void -s390_expand_plus_operand (target, src, scratch) - register rtx target; - register rtx src; - register rtx scratch; +s390_expand_plus_operand (register rtx target, register rtx src, + register rtx scratch) { rtx sum1, sum2; struct s390_address ad; @@ -1693,14 +2000,14 @@ s390_expand_plus_operand (target, src, scratch) canonical form so that they will be recognized. */ static int -s390_decompose_address (addr, out) - register rtx addr; - struct s390_address *out; +s390_decompose_address (register rtx addr, struct s390_address *out) { rtx base = NULL_RTX; rtx indx = NULL_RTX; rtx disp = NULL_RTX; int pointer = FALSE; + int base_ptr = FALSE; + int indx_ptr = FALSE; /* Decompose address into base + index + displacement. */ @@ -1746,35 +2053,18 @@ s390_decompose_address (addr, out) disp = addr; /* displacement */ - /* Prefer to use pointer as base, not index. */ - if (base && indx) - { - int base_ptr = GET_CODE (base) == UNSPEC - || (REG_P (base) && REG_POINTER (base)); - int indx_ptr = GET_CODE (indx) == UNSPEC - || (REG_P (indx) && REG_POINTER (indx)); - - if (!base_ptr && indx_ptr) - { - rtx tmp = base; - base = indx; - indx = tmp; - } - } - /* Validate base register. */ if (base) { if (GET_CODE (base) == UNSPEC) { - if (XVECLEN (base, 0) != 1 || XINT (base, 1) != 101) - return FALSE; - base = XVECEXP (base, 0, 0); - pointer = TRUE; + if (XVECLEN (base, 0) != 1 || XINT (base, 1) != UNSPEC_LTREL_BASE) + return FALSE; + base = gen_rtx_REG (Pmode, BASE_REGISTER); } if (GET_CODE (base) != REG || GET_MODE (base) != Pmode) - return FALSE; + return FALSE; if (REGNO (base) == BASE_REGISTER || REGNO (base) == STACK_POINTER_REGNUM @@ -1783,11 +2073,9 @@ s390_decompose_address (addr, out) && frame_pointer_needed && REGNO (base) == HARD_FRAME_POINTER_REGNUM) || REGNO (base) == ARG_POINTER_REGNUM - || (REGNO (base) >= FIRST_VIRTUAL_REGISTER - && REGNO (base) <= LAST_VIRTUAL_REGISTER) || (flag_pic && REGNO (base) == PIC_OFFSET_TABLE_REGNUM)) - pointer = TRUE; + pointer = base_ptr = TRUE; } /* Validate index register. */ @@ -1795,14 +2083,13 @@ s390_decompose_address (addr, out) { if (GET_CODE (indx) == UNSPEC) { - if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != 101) - return FALSE; - indx = XVECEXP (indx, 0, 0); - pointer = TRUE; + if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != UNSPEC_LTREL_BASE) + return FALSE; + indx = gen_rtx_REG (Pmode, BASE_REGISTER); } if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode) - return FALSE; + return FALSE; if (REGNO (indx) == BASE_REGISTER || REGNO (indx) == STACK_POINTER_REGNUM @@ -1811,11 +2098,18 @@ s390_decompose_address (addr, out) && frame_pointer_needed && REGNO (indx) == HARD_FRAME_POINTER_REGNUM) || REGNO (indx) == ARG_POINTER_REGNUM - || (REGNO (indx) >= FIRST_VIRTUAL_REGISTER - && REGNO (indx) <= LAST_VIRTUAL_REGISTER) || (flag_pic && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM)) - pointer = TRUE; + pointer = indx_ptr = TRUE; + } + + /* Prefer to use pointer as base, not index. */ + if (base && indx && !base_ptr + && (indx_ptr || (!REG_POINTER (base) && REG_POINTER (indx)))) + { + rtx tmp = base; + base = indx; + indx = tmp; } /* Validate displacement. */ @@ -1834,16 +2128,16 @@ s390_decompose_address (addr, out) this is fixed up by reload in any case. */ if (base != arg_pointer_rtx && indx != arg_pointer_rtx) { - if (INTVAL (disp) < 0 || INTVAL (disp) >= 4096) + if (!DISP_IN_RANGE (INTVAL (disp))) return FALSE; } } - /* In the small-PIC case, the linker converts @GOT12 + /* In the small-PIC case, the linker converts @GOT and @GOTNTPOFF offsets to possible displacements. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == UNSPEC - && (XINT (XEXP (disp, 0), 1) == 110 + && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF)) { if (flag_pic != 1) @@ -1860,7 +2154,7 @@ s390_decompose_address (addr, out) { pointer = TRUE; } - + /* Likewise if a constant offset is present. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == PLUS @@ -1872,7 +2166,7 @@ s390_decompose_address (addr, out) pointer = TRUE; } - /* We can convert literal pool addresses to + /* We can convert literal pool addresses to displacements by basing them off the base register. */ else { @@ -1899,7 +2193,7 @@ s390_decompose_address (addr, out) if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp))) return FALSE; - /* Either base or index must be free to + /* Either base or index must be free to hold the base register. */ if (base && indx) return FALSE; @@ -1910,7 +2204,8 @@ s390_decompose_address (addr, out) else base = gen_rtx_REG (Pmode, BASE_REGISTER); - disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), 100); + disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), + UNSPEC_LTREL_OFFSET); disp = gen_rtx_CONST (Pmode, disp); if (offset) @@ -1922,7 +2217,7 @@ s390_decompose_address (addr, out) if (!base && !indx) pointer = TRUE; - + if (out) { out->base = base; @@ -1938,10 +2233,8 @@ s390_decompose_address (addr, out) STRICT specifies whether strict register checking applies. */ int -legitimate_address_p (mode, addr, strict) - enum machine_mode mode ATTRIBUTE_UNUSED; - register rtx addr; - int strict; +legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + register rtx addr, int strict) { struct s390_address ad; if (!s390_decompose_address (addr, &ad)) @@ -1970,8 +2263,7 @@ legitimate_address_p (mode, addr, strict) address, as LA performs only a 31-bit addition. */ int -legitimate_la_operand_p (op) - register rtx op; +legitimate_la_operand_p (register rtx op) { struct s390_address addr; if (!s390_decompose_address (op, &addr)) @@ -1985,10 +2277,9 @@ legitimate_la_operand_p (op) /* Return 1 if OP is a valid operand for the LA instruction, and we prefer to use LA over addition to compute it. */ - + int -preferred_la_operand_p (op) - register rtx op; +preferred_la_operand_p (register rtx op) { struct s390_address addr; if (!s390_decompose_address (op, &addr)) @@ -2012,9 +2303,7 @@ preferred_la_operand_p (op) where legitimate_la_operand_p (SRC) returns false. */ void -s390_load_address (dst, src) - rtx dst; - rtx src; +s390_load_address (rtx dst, rtx src) { if (TARGET_64BIT) emit_move_insn (dst, src); @@ -2033,7 +2322,7 @@ s390_load_address (dst, src) 2. Static data references, constant pool addresses, and code labels compute the address as an offset from the GOT, whose base is in - the PIC reg. Static data objects have SYMBOL_REF_FLAG set to + the PIC reg. Static data objects have SYMBOL_FLAG_LOCAL set to differentiate them from global data objects. The returned address is the PIC reg + an unspec constant. @@ -2041,41 +2330,37 @@ s390_load_address (dst, src) reg also appears in the address. */ rtx -legitimize_pic_address (orig, reg) - rtx orig; - rtx reg; +legitimize_pic_address (rtx orig, rtx reg) { rtx addr = orig; rtx new = orig; rtx base; if (GET_CODE (addr) == LABEL_REF - || (GET_CODE (addr) == SYMBOL_REF - && (SYMBOL_REF_FLAG (addr) - || CONSTANT_POOL_ADDRESS_P (addr)))) + || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))) { /* This is a local symbol. */ - if (TARGET_64BIT && larl_operand (addr, VOIDmode)) + if (TARGET_CPU_ZARCH && larl_operand (addr, VOIDmode)) { - /* Access local symbols PC-relative via LARL. - This is the same as in the non-PIC case, so it is + /* Access local symbols PC-relative via LARL. + This is the same as in the non-PIC case, so it is handled automatically ... */ } else { - /* Access local symbols relative to the literal pool. */ + /* Access local symbols relative to the GOT. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); - addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 100); + if (reload_in_progress || reload_completed) + regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; + + addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); addr = gen_rtx_CONST (Pmode, addr); addr = force_const_mem (Pmode, addr); emit_move_insn (temp, addr); - base = gen_rtx_REG (Pmode, BASE_REGISTER); - base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); - new = gen_rtx_PLUS (Pmode, base, temp); - + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); if (reg != 0) { emit_move_insn (reg, new); @@ -2091,12 +2376,12 @@ legitimize_pic_address (orig, reg) if (flag_pic == 1) { /* Assume GOT offset < 4k. This is handled the same way - in both 31- and 64-bit code (@GOT12). */ + in both 31- and 64-bit code (@GOT). */ if (reload_in_progress || reload_completed) regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; - new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 110); + new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); new = gen_rtx_CONST (Pmode, new); new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); new = gen_rtx_MEM (Pmode, new); @@ -2104,14 +2389,14 @@ legitimize_pic_address (orig, reg) emit_move_insn (reg, new); new = reg; } - else if (TARGET_64BIT) + else if (TARGET_CPU_ZARCH) { /* If the GOT offset might be >= 4k, we determine the position of the GOT entry via a PC-relative LARL (@GOTENT). */ rtx temp = gen_reg_rtx (Pmode); - new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 111); + new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); new = gen_rtx_CONST (Pmode, new); emit_move_insn (temp, new); @@ -2122,7 +2407,7 @@ legitimize_pic_address (orig, reg) } else { - /* If the GOT offset might be >= 4k, we have to load it + /* If the GOT offset might be >= 4k, we have to load it from the literal pool (@GOT). */ rtx temp = gen_reg_rtx (Pmode); @@ -2130,7 +2415,7 @@ legitimize_pic_address (orig, reg) if (reload_in_progress || reload_completed) regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; - addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 112); + addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); addr = gen_rtx_CONST (Pmode, addr); addr = force_const_mem (Pmode, addr); emit_move_insn (temp, addr); @@ -2141,7 +2426,7 @@ legitimize_pic_address (orig, reg) emit_move_insn (reg, new); new = reg; } - } + } else { if (GET_CODE (addr) == CONST) @@ -2153,35 +2438,41 @@ legitimize_pic_address (orig, reg) abort (); switch (XINT (addr, 1)) { - /* If someone moved an @GOT or lt-relative UNSPEC + /* If someone moved a GOT-relative UNSPEC out of the literal pool, force them back in. */ - case 100: - case 112: - case 114: + case UNSPEC_GOTOFF: + case UNSPEC_PLTOFF: new = force_const_mem (Pmode, orig); break; + /* @GOT is OK as is if small. */ + case UNSPEC_GOT: + if (flag_pic == 2) + new = force_const_mem (Pmode, orig); + break; + /* @GOTENT is OK as is. */ - case 111: + case UNSPEC_GOTENT: break; /* @PLT is OK as is on 64-bit, must be converted to - lt-relative PLT on 31-bit. */ - case 113: - if (!TARGET_64BIT) + GOT-relative @PLTOFF on 31-bit. */ + case UNSPEC_PLT: + if (!TARGET_CPU_ZARCH) { rtx temp = reg? reg : gen_reg_rtx (Pmode); + if (reload_in_progress || reload_completed) + regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; + addr = XVECEXP (addr, 0, 0); - addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 114); + addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), + UNSPEC_PLTOFF); addr = gen_rtx_CONST (Pmode, addr); addr = force_const_mem (Pmode, addr); emit_move_insn (temp, addr); - base = gen_rtx_REG (Pmode, BASE_REGISTER); - base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); - new = gen_rtx_PLUS (Pmode, base, temp); - + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); if (reg != 0) { emit_move_insn (reg, new); @@ -2201,23 +2492,21 @@ legitimize_pic_address (orig, reg) if (GET_CODE (addr) == PLUS) { rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); - /* Check first to see if this is a constant offset + /* Check first to see if this is a constant offset from a local symbol reference. */ if ((GET_CODE (op0) == LABEL_REF - || (GET_CODE (op0) == SYMBOL_REF - && (SYMBOL_REF_FLAG (op0) - || CONSTANT_POOL_ADDRESS_P (op0)))) + || (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (op0))) && GET_CODE (op1) == CONST_INT) { - if (TARGET_64BIT && larl_operand (op0, VOIDmode)) + if (TARGET_CPU_ZARCH && larl_operand (op0, VOIDmode)) { if (INTVAL (op1) & 1) { - /* LARL can't handle odd offsets, so emit a + /* LARL can't handle odd offsets, so emit a pair of LARL and LA. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); - if (INTVAL (op1) < 0 || INTVAL (op1) >= 4096) + if (!DISP_IN_RANGE (INTVAL (op1))) { int even = INTVAL (op1) - 1; op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even)); @@ -2242,20 +2531,21 @@ legitimize_pic_address (orig, reg) } else { - /* Access local symbols relative to the literal pool. */ + /* Access local symbols relative to the GOT. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); - addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 100); + if (reload_in_progress || reload_completed) + regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; + + addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), + UNSPEC_GOTOFF); addr = gen_rtx_PLUS (Pmode, addr, op1); addr = gen_rtx_CONST (Pmode, addr); addr = force_const_mem (Pmode, addr); - emit_move_insn (temp, addr); - - base = gen_rtx_REG (Pmode, BASE_REGISTER); - base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); - new = gen_rtx_PLUS (Pmode, base, temp); + emit_move_insn (temp, addr); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); if (reg != 0) { emit_move_insn (reg, new); @@ -2264,16 +2554,15 @@ legitimize_pic_address (orig, reg) } } - /* Now, check whether it is an LT-relative symbol plus offset + /* Now, check whether it is a GOT relative symbol plus offset that was pulled out of the literal pool. Force it back in. */ else if (GET_CODE (op0) == UNSPEC - && GET_CODE (op1) == CONST_INT) + && GET_CODE (op1) == CONST_INT + && XINT (op0, 1) == UNSPEC_GOTOFF) { if (XVECLEN (op0, 0) != 1) abort (); - if (XINT (op0, 1) != 100) - abort (); new = force_const_mem (Pmode, orig); } @@ -2308,7 +2597,7 @@ legitimize_pic_address (orig, reg) /* Load the thread pointer into a register. */ static rtx -get_thread_pointer () +get_thread_pointer (void) { rtx tp; @@ -2323,7 +2612,7 @@ get_thread_pointer () static GTY(()) rtx s390_tls_symbol; rtx -s390_tls_get_offset () +s390_tls_get_offset (void) { if (!s390_tls_symbol) s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset"); @@ -2335,9 +2624,7 @@ s390_tls_get_offset () this (thread-local) address. REG may be used as temporary. */ static rtx -legitimize_tls_address (addr, reg) - rtx addr; - rtx reg; +legitimize_tls_address (rtx addr, rtx reg) { rtx new, tls_call, temp, base, r2, insn; @@ -2417,7 +2704,7 @@ legitimize_tls_address (addr, reg) temp = gen_reg_rtx (Pmode); emit_move_insn (temp, new); } - else if (TARGET_64BIT) + else if (TARGET_CPU_ZARCH) { /* If the GOT offset might be >= 4k, we determine the position of the GOT entry via a PC-relative LARL. */ @@ -2434,7 +2721,7 @@ legitimize_tls_address (addr, reg) } else if (flag_pic) { - /* If the GOT offset might be >= 4k, we have to load it + /* If the GOT offset might be >= 4k, we have to load it from the literal pool. */ if (reload_in_progress || reload_completed) @@ -2506,7 +2793,7 @@ legitimize_tls_address (addr, reg) switch (XINT (XEXP (addr, 0), 1)) { case UNSPEC_INDNTPOFF: - if (TARGET_64BIT) + if (TARGET_CPU_ZARCH) new = addr; else abort (); @@ -2526,8 +2813,7 @@ legitimize_tls_address (addr, reg) /* Emit insns to move operands[1] into operands[0]. */ void -emit_symbolic_move (operands) - rtx *operands; +emit_symbolic_move (rtx *operands) { rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); @@ -2551,10 +2837,8 @@ emit_symbolic_move (operands) See comments by legitimize_pic_address for details. */ rtx -legitimize_address (x, oldx, mode) - register rtx x; - register rtx oldx ATTRIBUTE_UNUSED; - enum machine_mode mode ATTRIBUTE_UNUSED; +legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) { rtx constant_term = const0_rtx; @@ -2568,8 +2852,8 @@ legitimize_address (x, oldx, mode) else if (flag_pic) { if (SYMBOLIC_CONST (x) - || (GET_CODE (x) == PLUS - && (SYMBOLIC_CONST (XEXP (x, 0)) + || (GET_CODE (x) == PLUS + && (SYMBOLIC_CONST (XEXP (x, 0)) || SYMBOLIC_CONST (XEXP (x, 1))))) x = legitimize_pic_address (x, 0); @@ -2581,15 +2865,15 @@ legitimize_address (x, oldx, mode) /* Optimize loading of large displacements by splitting them into the multiple of 4K and the rest; this allows the - former to be CSE'd if possible. + former to be CSE'd if possible. Don't do this if the displacement is added to a register pointing into the stack frame, as the offsets will change later anyway. */ if (GET_CODE (constant_term) == CONST_INT - && (INTVAL (constant_term) < 0 - || INTVAL (constant_term) >= 4096) + && !TARGET_LONG_DISPLACEMENT + && !DISP_IN_RANGE (INTVAL (constant_term)) && !(REG_P (x) && REGNO_PTR_FRAME_P (REGNO (x)))) { HOST_WIDE_INT lower = INTVAL (constant_term) & 0xfff; @@ -2636,39 +2920,17 @@ legitimize_address (x, oldx, mode) /* Emit code to move LEN bytes from DST to SRC. */ void -s390_expand_movstr (dst, src, len) - rtx dst; - rtx src; - rtx len; +s390_expand_movstr (rtx dst, rtx src, rtx len) { - rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) = - TARGET_64BIT ? gen_movstr_short_64 : gen_movstr_short_31; - rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) = - TARGET_64BIT ? gen_movstr_long_64 : gen_movstr_long_31; - - if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) { if (INTVAL (len) > 0) - emit_insn ((*gen_short) (dst, src, GEN_INT (INTVAL (len) - 1))); + emit_insn (gen_movstr_short (dst, src, GEN_INT (INTVAL (len) - 1))); } else if (TARGET_MVCLE) { - enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode; - enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode; - rtx reg0 = gen_reg_rtx (double_mode); - rtx reg1 = gen_reg_rtx (double_mode); - - emit_move_insn (gen_highpart (single_mode, reg0), - force_operand (XEXP (dst, 0), NULL_RTX)); - emit_move_insn (gen_highpart (single_mode, reg1), - force_operand (XEXP (src, 0), NULL_RTX)); - - convert_move (gen_lowpart (single_mode, reg0), len, 1); - convert_move (gen_lowpart (single_mode, reg1), len, 1); - - emit_insn ((*gen_long) (reg0, reg1, reg0, reg1)); + emit_insn (gen_movstr_long (dst, src, convert_to_mode (Pmode, len, 1))); } else @@ -2680,9 +2942,9 @@ s390_expand_movstr (dst, src, len) mode = GET_MODE (len); if (mode == VOIDmode) - mode = word_mode; + mode = Pmode; - type = (*lang_hooks.types.type_for_mode) (mode, 1); + type = lang_hooks.types.type_for_mode (mode, 1); if (!type) abort (); @@ -2692,14 +2954,14 @@ s390_expand_movstr (dst, src, len) blocks = gen_reg_rtx (mode); convert_move (count, len, 1); - emit_cmp_and_jump_insns (count, const0_rtx, + emit_cmp_and_jump_insns (count, const0_rtx, EQ, NULL_RTX, mode, 1, end_label); emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX)); emit_move_insn (src_addr, force_operand (XEXP (src, 0), NULL_RTX)); dst = change_address (dst, VOIDmode, dst_addr); src = change_address (src, VOIDmode, src_addr); - + temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); if (temp != count) emit_move_insn (count, temp); @@ -2713,19 +2975,20 @@ s390_expand_movstr (dst, src, len) make_tree (type, blocks), make_tree (type, const0_rtx))); - emit_insn ((*gen_short) (dst, src, GEN_INT (255))); - s390_load_address (dst_addr, + emit_insn (gen_movstr_short (dst, src, GEN_INT (255))); + s390_load_address (dst_addr, gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256))); - s390_load_address (src_addr, + s390_load_address (src_addr, gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256))); - + temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); if (temp != blocks) emit_move_insn (blocks, temp); expand_end_loop (); - emit_insn ((*gen_short) (dst, src, convert_to_mode (word_mode, count, 1))); + emit_insn (gen_movstr_short (dst, src, + convert_to_mode (Pmode, count, 1))); emit_label (end_label); } } @@ -2733,37 +2996,17 @@ s390_expand_movstr (dst, src, len) /* Emit code to clear LEN bytes at DST. */ void -s390_expand_clrstr (dst, len) - rtx dst; - rtx len; +s390_expand_clrstr (rtx dst, rtx len) { - rtx (*gen_short) PARAMS ((rtx, rtx)) = - TARGET_64BIT ? gen_clrstr_short_64 : gen_clrstr_short_31; - rtx (*gen_long) PARAMS ((rtx, rtx, rtx)) = - TARGET_64BIT ? gen_clrstr_long_64 : gen_clrstr_long_31; - - if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) { if (INTVAL (len) > 0) - emit_insn ((*gen_short) (dst, GEN_INT (INTVAL (len) - 1))); + emit_insn (gen_clrstr_short (dst, GEN_INT (INTVAL (len) - 1))); } else if (TARGET_MVCLE) { - enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode; - enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode; - rtx reg0 = gen_reg_rtx (double_mode); - rtx reg1 = gen_reg_rtx (double_mode); - - emit_move_insn (gen_highpart (single_mode, reg0), - force_operand (XEXP (dst, 0), NULL_RTX)); - convert_move (gen_lowpart (single_mode, reg0), len, 1); - - emit_move_insn (gen_highpart (single_mode, reg1), const0_rtx); - emit_move_insn (gen_lowpart (single_mode, reg1), const0_rtx); - - emit_insn ((*gen_long) (reg0, reg1, reg0)); + emit_insn (gen_clrstr_long (dst, convert_to_mode (Pmode, len, 1))); } else @@ -2775,9 +3018,9 @@ s390_expand_clrstr (dst, len) mode = GET_MODE (len); if (mode == VOIDmode) - mode = word_mode; + mode = Pmode; - type = (*lang_hooks.types.type_for_mode) (mode, 1); + type = lang_hooks.types.type_for_mode (mode, 1); if (!type) abort (); @@ -2787,12 +3030,12 @@ s390_expand_clrstr (dst, len) blocks = gen_reg_rtx (mode); convert_move (count, len, 1); - emit_cmp_and_jump_insns (count, const0_rtx, + emit_cmp_and_jump_insns (count, const0_rtx, EQ, NULL_RTX, mode, 1, end_label); emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX)); dst = change_address (dst, VOIDmode, dst_addr); - + temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); if (temp != count) emit_move_insn (count, temp); @@ -2806,17 +3049,17 @@ s390_expand_clrstr (dst, len) make_tree (type, blocks), make_tree (type, const0_rtx))); - emit_insn ((*gen_short) (dst, GEN_INT (255))); - s390_load_address (dst_addr, + emit_insn (gen_clrstr_short (dst, GEN_INT (255))); + s390_load_address (dst_addr, gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (256))); - + temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); if (temp != blocks) emit_move_insn (blocks, temp); expand_end_loop (); - emit_insn ((*gen_short) (dst, convert_to_mode (word_mode, count, 1))); + emit_insn (gen_clrstr_short (dst, convert_to_mode (Pmode, count, 1))); emit_label (end_label); } } @@ -2825,17 +3068,9 @@ s390_expand_clrstr (dst, len) and return the result in TARGET. */ void -s390_expand_cmpstr (target, op0, op1, len) - rtx target; - rtx op0; - rtx op1; - rtx len; -{ - rtx (*gen_short) PARAMS ((rtx, rtx, rtx)) = - TARGET_64BIT ? gen_cmpstr_short_64 : gen_cmpstr_short_31; - rtx (*gen_long) PARAMS ((rtx, rtx, rtx, rtx)) = - TARGET_64BIT ? gen_cmpstr_long_64 : gen_cmpstr_long_31; - rtx (*gen_result) PARAMS ((rtx)) = +s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) +{ + rtx (*gen_result) (rtx) = GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si; op0 = protect_from_queue (op0, 0); @@ -2846,8 +3081,8 @@ s390_expand_cmpstr (target, op0, op1, len) { if (INTVAL (len) > 0) { - emit_insn ((*gen_short) (op0, op1, GEN_INT (INTVAL (len) - 1))); - emit_insn ((*gen_result) (target)); + emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1))); + emit_insn (gen_result (target)); } else emit_move_insn (target, const0_rtx); @@ -2855,21 +3090,8 @@ s390_expand_cmpstr (target, op0, op1, len) else /* if (TARGET_MVCLE) */ { - enum machine_mode double_mode = TARGET_64BIT ? TImode : DImode; - enum machine_mode single_mode = TARGET_64BIT ? DImode : SImode; - rtx reg0 = gen_reg_rtx (double_mode); - rtx reg1 = gen_reg_rtx (double_mode); - - emit_move_insn (gen_highpart (single_mode, reg0), - force_operand (XEXP (op0, 0), NULL_RTX)); - emit_move_insn (gen_highpart (single_mode, reg1), - force_operand (XEXP (op1, 0), NULL_RTX)); - - convert_move (gen_lowpart (single_mode, reg0), len, 1); - convert_move (gen_lowpart (single_mode, reg1), len, 1); - - emit_insn ((*gen_long) (reg0, reg1, reg0, reg1)); - emit_insn ((*gen_result) (target)); + emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1))); + emit_insn (gen_result (target)); } #if 0 @@ -2884,9 +3106,9 @@ s390_expand_cmpstr (target, op0, op1, len) mode = GET_MODE (len); if (mode == VOIDmode) - mode = word_mode; + mode = Pmode; - type = (*lang_hooks.types.type_for_mode) (mode, 1); + type = lang_hooks.types.type_for_mode (mode, 1); if (!type) abort (); @@ -2896,14 +3118,14 @@ s390_expand_cmpstr (target, op0, op1, len) blocks = gen_reg_rtx (mode); convert_move (count, len, 1); - emit_cmp_and_jump_insns (count, const0_rtx, + emit_cmp_and_jump_insns (count, const0_rtx, EQ, NULL_RTX, mode, 1, end_label); emit_move_insn (addr0, force_operand (XEXP (op0, 0), NULL_RTX)); emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX)); op0 = change_address (op0, VOIDmode, addr0); op1 = change_address (op1, VOIDmode, addr1); - + temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0); if (temp != count) emit_move_insn (count, temp); @@ -2917,39 +3139,60 @@ s390_expand_cmpstr (target, op0, op1, len) make_tree (type, blocks), make_tree (type, const0_rtx))); - emit_insn ((*gen_short) (op0, op1, GEN_INT (255))); + emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255))); temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx); - temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp, + temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp, gen_rtx_LABEL_REF (VOIDmode, end_label), pc_rtx); temp = gen_rtx_SET (VOIDmode, pc_rtx, temp); emit_jump_insn (temp); - s390_load_address (addr0, + s390_load_address (addr0, gen_rtx_PLUS (Pmode, addr0, GEN_INT (256))); - s390_load_address (addr1, + s390_load_address (addr1, gen_rtx_PLUS (Pmode, addr1, GEN_INT (256))); - + temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, 0); if (temp != blocks) emit_move_insn (blocks, temp); expand_end_loop (); - emit_insn ((*gen_short) (op0, op1, convert_to_mode (word_mode, count, 1))); + emit_insn (gen_cmpmem_short (op0, op1, + convert_to_mode (Pmode, count, 1))); emit_label (end_label); - emit_insn ((*gen_result) (target)); + emit_insn (gen_result (target)); } #endif } +/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL. + We need to emit DTP-relative relocations. */ + +void +s390_output_dwarf_dtprel (FILE *file, int size, rtx x) +{ + switch (size) + { + case 4: + fputs ("\t.long\t", file); + break; + case 8: + fputs ("\t.quad\t", file); + break; + default: + abort (); + } + output_addr_const (file, x); + fputs ("@DTPOFF", file); +} + /* In the name of slightly smaller debug output, and to cater to general assembler losage, recognize various UNSPEC sequences and turn them back into a direct symbol reference. */ -rtx -s390_simplify_dwarf_addr (orig_x) - rtx orig_x; +static rtx +s390_delegitimize_address (rtx orig_x) { rtx x = orig_x, y; @@ -2964,7 +3207,7 @@ s390_simplify_dwarf_addr (orig_x) { y = XEXP (XEXP (x, 1), 0); if (GET_CODE (y) == UNSPEC - && XINT (y, 1) == 110) + && XINT (y, 1) == UNSPEC_GOT) return XVECEXP (y, 0, 0); return orig_x; } @@ -2973,19 +3216,53 @@ s390_simplify_dwarf_addr (orig_x) { y = XEXP (x, 0); if (GET_CODE (y) == UNSPEC - && XINT (y, 1) == 111) + && XINT (y, 1) == UNSPEC_GOTENT) return XVECEXP (y, 0, 0); return orig_x; } - return orig_x; + return orig_x; +} + +/* Output shift count operand OP to stdio stream FILE. */ + +static void +print_shift_count_operand (FILE *file, rtx op) +{ + HOST_WIDE_INT offset = 0; + + /* We can have an integer constant, an address register, + or a sum of the two. */ + if (GET_CODE (op) == CONST_INT) + { + offset = INTVAL (op); + op = NULL_RTX; + } + if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) + { + offset = INTVAL (XEXP (op, 1)); + op = XEXP (op, 0); + } + while (op && GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + /* Sanity check. */ + if (op && (GET_CODE (op) != REG + || REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO_REG_CLASS (REGNO (op)) != ADDR_REGS)) + abort (); + + /* Shift counts are truncated to the low six bits anyway. */ + fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & 63); + if (op) + fprintf (file, "(%s)", reg_names[REGNO (op)]); } /* Locate some local-dynamic symbol still in use by this function so that we can print its name in local-dynamic base patterns. */ static const char * -get_some_local_dynamic_name () +get_some_local_dynamic_name (void) { rtx insn; @@ -3001,9 +3278,7 @@ get_some_local_dynamic_name () } static int -get_some_local_dynamic_name_1 (px, data) - rtx *px; - void *data ATTRIBUTE_UNUSED; +get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) { rtx x = *px; @@ -3023,13 +3298,11 @@ get_some_local_dynamic_name_1 (px, data) return 0; } -/* Output symbolic constant X in assembler syntax to +/* Output symbolic constant X in assembler syntax to stdio stream FILE. */ void -s390_output_symbolic_const (file, x) - FILE *file; - rtx x; +s390_output_symbolic_const (FILE *file, rtx x) { switch (GET_CODE (x)) { @@ -3063,37 +3336,25 @@ s390_output_symbolic_const (file, x) output_operand_lossage ("invalid UNSPEC as operand (1)"); switch (XINT (x, 1)) { - case 100: - case 104: - s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "-"); - s390_output_symbolic_const (file, cfun->machine->literal_pool_label); - break; - case 105: - s390_output_symbolic_const (file, cfun->machine->literal_pool_label); - fprintf (file, "-"); - s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); - break; - case 110: - s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@GOT12"); - break; - case 111: + case UNSPEC_GOTENT: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOTENT"); break; - case 112: + case UNSPEC_GOT: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOT"); break; - case 113: + case UNSPEC_GOTOFF: + s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); + fprintf (file, "@GOTOFF"); + break; + case UNSPEC_PLT: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@PLT"); break; - case 114: + case UNSPEC_PLTOFF: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@PLT-"); - s390_output_symbolic_const (file, cfun->machine->literal_pool_label); + fprintf (file, "@PLTOFF"); break; case UNSPEC_TLSGD: s390_output_symbolic_const (file, XVECEXP (x, 0, 0)); @@ -3131,13 +3392,11 @@ s390_output_symbolic_const (file, x) } } -/* Output address operand ADDR in assembler syntax to +/* Output address operand ADDR in assembler syntax to stdio stream FILE. */ void -print_operand_address (file, addr) - FILE *file; - rtx addr; +print_operand_address (FILE *file, rtx addr) { struct s390_address ad; @@ -3145,7 +3404,7 @@ print_operand_address (file, addr) || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base)) || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx))) output_operand_lossage ("Cannot decompose address."); - + if (ad.disp) s390_output_symbolic_const (file, ad.disp); else @@ -3158,8 +3417,8 @@ print_operand_address (file, addr) fprintf (file, "(%s)", reg_names[REGNO (ad.base)]); } -/* Output operand X in assembler syntax to stdio stream FILE. - CODE specified the format flag. The following format flags +/* Output operand X in assembler syntax to stdio stream FILE. + CODE specified the format flag. The following format flags are recognized: 'C': print opcode suffix for branch condition. @@ -3169,16 +3428,16 @@ print_operand_address (file, addr) 'R': print only the base register of a memory reference. 'N': print the second word of a DImode operand. 'M': print the second word of a TImode operand. + 'Y': print shift count operand. 'b': print integer X as if it's an unsigned byte. 'x': print integer X as if it's an unsigned word. - 'h': print integer X as if it's a signed word. */ + 'h': print integer X as if it's a signed word. + 'i': print the first nonzero HImode part of X. + 'j': print the first HImode part unequal to 0xffff of X. */ void -print_operand (file, x, code) - FILE *file; - rtx x; - int code; +print_operand (FILE *file, rtx x, int code) { switch (code) { @@ -3261,6 +3520,10 @@ print_operand (file, x, code) else abort (); break; + + case 'Y': + print_shift_count_operand (file, x); + return; } switch (GET_CODE (x)) @@ -3287,6 +3550,12 @@ print_operand (file, x, code) fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff); else if (code == 'h') fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xffff) ^ 0x8000) - 0x8000); + else if (code == 'i') + fprintf (file, HOST_WIDE_INT_PRINT_DEC, + s390_extract_part (x, HImode, 0)); + else if (code == 'j') + fprintf (file, HOST_WIDE_INT_PRINT_DEC, + s390_extract_part (x, HImode, -1)); else fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); break; @@ -3315,44 +3584,35 @@ print_operand (file, x, code) handle values smaller than INT_MIN when printed in decimal. */ static bool -s390_assemble_integer (x, size, aligned_p) - rtx x; - unsigned int size; - int aligned_p; +s390_assemble_integer (rtx x, unsigned int size, int aligned_p) { if (size == 8 && aligned_p && GET_CODE (x) == CONST_INT && INTVAL (x) < INT_MIN) { - fputs ("\t.quad\t", asm_out_file); - fprintf (asm_out_file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x)); - putc ('\n', asm_out_file); + fprintf (asm_out_file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n", + INTVAL (x)); return true; } return default_assemble_integer (x, size, aligned_p); } - -#define DEBUG_SCHED 0 - -/* Returns true if register REGNO is used for forming +/* Returns true if register REGNO is used for forming a memory address in expression X. */ static int -reg_used_in_mem_p (regno, x) - int regno; - rtx x; +reg_used_in_mem_p (int regno, rtx x) { enum rtx_code code = GET_CODE (x); int i, j; const char *fmt; - + if (code == MEM) { if (refers_to_regno_p (regno, regno+1, XEXP (x, 0), 0)) return 1; } - else if (code == SET + else if (code == SET && GET_CODE (SET_DEST (x)) == PC) { if (refers_to_regno_p (regno, regno+1, @@ -3366,7 +3626,7 @@ reg_used_in_mem_p (regno, x) if (fmt[i] == 'e' && reg_used_in_mem_p (regno, XEXP (x, i))) return 1; - + else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) if (reg_used_in_mem_p (regno, XVECEXP (x, i, j))) @@ -3378,13 +3638,14 @@ reg_used_in_mem_p (regno, x) /* Returns true if expression DEP_RTX sets an address register used by instruction INSN to address memory. */ -static int -addr_generation_dependency_p (dep_rtx, insn) - rtx dep_rtx; - rtx insn; +static int +addr_generation_dependency_p (rtx dep_rtx, rtx insn) { rtx target, pat; + if (GET_CODE (dep_rtx) == INSN) + dep_rtx = PATTERN (dep_rtx); + if (GET_CODE (dep_rtx) == SET) { target = SET_DEST (dep_rtx); @@ -3397,7 +3658,7 @@ addr_generation_dependency_p (dep_rtx, insn) { int regno = REGNO (target); - if (get_attr_type (insn) == TYPE_LA) + if (s390_safe_attr_type (insn) == TYPE_LA) { pat = PATTERN (insn); if (GET_CODE (pat) == PARALLEL) @@ -3411,31 +3672,48 @@ addr_generation_dependency_p (dep_rtx, insn) else abort(); } - else if (get_attr_atype (insn) == ATYPE_MEM) + else if (get_attr_atype (insn) == ATYPE_AGEN) return reg_used_in_mem_p (regno, PATTERN (insn)); } } return 0; } +/* Return 1, if dep_insn sets register used in insn in the agen unit. */ + +int +s390_agen_dep_p (rtx dep_insn, rtx insn) +{ + rtx dep_rtx = PATTERN (dep_insn); + int i; + + if (GET_CODE (dep_rtx) == SET + && addr_generation_dependency_p (dep_rtx, insn)) + return 1; + else if (GET_CODE (dep_rtx) == PARALLEL) + { + for (i = 0; i < XVECLEN (dep_rtx, 0); i++) + { + if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn)) + return 1; + } + } + return 0; +} /* Return the modified cost of the dependency of instruction INSN - on instruction DEP_INSN through the link LINK. COST is the + on instruction DEP_INSN through the link LINK. COST is the default cost of that dependency. Data dependencies are all handled without delay. However, if a - register is modified and subsequently used as base or index + register is modified and subsequently used as base or index register of a memory reference, at least 4 cycles need to pass - between setting and using the register to avoid pipeline stalls. + between setting and using the register to avoid pipeline stalls. An exception is the LA instruction. An address generated by LA can be used by introducing only a one cycle stall on the pipeline. */ static int -s390_adjust_cost (insn, link, dep_insn, cost) - rtx insn; - rtx link; - rtx dep_insn; - int cost; +s390_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) { rtx dep_rtx; int i; @@ -3451,100 +3729,117 @@ s390_adjust_cost (insn, link, dep_insn, cost) if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) return cost; + /* DFA based scheduling checks address dependency in md file. */ + if (s390_use_dfa_pipeline_interface ()) + { + /* Operand forward in case of lr, load and la. */ + if (s390_tune == PROCESSOR_2084_Z990 + && cost == 1 + && (s390_safe_attr_type (dep_insn) == TYPE_LA + || s390_safe_attr_type (dep_insn) == TYPE_LR + || s390_safe_attr_type (dep_insn) == TYPE_LOAD)) + return 0; + return cost; + } + dep_rtx = PATTERN (dep_insn); - if (GET_CODE (dep_rtx) == SET) - { - if (addr_generation_dependency_p (dep_rtx, insn)) - { - cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; - if (DEBUG_SCHED) - { - fprintf (stderr, "\n\nAddress dependency detected: cost %d\n", - cost); - debug_rtx (dep_insn); - debug_rtx (insn); - } - } - } + if (GET_CODE (dep_rtx) == SET + && addr_generation_dependency_p (dep_rtx, insn)) + cost += (s390_safe_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; else if (GET_CODE (dep_rtx) == PARALLEL) { for (i = 0; i < XVECLEN (dep_rtx, 0); i++) { - if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), - insn)) - { - cost += (get_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; - if (DEBUG_SCHED) - { - fprintf (stderr, "\n\nAddress dependency detected: cost %d\n" - ,cost); - debug_rtx (dep_insn); - debug_rtx (insn); - } - } + if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn)) + cost += (s390_safe_attr_type (dep_insn) == TYPE_LA) ? 1 : 4; } } return cost; } - - /* A C statement (sans semicolon) to update the integer scheduling priority - INSN_PRIORITY (INSN). Reduce the priority to execute the INSN earlier, - increase the priority to execute INSN later. Do not define this macro if - you do not need to adjust the scheduling priorities of insns. + INSN_PRIORITY (INSN). Increase the priority to execute the INSN earlier, + reduce the priority to execute INSN later. Do not define this macro if + you do not need to adjust the scheduling priorities of insns. - A LA instruction maybe scheduled later, since the pipeline bypasses the - calculated value. */ + A STD instruction should be scheduled earlier, + in order to use the bypass. */ static int -s390_adjust_priority (insn, priority) - rtx insn ATTRIBUTE_UNUSED; - int priority; +s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority) { if (! INSN_P (insn)) return priority; - if (GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER) + if (s390_tune != PROCESSOR_2084_Z990) return priority; - - switch (get_attr_type (insn)) + + switch (s390_safe_attr_type (insn)) { - default: - break; - - case TYPE_LA: - if (priority >= 0 && priority < 0x01000000) - priority <<= 3; - break; - case TYPE_LM: - /* LM in epilogue should never be scheduled. This - is due to literal access done in function body. - The usage of register 13 is not mentioned explicitly, - leading to scheduling 'LM' accross this instructions. - */ - priority = 0x7fffffff; - break; + case TYPE_FSTORED: + case TYPE_FSTORES: + priority = priority << 3; + break; + case TYPE_STORE: + priority = priority << 1; + break; + default: + break; } - return priority; } +/* The number of instructions that can be issued per cycle. */ + +static int +s390_issue_rate (void) +{ + if (s390_tune == PROCESSOR_2084_Z990) + return 3; + return 1; +} + +/* If the following function returns TRUE, we will use the the DFA + insn scheduler. */ + +static int +s390_use_dfa_pipeline_interface (void) +{ + if (s390_tune == PROCESSOR_2064_Z900 + || s390_tune == PROCESSOR_2084_Z990) + return 1; + + return 0; +} + +static int +s390_first_cycle_multipass_dfa_lookahead (void) +{ + return s390_use_dfa_pipeline_interface () ? 4 : 0; +} + +/* Called after issuing each insn. + Triggers default sort algorithm to better slot instructions. */ + +static int +s390_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED, + int sched_verbose ATTRIBUTE_UNUSED, + rtx *ready ATTRIBUTE_UNUSED, + int *pn_ready ATTRIBUTE_UNUSED, + int clock_var ATTRIBUTE_UNUSED) +{ + return s390_issue_rate(); +} -/* Split all branches that exceed the maximum distance. - Returns true if this created a new literal pool entry. - Code generated by this routine is allowed to use - TEMP_REG as temporary scratch register. If this is - done, TEMP_USED is set to true. */ +/* Split all branches that exceed the maximum distance. + Returns true if this created a new literal pool entry. */ -static int -s390_split_branches (temp_reg, temp_used) - rtx temp_reg; - bool *temp_used; +static int +s390_split_branches (void) { + rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); int new_literal = 0; rtx insn, pat, tmp, target; rtx *label; @@ -3566,15 +3861,15 @@ s390_split_branches (temp_reg, temp_used) if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx) continue; - if (GET_CODE (SET_SRC (pat)) == LABEL_REF) + if (GET_CODE (SET_SRC (pat)) == LABEL_REF) { label = &SET_SRC (pat); - } - else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) + } + else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) { - if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF) + if (GET_CODE (XEXP (SET_SRC (pat), 1)) == LABEL_REF) label = &XEXP (SET_SRC (pat), 1); - else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF) + else if (GET_CODE (XEXP (SET_SRC (pat), 2)) == LABEL_REF) label = &XEXP (SET_SRC (pat), 2); else continue; @@ -3582,19 +3877,14 @@ s390_split_branches (temp_reg, temp_used) else continue; - if (get_attr_length (insn) <= (TARGET_64BIT ? 6 : 4)) + if (get_attr_length (insn) <= 4) continue; - *temp_used = 1; - - if (TARGET_64BIT) - { - tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, *label), insn); - INSN_ADDRESSES_NEW (tmp, -1); + /* We are going to use the return register as scratch register, + make sure it will be saved/restored by the prologue/epilogue. */ + cfun->machine->save_return_addr_p = 1; - target = temp_reg; - } - else if (!flag_pic) + if (!flag_pic) { new_literal = 1; tmp = force_const_mem (Pmode, *label); @@ -3606,14 +3896,16 @@ s390_split_branches (temp_reg, temp_used) else { new_literal = 1; - tmp = gen_rtx_UNSPEC (SImode, gen_rtvec (1, *label), 104); - tmp = gen_rtx_CONST (SImode, tmp); - tmp = force_const_mem (SImode, tmp); - tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn); + target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, *label), + UNSPEC_LTREL_OFFSET); + target = gen_rtx_CONST (Pmode, target); + target = force_const_mem (Pmode, target); + tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, target), insn); INSN_ADDRESSES_NEW (tmp, -1); - target = gen_rtx_REG (Pmode, BASE_REGISTER); - target = gen_rtx_PLUS (Pmode, target, temp_reg); + target = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (target, 0)), + UNSPEC_LTREL_BASE); + target = gen_rtx_PLUS (Pmode, temp_reg, target); } if (!validate_change (insn, label, target, 0)) @@ -3624,22 +3916,29 @@ s390_split_branches (temp_reg, temp_used) } -/* Find a literal pool symbol referenced in RTX X, and store - it at REF. Will abort if X contains references to more than +/* Find a literal pool symbol referenced in RTX X, and store + it at REF. Will abort if X contains references to more than one such pool symbol; multiple references to the same symbol - are allowed, however. + are allowed, however. - The rtx pointed to by REF must be initialized to NULL_RTX + The rtx pointed to by REF must be initialized to NULL_RTX by the caller before calling this routine. */ static void -find_constant_pool_ref (x, ref) - rtx x; - rtx *ref; +find_constant_pool_ref (rtx x, rtx *ref) { int i, j; const char *fmt; + /* Ignore LTREL_BASE references. */ + if (GET_CODE (x) == UNSPEC + && XINT (x, 1) == UNSPEC_LTREL_BASE) + return; + /* Likewise POOL_ENTRY insns. */ + if (GET_CODE (x) == UNSPEC_VOLATILE + && XINT (x, 1) == UNSPECV_POOL_ENTRY) + return; + if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) { @@ -3668,10 +3967,7 @@ find_constant_pool_ref (x, ref) in X by the address ADDR. Fix up MEMs as required. */ static void -replace_constant_pool_ref (x, ref, addr) - rtx *x; - rtx ref; - rtx addr; +replace_constant_pool_ref (rtx *x, rtx ref, rtx addr) { int i, j; const char *fmt; @@ -3738,135 +4034,55 @@ replace_constant_pool_ref (x, ref, addr) } } -/* Check whether ADDR is an address that uses the base register, - without actually constituting a literal pool access. (This happens - in 31-bit PIC mode, where the base register is used as anchor for - relative addressing of local symbols.) - - Returns 1 if the base register occupies the base slot, - returns 2 if the base register occupies the index slot, - returns 0 if the address is not of this form. */ - -static int -find_base_register_in_addr (addr) - struct s390_address *addr; -{ - /* If DISP is complex, we might have a literal pool reference. */ - if (addr->disp && GET_CODE (addr->disp) != CONST_INT) - return 0; - - if (addr->base && REG_P (addr->base) && REGNO (addr->base) == BASE_REGISTER) - return 1; - - if (addr->indx && REG_P (addr->indx) && REGNO (addr->indx) == BASE_REGISTER) - return 2; +/* Check whether X contains an UNSPEC_LTREL_BASE. + Return its constant pool symbol if found, NULL_RTX otherwise. */ - return 0; -} - -/* Return true if X contains an address that uses the base register, - without actually constituting a literal pool access. */ - -static bool -find_base_register_ref (x) - rtx x; +static rtx +find_ltrel_base (rtx x) { - bool retv = FALSE; - struct s390_address addr; int i, j; const char *fmt; - /* Addresses can only occur inside a MEM ... */ - if (GET_CODE (x) == MEM) - { - if (s390_decompose_address (XEXP (x, 0), &addr) - && find_base_register_in_addr (&addr)) - return TRUE; - } - - /* ... or a load-address type pattern. */ - if (GET_CODE (x) == SET && GET_CODE (SET_DEST (x)) == REG) - { - if (s390_decompose_address (SET_SRC (x), &addr) - && find_base_register_in_addr (&addr)) - return TRUE; - } + if (GET_CODE (x) == UNSPEC + && XINT (x, 1) == UNSPEC_LTREL_BASE) + return XVECEXP (x, 0, 0); fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { if (fmt[i] == 'e') { - retv |= find_base_register_ref (XEXP (x, i)); + rtx fnd = find_ltrel_base (XEXP (x, i)); + if (fnd) + return fnd; } else if (fmt[i] == 'E') { for (j = 0; j < XVECLEN (x, i); j++) - retv |= find_base_register_ref (XVECEXP (x, i, j)); + { + rtx fnd = find_ltrel_base (XVECEXP (x, i, j)); + if (fnd) + return fnd; + } } } - return retv; + return NULL_RTX; } -/* If X contains an address that uses the base register, - without actually constituting a literal pool access, - replace the base register with REPL in all such cases. - - Handles both MEMs and load address patterns. */ +/* Replace any occurrence of UNSPEC_LTREL_BASE in X with BASE. */ static void -replace_base_register_ref (x, repl) - rtx *x; - rtx repl; +replace_ltrel_base (rtx *x, rtx base) { - struct s390_address addr; - rtx new_addr; - int i, j, pos; + int i, j; const char *fmt; - /* Addresses can only occur inside a MEM ... */ - if (GET_CODE (*x) == MEM) - { - if (s390_decompose_address (XEXP (*x, 0), &addr) - && (pos = find_base_register_in_addr (&addr))) - { - if (pos == 1) - addr.base = repl; - else - addr.indx = repl; - - new_addr = addr.base; - if (addr.indx) - new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx); - if (addr.disp) - new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp); - - *x = replace_equiv_address (*x, new_addr); - return; - } - } - - /* ... or a load-address type pattern. */ - if (GET_CODE (*x) == SET && GET_CODE (SET_DEST (*x)) == REG) + if (GET_CODE (*x) == UNSPEC + && XINT (*x, 1) == UNSPEC_LTREL_BASE) { - if (s390_decompose_address (SET_SRC (*x), &addr) - && (pos = find_base_register_in_addr (&addr))) - { - if (pos == 1) - addr.base = repl; - else - addr.indx = repl; - - new_addr = addr.base; - if (addr.indx) - new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.indx); - if (addr.disp) - new_addr = gen_rtx_PLUS (Pmode, new_addr, addr.disp); - - SET_SRC (*x) = new_addr; - return; - } + *x = base; + return; } fmt = GET_RTX_FORMAT (GET_CODE (*x)); @@ -3874,37 +4090,30 @@ replace_base_register_ref (x, repl) { if (fmt[i] == 'e') { - replace_base_register_ref (&XEXP (*x, i), repl); + replace_ltrel_base (&XEXP (*x, i), base); } else if (fmt[i] == 'E') { for (j = 0; j < XVECLEN (*x, i); j++) - replace_base_register_ref (&XVECEXP (*x, i, j), repl); + replace_ltrel_base (&XVECEXP (*x, i, j), base); } } } -/* We keep a list of constants we which we have to add to internal +/* We keep a list of constants which we have to add to internal constant tables in the middle of large functions. */ -#define NR_C_MODES 6 -enum machine_mode constant_modes[NR_C_MODES] = +#define NR_C_MODES 7 +enum machine_mode constant_modes[NR_C_MODES] = { + TImode, DFmode, DImode, SFmode, SImode, HImode, QImode }; -rtx (*gen_consttable[NR_C_MODES])(rtx) = -{ - gen_consttable_df, gen_consttable_di, - gen_consttable_sf, gen_consttable_si, - gen_consttable_hi, - gen_consttable_qi -}; - struct constant { struct constant *next; @@ -3922,45 +4131,36 @@ struct constant_pool struct constant *constants[NR_C_MODES]; rtx label; int size; - bool anchor; }; -static struct constant_pool * s390_chunkify_start PARAMS ((rtx, bool *)); -static void s390_chunkify_finish PARAMS ((struct constant_pool *, rtx)); -static void s390_chunkify_cancel PARAMS ((struct constant_pool *)); +static struct constant_pool * s390_mainpool_start (void); +static void s390_mainpool_finish (struct constant_pool *, rtx base_reg); +static void s390_mainpool_cancel (struct constant_pool *); + +static struct constant_pool * s390_chunkify_start (rtx base_reg); +static void s390_chunkify_finish (struct constant_pool *, rtx base_reg); +static void s390_chunkify_cancel (struct constant_pool *); -static struct constant_pool *s390_start_pool PARAMS ((struct constant_pool **, rtx)); -static void s390_end_pool PARAMS ((struct constant_pool *, rtx)); -static void s390_add_pool_insn PARAMS ((struct constant_pool *, rtx)); -static struct constant_pool *s390_find_pool PARAMS ((struct constant_pool *, rtx)); -static void s390_add_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode)); -static rtx s390_find_constant PARAMS ((struct constant_pool *, rtx, enum machine_mode)); -static void s390_add_anchor PARAMS ((struct constant_pool *)); -static rtx s390_dump_pool PARAMS ((struct constant_pool *)); -static void s390_free_pool PARAMS ((struct constant_pool *)); +static struct constant_pool *s390_start_pool (struct constant_pool **, rtx); +static void s390_end_pool (struct constant_pool *, rtx); +static void s390_add_pool_insn (struct constant_pool *, rtx); +static struct constant_pool *s390_find_pool (struct constant_pool *, rtx); +static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode); +static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode); +static rtx s390_dump_pool (struct constant_pool *, bool); +static struct constant_pool *s390_alloc_pool (void); +static void s390_free_pool (struct constant_pool *); /* Create new constant pool covering instructions starting at INSN and chain it to the end of POOL_LIST. */ static struct constant_pool * -s390_start_pool (pool_list, insn) - struct constant_pool **pool_list; - rtx insn; +s390_start_pool (struct constant_pool **pool_list, rtx insn) { struct constant_pool *pool, **prev; - int i; - pool = (struct constant_pool *) xmalloc (sizeof *pool); - pool->next = NULL; - for (i = 0; i < NR_C_MODES; i++) - pool->constants[i] = NULL; - - pool->label = gen_label_rtx (); + pool = s390_alloc_pool (); pool->first_insn = insn; - pool->pool_insn = NULL_RTX; - pool->insns = BITMAP_XMALLOC (); - pool->size = 0; - pool->anchor = FALSE; for (prev = pool_list; *prev; prev = &(*prev)->next) ; @@ -3973,9 +4173,7 @@ s390_start_pool (pool_list, insn) placeholder insn representing the pool. */ static void -s390_end_pool (pool, insn) - struct constant_pool *pool; - rtx insn; +s390_end_pool (struct constant_pool *pool, rtx insn) { rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */); @@ -3989,9 +4187,7 @@ s390_end_pool (pool, insn) /* Add INSN to the list of insns covered by POOL. */ static void -s390_add_pool_insn (pool, insn) - struct constant_pool *pool; - rtx insn; +s390_add_pool_insn (struct constant_pool *pool, rtx insn) { bitmap_set_bit (pool->insns, INSN_UID (insn)); } @@ -3999,9 +4195,7 @@ s390_add_pool_insn (pool, insn) /* Return pool out of POOL_LIST that covers INSN. */ static struct constant_pool * -s390_find_pool (pool_list, insn) - struct constant_pool *pool_list; - rtx insn; +s390_find_pool (struct constant_pool *pool_list, rtx insn) { struct constant_pool *pool; @@ -4015,10 +4209,7 @@ s390_find_pool (pool_list, insn) /* Add constant VAL of mode MODE to the constant pool POOL. */ static void -s390_add_constant (pool, val, mode) - struct constant_pool *pool; - rtx val; - enum machine_mode mode; +s390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode) { struct constant *c; int i; @@ -4047,77 +4238,55 @@ s390_add_constant (pool, val, mode) /* Find constant VAL of mode MODE in the constant pool POOL. Return an RTX describing the distance from the start of the pool to the location of the new constant. */ - + static rtx -s390_find_constant (pool, val, mode) - struct constant_pool *pool; - rtx val; - enum machine_mode mode; +s390_find_constant (struct constant_pool *pool, rtx val, + enum machine_mode mode) { struct constant *c; rtx offset; int i; - + for (i = 0; i < NR_C_MODES; i++) if (constant_modes[i] == mode) break; if (i == NR_C_MODES) abort (); - + for (c = pool->constants[i]; c != NULL; c = c->next) if (rtx_equal_p (val, c->value)) break; - + if (c == NULL) abort (); - + offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label), gen_rtx_LABEL_REF (Pmode, pool->label)); offset = gen_rtx_CONST (Pmode, offset); return offset; } -/* Set 'anchor' flag in POOL. */ - -static void -s390_add_anchor (pool) - struct constant_pool *pool; -{ - if (!pool->anchor) - { - pool->anchor = TRUE; - pool->size += 4; - } -} - -/* Dump out the constants in POOL. */ +/* Dump out the constants in POOL. If REMOTE_LABEL is true, + do not emit the pool base label. */ static rtx -s390_dump_pool (pool) - struct constant_pool *pool; +s390_dump_pool (struct constant_pool *pool, bool remote_label) { struct constant *c; rtx insn; int i; - /* Pool start insn switches to proper section + /* Pool start insn switches to proper section and guarantees necessary alignment. */ - if (TARGET_64BIT) + if (TARGET_CPU_ZARCH) insn = emit_insn_after (gen_pool_start_64 (), pool->pool_insn); else insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn); INSN_ADDRESSES_NEW (insn, -1); - insn = emit_label_after (pool->label, insn); - INSN_ADDRESSES_NEW (insn, -1); - - /* Emit anchor if we need one. */ - if (pool->anchor) + if (!remote_label) { - rtx anchor = gen_rtx_LABEL_REF (VOIDmode, pool->label); - anchor = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, anchor), 105); - anchor = gen_rtx_CONST (VOIDmode, anchor); - insn = emit_insn_after (gen_consttable_si (anchor), insn); + insn = emit_label_after (pool->label, insn); INSN_ADDRESSES_NEW (insn, -1); } @@ -4126,27 +4295,31 @@ s390_dump_pool (pool) for (i = 0; i < NR_C_MODES; i++) for (c = pool->constants[i]; c; c = c->next) { - /* Convert 104 unspecs to pool-relative references. */ + /* Convert UNSPEC_LTREL_OFFSET unspecs to pool-relative references. */ rtx value = c->value; if (GET_CODE (value) == CONST && GET_CODE (XEXP (value, 0)) == UNSPEC - && XINT (XEXP (value, 0), 1) == 104 + && XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET && XVECLEN (XEXP (value, 0), 0) == 1) { value = gen_rtx_MINUS (Pmode, XVECEXP (XEXP (value, 0), 0, 0), - gen_rtx_LABEL_REF (VOIDmode, pool->label)); + gen_rtx_LABEL_REF (VOIDmode, pool->label)); value = gen_rtx_CONST (VOIDmode, value); } insn = emit_label_after (c->label, insn); INSN_ADDRESSES_NEW (insn, -1); - insn = emit_insn_after (gen_consttable[i] (value), insn); + + value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i], + gen_rtvec (1, value), + UNSPECV_POOL_ENTRY); + insn = emit_insn_after (value, insn); INSN_ADDRESSES_NEW (insn, -1); } - /* Pool end insn switches back to previous section + /* Pool end insn switches back to previous section and guarantees necessary alignment. */ - if (TARGET_64BIT) + if (TARGET_CPU_ZARCH) insn = emit_insn_after (gen_pool_end_64 (), insn); else insn = emit_insn_after (gen_pool_end_31 (), insn); @@ -4161,11 +4334,32 @@ s390_dump_pool (pool) return insn; } +/* Allocate new constant_pool structure. */ + +static struct constant_pool * +s390_alloc_pool (void) +{ + struct constant_pool *pool; + int i; + + pool = (struct constant_pool *) xmalloc (sizeof *pool); + pool->next = NULL; + for (i = 0; i < NR_C_MODES; i++) + pool->constants[i] = NULL; + + pool->label = gen_label_rtx (); + pool->first_insn = NULL_RTX; + pool->pool_insn = NULL_RTX; + pool->insns = BITMAP_XMALLOC (); + pool->size = 0; + + return pool; +} + /* Free all memory used by POOL. */ static void -s390_free_pool (pool) - struct constant_pool *pool; +s390_free_pool (struct constant_pool *pool) { int i; @@ -4182,90 +4376,263 @@ s390_free_pool (pool) BITMAP_XFREE (pool->insns); free (pool); -} +} + + +/* Collect main literal pool. Return NULL on overflow. */ + +static struct constant_pool * +s390_mainpool_start (void) +{ + struct constant_pool *pool; + rtx insn; + + pool = s390_alloc_pool (); + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE + && XINT (PATTERN (insn), 1) == UNSPECV_MAIN_POOL) + { + if (pool->pool_insn) + abort (); + pool->pool_insn = insn; + } + + if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) + { + rtx pool_ref = NULL_RTX; + find_constant_pool_ref (PATTERN (insn), &pool_ref); + if (pool_ref) + { + rtx constant = get_pool_constant (pool_ref); + enum machine_mode mode = get_pool_mode (pool_ref); + s390_add_constant (pool, constant, mode); + } + } + } + + if (!pool->pool_insn) + abort (); + + if (pool->size >= 4096) + { + /* We're going to chunkify the pool, so remove the main + pool placeholder insn. */ + remove_insn (pool->pool_insn); + + s390_free_pool (pool); + pool = NULL; + } + + return pool; +} + +/* POOL holds the main literal pool as collected by s390_mainpool_start. + Modify the current function to output the pool constants as well as + the pool register setup instruction. BASE_REG is the register to + be used as pool base register. */ + +static void +s390_mainpool_finish (struct constant_pool *pool, rtx base_reg) +{ + rtx insn; + + /* If the pool is empty, we're done. */ + if (pool->size == 0) + { + remove_insn (pool->pool_insn); + s390_free_pool (pool); + return; + } + + /* We need correct insn addresses. */ + shorten_branches (get_insns ()); + + /* On zSeries, we use a LARL to load the pool register. The pool is + located in the .rodata section, so we emit it after the function. */ + if (TARGET_CPU_ZARCH) + { + insn = gen_main_base_64 (base_reg, pool->label); + insn = emit_insn_after (insn, pool->pool_insn); + INSN_ADDRESSES_NEW (insn, -1); + remove_insn (pool->pool_insn); + + insn = get_last_insn (); + pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); + INSN_ADDRESSES_NEW (pool->pool_insn, -1); + + s390_dump_pool (pool, 0); + } + + /* On S/390, if the total size of the function's code plus literal pool + does not exceed 4096 bytes, we use BASR to set up a function base + pointer, and emit the literal pool at the end of the function. */ + else if (INSN_ADDRESSES (INSN_UID (get_last_insn ())) + + pool->size + 8 /* alignment slop */ < 4096) + { + insn = gen_main_base_31_small (base_reg, pool->label); + insn = emit_insn_after (insn, pool->pool_insn); + INSN_ADDRESSES_NEW (insn, -1); + remove_insn (pool->pool_insn); + + insn = emit_label_after (pool->label, insn); + INSN_ADDRESSES_NEW (insn, -1); + + insn = get_last_insn (); + pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); + INSN_ADDRESSES_NEW (pool->pool_insn, -1); + + s390_dump_pool (pool, 1); + } + + /* Otherwise, we emit an inline literal pool and use BASR to branch + over it, setting up the pool register at the same time. */ + else + { + rtx pool_end = gen_label_rtx (); + + insn = gen_main_base_31_large (base_reg, pool->label, pool_end); + insn = emit_insn_after (insn, pool->pool_insn); + INSN_ADDRESSES_NEW (insn, -1); + remove_insn (pool->pool_insn); + + insn = emit_label_after (pool->label, insn); + INSN_ADDRESSES_NEW (insn, -1); + + pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn); + INSN_ADDRESSES_NEW (pool->pool_insn, -1); + + insn = emit_label_after (pool_end, pool->pool_insn); + INSN_ADDRESSES_NEW (insn, -1); + + s390_dump_pool (pool, 1); + } + + + /* Replace all literal pool references. */ + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (INSN_P (insn)) + replace_ltrel_base (&PATTERN (insn), base_reg); + + if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) + { + rtx addr, pool_ref = NULL_RTX; + find_constant_pool_ref (PATTERN (insn), &pool_ref); + if (pool_ref) + { + addr = s390_find_constant (pool, get_pool_constant (pool_ref), + get_pool_mode (pool_ref)); + addr = gen_rtx_PLUS (Pmode, base_reg, addr); + replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); + INSN_CODE (insn) = -1; + } + } + } -/* Chunkify the literal pool if required. + /* Free the pool. */ + s390_free_pool (pool); +} + +/* POOL holds the main literal pool as collected by s390_mainpool_start. + We have decided we cannot use this pool, so revert all changes + to the current function that were done by s390_mainpool_start. */ +static void +s390_mainpool_cancel (struct constant_pool *pool) +{ + /* We didn't actually change the instruction stream, so simply + free the pool memory. */ + s390_free_pool (pool); +} - Code generated by this routine is allowed to use - TEMP_REG as temporary scratch register. If this is - done, TEMP_USED is set to true. */ + +/* Chunkify the literal pool. BASE_REG is to be used as pool + register. */ #define S390_POOL_CHUNK_MIN 0xc00 #define S390_POOL_CHUNK_MAX 0xe00 -static struct constant_pool * -s390_chunkify_start (temp_reg, temp_used) - rtx temp_reg; - bool *temp_used; +static struct constant_pool * +s390_chunkify_start (rtx base_reg) { - rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER); - struct constant_pool *curr_pool = NULL, *pool_list = NULL; int extra_size = 0; bitmap far_labels; + rtx pending_ltrel = NULL_RTX; rtx insn; - rtx (*gen_reload_base) PARAMS ((rtx, rtx)) = - TARGET_64BIT? gen_reload_base_64 : gen_reload_base_31; - + rtx (*gen_reload_base) (rtx, rtx) = + TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31; - /* Do we need to chunkify the literal pool? */ - - if (get_pool_size () < S390_POOL_CHUNK_MAX) - return NULL; /* We need correct insn addresses. */ shorten_branches (get_insns ()); - /* Scan all insns and move literals to pool chunks. - Also, emit anchor reload insns before every insn that uses - the literal pool base register as anchor pointer. */ + /* Scan all insns and move literals to pool chunks. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { + /* Check for pending LTREL_BASE. */ + if (INSN_P (insn)) + { + rtx ltrel_base = find_ltrel_base (PATTERN (insn)); + if (ltrel_base) + { + if (ltrel_base == pending_ltrel) + pending_ltrel = NULL_RTX; + else + abort (); + } + } + if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) { rtx pool_ref = NULL_RTX; find_constant_pool_ref (PATTERN (insn), &pool_ref); if (pool_ref) { + rtx constant = get_pool_constant (pool_ref); + enum machine_mode mode = get_pool_mode (pool_ref); + if (!curr_pool) curr_pool = s390_start_pool (&pool_list, insn); - s390_add_constant (curr_pool, get_pool_constant (pool_ref), - get_pool_mode (pool_ref)); + s390_add_constant (curr_pool, constant, mode); s390_add_pool_insn (curr_pool, insn); - } - else if (!TARGET_64BIT && flag_pic - && find_base_register_ref (PATTERN (insn))) - { - rtx new = gen_reload_anchor (temp_reg, base_reg); - new = emit_insn_before (new, insn); - INSN_ADDRESSES_NEW (new, INSN_ADDRESSES (INSN_UID (insn))); - extra_size += 8; - *temp_used = 1; - - if (!curr_pool) - curr_pool = s390_start_pool (&pool_list, new); - - s390_add_anchor (curr_pool); - s390_add_pool_insn (curr_pool, insn); + /* Don't split the pool chunk between a LTREL_OFFSET load + and the corresponding LTREL_BASE. */ + if (GET_CODE (constant) == CONST + && GET_CODE (XEXP (constant, 0)) == UNSPEC + && XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET) + { + if (pending_ltrel) + abort (); + pending_ltrel = pool_ref; + } } } if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL) - if (curr_pool) - s390_add_pool_insn (curr_pool, insn); + { + if (curr_pool) + s390_add_pool_insn (curr_pool, insn); + /* An LTREL_BASE must follow within the same basic block. */ + if (pending_ltrel) + abort (); + } - if (!curr_pool + if (!curr_pool || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn) || INSN_ADDRESSES (INSN_UID (insn)) == -1) continue; - if (TARGET_64BIT) + if (TARGET_CPU_ZARCH) { if (curr_pool->size < S390_POOL_CHUNK_MAX) continue; @@ -4276,7 +4643,7 @@ s390_chunkify_start (temp_reg, temp_used) else { int chunk_size = INSN_ADDRESSES (INSN_UID (insn)) - - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn)) + - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn)) + extra_size; /* We will later have to insert base register reload insns. @@ -4310,13 +4677,12 @@ s390_chunkify_start (temp_reg, temp_used) if (get_attr_length (insn) == 0) continue; - /* Don't separate insns created by s390_split_branches. */ - if (GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET - && rtx_equal_p (SET_DEST (PATTERN (insn)), temp_reg)) + /* Don't separate LTREL_BASE from the corresponding + LTREL_OFFSET load. */ + if (pending_ltrel) continue; - label = gen_label_rtx (); + label = gen_label_rtx (); jump = emit_jump_insn_after (gen_jump (label), insn); barrier = emit_barrier_after (jump); insn = emit_label_after (label, barrier); @@ -4336,9 +4702,11 @@ s390_chunkify_start (temp_reg, temp_used) if (curr_pool) s390_end_pool (curr_pool, NULL_RTX); + if (pending_ltrel) + abort (); - /* Find all labels that are branched into + /* Find all labels that are branched into from an insn belonging to a different chunk. */ far_labels = BITMAP_XMALLOC (); @@ -4352,11 +4720,11 @@ s390_chunkify_start (temp_reg, temp_used) Don't do that, however, if it is the label before a jump table. */ - if (GET_CODE (insn) == CODE_LABEL + if (GET_CODE (insn) == CODE_LABEL && (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn))) { rtx vec_insn = next_real_insn (insn); - rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? + rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? PATTERN (vec_insn) : NULL_RTX; if (!vec_pat || !(GET_CODE (vec_pat) == ADDR_VEC @@ -4366,22 +4734,22 @@ s390_chunkify_start (temp_reg, temp_used) /* If we have a direct jump (conditional or unconditional) or a casesi jump, check all potential targets. */ - else if (GET_CODE (insn) == JUMP_INSN) + else if (GET_CODE (insn) == JUMP_INSN) { rtx pat = PATTERN (insn); if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2) pat = XVECEXP (pat, 0, 0); - if (GET_CODE (pat) == SET) + if (GET_CODE (pat) == SET) { rtx label = JUMP_LABEL (insn); if (label) { - if (s390_find_pool (pool_list, label) + if (s390_find_pool (pool_list, label) != s390_find_pool (pool_list, insn)) bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label)); } - } + } else if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2 && GET_CODE (XVECEXP (pat, 0, 0)) == SET @@ -4391,7 +4759,7 @@ s390_chunkify_start (temp_reg, temp_used) /* Find the jump table used by this casesi jump. */ rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0); rtx vec_insn = next_real_insn (vec_label); - rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? + rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ? PATTERN (vec_insn) : NULL_RTX; if (vec_pat && (GET_CODE (vec_pat) == ADDR_VEC @@ -4403,7 +4771,7 @@ s390_chunkify_start (temp_reg, temp_used) { rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0); - if (s390_find_pool (pool_list, label) + if (s390_find_pool (pool_list, label) != s390_find_pool (pool_list, insn)) bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label)); } @@ -4424,7 +4792,7 @@ s390_chunkify_start (temp_reg, temp_used) /* Insert base register reload insns at every far label. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CODE_LABEL + if (GET_CODE (insn) == CODE_LABEL && bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn))) { struct constant_pool *pool = s390_find_pool (pool_list, insn); @@ -4448,26 +4816,24 @@ s390_chunkify_start (temp_reg, temp_used) } /* POOL_LIST is a chunk list as prepared by s390_chunkify_start. - After we have decided to use this list, finish implementing - all changes to the current function as required. + After we have decided to use this list, finish implementing + all changes to the current function as required. BASE_REG is + to be used as pool base register. */ - Code generated by this routine is allowed to use - TEMP_REG as temporary scratch register. */ - static void -s390_chunkify_finish (pool_list, temp_reg) - struct constant_pool *pool_list; - rtx temp_reg; +s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg) { - rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER); struct constant_pool *curr_pool = NULL; rtx insn; - - + + /* Replace all literal pool references. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { + if (INSN_P (insn)) + replace_ltrel_base (&PATTERN (insn), base_reg); + curr_pool = s390_find_pool (pool_list, insn); if (!curr_pool) continue; @@ -4484,20 +4850,14 @@ s390_chunkify_finish (pool_list, temp_reg) replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); INSN_CODE (insn) = -1; } - - else if (!TARGET_64BIT && flag_pic - && find_base_register_ref (PATTERN (insn))) - { - replace_base_register_ref (&PATTERN (insn), temp_reg); - } } } /* Dump out all literal pools. */ - + for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) - s390_dump_pool (curr_pool); - + s390_dump_pool (curr_pool, 0); + /* Free pool list. */ while (pool_list) @@ -4511,10 +4871,9 @@ s390_chunkify_finish (pool_list, temp_reg) /* POOL_LIST is a chunk list as prepared by s390_chunkify_start. We have decided we cannot use this list, so revert all changes to the current function that were done by s390_chunkify_start. */ - + static void -s390_chunkify_cancel (pool_list) - struct constant_pool *pool_list; +s390_chunkify_cancel (struct constant_pool *pool_list) { struct constant_pool *curr_pool = NULL; rtx insn; @@ -4544,7 +4903,7 @@ s390_chunkify_cancel (pool_list) remove_insn (curr_pool->pool_insn); } - /* Remove all base/anchor register reload insns. */ + /* Remove all base register reload insns. */ for (insn = get_insns (); insn; ) { @@ -4553,8 +4912,7 @@ s390_chunkify_cancel (pool_list) if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC - && (XINT (SET_SRC (PATTERN (insn)), 1) == 210 - || XINT (SET_SRC (PATTERN (insn)), 1) == 211)) + && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE) remove_insn (insn); insn = next_insn; @@ -4571,98 +4929,80 @@ s390_chunkify_cancel (pool_list) } -/* Index of constant pool chunk that is currently being processed. - Set to -1 before function output has started. */ -int s390_pool_count = -1; - -/* Number of elements of current constant pool. */ -int s390_nr_constants; - -/* Output main constant pool to stdio stream FILE. */ +/* Output to FILE the constant pool entry EXP in mode MODE + with alignment ALIGN. */ void -s390_output_constant_pool (start_label, end_label) - rtx start_label; - rtx end_label; +s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode, + unsigned int align) { - if (TARGET_64BIT) - { - readonly_data_section (); - ASM_OUTPUT_ALIGN (asm_out_file, 3); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", - CODE_LABEL_NUMBER (start_label)); - } - else - { - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", - CODE_LABEL_NUMBER (start_label)); - ASM_OUTPUT_ALIGN (asm_out_file, 2); - } + REAL_VALUE_TYPE r; - s390_pool_count = 0; - output_constant_pool (current_function_name, current_function_decl); - s390_pool_count = -1; - if (TARGET_64BIT) - function_section (current_function_decl); - else + switch (GET_MODE_CLASS (mode)) { - ASM_OUTPUT_ALIGN (asm_out_file, 1); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (end_label)); + case MODE_FLOAT: + if (GET_CODE (exp) != CONST_DOUBLE) + abort (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, exp); + assemble_real (r, mode, align); + break; + + case MODE_INT: + if (GET_CODE (exp) == CONST + || GET_CODE (exp) == SYMBOL_REF + || GET_CODE (exp) == LABEL_REF) + { + fputs (integer_asm_op (GET_MODE_SIZE (mode), TRUE), file); + s390_output_symbolic_const (file, exp); + fputc ('\n', file); + } + else + { + assemble_integer (exp, GET_MODE_SIZE (mode), align, 1); + } + break; + + default: + abort (); } } + /* Rework the prolog/epilog to avoid saving/restoring - registers unnecessarily. If TEMP_REGNO is nonnegative, - it specifies the number of a caller-saved register used - as temporary scratch register by code emitted during - machine dependent reorg. */ + registers unnecessarily. BASE_USED specifies whether + the literal pool base register needs to be saved. */ static void -s390_optimize_prolog (temp_regno) - int temp_regno; +s390_optimize_prolog (bool base_used) { int save_first, save_last, restore_first, restore_last; int i, j; rtx insn, new_insn, next_insn; /* Recompute regs_ever_live data for special registers. */ - regs_ever_live[BASE_REGISTER] = 0; - regs_ever_live[RETURN_REGNUM] = 0; + regs_ever_live[BASE_REGISTER] = base_used; + regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p; regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; - /* If there is (possibly) any pool entry, we need to - load the base register. - ??? FIXME: this should be more precise. */ - if (get_pool_size ()) - regs_ever_live[BASE_REGISTER] = 1; - - /* In non-leaf functions, the prolog/epilog code relies - on RETURN_REGNUM being saved in any case. */ - if (!current_function_is_leaf) - regs_ever_live[RETURN_REGNUM] = 1; - - /* We need to save/restore the temporary register. */ - if (temp_regno >= 0) - regs_ever_live[temp_regno] = 1; - /* Find first and last gpr to be saved. */ - + for (i = 6; i < 16; i++) if (regs_ever_live[i]) if (!global_regs[i] - || i == STACK_POINTER_REGNUM + || i == STACK_POINTER_REGNUM || i == RETURN_REGNUM - || i == BASE_REGISTER + || i == BASE_REGISTER || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) break; for (j = 15; j > i; j--) if (regs_ever_live[j]) if (!global_regs[j] - || j == STACK_POINTER_REGNUM + || j == STACK_POINTER_REGNUM || j == RETURN_REGNUM - || j == BASE_REGISTER + || j == BASE_REGISTER || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM)) break; @@ -4691,7 +5031,7 @@ s390_optimize_prolog (temp_regno) /* If all special registers are in fact used, there's nothing we can do, so no point in walking the insn list. */ if (i <= BASE_REGISTER && j >= BASE_REGISTER - && i <= RETURN_REGNUM && j >= RETURN_REGNUM) + && (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM))) return; @@ -4706,10 +5046,9 @@ s390_optimize_prolog (temp_regno) if (GET_CODE (insn) != INSN) continue; - if (GET_CODE (PATTERN (insn)) != PARALLEL) - continue; - if (store_multiple_operation (PATTERN (insn), VOIDmode)) + if (GET_CODE (PATTERN (insn)) == PARALLEL + && store_multiple_operation (PATTERN (insn), VOIDmode)) { set = XVECEXP (PATTERN (insn), 0, 0); first = REGNO (SET_SRC (set)); @@ -4720,9 +5059,31 @@ s390_optimize_prolog (temp_regno) if (GET_CODE (base) != REG || off < 0) continue; - if (first > BASE_REGISTER && first > RETURN_REGNUM) + if (first > BASE_REGISTER || last < BASE_REGISTER) continue; - if (last < BASE_REGISTER && last < RETURN_REGNUM) + + if (save_first != -1) + { + new_insn = save_gprs (base, off, save_first, save_last); + new_insn = emit_insn_before (new_insn, insn); + INSN_ADDRESSES_NEW (new_insn, -1); + } + + remove_insn (insn); + continue; + } + + if (GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_SRC (PATTERN (insn))) == REG + && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGISTER + && GET_CODE (SET_DEST (PATTERN (insn))) == MEM) + { + set = PATTERN (insn); + offset = const0_rtx; + base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); + off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD; + + if (GET_CODE (base) != REG || off < 0) continue; if (save_first != -1) @@ -4733,9 +5094,11 @@ s390_optimize_prolog (temp_regno) } remove_insn (insn); + continue; } - if (load_multiple_operation (PATTERN (insn), VOIDmode)) + if (GET_CODE (PATTERN (insn)) == PARALLEL + && load_multiple_operation (PATTERN (insn), VOIDmode)) { set = XVECEXP (PATTERN (insn), 0, 0); first = REGNO (SET_DEST (set)); @@ -4746,9 +5109,7 @@ s390_optimize_prolog (temp_regno) if (GET_CODE (base) != REG || off < 0) continue; - if (first > BASE_REGISTER && first > RETURN_REGNUM) - continue; - if (last < BASE_REGISTER && last < RETURN_REGNUM) + if (first > BASE_REGISTER || last < BASE_REGISTER) continue; if (restore_first != -1) @@ -4759,103 +5120,80 @@ s390_optimize_prolog (temp_regno) } remove_insn (insn); + continue; } - } -} - -/* Check whether any insn in the function makes use of the original - value of RETURN_REG (e.g. for __builtin_return_address). - If so, insert an insn reloading that value. - - Return true if any such insn was found. */ - -static bool -s390_fixup_clobbered_return_reg (return_reg) - rtx return_reg; -{ - bool replacement_done = 0; - rtx insn; - - /* If we never called __builtin_return_address, register 14 - might have been used as temp during the prolog; we do - not want to touch those uses. */ - if (!has_hard_reg_initial_val (Pmode, REGNO (return_reg))) - return false; - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - rtx reg, off, new_insn; + if (GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_DEST (PATTERN (insn))) == REG + && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGISTER + && GET_CODE (SET_SRC (PATTERN (insn))) == MEM) + { + set = PATTERN (insn); + offset = const0_rtx; + base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); + off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD; - if (GET_CODE (insn) != INSN) - continue; - if (!reg_referenced_p (return_reg, PATTERN (insn))) - continue; - if (GET_CODE (PATTERN (insn)) == PARALLEL - && store_multiple_operation (PATTERN (insn), VOIDmode)) - continue; + if (GET_CODE (base) != REG || off < 0) + continue; - if (frame_pointer_needed) - reg = hard_frame_pointer_rtx; - else - reg = stack_pointer_rtx; + if (restore_first != -1) + { + new_insn = restore_gprs (base, off, restore_first, restore_last); + new_insn = emit_insn_before (new_insn, insn); + INSN_ADDRESSES_NEW (new_insn, -1); + } - off = GEN_INT (cfun->machine->frame_size + REGNO (return_reg) * UNITS_PER_WORD); - if (INTVAL (off) >= 4096) - { - off = force_const_mem (Pmode, off); - new_insn = gen_rtx_SET (Pmode, return_reg, off); - new_insn = emit_insn_before (new_insn, insn); - INSN_ADDRESSES_NEW (new_insn, -1); - off = return_reg; + remove_insn (insn); + continue; } - - new_insn = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, reg, off)); - new_insn = gen_rtx_SET (Pmode, return_reg, new_insn); - new_insn = emit_insn_before (new_insn, insn); - INSN_ADDRESSES_NEW (new_insn, -1); - - replacement_done = 1; } - - return replacement_done; } /* Perform machine-dependent processing. */ -void -s390_machine_dependent_reorg (first) - rtx first ATTRIBUTE_UNUSED; +static void +s390_reorg (void) { - bool fixed_up_clobbered_return_reg = 0; - rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); - bool temp_used = 0; + rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER); + bool base_used = false; + bool pool_overflow = false; /* Make sure all splits have been performed; splits after machine_dependent_reorg might confuse insn length counts. */ split_all_insns_noflow (); - /* There are two problematic situations we need to correct: - + /* In small leaf functions, try to use an unused call-clobbered + register as base register to avoid save/restore overhead. */ + if (current_function_is_leaf && !regs_ever_live[5]) + base_reg = gen_rtx_REG (Pmode, 5); + + + /* Install the main literal pool and the associated base + register load insns. + + In addition, there are two problematic situations we need + to correct: + - the literal pool might be > 4096 bytes in size, so that some of its elements cannot be directly accessed - + - a branch target might be > 64K away from the branch, so that it is not possible to use a PC-relative instruction. - + To fix those, we split the single literal pool into multiple pool chunks, reloading the pool base register at various points throughout the function to ensure it always points to the pool chunk the following code expects, and / or replace PC-relative branches by absolute branches. - + However, the two problems are interdependent: splitting the literal pool can move a branch further away from its target, causing the 64K limit to overflow, and on the other hand, replacing a PC-relative branch by an absolute branch means we need to put the branch target address into the literal pool, possibly causing it to overflow. - + So, we loop trying to fix up both problems until we manage to satisfy both conditions at the same time. Note that the loop is guaranteed to terminate as every pass of the loop @@ -4863,49 +5201,52 @@ s390_machine_dependent_reorg (first) in the function. (This is not completely true as there might be branch-over-pool insns introduced by chunkify_start. Those never need to be split however.) */ - + for (;;) { - struct constant_pool *pool_list; - - /* Try to chunkify the literal pool. */ - pool_list = s390_chunkify_start (temp_reg, &temp_used); + struct constant_pool *pool = NULL; + + /* Collect the literal pool. */ + if (!pool_overflow) + { + pool = s390_mainpool_start (); + if (!pool) + pool_overflow = true; + } + + /* If literal pool overflowed, start to chunkify it. */ + if (pool_overflow) + pool = s390_chunkify_start (base_reg); /* Split out-of-range branches. If this has created new literal pool entries, cancel current chunk list and - recompute it. */ - if (s390_split_branches (temp_reg, &temp_used)) + recompute it. zSeries machines have large branch + instructions, so we never need to split a branch. */ + if (!TARGET_CPU_ZARCH && s390_split_branches ()) { - if (pool_list) - s390_chunkify_cancel (pool_list); - + if (pool_overflow) + s390_chunkify_cancel (pool); + else + s390_mainpool_cancel (pool); + continue; } - /* Check whether we have clobbered a use of the return - register (e.g. for __builtin_return_address). If so, - add insns reloading the register where necessary. */ - if (temp_used && !fixed_up_clobbered_return_reg - && s390_fixup_clobbered_return_reg (temp_reg)) - { - fixed_up_clobbered_return_reg = 1; + /* If we made it up to here, both conditions are satisfied. + Finish up literal pool related changes. */ + if ((pool_overflow || pool->size > 0) + && REGNO (base_reg) == BASE_REGISTER) + base_used = true; - /* The fixup insns might have caused a jump to overflow. */ - if (pool_list) - s390_chunkify_cancel (pool_list); + if (pool_overflow) + s390_chunkify_finish (pool, base_reg); + else + s390_mainpool_finish (pool, base_reg); - continue; - } - - /* If we made it up to here, both conditions are satisfied. - Finish up pool chunkification if required. */ - if (pool_list) - s390_chunkify_finish (pool_list, temp_reg); - break; } - - s390_optimize_prolog (temp_used? RETURN_REGNUM : -1); + + s390_optimize_prolog (base_used); } @@ -4914,32 +5255,35 @@ s390_machine_dependent_reorg (first) frame pointer of that frame. */ rtx -s390_return_addr_rtx (count, frame) - int count; - rtx frame; +s390_return_addr_rtx (int count, rtx frame) { rtx addr; - /* For the current frame, we use the initial value of RETURN_REGNUM. - This works both in leaf and non-leaf functions. */ + /* Without backchain, we fail for all but the current frame. */ + + if (!TARGET_BACKCHAIN && count > 0) + return NULL_RTX; + + /* For the current frame, we need to make sure the initial + value of RETURN_REGNUM is actually saved. */ if (count == 0) - return get_hard_reg_initial_val (Pmode, RETURN_REGNUM); + cfun->machine->save_return_addr_p = true; - /* For frames farther back, we read the stack slot where the + /* To retrieve the return address we read the stack slot where the corresponding RETURN_REGNUM value was saved. */ addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD); addr = memory_address (Pmode, addr); return gen_rtx_MEM (Pmode, addr); -} +} /* Find first call clobbered register unsused in a function. This could be used as base register in a leaf function or for holding the return address before epilogue. */ static int -find_unused_clobbered_reg () +find_unused_clobbered_reg (void) { int i; for (i = 0; i < 6; i++) @@ -4951,19 +5295,18 @@ find_unused_clobbered_reg () /* Fill FRAME with info about frame of current function. */ static void -s390_frame_info () +s390_frame_info (void) { - char gprs_ever_live[16]; int i, j; HOST_WIDE_INT fsize = get_frame_size (); - if (fsize > 0x7fff0000) + if (!TARGET_64BIT && fsize > 0x7fff0000) fatal_error ("Total size of local variables exceeds architecture limit."); /* fprs 8 - 15 are caller saved for 64 Bit ABI. */ cfun->machine->save_fprs_p = 0; if (TARGET_64BIT) - for (i = 24; i < 32; i++) + for (i = 24; i < 32; i++) if (regs_ever_live[i] && !global_regs[i]) { cfun->machine->save_fprs_p = 1; @@ -4973,38 +5316,49 @@ s390_frame_info () cfun->machine->frame_size = fsize + cfun->machine->save_fprs_p * 64; /* Does function need to setup frame and save area. */ - + if (! current_function_is_leaf || cfun->machine->frame_size > 0 - || current_function_calls_alloca + || current_function_calls_alloca || current_function_stdarg) cfun->machine->frame_size += STARTING_FRAME_OFFSET; + /* If we use the return register, we'll need to make sure + it is going to be saved/restored. */ + + if (!current_function_is_leaf + || regs_ever_live[RETURN_REGNUM]) + cfun->machine->save_return_addr_p = 1; + /* Find first and last gpr to be saved. Note that at this point, - we assume the return register and the base register always - need to be saved. This is done because the usage of these + we assume the base register and -on S/390- the return register + always need to be saved. This is done because the usage of these register might change even after the prolog was emitted. If it turns out later that we really don't need them, the prolog/epilog code is modified again. */ - for (i = 0; i < 16; i++) - gprs_ever_live[i] = regs_ever_live[i] && !global_regs[i]; + regs_ever_live[BASE_REGISTER] = 1; + if (!TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p) + regs_ever_live[RETURN_REGNUM] = 1; + regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; - if (flag_pic) - gprs_ever_live[PIC_OFFSET_TABLE_REGNUM] = - regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; - gprs_ever_live[BASE_REGISTER] = 1; - gprs_ever_live[RETURN_REGNUM] = 1; - gprs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; - for (i = 6; i < 16; i++) - if (gprs_ever_live[i]) - break; + if (regs_ever_live[i]) + if (!global_regs[i] + || i == STACK_POINTER_REGNUM + || i == RETURN_REGNUM + || i == BASE_REGISTER + || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) + break; for (j = 15; j > i; j--) - if (gprs_ever_live[j]) - break; - + if (regs_ever_live[j]) + if (!global_regs[j] + || j == STACK_POINTER_REGNUM + || j == RETURN_REGNUM + || j == BASE_REGISTER + || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM)) + break; /* Save / Restore from gpr i to j. */ cfun->machine->first_save_gpr = i; @@ -5016,11 +5370,11 @@ s390_frame_info () cfun->machine->first_save_gpr = 2; } -/* Return offset between argument pointer and frame pointer +/* Return offset between argument pointer and frame pointer initially after prologue. */ -int -s390_arg_frame_offset () +HOST_WIDE_INT +s390_arg_frame_offset (void) { HOST_WIDE_INT fsize = get_frame_size (); int save_fprs_p, i; @@ -5028,7 +5382,7 @@ s390_arg_frame_offset () /* fprs 8 - 15 are caller saved for 64 Bit ABI. */ save_fprs_p = 0; if (TARGET_64BIT) - for (i = 24; i < 32; i++) + for (i = 24; i < 32; i++) if (regs_ever_live[i] && !global_regs[i]) { save_fprs_p = 1; @@ -5038,23 +5392,20 @@ s390_arg_frame_offset () fsize = fsize + save_fprs_p * 64; /* Does function need to setup frame and save area. */ - + if (! current_function_is_leaf || fsize > 0 - || current_function_calls_alloca + || current_function_calls_alloca || current_function_stdarg) fsize += STARTING_FRAME_OFFSET; return fsize + STACK_POINTER_OFFSET; } /* Emit insn to save fpr REGNUM at offset OFFSET relative - to register BASE. Return generated insn. */ + to register BASE. Return generated insn. */ static rtx -save_fpr (base, offset, regnum) - rtx base; - int offset; - int regnum; +save_fpr (rtx base, int offset, int regnum) { rtx addr; addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); @@ -5064,13 +5415,10 @@ save_fpr (base, offset, regnum) } /* Emit insn to restore fpr REGNUM from offset OFFSET relative - to register BASE. Return generated insn. */ + to register BASE. Return generated insn. */ static rtx -restore_fpr (base, offset, regnum) - rtx base; - int offset; - int regnum; +restore_fpr (rtx base, int offset, int regnum) { rtx addr; addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); @@ -5080,15 +5428,11 @@ restore_fpr (base, offset, regnum) } /* Generate insn to save registers FIRST to LAST into - the register save area located at offset OFFSET + the register save area located at offset OFFSET relative to register BASE. */ static rtx -save_gprs (base, offset, first, last) - rtx base; - int offset; - int first; - int last; +save_gprs (rtx base, int offset, int first, int last) { rtx addr, insn, note; int i; @@ -5119,7 +5463,7 @@ save_gprs (base, offset, first, last) inside the store-multiple pattern. However, we must not emit DWARF records for registers 2..5 - if they are stored for use by variable arguments ... + if they are stored for use by variable arguments ... ??? Unfortunately, it is not enough to simply not the the FRAME_RELATED flags for those SETs, because the first SET @@ -5140,13 +5484,13 @@ save_gprs (base, offset, first, last) else if (last >= 6) { addr = plus_constant (base, offset + 6 * UNITS_PER_WORD); - note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), + note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), gen_rtx_REG (Pmode, 6), GEN_INT (last - 6 + 1)); note = PATTERN (note); REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, + gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, note, REG_NOTES (insn)); for (i = 0; i < XVECLEN (note, 0); i++) @@ -5160,15 +5504,11 @@ save_gprs (base, offset, first, last) } /* Generate insn to restore registers FIRST to LAST from - the register save area located at offset OFFSET + the register save area located at offset OFFSET relative to register BASE. */ static rtx -restore_gprs (base, offset, first, last) - rtx base; - int offset; - int first; - int last; +restore_gprs (rtx base, int offset, int first, int last) { rtx addr, insn; @@ -5193,82 +5533,98 @@ restore_gprs (base, offset, first, last) return insn; } +/* Emit code to load the GOT register. If MAYBE_DEAD is true, + annotate generated insns with REG_MAYBE_DEAD notes. */ + +static GTY(()) rtx got_symbol; +void +s390_load_got (int maybe_dead) +{ + if (!got_symbol) + { + got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL; + } + + if (TARGET_CPU_ZARCH) + { + rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol); + if (maybe_dead) + REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, + REG_NOTES (insn)); + } + else + { + rtx offset, insn; + + offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol), + UNSPEC_LTREL_OFFSET); + offset = gen_rtx_CONST (Pmode, offset); + offset = force_const_mem (Pmode, offset); + + insn = emit_move_insn (pic_offset_table_rtx, offset); + if (maybe_dead) + REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, + REG_NOTES (insn)); + + offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)), + UNSPEC_LTREL_BASE); + offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset); + + insn = emit_move_insn (pic_offset_table_rtx, offset); + if (maybe_dead) + REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, + REG_NOTES (insn)); + } +} + /* Expand the prologue into a bunch of separate insns. */ void -s390_emit_prologue () +s390_emit_prologue (void) { rtx insn, addr; rtx temp_reg; - rtx pool_start_label, pool_end_label; int i; /* Compute frame_info. */ s390_frame_info (); - /* Choose best register to use for temp use within prologue. */ - + /* Choose best register to use for temp use within prologue. + See below for why TPF must use the register 1. */ + if (!current_function_is_leaf - && !has_hard_reg_initial_val (Pmode, RETURN_REGNUM) - && get_pool_size () < S390_POOL_CHUNK_MAX / 2) + && !TARGET_TPF) temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); else temp_reg = gen_rtx_REG (Pmode, 1); /* Save call saved gprs. */ - insn = save_gprs (stack_pointer_rtx, 0, + insn = save_gprs (stack_pointer_rtx, 0, cfun->machine->first_save_gpr, cfun->machine->last_save_gpr); emit_insn (insn); - /* Dump constant pool and set constant pool register. */ + /* Dummy insn to mark literal pool slot. */ + + emit_insn (gen_main_pool ()); - pool_start_label = gen_label_rtx(); - pool_end_label = gen_label_rtx(); - cfun->machine->literal_pool_label = pool_start_label; - - if (TARGET_64BIT) - insn = emit_insn (gen_literal_pool_64 (gen_rtx_REG (Pmode, BASE_REGISTER), - pool_start_label, pool_end_label)); - else - insn = emit_insn (gen_literal_pool_31 (gen_rtx_REG (Pmode, BASE_REGISTER), - pool_start_label, pool_end_label)); - /* Save fprs for variable args. */ if (current_function_stdarg) - { - /* Save fpr 0 and 2. */ - - save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 32, 16); - save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 24, 17); - - if (TARGET_64BIT) - { - /* Save fpr 4 and 6. */ - - save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18); - save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19); - } - } + for (i = 16; i < (TARGET_64BIT ? 20 : 18); i++) + save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i); /* Save fprs 4 and 6 if used (31 bit ABI). */ if (!TARGET_64BIT) - { - /* Save fpr 4 and 6. */ - if (regs_ever_live[18] && !global_regs[18]) - { - insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 16, 18); - RTX_FRAME_RELATED_P (insn) = 1; - } - if (regs_ever_live[19] && !global_regs[19]) + for (i = 18; i < 20; i++) + if (regs_ever_live[i] && !global_regs[i]) { - insn = save_fpr (stack_pointer_rtx, STACK_POINTER_OFFSET - 8, 19); + insn = save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i); RTX_FRAME_RELATED_P (insn) = 1; } - } /* Decrement stack pointer. */ @@ -5277,21 +5633,31 @@ s390_emit_prologue () rtx frame_off = GEN_INT (-cfun->machine->frame_size); /* Save incoming stack pointer into temp reg. */ - + if (TARGET_BACKCHAIN || cfun->machine->save_fprs_p) { insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx)); } - - /* Substract frame size from stack pointer. */ - frame_off = GEN_INT (-cfun->machine->frame_size); - if (!CONST_OK_FOR_LETTER_P (-cfun->machine->frame_size, 'K')) - frame_off = force_const_mem (Pmode, frame_off); + /* Subtract frame size from stack pointer. */ + + if (DISP_IN_RANGE (INTVAL (frame_off))) + { + insn = gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + frame_off)); + insn = emit_insn (insn); + } + else + { + if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K")) + frame_off = force_const_mem (Pmode, frame_off); + + insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off)); + } - insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off)); RTX_FRAME_RELATED_P (insn) = 1; - REG_NOTES (insn) = + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, stack_pointer_rtx, gen_rtx_PLUS (Pmode, stack_pointer_rtx, @@ -5299,7 +5665,7 @@ s390_emit_prologue () REG_NOTES (insn)); /* Set backchain. */ - + if (TARGET_BACKCHAIN) { addr = gen_rtx_MEM (Pmode, stack_pointer_rtx); @@ -5319,7 +5685,7 @@ s390_emit_prologue () } /* Save fprs 8 - 15 (64 bit ABI). */ - + if (cfun->machine->save_fprs_p) { insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64))); @@ -5327,22 +5693,22 @@ s390_emit_prologue () for (i = 24; i < 32; i++) if (regs_ever_live[i] && !global_regs[i]) { - rtx addr = plus_constant (stack_pointer_rtx, + rtx addr = plus_constant (stack_pointer_rtx, cfun->machine->frame_size - 64 + (i-24)*8); insn = save_fpr (temp_reg, (i-24)*8, i); RTX_FRAME_RELATED_P (insn) = 1; - REG_NOTES (insn) = + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, + gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, addr), gen_rtx_REG (DFmode, i)), REG_NOTES (insn)); } } - + /* Set frame pointer, if needed. */ - + if (frame_pointer_needed) { insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); @@ -5350,54 +5716,70 @@ s390_emit_prologue () } /* Set up got pointer, if needed. */ - + if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) + s390_load_got(true); + + if (TARGET_TPF) { - rtx got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - SYMBOL_REF_FLAG (got_symbol) = 1; + /* Generate a BAS instruction to serve as a function + entry intercept to facilitate the use of tracing + algorithms located at the branch target. - if (TARGET_64BIT) - { - insn = emit_insn (gen_movdi (pic_offset_table_rtx, - got_symbol)); + This must use register 1. */ + rtx addr; + rtx unkn; + rtx link; - /* It can happen that the GOT pointer isn't really needed ... */ - REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, - REG_NOTES (insn)); - } - else - { - got_symbol = gen_rtx_UNSPEC (VOIDmode, - gen_rtvec (1, got_symbol), 100); - got_symbol = gen_rtx_CONST (VOIDmode, got_symbol); - got_symbol = force_const_mem (Pmode, got_symbol); - insn = emit_move_insn (pic_offset_table_rtx, - got_symbol); - REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, - REG_NOTES (insn)); - - got_symbol = gen_rtx_REG (Pmode, BASE_REGISTER); - got_symbol = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got_symbol), 101); - got_symbol = gen_rtx_PLUS (Pmode, got_symbol, pic_offset_table_rtx); - insn = emit_move_insn (pic_offset_table_rtx, got_symbol); - REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX, - REG_NOTES (insn)); - } - } + addr = GEN_INT (0xfe0); + unkn = CONST0_RTX (SImode); + link = gen_rtx_REG (Pmode, 1); + + emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link)); + + /* Emit a blockage here so that all code + lies between the profiling mechanisms. */ + emit_insn (gen_blockage ()); + } } /* Expand the epilogue into a bunch of separate insns. */ void -s390_emit_epilogue () +s390_emit_epilogue (void) { rtx frame_pointer, return_reg; int area_bottom, area_top, offset = 0; rtvec p; + int i; + + if (TARGET_TPF) + { + + /* Generate a BAS instruction to serve as a function + entry intercept to facilitate the use of tracing + algorithms located at the branch target. + + This must use register 1. */ + + rtx addr; + rtx unkn; + rtx link; + + addr = GEN_INT (0xfe6); + unkn = CONST0_RTX (SImode); + link = gen_rtx_REG (Pmode, 1); + + /* Emit a blockage here so that all code + lies between the profiling mechanisms. */ + emit_insn (gen_blockage ()); + + emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link)); + } /* Check whether to use frame or stack pointer for restore. */ - frame_pointer = frame_pointer_needed ? + frame_pointer = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; /* Compute which parts of the save area we need to access. */ @@ -5425,31 +5807,25 @@ s390_emit_epilogue () } else { - if (regs_ever_live[18] && !global_regs[18]) - { - if (area_bottom > STACK_POINTER_OFFSET - 16) - area_bottom = STACK_POINTER_OFFSET - 16; - if (area_top < STACK_POINTER_OFFSET - 8) - area_top = STACK_POINTER_OFFSET - 8; - } - if (regs_ever_live[19] && !global_regs[19]) - { - if (area_bottom > STACK_POINTER_OFFSET - 8) - area_bottom = STACK_POINTER_OFFSET - 8; - if (area_top < STACK_POINTER_OFFSET) - area_top = STACK_POINTER_OFFSET; - } + for (i = 18; i < 20; i++) + if (regs_ever_live[i] && !global_regs[i]) + { + if (area_bottom > 16*UNITS_PER_WORD + 8*(i-16)) + area_bottom = 16*UNITS_PER_WORD + 8*(i-16); + if (area_top < 16*UNITS_PER_WORD + 8*(i-16) + 8) + area_top = 16*UNITS_PER_WORD + 8*(i-16) + 8; + } } - /* Check whether we can access the register save area. + /* Check whether we can access the register save area. If not, increment the frame pointer as required. */ if (area_top <= area_bottom) { /* Nothing to restore. */ } - else if (cfun->machine->frame_size + area_bottom >= 0 - && cfun->machine->frame_size + area_top <= 4096) + else if (DISP_IN_RANGE (cfun->machine->frame_size + area_bottom) + && DISP_IN_RANGE (cfun->machine->frame_size + area_top-1)) { /* Area is in range. */ offset = cfun->machine->frame_size; @@ -5458,38 +5834,45 @@ s390_emit_epilogue () { rtx insn, frame_off; - offset = area_bottom < 0 ? -area_bottom : 0; + offset = area_bottom < 0 ? -area_bottom : 0; frame_off = GEN_INT (cfun->machine->frame_size - offset); - if (!CONST_OK_FOR_LETTER_P (INTVAL (frame_off), 'K')) - frame_off = force_const_mem (Pmode, frame_off); + if (DISP_IN_RANGE (INTVAL (frame_off))) + { + insn = gen_rtx_SET (VOIDmode, frame_pointer, + gen_rtx_PLUS (Pmode, frame_pointer, frame_off)); + insn = emit_insn (insn); + } + else + { + if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K")) + frame_off = force_const_mem (Pmode, frame_off); - insn = emit_insn (gen_add2_insn (frame_pointer, frame_off)); + insn = emit_insn (gen_add2_insn (frame_pointer, frame_off)); + } } /* Restore call saved fprs. */ if (TARGET_64BIT) { - int i; - if (cfun->machine->save_fprs_p) for (i = 24; i < 32; i++) if (regs_ever_live[i] && !global_regs[i]) - restore_fpr (frame_pointer, + restore_fpr (frame_pointer, offset - 64 + (i-24) * 8, i); } else { - if (regs_ever_live[18] && !global_regs[18]) - restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 16, 18); - if (regs_ever_live[19] && !global_regs[19]) - restore_fpr (frame_pointer, offset + STACK_POINTER_OFFSET - 8, 19); + for (i = 18; i < 20; i++) + if (regs_ever_live[i] && !global_regs[i]) + restore_fpr (frame_pointer, + offset + 16*UNITS_PER_WORD + 8*(i-16), i); } /* Return register. */ - return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); + return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); /* Restore call saved gprs. */ @@ -5498,43 +5881,45 @@ s390_emit_epilogue () rtx insn, addr; int i; - /* Check for global register and save them + /* Check for global register and save them to stack location from where they get restored. */ - for (i = cfun->machine->first_restore_gpr; + for (i = cfun->machine->first_restore_gpr; i <= cfun->machine->last_save_gpr; i++) { - /* These registers are special and need to be + /* These registers are special and need to be restored in any case. */ - if (i == STACK_POINTER_REGNUM + if (i == STACK_POINTER_REGNUM || i == RETURN_REGNUM - || i == BASE_REGISTER + || i == BASE_REGISTER || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM)) continue; if (global_regs[i]) { - addr = plus_constant (frame_pointer, + addr = plus_constant (frame_pointer, offset + i * UNITS_PER_WORD); addr = gen_rtx_MEM (Pmode, addr); set_mem_alias_set (addr, s390_sr_alias_set); emit_move_insn (addr, gen_rtx_REG (Pmode, i)); - } + } } /* Fetch return address from stack before load multiple, this will do good for scheduling. */ - if (!current_function_is_leaf) + if (cfun->machine->save_return_addr_p + || (cfun->machine->first_restore_gpr < BASE_REGISTER + && cfun->machine->last_save_gpr > RETURN_REGNUM)) { int return_regnum = find_unused_clobbered_reg(); if (!return_regnum) return_regnum = 4; return_reg = gen_rtx_REG (Pmode, return_regnum); - - addr = plus_constant (frame_pointer, - offset + RETURN_REGNUM * UNITS_PER_WORD); + + addr = plus_constant (frame_pointer, + offset + RETURN_REGNUM * UNITS_PER_WORD); addr = gen_rtx_MEM (Pmode, addr); set_mem_alias_set (addr, s390_sr_alias_set); emit_move_insn (return_reg, addr); @@ -5544,10 +5929,10 @@ s390_emit_epilogue () explicit in insn RTX code, we have to add a barrier here to prevent incorrect scheduling. */ - emit_insn (gen_blockage()); + emit_insn (gen_blockage()); - insn = restore_gprs (frame_pointer, offset, - cfun->machine->first_restore_gpr, + insn = restore_gprs (frame_pointer, offset, + cfun->machine->first_restore_gpr, cfun->machine->last_save_gpr); emit_insn (insn); } @@ -5555,21 +5940,19 @@ s390_emit_epilogue () /* Return to caller. */ p = rtvec_alloc (2); - + RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode); RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg); emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p)); } -/* Return the size in bytes of a function argument of +/* Return the size in bytes of a function argument of type TYPE and/or mode MODE. At least one of TYPE or MODE must be specified. */ static int -s390_function_arg_size (mode, type) - enum machine_mode mode; - tree type; +s390_function_arg_size (enum machine_mode mode, tree type) { if (type) return int_size_in_bytes (type); @@ -5582,6 +5965,83 @@ s390_function_arg_size (mode, type) abort (); } +/* Return true if a function argument of type TYPE and mode MODE + is to be passed in a floating-point register, if available. */ + +static bool +s390_function_arg_float (enum machine_mode mode, tree type) +{ + int size = s390_function_arg_size (mode, type); + if (size > 8) + return false; + + /* Soft-float changes the ABI: no floating-point registers are used. */ + if (TARGET_SOFT_FLOAT) + return false; + + /* No type info available for some library calls ... */ + if (!type) + return mode == SFmode || mode == DFmode; + + /* The ABI says that record types with a single member are treated + just like that member would be. */ + while (TREE_CODE (type) == RECORD_TYPE) + { + tree field, single = NULL_TREE; + + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (single == NULL_TREE) + single = TREE_TYPE (field); + else + return false; + } + + if (single == NULL_TREE) + return false; + else + type = single; + } + + return TREE_CODE (type) == REAL_TYPE; +} + +/* Return true if a function argument of type TYPE and mode MODE + is to be passed in an integer register, or a pair of integer + registers, if available. */ + +static bool +s390_function_arg_integer (enum machine_mode mode, tree type) +{ + int size = s390_function_arg_size (mode, type); + if (size > 8) + return false; + + /* No type info available for some library calls ... */ + if (!type) + return GET_MODE_CLASS (mode) == MODE_INT + || (TARGET_SOFT_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT); + + /* We accept small integral (and similar) types. */ + if (INTEGRAL_TYPE_P (type) + || POINTER_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE + || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE)) + return true; + + /* We also accept structs of size 1, 2, 4, 8 that are not + passed in floating-point registers. */ + if (AGGREGATE_TYPE_P (type) + && exact_log2 (size) >= 0 + && !s390_function_arg_float (mode, type)) + return true; + + return false; +} + /* Return 1 if a function argument of type TYPE and mode MODE is to be passed by reference. The ABI specifies that only structures of size 1, 2, 4, or 8 bytes are passed by value, @@ -5589,23 +6049,23 @@ s390_function_arg_size (mode, type) reference. */ int -s390_function_arg_pass_by_reference (mode, type) - enum machine_mode mode; - tree type; +s390_function_arg_pass_by_reference (enum machine_mode mode, tree type) { int size = s390_function_arg_size (mode, type); + if (size > 8) + return true; if (type) { - if (AGGREGATE_TYPE_P (type) && - size != 1 && size != 2 && size != 4 && size != 8) + if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0) return 1; - if (TREE_CODE (type) == COMPLEX_TYPE) + if (TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) return 1; } - return 0; + return 0; } /* Update the data in CUM to advance over an argument of mode MODE and @@ -5615,25 +6075,24 @@ s390_function_arg_pass_by_reference (mode, type) matching an ellipsis). */ void -s390_function_arg_advance (cum, mode, type, named) - CUMULATIVE_ARGS *cum; - enum machine_mode mode; - tree type; - int named ATTRIBUTE_UNUSED; +s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int named ATTRIBUTE_UNUSED) { - if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode)) + if (s390_function_arg_pass_by_reference (mode, type)) { - cum->fprs++; + cum->gprs += 1; } - else if (s390_function_arg_pass_by_reference (mode, type)) + else if (s390_function_arg_float (mode, type)) { - cum->gprs += 1; + cum->fprs += 1; } - else + else if (s390_function_arg_integer (mode, type)) { int size = s390_function_arg_size (mode, type); cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD); } + else + abort (); } /* Define where to put the arguments to a function. @@ -5647,7 +6106,7 @@ s390_function_arg_advance (cum, mode, type, named) 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). + (otherwise it is an extra parameter matching an ellipsis). On S/390, we use general purpose registers 2 through 6 to pass integer, pointer, and certain structure arguments, and @@ -5656,23 +6115,20 @@ s390_function_arg_advance (cum, mode, type, named) are pushed to the stack. */ rtx -s390_function_arg (cum, mode, type, named) - CUMULATIVE_ARGS *cum; - enum machine_mode mode; - tree type; - int named ATTRIBUTE_UNUSED; +s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, + int named ATTRIBUTE_UNUSED) { if (s390_function_arg_pass_by_reference (mode, type)) return 0; - if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode)) + if (s390_function_arg_float (mode, type)) { if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2)) return 0; else return gen_rtx (REG, mode, cum->fprs + 16); } - else + else if (s390_function_arg_integer (mode, type)) { int size = s390_function_arg_size (mode, type); int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD; @@ -5682,6 +6138,68 @@ s390_function_arg (cum, mode, type, named) else return gen_rtx (REG, mode, cum->gprs + 2); } + + /* After the real arguments, expand_call calls us once again + with a void_type_node type. Whatever we return here is + passed as operand 2 to the call expanders. + + We don't need this feature ... */ + else if (type == void_type_node) + return const0_rtx; + + abort (); +} + +/* Return true if return values of type TYPE should be returned + in a memory buffer whose address is passed by the caller as + hidden first argument. */ + +static bool +s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED) +{ + /* We accept small integral (and similar) types. */ + if (INTEGRAL_TYPE_P (type) + || POINTER_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE + || TREE_CODE (type) == REAL_TYPE) + return int_size_in_bytes (type) > 8; + + /* Aggregates and similar constructs are always returned + in memory. */ + if (AGGREGATE_TYPE_P (type) + || TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) + return true; + + /* ??? We get called on all sorts of random stuff from + aggregate_value_p. We can't abort, but it's not clear + what's safe to return. Pretend it's a struct I guess. */ + return true; +} + +/* Define where to return a (scalar) value of type TYPE. + If TYPE is null, define where to return a (scalar) + value of mode MODE from a libcall. */ + +rtx +s390_function_value (tree type, enum machine_mode mode) +{ + if (type) + { + int unsignedp = TREE_UNSIGNED (type); + mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1); + } + + if (GET_MODE_CLASS (mode) != MODE_INT + && GET_MODE_CLASS (mode) != MODE_FLOAT) + abort (); + if (GET_MODE_SIZE (mode) > 8) + abort (); + + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT) + return gen_rtx_REG (mode, 16); + else + return gen_rtx_REG (mode, 2); } @@ -5695,31 +6213,30 @@ s390_function_arg (cum, mode, type, named) long __fpr; void *__overflow_arg_area; void *__reg_save_area; - } va_list[1]; where __gpr and __fpr hold the number of general purpose or floating point arguments used up to now, respectively, - __overflow_arg_area points to the stack location of the + __overflow_arg_area points to the stack location of the next argument passed on the stack, and __reg_save_area always points to the start of the register area in the call frame of the current function. The function prologue saves all registers used for argument passing into this area if the function uses variable arguments. */ -tree -s390_build_va_list () +static tree +s390_build_builtin_va_list (void) { tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; - record = (*lang_hooks.types.make_type) (RECORD_TYPE); + record = lang_hooks.types.make_type (RECORD_TYPE); type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); - f_gpr = build_decl (FIELD_DECL, get_identifier ("__gpr"), + f_gpr = build_decl (FIELD_DECL, get_identifier ("__gpr"), long_integer_type_node); - f_fpr = build_decl (FIELD_DECL, get_identifier ("__fpr"), + f_fpr = build_decl (FIELD_DECL, get_identifier ("__fpr"), long_integer_type_node); f_ovf = build_decl (FIELD_DECL, get_identifier ("__overflow_arg_area"), ptr_type_node); @@ -5758,9 +6275,7 @@ s390_build_va_list () (relative to the virtual arg pointer). */ void -s390_va_start (valist, nextarg) - tree valist; - rtx nextarg ATTRIBUTE_UNUSED; +s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) { HOST_WIDE_INT n_gpr, n_fpr; int off; @@ -5815,15 +6330,15 @@ s390_va_start (valist, nextarg) expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } -/* Implement va_arg by updating the va_list structure +/* Implement va_arg by updating the va_list structure VALIST as required to retrieve an argument of type - TYPE, and returning that argument. - + TYPE, and returning that argument. + Generates code equivalent to: - + if (integral value) { if (size <= 4 && args.gpr < 5 || - size > 4 && args.gpr < 4 ) + size > 4 && args.gpr < 4 ) ret = args.reg_save_area[args.gpr+8] else ret = *args.overflow_arg_area++; @@ -5840,9 +6355,7 @@ s390_va_start (valist, nextarg) } */ rtx -s390_va_arg (valist, type) - tree valist; - tree type; +s390_va_arg (tree valist, tree type) { tree f_gpr, f_fpr, f_ovf, f_sav; tree gpr, fpr, ovf, sav, reg, t, u; @@ -5879,7 +6392,7 @@ s390_va_arg (valist, type) size = UNITS_PER_WORD; max_reg = 4; } - else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT) + else if (s390_function_arg_float (TYPE_MODE (type), type)) { if (TARGET_DEBUG_ARG) { @@ -5909,13 +6422,9 @@ s390_va_arg (valist, type) reg = gpr; n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; sav_ofs = 2 * UNITS_PER_WORD; - if (TARGET_64BIT) - sav_ofs += TYPE_MODE (type) == SImode ? 4 : - TYPE_MODE (type) == HImode ? 6 : - TYPE_MODE (type) == QImode ? 7 : 0; - else - sav_ofs += TYPE_MODE (type) == HImode ? 2 : - TYPE_MODE (type) == QImode ? 3 : 0; + + if (size < UNITS_PER_WORD) + sav_ofs += UNITS_PER_WORD - size; sav_scale = UNITS_PER_WORD; if (n_reg > 1) @@ -5982,10 +6491,10 @@ s390_va_arg (valist, type) emit_label (lab_over); - /* If less than max_regs a registers are retrieved out + /* If less than max_regs a registers are retrieved out of register save area, increment. */ - u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, + u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0)); TREE_SIDE_EFFECTS (u) = 1; expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -6023,7 +6532,7 @@ static unsigned int const code_for_builtin_31[S390_BUILTIN_max] = { }; static void -s390_init_builtins () +s390_init_builtins (void) { tree ftype; @@ -6045,16 +6554,13 @@ s390_init_builtins () IGNORE is nonzero if the value is to be ignored. */ static rtx -s390_expand_builtin (exp, target, subtarget, mode, ignore) - tree exp; - rtx target; - rtx subtarget ATTRIBUTE_UNUSED; - enum machine_mode mode ATTRIBUTE_UNUSED; - int ignore ATTRIBUTE_UNUSED; +s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) { #define MAX_ARGS 2 - unsigned int const *code_for_builtin = + unsigned int const *code_for_builtin = TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31; tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); @@ -6137,8 +6643,7 @@ s390_expand_builtin (exp, target, subtarget, mode, ignore) gpr 0 is used to hold the static chain. */ void -s390_trampoline_template (file) - FILE *file; +s390_trampoline_template (FILE *file) { if (TARGET_64BIT) { @@ -6165,18 +6670,15 @@ s390_trampoline_template (file) CXT is an RTX for the static chain value for the function. */ void -s390_initialize_trampoline (addr, fnaddr, cxt) - rtx addr; - rtx fnaddr; - rtx cxt; +s390_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) { - emit_move_insn (gen_rtx + emit_move_insn (gen_rtx (MEM, Pmode, - memory_address (Pmode, + memory_address (Pmode, plus_constant (addr, (TARGET_64BIT ? 20 : 12) ))), cxt); emit_move_insn (gen_rtx (MEM, Pmode, - memory_address (Pmode, + memory_address (Pmode, plus_constant (addr, (TARGET_64BIT ? 28 : 16) ))), fnaddr); } @@ -6184,16 +6686,14 @@ s390_initialize_trampoline (addr, fnaddr, cxt) LOW and HIGH, independent of the host word size. */ rtx -s390_gen_rtx_const_DI (high, low) - int high; - int low; +s390_gen_rtx_const_DI (int high, int low) { #if HOST_BITS_PER_WIDE_INT >= 64 HOST_WIDE_INT val; val = (HOST_WIDE_INT)high; val <<= 32; val |= (HOST_WIDE_INT)low; - + return GEN_INT (val); #else #if HOST_BITS_PER_WIDE_INT >= 32 @@ -6202,15 +6702,13 @@ s390_gen_rtx_const_DI (high, low) abort (); #endif #endif -} +} /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ void -s390_function_profiler (file, labelno) - FILE *file; - int labelno; +s390_function_profiler (FILE *file, int labelno) { rtx op[7]; @@ -6225,12 +6723,12 @@ s390_function_profiler (file, labelno) op[2] = gen_rtx_REG (Pmode, 1); op[3] = gen_rtx_SYMBOL_REF (Pmode, label); - SYMBOL_REF_FLAG (op[3]) = 1; + SYMBOL_REF_FLAGS (op[3]) = SYMBOL_FLAG_LOCAL; op[4] = gen_rtx_SYMBOL_REF (Pmode, "_mcount"); if (flag_pic) { - op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), 113); + op[4] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[4]), UNSPEC_PLT); op[4] = gen_rtx_CONST (Pmode, op[4]); } @@ -6249,7 +6747,7 @@ s390_function_profiler (file, labelno) output_asm_insn ("bras\t%2,%l6", op); output_asm_insn (".long\t%4", op); output_asm_insn (".long\t%3", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6])); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6])); output_asm_insn ("l\t%0,0(%2)", op); output_asm_insn ("l\t%2,4(%2)", op); output_asm_insn ("basr\t%0,%0", op); @@ -6262,10 +6760,10 @@ s390_function_profiler (file, labelno) output_asm_insn ("st\t%0,%1", op); output_asm_insn ("bras\t%2,%l6", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5])); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[5])); output_asm_insn (".long\t%4-%l5", op); output_asm_insn (".long\t%3-%l5", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6])); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[6])); output_asm_insn ("lr\t%0,%2", op); output_asm_insn ("a\t%0,0(%2)", op); output_asm_insn ("a\t%2,4(%2)", op); @@ -6278,144 +6776,57 @@ s390_function_profiler (file, labelno) constants go in the function section; in 64-bit mode in .rodata. */ static void -s390_select_rtx_section (mode, x, align) - enum machine_mode mode ATTRIBUTE_UNUSED; - rtx x ATTRIBUTE_UNUSED; - unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED; +s390_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) { - if (TARGET_64BIT) + if (TARGET_CPU_ZARCH) readonly_data_section (); else function_section (current_function_decl); } /* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF - into its name and SYMBOL_REF_FLAG. */ + into its SYMBOL_REF_FLAGS. */ static void -s390_encode_section_info (decl, first) - tree decl; - int first ATTRIBUTE_UNUSED; +s390_encode_section_info (tree decl, rtx rtl, int first) { - bool local_p = (*targetm.binds_local_p) (decl); - rtx rtl, symbol; - - rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl); - if (GET_CODE (rtl) != MEM) - return; - symbol = XEXP (rtl, 0); - if (GET_CODE (symbol) != SYMBOL_REF) - return; + default_encode_section_info (decl, rtl, first); - /* When using PIC, SYMBOL_REF_FLAG marks non-global symbols - that can be accessed directly. */ - if (flag_pic) - SYMBOL_REF_FLAG (symbol) = local_p; - - /* Encode thread-local data with %[GLil] for "global dynamic", - "local dynamic", "initial exec" or "local exec" TLS models, - respectively. */ - - if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) - { - const char *symbol_str = XSTR (symbol, 0); - char *newstr; - size_t len; - enum tls_model kind = decl_tls_model (decl); - - if (!flag_pic) - { - /* We don't allow non-pic code for shared libraries, - so don't generate GD/LD TLS models for non-pic code. */ - switch (kind) - { - case TLS_MODEL_GLOBAL_DYNAMIC: - kind = TLS_MODEL_INITIAL_EXEC; break; - case TLS_MODEL_LOCAL_DYNAMIC: - kind = TLS_MODEL_LOCAL_EXEC; break; - default: - break; - } - } - - if (symbol_str[0] == '%') - { - if (symbol_str[1] == tls_model_chars[kind]) - return; - symbol_str += 2; - } - len = strlen (symbol_str) + 1; - newstr = alloca (len + 2); - - newstr[0] = '%'; - newstr[1] = tls_model_chars[kind]; - memcpy (newstr + 2, symbol_str, len); - - XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1); - } - - /* If a variable has a forced alignment to < 2 bytes, mark it - with '@' to prevent it from being used as LARL operand. */ - - else if (TREE_CODE (decl) == VAR_DECL - && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16 - && XSTR (symbol, 0)[0] != '@') - { - const char *symbol_str = XSTR (symbol, 0); - size_t len = strlen (symbol_str) + 1; - char *newstr = alloca (len + 1); - - newstr[0] = '@'; - memcpy (newstr + 1, symbol_str, len); - - XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 1 - 1); - } -} - -/* Undo the above when printing symbol names. */ - -static const char * -s390_strip_name_encoding (str) - const char *str; -{ - if (str[0] == '%') - str += 2; - if (str[0] == '@') - str += 1; - if (str[0] == '*') - str += 1; - return str; + /* If a variable has a forced alignment to < 2 bytes, mark it with + SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL operand. */ + if (TREE_CODE (decl) == VAR_DECL + && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16) + SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1; } /* Output thunk to FILE that implements a C++ virtual function call (with - multiple inheritance) to FUNCTION. The thunk adjusts the this pointer + multiple inheritance) to FUNCTION. The thunk adjusts the this pointer by DELTA, and unless VCALL_OFFSET is zero, applies an additional adjustment stored at VCALL_OFFSET in the vtable whose address is located at offset 0 relative to the resulting this pointer. */ static void -s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) - FILE *file; - tree thunk ATTRIBUTE_UNUSED; - HOST_WIDE_INT delta; - HOST_WIDE_INT vcall_offset; - tree function; +s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, + tree function) { rtx op[10]; int nonlocal = 0; /* Operand 0 is the target function. */ op[0] = XEXP (DECL_RTL (function), 0); - if (flag_pic && !SYMBOL_REF_FLAG (op[0])) + if (flag_pic && !SYMBOL_REF_LOCAL_P (op[0])) { nonlocal = 1; op[0] = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op[0]), - TARGET_64BIT ? 113 : flag_pic == 2 ? 112 : 110); + TARGET_64BIT ? UNSPEC_PLT : UNSPEC_GOT); op[0] = gen_rtx_CONST (Pmode, op[0]); } /* Operand 1 is the 'this' pointer. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) op[1] = gen_rtx_REG (Pmode, 3); else op[1] = gen_rtx_REG (Pmode, 2); @@ -6442,8 +6853,10 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) if (TARGET_64BIT) { /* Setup literal pool pointer if required. */ - if (!CONST_OK_FOR_LETTER_P (delta, 'K') - || !CONST_OK_FOR_LETTER_P (vcall_offset, 'K')) + if ((!DISP_IN_RANGE (delta) + && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K")) + || (!DISP_IN_RANGE (vcall_offset) + && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))) { op[5] = gen_label_rtx (); output_asm_insn ("larl\t%4,%5", op); @@ -6452,9 +6865,11 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) /* Add DELTA to this pointer. */ if (delta) { - if (CONST_OK_FOR_LETTER_P (delta, 'J')) + if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J")) output_asm_insn ("la\t%1,%2(%1)", op); - else if (CONST_OK_FOR_LETTER_P (delta, 'K')) + else if (DISP_IN_RANGE (delta)) + output_asm_insn ("lay\t%1,%2(%1)", op); + else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K")) output_asm_insn ("aghi\t%1,%2", op); else { @@ -6466,12 +6881,12 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) /* Perform vcall adjustment. */ if (vcall_offset) { - if (CONST_OK_FOR_LETTER_P (vcall_offset, 'J')) + if (DISP_IN_RANGE (vcall_offset)) { output_asm_insn ("lg\t%4,0(%1)", op); output_asm_insn ("ag\t%1,%3(%4)", op); } - else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K')) + else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")) { output_asm_insn ("lghi\t%4,%3", op); output_asm_insn ("ag\t%4,0(%1)", op); @@ -6485,7 +6900,7 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) output_asm_insn ("ag\t%1,0(%4)", op); } } - + /* Jump to target. */ output_asm_insn ("jg\t%0", op); @@ -6493,16 +6908,19 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) if (op[5]) { output_asm_insn (".align\t4", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[5])); } if (op[6]) { - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[6])); output_asm_insn (".long\t%2", op); } if (op[7]) { - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[7])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[7])); output_asm_insn (".long\t%3", op); } } @@ -6510,20 +6928,25 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) { /* Setup base pointer if required. */ if (!vcall_offset - || !CONST_OK_FOR_LETTER_P (delta, 'K') - || !CONST_OK_FOR_LETTER_P (vcall_offset, 'K')) + || (!DISP_IN_RANGE (delta) + && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K")) + || (!DISP_IN_RANGE (delta) + && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))) { op[5] = gen_label_rtx (); output_asm_insn ("basr\t%4,0", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[5])); } /* Add DELTA to this pointer. */ if (delta) { - if (CONST_OK_FOR_LETTER_P (delta, 'J')) + if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J")) output_asm_insn ("la\t%1,%2(%1)", op); - else if (CONST_OK_FOR_LETTER_P (delta, 'K')) + else if (DISP_IN_RANGE (delta)) + output_asm_insn ("lay\t%1,%2(%1)", op); + else if (CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K")) output_asm_insn ("ahi\t%1,%2", op); else { @@ -6535,12 +6958,17 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) /* Perform vcall adjustment. */ if (vcall_offset) { - if (CONST_OK_FOR_LETTER_P (vcall_offset, 'J')) + if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'J', "J")) { output_asm_insn ("lg\t%4,0(%1)", op); output_asm_insn ("a\t%1,%3(%4)", op); } - else if (CONST_OK_FOR_LETTER_P (vcall_offset, 'K')) + else if (DISP_IN_RANGE (vcall_offset)) + { + output_asm_insn ("lg\t%4,0(%1)", op); + output_asm_insn ("ay\t%1,%3(%4)", op); + } + else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")) { output_asm_insn ("lhi\t%4,%3", op); output_asm_insn ("a\t%4,0(%1)", op); @@ -6558,7 +6986,8 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) Re-setup the base pointer (with a different base). */ op[5] = gen_label_rtx (); output_asm_insn ("basr\t%4,0", op); - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[5])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[5])); } /* Jump to target. */ @@ -6593,10 +7022,10 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) if (nonlocal) { op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - SYMBOL_REF_FLAG (op[0]) = 1; + SYMBOL_REF_FLAGS (op[0]) = SYMBOL_FLAG_LOCAL; } - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[8])); + targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[8])); if (!flag_pic) output_asm_insn (".long\t%0", op); else @@ -6604,21 +7033,29 @@ s390_output_mi_thunk (file, thunk, delta, vcall_offset, function) if (op[6]) { - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[6])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[6])); output_asm_insn (".long\t%2", op); } if (op[7]) { - ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (op[7])); + targetm.asm_out.internal_label (file, "L", + CODE_LABEL_NUMBER (op[7])); output_asm_insn (".long\t%3", op); } } } +bool +s390_valid_pointer_mode (enum machine_mode mode) +{ + return (mode == SImode || (TARGET_64BIT && mode == DImode)); +} + /* How to allocate a 'struct machine_function'. */ static struct machine_function * -s390_init_machine_status () +s390_init_machine_status (void) { return ggc_alloc_cleared (sizeof (struct machine_function)); } diff --git a/contrib/gcc/config/s390/s390.h b/contrib/gcc/config/s390/s390.h index c3dad68..d2416c8 100644 --- a/contrib/gcc/config/s390/s390.h +++ b/contrib/gcc/config/s390/s390.h @@ -1,23 +1,25 @@ /* Definitions of target machine for GNU compiler, for IBM S/390 - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +This file is part of GCC. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef _S390_H #define _S390_H @@ -25,9 +27,49 @@ Boston, MA 02111-1307, USA. */ /* Override the __fixdfdi etc. routines when building libgcc2. ??? This should be done in a cleaner way ... */ #if defined (IN_LIBGCC2) && !defined (__s390x__) -#include <s390/fixdfdi.h> +#include <config/s390/fixdfdi.h> #endif +/* Which processor to generate code or schedule for. The cpu attribute + defines a list that mirrors this list, so changes to s390.md must be + made at the same time. */ + +enum processor_type +{ + PROCESSOR_9672_G5, + PROCESSOR_9672_G6, + PROCESSOR_2064_Z900, + PROCESSOR_2084_Z990, + PROCESSOR_max +}; + +/* Optional architectural facilities supported by the processor. */ + +enum processor_flags +{ + PF_IEEE_FLOAT = 1, + PF_ZARCH = 2, + PF_LONG_DISPLACEMENT = 4 +}; + +extern enum processor_type s390_tune; +extern enum processor_flags s390_tune_flags; +extern const char *s390_tune_string; + +extern enum processor_type s390_arch; +extern enum processor_flags s390_arch_flags; +extern const char *s390_arch_string; + +#define TARGET_CPU_IEEE_FLOAT \ + (s390_arch_flags & PF_IEEE_FLOAT) +#define TARGET_CPU_ZARCH \ + (s390_arch_flags & PF_ZARCH) +#define TARGET_CPU_LONG_DISPLACEMENT \ + (s390_arch_flags & PF_LONG_DISPLACEMENT) + +#define TARGET_LONG_DISPLACEMENT \ + (TARGET_ZARCH && TARGET_CPU_LONG_DISPLACEMENT) + /* Run-time target specification. */ @@ -46,39 +88,85 @@ Boston, MA 02111-1307, USA. */ /* Optional target features. */ extern int target_flags; -#define TARGET_HARD_FLOAT (target_flags & 1) -#define TARGET_SOFT_FLOAT (!(target_flags & 1)) -#define TARGET_BACKCHAIN (target_flags & 2) -#define TARGET_SMALL_EXEC (target_flags & 4) -#define TARGET_DEBUG_ARG (target_flags & 8) -#define TARGET_64BIT (target_flags & 16) -#define TARGET_MVCLE (target_flags & 32) +#define MASK_HARD_FLOAT 0x01 +#define MASK_BACKCHAIN 0x02 +#define MASK_SMALL_EXEC 0x04 +#define MASK_DEBUG_ARG 0x08 +#define MASK_64BIT 0x10 +#define MASK_ZARCH 0x20 +#define MASK_MVCLE 0x40 +#define MASK_TPF 0x80 +#define MASK_NO_FUSED_MADD 0x100 + +#define TARGET_HARD_FLOAT (target_flags & MASK_HARD_FLOAT) +#define TARGET_SOFT_FLOAT (!(target_flags & MASK_HARD_FLOAT)) +#define TARGET_BACKCHAIN (target_flags & MASK_BACKCHAIN) +#define TARGET_SMALL_EXEC (target_flags & MASK_SMALL_EXEC) +#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG) +#define TARGET_64BIT (target_flags & MASK_64BIT) +#define TARGET_ZARCH (target_flags & MASK_ZARCH) +#define TARGET_MVCLE (target_flags & MASK_MVCLE) +#define TARGET_TPF (target_flags & MASK_TPF) +#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD) +#define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD) /* ??? Once this actually works, it could be made a runtime option. */ #define TARGET_IBM_FLOAT 0 #define TARGET_IEEE_FLOAT 1 #ifdef DEFAULT_TARGET_64BIT -#define TARGET_DEFAULT 0x13 +#define TARGET_DEFAULT 0x31 #else -#define TARGET_DEFAULT 0x3 +#define TARGET_DEFAULT 0x1 #endif -#define TARGET_SWITCHES \ -{ { "hard-float", 1, N_("Use hardware fp")}, \ - { "soft-float", -1, N_("Don't use hardware fp")}, \ - { "backchain", 2, N_("Set backchain")}, \ - { "no-backchain", -2, N_("Don't set backchain (faster, but debug harder")}, \ - { "small-exec", 4, N_("Use bras for executable < 64k")}, \ - { "no-small-exec",-4, N_("Don't use bras")}, \ - { "debug", 8, N_("Additional debug prints")}, \ - { "no-debug", -8, N_("Don't print additional debug prints")}, \ - { "64", 16, N_("64 bit mode")}, \ - { "31", -16, N_("31 bit mode")}, \ - { "mvcle", 32, N_("mvcle use")}, \ - { "no-mvcle", -32, N_("mvc&ex")}, \ +#define TARGET_SWITCHES \ +{ { "hard-float", 1, N_("Use hardware fp")}, \ + { "soft-float", -1, N_("Don't use hardware fp")}, \ + { "backchain", 2, N_("Set backchain")}, \ + { "no-backchain", -2, N_("Don't set backchain (faster, but debug harder")},\ + { "small-exec", 4, N_("Use bras for executable < 64k")}, \ + { "no-small-exec", -4, N_("Don't use bras")}, \ + { "debug", 8, N_("Additional debug prints")}, \ + { "no-debug", -8, N_("Don't print additional debug prints")}, \ + { "64", 16, N_("64 bit ABI")}, \ + { "31", -16, N_("31 bit ABI")}, \ + { "zarch", 32, N_("z/Architecture")}, \ + { "esa", -32, N_("ESA/390 architecture")}, \ + { "mvcle", 64, N_("mvcle use")}, \ + { "no-mvcle", -64, N_("mvc&ex")}, \ + { "tpf", 128, N_("enable tpf OS code")}, \ + { "no-tpf", -128, N_("disable tpf OS code")}, \ + { "no-fused-madd", 256, N_("disable fused multiply/add instructions")},\ + { "fused-madd", -256, N_("enable fused multiply/add instructions")}, \ { "", TARGET_DEFAULT, 0 } } +#define TARGET_OPTIONS \ +{ { "tune=", &s390_tune_string, \ + N_("Schedule code for given CPU"), 0}, \ + { "arch=", &s390_arch_string, \ + N_("Generate code for given CPU"), 0}, \ +} + +/* Support for configure-time defaults. */ +#define OPTION_DEFAULT_SPECS \ + { "mode", "%{!mesa:%{!mzarch:-m%(VALUE)}}" }, \ + { "arch", "%{!march=*:-march=%(VALUE)}" }, \ + { "tune", "%{!mtune=*:-mtune=%(VALUE)}" } + +/* Defaulting rules. */ +#ifdef DEFAULT_TARGET_64BIT +#define DRIVER_SELF_SPECS \ + "%{!m31:%{!m64:-m64}}", \ + "%{!mesa:%{!mzarch:%{m31:-mesa}%{m64:-mzarch}}}", \ + "%{!march=*:%{mesa:-march=g5}%{mzarch:-march=z900}}" +#else +#define DRIVER_SELF_SPECS \ + "%{!m31:%{!m64:-m31}}", \ + "%{!mesa:%{!mzarch:%{m31:-mesa}%{m64:-mzarch}}}", \ + "%{!march=*:%{mesa:-march=g5}%{mzarch:-march=z900}}" +#endif + /* Target version string. Overridden by the OS header. */ #ifdef DEFAULT_TARGET_64BIT #define TARGET_VERSION fprintf (stderr, " (zSeries)"); @@ -158,7 +246,7 @@ if (INTEGRAL_MODE_P (MODE) && \ NONLOCAL needs twice Pmode to maintain both backchain and SP. */ #define STACK_SAVEAREA_MODE(LEVEL) \ (LEVEL == SAVE_FUNCTION ? VOIDmode \ - : LEVEL == SAVE_NONLOCAL ? (TARGET_64BIT ? TImode : DImode) : Pmode) + : LEVEL == SAVE_NONLOCAL ? (TARGET_64BIT ? OImode : TImode) : Pmode) /* Define target floating point format. */ #define TARGET_FLOAT_FORMAT \ @@ -186,7 +274,7 @@ if (INTEGRAL_MODE_P (MODE) && \ /* We have 16 general purpose registers (registers 0-15), and 16 floating point registers (registers 16-31). (On non-IEEE machines, we have only 4 fp registers.) - + Amongst the general purpose registers, some are used for specific purposes: GPR 11: Hard frame pointer (if needed) @@ -194,7 +282,7 @@ if (INTEGRAL_MODE_P (MODE) && \ GPR 13: Literal pool base register GPR 14: Return address register GPR 15: Stack pointer - + Registers 32-34 are 'fake' hard registers that do not correspond to actual hardware: Reg 32: Argument pointer @@ -226,7 +314,7 @@ if (INTEGRAL_MODE_P (MODE) && \ GPRs 6-15 are always call-saved. GPR 12 is fixed if used as GOT pointer. GPR 13 is always fixed (as literal pool pointer). - GPR 14 is always fixed (as return address). + GPR 14 is always fixed on S/390 machines (as return address). GPR 15 is always fixed (as stack pointer). The 'fake' hard registers are call-clobbered and fixed. @@ -277,6 +365,11 @@ do \ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ } \ + if (TARGET_CPU_ZARCH) \ + { \ + fixed_regs[RETURN_REGNUM] = 0; \ + call_used_regs[RETURN_REGNUM] = 0; \ + } \ if (TARGET_64BIT) \ { \ for (i = 24; i < 32; i++) \ @@ -291,26 +384,26 @@ do \ /* Preferred register allocation order. */ #define REG_ALLOC_ORDER \ -{ 1, 2, 3, 4, 5, 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, \ +{ 1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14, \ 16, 17, 18, 19, 20, 21, 22, 23, \ 24, 25, 26, 27, 28, 29, 30, 31, \ 15, 32, 33, 34 } /* Fitting values into registers. */ - + /* Integer modes <= word size fit into any GPR. Integer modes > word size fit into successive GPRs, starting with an even-numbered register. SImode and DImode fit into FPRs as well. - + Floating point modes <= word size fit into any FPR or GPR. Floating point modes > word size (i.e. DFmode on 32-bit) fit into any FPR, or an even-odd GPR pair. - + Complex floating point modes fit either into two FPRs, or into successive GPRs (again starting with an even number). - + Condition code modes fit only into the CC register. */ #define HARD_REGNO_NREGS(REGNO, MODE) \ @@ -352,19 +445,19 @@ do \ ? reg_classes_intersect_p (FP_REGS, CLASS) : 0) /* Register classes. */ - + /* We use the following register classes: GENERAL_REGS All general purpose registers ADDR_REGS All general purpose registers except %r0 (These registers can be used in address generation) FP_REGS All floating point registers - + GENERAL_FP_REGS Union of GENERAL_REGS and FP_REGS ADDR_FP_REGS Union of ADDR_REGS and FP_REGS - + NO_REGS No registers ALL_REGS All registers - + Note that the 'fake' frame pointer and argument pointer registers are included amongst the address registers here. The condition code register is only included in ALL_REGS. */ @@ -444,23 +537,23 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; (C) == 'd' ? GENERAL_REGS : \ (C) == 'f' ? FP_REGS : NO_REGS) -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'I' ? (unsigned long) (VALUE) < 256 : \ - (C) == 'J' ? (unsigned long) (VALUE) < 4096 : \ - (C) == 'K' ? (VALUE) >= -32768 && (VALUE) < 32768 : \ - (C) == 'L' ? (unsigned long) (VALUE) < 65536 : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 +#define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR) \ + s390_const_ok_for_constraint_p ((VALUE), (C), (STR)) -#define EXTRA_CONSTRAINT(OP, C) \ - ((C) == 'Q' ? q_constraint (OP) : \ - (C) == 'S' ? larl_operand (OP, GET_MODE (OP)) : 0) +#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(VALUE, C, STR) 1 -#define EXTRA_MEMORY_CONSTRAINT(C) ((C) == 'Q') +#define EXTRA_CONSTRAINT_STR(OP, C, STR) \ + s390_extra_constraint_str ((OP), (C), (STR)) +#define EXTRA_MEMORY_CONSTRAINT(C, STR) \ + ((C) == 'Q' || (C) == 'R' || (C) == 'S' || (C) == 'T') +#define EXTRA_ADDRESS_CONSTRAINT(C, STR) \ + ((C) == 'U' || (C) == 'W' || (C) == 'Y') +#define CONSTRAINT_LEN(C, STR) \ + ((C) == 'N' ? 5 : DEFAULT_CONSTRAINT_LEN ((C), (STR))) /* Stack layout and calling conventions. */ - + /* Our stack grows from higher to lower addresses. However, local variables are accessed by positive offsets, and function arguments are stored at increasing addresses. */ @@ -490,7 +583,7 @@ extern int current_function_outgoing_args_size; the argument area. */ #define FIRST_PARM_OFFSET(FNDECL) 0 -/* The return address of the current frame is retrieved +/* The return address of the current frame is retrieved from the initial value of register RETURN_REGNUM. For frames farther back, we use the stack slot where the corresponding RETURN_REGNUM register was saved. */ @@ -498,7 +591,7 @@ extern int current_function_outgoing_args_size; #define DYNAMIC_CHAIN_ADDRESS(FRAME) \ ((FRAME) != hard_frame_pointer_rtx ? (FRAME) : \ plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET)) - + #define RETURN_ADDR_RTX(COUNT, FRAME) \ s390_return_addr_rtx ((COUNT), DYNAMIC_CHAIN_ADDRESS ((FRAME))) @@ -507,7 +600,7 @@ extern int current_function_outgoing_args_size; /* Exception handling. */ - + /* Describe calling conventions for DWARF-2 exception handling. */ #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, RETURN_REGNUM) #define INCOMING_FRAME_SP_OFFSET STACK_POINTER_OFFSET @@ -517,7 +610,7 @@ extern int current_function_outgoing_args_size; #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 6 : INVALID_REGNUM) #define EH_RETURN_HANDLER_RTX \ gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, \ - TARGET_64BIT? -48 : -40)) + -STACK_POINTER_OFFSET + UNITS_PER_WORD*RETURN_REGNUM)) /* Select a format to encode pointers in exception handling data. */ #define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ @@ -533,8 +626,8 @@ extern int current_function_outgoing_args_size; #define HARD_FRAME_POINTER_REGNUM 11 #define ARG_POINTER_REGNUM 32 -/* The static chain must be call-clobbered, but not used for - function argument passing. As register 1 is clobbered by +/* The static chain must be call-clobbered, but not used for + function argument passing. As register 1 is clobbered by the trampoline code, we only have one option. */ #define STATIC_CHAIN_REGNUM 0 @@ -554,7 +647,7 @@ extern int current_function_outgoing_args_size; {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} #define CAN_ELIMINATE(FROM, TO) (1) @@ -575,7 +668,7 @@ extern int current_function_outgoing_args_size; /* Stack arguments. */ - + /* We need current_function_outgoing_args to be valid. */ #define ACCUMULATE_OUTGOING_ARGS 1 @@ -584,7 +677,7 @@ extern int current_function_outgoing_args_size; /* Register arguments. */ - + typedef struct s390_arg_structure { int gprs; /* gpr so far */ @@ -592,7 +685,7 @@ typedef struct s390_arg_structure } CUMULATIVE_ARGS; -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, NN) \ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, NN, N_NAMED_ARGS) \ ((CUM).gprs=0, (CUM).fprs=0) #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ @@ -613,41 +706,22 @@ CUMULATIVE_ARGS; /* Scalar return values. */ - -/* We return scalars in general purpose register 2 for integral values, - and floating point register 0 for fp values. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE) \ - && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \ - || POINTER_TYPE_P (VALTYPE) \ - ? word_mode : TYPE_MODE (VALTYPE), \ - TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_HARD_FLOAT ? 16 : 2) - -/* Define how to find the value returned by a library function assuming - the value has mode MODE. */ -#define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT \ - || TARGET_SOFT_FLOAT ) ? 2 : 16) -#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, RET_REG (MODE)) - -/* Only gpr 2 and fpr 0 are ever used as return registers. */ -#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16) +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + s390_function_value ((VALTYPE), VOIDmode) -/* Aggregate return values. */ +#define LIBCALL_VALUE(MODE) \ + s390_function_value (NULL, (MODE)) -/* The definition of this macro implies that there are cases where - a scalar value cannot be returned in registers. */ -#define RETURN_IN_MEMORY(type) \ - (TYPE_MODE (type) == BLKmode || \ - GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_INT || \ - GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT) +/* Only gpr 2 and fpr 0 are ever used as return registers. */ +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16) /* Structure value address is passed as invisible first argument (gpr 2). */ #define STRUCT_VALUE 0 /* Function entry and exit. */ - + /* When returning from a function, the stack pointer does not matter. */ #define EXIT_IGNORE_STACK 1 @@ -662,9 +736,6 @@ CUMULATIVE_ARGS; /* Implementing the varargs macros. */ -#define BUILD_VA_LIST_TYPE(VALIST) \ - (VALIST) = s390_build_va_list () - #define EXPAND_BUILTIN_VA_START(valist, nextarg) \ s390_va_start (valist, nextarg) @@ -684,7 +755,7 @@ CUMULATIVE_ARGS; /* Library calls. */ - + /* We should use memcpy, not bcopy. */ #define TARGET_MEM_FUNCTIONS @@ -711,7 +782,7 @@ CUMULATIVE_ARGS; #define REG_OK_FOR_INDEX_NONSTRICT_P(X) \ ((GET_MODE (X) == Pmode) && \ ((REGNO (X) >= FIRST_PSEUDO_REGISTER) \ - || REGNO_REG_CLASS (REGNO (X)) == ADDR_REGS)) + || REGNO_REG_CLASS (REGNO (X)) == ADDR_REGS)) #define REG_OK_FOR_BASE_NONSTRICT_P(X) REG_OK_FOR_INDEX_NONSTRICT_P (X) @@ -781,7 +852,7 @@ CUMULATIVE_ARGS; /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, return the mode to be used for the comparison. */ #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y)) - + /* Define the information needed to generate branch and scc insns. This is stored from the compare operation. Note that we can't use "rtx" here since it hasn't been defined! */ @@ -790,77 +861,6 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1; /* Relative costs of operations. */ -/* A part of a C `switch' statement that describes the relative costs - of constant RTL expressions. It must contain `case' labels for - expression codes `const_int', `const', `symbol_ref', `label_ref' - and `const_double'. Each case must ultimately reach a `return' - statement to return the relative cost of the use of that kind of - constant value in an expression. The cost may depend on the - precise value of the constant, which is available for examination - in X, and the rtx code of the expression in which it is contained, - found in OUTER_CODE. - - CODE is the expression code--redundant, since it can be obtained - with `GET_CODE (X)'. */ -/* Force_const_mem does not work out of reload, because the saveable_obstack - is set to reload_obstack, which does not live long enough. - Because of this we cannot use force_const_mem in addsi3. - This leads to problems with gen_add2_insn with a constant greater - than a short. Because of that we give an addition of greater - constants a cost of 3 (reload1.c 10096). */ - -#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ - case CONST: \ - if ((GET_CODE (XEXP (RTX, 0)) == MINUS) && \ - (GET_CODE (XEXP (XEXP (RTX, 0), 1)) != CONST_INT)) \ - return 1000; \ - case CONST_INT: \ - if ((OUTER_CODE == PLUS) && \ - ((INTVAL (RTX) > 32767) || \ - (INTVAL (RTX) < -32768))) \ - return COSTS_N_INSNS (3); \ - case LABEL_REF: \ - case SYMBOL_REF: \ - case CONST_DOUBLE: \ - return 0; \ - - -/* Like `CONST_COSTS' but applies to nonconstant RTL expressions. - This can be used, for example, to indicate how costly a multiply - instruction is. In writing this macro, you can use the construct - `COSTS_N_INSNS (N)' to specify a cost equal to N fast - instructions. OUTER_CODE is the code of the expression in which X - is contained. */ - -#define RTX_COSTS(X, CODE, OUTER_CODE) \ - case ASHIFT: \ - case ASHIFTRT: \ - case LSHIFTRT: \ - case PLUS: \ - case AND: \ - case IOR: \ - case XOR: \ - case MINUS: \ - case NEG: \ - case NOT: \ - return COSTS_N_INSNS (1); \ - case MULT: \ - if (GET_MODE (XEXP (X, 0)) == DImode) \ - return COSTS_N_INSNS (40); \ - else \ - return COSTS_N_INSNS (7); \ - case DIV: \ - case UDIV: \ - case MOD: \ - case UMOD: \ - return COSTS_N_INSNS (33); - - -/* An expression giving the cost of an addressing mode that contains - ADDRESS. If not defined, the cost is computed from the ADDRESS - expression and the `CONST_COSTS' values. */ -#define ADDRESS_COST(RTX) s390_address_cost ((RTX)) - /* On s390, copy between fprs and gprs is expensive. */ #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ (( ( reg_classes_intersect_p ((CLASS1), GENERAL_REGS) \ @@ -925,7 +925,7 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1; /* Position independent code. */ -extern int flag_pic; +extern int flag_pic; #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 12 : INVALID_REGNUM) @@ -950,26 +950,11 @@ extern int flag_pic; /* Advance the location counter by SIZE bytes. */ #define ASM_OUTPUT_SKIP(FILE, SIZE) \ - fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE)) - -/* Output a reference to a user-level label named NAME. */ -#define ASM_OUTPUT_LABELREF(FILE, NAME) \ - asm_fprintf ((FILE), "%U%s", (*targetm.strip_name_encoding) (NAME)) - -/* Store in OUTPUT a string (made with alloca) containing - an assembler-name for a local static variable named NAME. - LABELNO is an integer which is different for each call. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ - ((OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ - sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + fprintf ((FILE), "\t.set\t.,.+"HOST_WIDE_INT_PRINT_UNSIGNED"\n", (SIZE)) /* The LOCAL_LABEL_PREFIX variable is used by dbxelf.h. */ #define LOCAL_LABEL_PREFIX "." -/* Either simplify a location expression, or return the original. */ -#define ASM_SIMPLIFY_DWARF_ADDR(X) \ - s390_simplify_dwarf_addr (X) - /* How to refer to registers in assembler output. This sequence is indexed by compiler's hard-register-number (see above). */ #define REGISTER_NAMES \ @@ -980,6 +965,13 @@ extern int flag_pic; "%ap", "%cc", "%fp" \ } +/* Emit a dtp-relative reference to a TLS variable. */ + +#ifdef HAVE_AS_TLS +#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \ + s390_output_dwarf_dtprel (FILE, SIZE, X) +#endif + /* Print operand X (an rtx) in assembler syntax to file FILE. */ #define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE) #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) @@ -1008,71 +1000,13 @@ do { \ } while (0) -/* Constant Pool for all symbols operands which are changed with - force_const_mem during insn generation (expand_insn). */ - -extern int s390_pool_count; -extern int s390_nr_constants; - -#define ASM_OUTPUT_POOL_PROLOGUE(FILE, FUNNAME, fndecl, size) \ -{ \ - struct pool_constant *pool; \ - \ - if (s390_pool_count == -1) \ - { \ - s390_nr_constants = 0; \ - for (pool = first_pool; pool; pool = pool->next) \ - if (pool->mark) s390_nr_constants++; \ - return; \ - } \ -} - -#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, EXP, MODE, ALIGN, LABELNO, WIN) \ -{ \ - fprintf (FILE, ".LC%d:\n", LABELNO); \ - \ - /* Output the value of the constant itself. */ \ - switch (GET_MODE_CLASS (MODE)) \ - { \ - case MODE_FLOAT: \ - if (GET_CODE (EXP) != CONST_DOUBLE) \ - abort (); \ - \ - REAL_VALUE_FROM_CONST_DOUBLE (r, EXP); \ - assemble_real (r, MODE, ALIGN); \ - break; \ - \ - case MODE_INT: \ - case MODE_PARTIAL_INT: \ - if (GET_CODE (EXP) == CONST \ - || GET_CODE (EXP) == SYMBOL_REF \ - || GET_CODE (EXP) == LABEL_REF) \ - { \ - fputs (integer_asm_op (UNITS_PER_WORD, TRUE), FILE); \ - s390_output_symbolic_const (FILE, EXP); \ - fputc ('\n', (FILE)); \ - } \ - else \ - { \ - assemble_integer (EXP, GET_MODE_SIZE (MODE), ALIGN, 1); \ - if (GET_MODE_SIZE (MODE) == 1) \ - ASM_OUTPUT_SKIP ((FILE), 1); \ - } \ - break; \ - \ - default: \ - abort (); \ - } \ - goto WIN; \ -} - - /* Miscellaneous parameters. */ /* Define the codes that are matched by predicates in aux-output.c. */ #define PREDICATE_CODES \ {"s_operand", { SUBREG, MEM }}, \ {"s_imm_operand", { CONST_INT, CONST_DOUBLE, SUBREG, MEM }}, \ + {"shift_count_operand", { REG, SUBREG, PLUS, CONST_INT }}, \ {"bras_sym_operand",{ SYMBOL_REF, CONST }}, \ {"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \ {"load_multiple_operation", {PARALLEL}}, \ @@ -1080,20 +1014,14 @@ extern int s390_nr_constants; {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \ {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \ CONST_INT, CONST_DOUBLE }}, \ - {"s390_plus_operand", { PLUS }}, + {"s390_plus_operand", { PLUS }}, \ + {"s390_alc_comparison", { LTU, GTU, LEU, GEU }}, \ + {"s390_slb_comparison", { LTU, GTU, LEU, GEU }}, /* Specify the machine mode that this machine uses for the index in the tablejump instruction. */ #define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode) -/* Load from integral MODE < SI from memory into register makes sign_extend - or zero_extend - In our case sign_extension happens for Halfwords, other no extension. */ -#define LOAD_EXTEND_OP(MODE) \ -(TARGET_64BIT ? ((MODE) == QImode ? ZERO_EXTEND : \ - (MODE) == HImode ? SIGN_EXTEND : NIL) \ - : ((MODE) == HImode ? SIGN_EXTEND : NIL)) - /* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits is done just by pretending it is already truncated. */ #define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 @@ -1103,6 +1031,9 @@ extern int s390_nr_constants; between pointers and any other objects of this machine mode. */ #define Pmode ((enum machine_mode) (TARGET_64BIT ? DImode : SImode)) +/* This is -1 for "pointer mode" extend. See ptr_extend in s390.md. */ +#define POINTERS_EXTEND_UNSIGNED -1 + /* A function address in a call instruction is a byte address (for indexing purposes) so give the MEM rtx a byte's mode. */ #define FUNCTION_MODE QImode @@ -1110,10 +1041,4 @@ extern int s390_nr_constants; /* This macro definition sets up a default value for `main' to return. */ #define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) -/* In rare cases, correct code generation requires extra machine dependent - processing between the second jump optimization pass and delayed branch - scheduling. On those machines, define this macro as a C statement to act on - the code starting at INSN. */ -#define MACHINE_DEPENDENT_REORG(INSN) s390_machine_dependent_reorg (INSN) - -#endif +#endif diff --git a/contrib/gcc/config/s390/s390.md b/contrib/gcc/config/s390/s390.md index 8178516..ebb8b57 100644 --- a/contrib/gcc/config/s390/s390.md +++ b/contrib/gcc/config/s390/s390.md @@ -1,23 +1,25 @@ ;;- Machine description for GNU compiler -- S/390 / zSeries version. -;; Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +;; Free Software Foundation, Inc. ;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and ;; Ulrich Weigand (uweigand@de.ibm.com). -;; This file is part of GNU CC. -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. +;; This file is part of GCC. -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. +;; 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 GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; along with GCC; see the file COPYING. If not, write to the Free +;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. ;; ;; Special constraints for s/390 machine description: @@ -27,17 +29,42 @@ ;; I -- An 8-bit constant (0..255). ;; J -- A 12-bit constant (0..4095). ;; K -- A 16-bit constant (-32768..32767). -;; Q -- A memory reference without index-register. -;; S -- Valid operand for the LARL instruction. +;; L -- Value appropriate as displacement. +;; (0..4095) for short displacement +;; (-524288..524287) for long displacement +;; M -- Constant integer with a value of 0x7fffffff. +;; N -- Multiple letter constraint followed by 4 parameter letters. +;; 0..9: number of the part counting from most to least significant +;; H,Q: mode of the part +;; D,S,H: mode of the containing operand +;; 0,F: value of the other parts (F - all bits set) +;; +;; The constraint matches if the specified part of a constant +;; has a value different from its other parts. +;; Q -- Memory reference without index register and with short displacement. +;; R -- Memory reference with index register and short displacement. +;; S -- Memory reference without index register but with long displacement. +;; T -- Memory reference with index register and long displacement. +;; U -- Pointer with short displacement. +;; W -- Pointer with long displacement. +;; Y -- Shift count operand. ;; ;; Special formats used for outputting 390 instructions. ;; -;; %b -- Print a constant byte integer. xy -;; %h -- Print a signed 16-bit. wxyz -;; %N -- Print next register (second word of a DImode reg) or next word. -;; %M -- Print next register (second word of a TImode reg) or next word. -;; %O -- Print the offset of a memory reference (PLUS (REG) (CONST_INT)). -;; %R -- Print the register of a memory reference (PLUS (REG) (CONST_INT)). +;; %C: print opcode suffix for branch condition. +;; %D: print opcode suffix for inverse branch condition. +;; %J: print tls_load/tls_gdcall/tls_ldcall suffix +;; %O: print only the displacement of a memory reference. +;; %R: print only the base register of a memory reference. +;; %N: print the second word of a DImode operand. +;; %M: print the second word of a TImode operand. + +;; %b: print integer X as if it's an unsigned byte. +;; %x: print integer X as if it's an unsigned word. +;; %h: print integer X as if it's a signed word. +;; %i: print the first nonzero HImode part of X +;; %j: print the first HImode part unequal to 0xffff of X + ;; ;; We have a special constraint for pattern matching. ;; @@ -49,7 +76,24 @@ ;; (define_constants - [; TLS relocation specifiers + [; Miscellaneous + (UNSPEC_ROUND 1) + (UNSPEC_SETHIGH 10) + + ; GOT/PLT and lt-relative accesses + (UNSPEC_LTREL_OFFSET 100) + (UNSPEC_LTREL_BASE 101) + (UNSPEC_GOTENT 110) + (UNSPEC_GOT 111) + (UNSPEC_GOTOFF 112) + (UNSPEC_PLT 113) + (UNSPEC_PLTOFF 114) + + ; Literal pool + (UNSPEC_RELOAD_BASE 210) + (UNSPEC_MAIN_BASE 211) + + ; TLS relocation specifiers (UNSPEC_TLSGD 500) (UNSPEC_TLSLDM 501) (UNSPEC_NTPOFF 502) @@ -61,6 +105,9 @@ (UNSPEC_TP 510) (UNSPEC_TLSLDM_NTPOFF 511) (UNSPEC_TLS_LOAD 512) + + ; String Functions + (UNSPEC_SRST 600) ]) ;; @@ -68,25 +115,70 @@ ;; (define_constants - [; TLS support + [; Blockage + (UNSPECV_BLOCKAGE 0) + + ; Literal pool + (UNSPECV_POOL 200) + (UNSPECV_POOL_START 201) + (UNSPECV_POOL_END 202) + (UNSPECV_POOL_ENTRY 203) + (UNSPECV_MAIN_POOL 300) + + ; TLS support (UNSPECV_SET_TP 500) ]) +;; Processor type. This attribute must exactly match the processor_type +;; enumeration in s390.h. + +(define_attr "cpu" "g5,g6,z900,z990" + (const (symbol_ref "s390_tune"))) + ;; Define an insn type attribute. This is used in function unit delay ;; computations. -(define_attr "type" "none,integer,load,lr,la,lm,stm,cs,vs,store,imul,lmul,fmul,idiv,ldiv,fdiv,branch,jsr,other,o2,o3" +(define_attr "type" "none,integer,load,lr,la,larl,lm,stm, + cs,vs,store,imul,idiv, + branch,jsr,fsimpd,fsimps, + floadd,floads,fstored, fstores, + fmuld,fmuls,fdivd,fdivs, + ftoi,itof,fsqrtd,fsqrts, + other,o2,o3" (const_string "integer")) -;; Insn are devide in two classes: -;; mem: Insn accessing memory -;; reg: Insn operands all in registers +;; Operand type. Used to default length attribute values -(define_attr "atype" "reg,mem" - (const_string "reg")) +(define_attr "op_type" + "NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE,RXY,RSY,SIY" + (const_string "RX")) -;; Generic pipeline function unit. +;; Insn are devide in two classes: +;; agen: Insn using agen +;; reg: Insn not using agen + +(define_attr "atype" "agen,reg" +(cond [ (eq_attr "op_type" "E") (const_string "reg") + (eq_attr "op_type" "RR") (const_string "reg") + (eq_attr "op_type" "RX") (const_string "agen") + (eq_attr "op_type" "RI") (const_string "reg") + (eq_attr "op_type" "RRE") (const_string "reg") + (eq_attr "op_type" "RS") (const_string "agen") + (eq_attr "op_type" "RSI") (const_string "agen") + (eq_attr "op_type" "S") (const_string "agen") + (eq_attr "op_type" "SI") (const_string "agen") + (eq_attr "op_type" "SS") (const_string "agen") + (eq_attr "op_type" "SSE") (const_string "agen") + (eq_attr "op_type" "RXE") (const_string "agen") + (eq_attr "op_type" "RSE") (const_string "agen") + (eq_attr "op_type" "RIL") (const_string "agen") + (eq_attr "op_type" "RXY") (const_string "agen") + (eq_attr "op_type" "RSY") (const_string "agen") + (eq_attr "op_type" "SIY") (const_string "agen")] + (const_string "reg"))) + +;; Generic pipeline function unit. (define_function_unit "integer" 1 0 (eq_attr "type" "none") 0 0) @@ -95,18 +187,42 @@ (eq_attr "type" "integer") 1 1) (define_function_unit "integer" 1 0 + (eq_attr "type" "fsimpd") 1 1) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fsimps") 1 1) + +(define_function_unit "integer" 1 0 (eq_attr "type" "load") 1 1) (define_function_unit "integer" 1 0 + (eq_attr "type" "floadd") 1 1) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "floads") 1 1) + +(define_function_unit "integer" 1 0 (eq_attr "type" "la") 1 1) (define_function_unit "integer" 1 0 + (eq_attr "type" "larl") 1 1) + +(define_function_unit "integer" 1 0 (eq_attr "type" "lr") 1 1) (define_function_unit "integer" 1 0 + (eq_attr "type" "branch") 1 1) + +(define_function_unit "integer" 1 0 (eq_attr "type" "store") 1 1) (define_function_unit "integer" 1 0 + (eq_attr "type" "fstored") 1 1) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fstores") 1 1) + +(define_function_unit "integer" 1 0 (eq_attr "type" "lm") 2 2) (define_function_unit "integer" 1 0 @@ -125,13 +241,31 @@ (eq_attr "type" "imul") 7 7) (define_function_unit "integer" 1 0 - (eq_attr "type" "fmul") 6 6) + (eq_attr "type" "fmuld") 6 6) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fmuls") 6 6) (define_function_unit "integer" 1 0 (eq_attr "type" "idiv") 33 33) (define_function_unit "integer" 1 0 - (eq_attr "type" "fdiv") 33 33) + (eq_attr "type" "fdivd") 33 33) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fdivs") 33 33) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fsqrtd") 30 30) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "fsqrts") 30 30) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "ftoi") 2 2) + +(define_function_unit "integer" 1 0 + (eq_attr "type" "itof") 2 2) (define_function_unit "integer" 1 0 (eq_attr "type" "o2") 2 2) @@ -142,11 +276,10 @@ (define_function_unit "integer" 1 0 (eq_attr "type" "other") 5 5) -;; Operand type. Used to default length attribute values +;; Pipeline description for z900 -(define_attr "op_type" - "NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE" - (const_string "RX")) +(include "2064.md") +(include "2084.md") ;; Length in bytes. @@ -158,14 +291,16 @@ (eq_attr "op_type" "RRE") (const_int 4) (eq_attr "op_type" "RS") (const_int 4) (eq_attr "op_type" "RSI") (const_int 4) - (eq_attr "op_type" "RX") (const_int 4) (eq_attr "op_type" "S") (const_int 4) (eq_attr "op_type" "SI") (const_int 4) (eq_attr "op_type" "SS") (const_int 6) (eq_attr "op_type" "SSE") (const_int 6) (eq_attr "op_type" "RXE") (const_int 6) (eq_attr "op_type" "RSE") (const_int 6) - (eq_attr "op_type" "RIL") (const_int 6)] + (eq_attr "op_type" "RIL") (const_int 6) + (eq_attr "op_type" "RXY") (const_int 6) + (eq_attr "op_type" "RSY") (const_int 6) + (eq_attr "op_type" "SIY") (const_int 6)] (const_int 4))) ;; Define attributes for `asm' insns. @@ -182,11 +317,11 @@ ; CCU: Equal ULess UGreater -- (CL, CLR, CLI, CLM) ; CCS: Equal SLess SGreater -- (C, CR, CH, CHI, ICM) ; CCT: Zero Mixed Mixed Ones (TM, TMH, TML) - + ; CCZ -> CCL / CCZ1 ; CCZ1 -> CCA/CCU/CCS/CCT ; CCS -> CCA - + ; String: CLC, CLCL, CLCLE, CLST, CUSE, MVCL, MVCLE, MVPG, MVST, SRST ; Clobber: CKSM, CFC, CS, CDS, CUUTF, CUTFU, PLO, SPM, STCK, STCKE, TS, TRT, TRE, UPT @@ -200,48 +335,44 @@ (compare:CC (match_operand:DI 0 "register_operand" "") (match_operand:DI 1 "general_operand" "")))] "TARGET_64BIT" - " { s390_compare_op0 = operands[0]; s390_compare_op1 = operands[1]; DONE; -}") +}) (define_expand "cmpsi" [(set (reg:CC 33) (compare:CC (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "general_operand" "")))] "" - " { s390_compare_op0 = operands[0]; s390_compare_op1 = operands[1]; DONE; -}") +}) (define_expand "cmpdf" [(set (reg:CC 33) (compare:CC (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "general_operand" "")))] "TARGET_HARD_FLOAT" - " { s390_compare_op0 = operands[0]; s390_compare_op1 = operands[1]; DONE; -}") +}) (define_expand "cmpsf" [(set (reg:CC 33) (compare:CC (match_operand:SF 0 "register_operand" "") (match_operand:SF 1 "general_operand" "")))] "TARGET_HARD_FLOAT" - " { s390_compare_op0 = operands[0]; s390_compare_op1 = operands[1]; DONE; -}") +}) ; Test-under-Mask (zero_extract) instructions @@ -253,11 +384,10 @@ (match_operand:DI 2 "const_int_operand" "n")) (const_int 0)))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT - && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 + && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 && INTVAL (operands[1]) + INTVAL (operands[2]) <= 64 && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4 == INTVAL (operands[2]) >> 4" - "* { int part = INTVAL (operands[2]) >> 4; int block = (1 << INTVAL (operands[1])) - 1; @@ -267,13 +397,13 @@ switch (part) { - case 0: return \"tmhh\\t%0,%x2\"; - case 1: return \"tmhl\\t%0,%x2\"; - case 2: return \"tmlh\\t%0,%x2\"; - case 3: return \"tmll\\t%0,%x2\"; + case 0: return "tmhh\t%0,%x2"; + case 1: return "tmhl\t%0,%x2"; + case 2: return "tmlh\t%0,%x2"; + case 3: return "tmll\t%0,%x2"; default: abort (); } -}" +} [(set_attr "op_type" "RI")]) (define_insn "*tmsi_ext" @@ -283,11 +413,10 @@ (match_operand:SI 2 "const_int_operand" "n")) (const_int 0)))] "s390_match_ccmode(insn, CCTmode) - && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 + && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4 == INTVAL (operands[2]) >> 4" - "* { int part = INTVAL (operands[2]) >> 4; int block = (1 << INTVAL (operands[1])) - 1; @@ -297,146 +426,140 @@ switch (part) { - case 0: return \"tmh\\t%0,%x2\"; - case 1: return \"tml\\t%0,%x2\"; + case 0: return "tmh\t%0,%x2"; + case 1: return "tml\t%0,%x2"; default: abort (); } -}" +} [(set_attr "op_type" "RI")]) -(define_insn "*tmqi_ext" +(define_insn "*tmqisi_ext" [(set (reg 33) - (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q") - (match_operand:SI 1 "const_int_operand" "n") - (match_operand:SI 2 "const_int_operand" "n")) + (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,S") + (match_operand:SI 1 "const_int_operand" "n,n") + (match_operand:SI 2 "const_int_operand" "n,n")) (const_int 0)))] - "s390_match_ccmode(insn, CCTmode) - && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 + "!TARGET_64BIT && s390_match_ccmode(insn, CCTmode) + && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8" - "* { int block = (1 << INTVAL (operands[1])) - 1; int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]); operands[2] = GEN_INT (block << shift); - return \"tm\\t%0,%b2\"; -}" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2"; +} + [(set_attr "op_type" "SI,SIY")]) + +(define_insn "*tmqidi_ext" + [(set (reg 33) + (compare (zero_extract:DI (match_operand:QI 0 "memory_operand" "Q,S") + (match_operand:SI 1 "const_int_operand" "n,n") + (match_operand:SI 2 "const_int_operand" "n,n")) + (const_int 0)))] + "TARGET_64BIT && s390_match_ccmode(insn, CCTmode) + && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8" +{ + int block = (1 << INTVAL (operands[1])) - 1; + int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]); + + operands[2] = GEN_INT (block << shift); + return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2"; +} + [(set_attr "op_type" "SI,SIY")]) + ; Test-under-Mask instructions (define_insn "*tmdi_mem" [(set (reg 33) - (compare (and:DI (match_operand:DI 0 "memory_operand" "Q") - (match_operand:DI 1 "immediate_operand" "n")) - (match_operand:DI 2 "immediate_operand" "n")))] - "TARGET_64BIT - && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0)) - && s390_single_qi (operands[1], DImode, 0) >= 0" - "* + (compare (and:DI (match_operand:DI 0 "memory_operand" "Q,S") + (match_operand:DI 1 "immediate_operand" "n,n")) + (match_operand:DI 2 "immediate_operand" "n,n")))] + "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0)) + && s390_single_part (operands[1], DImode, QImode, 0) >= 0" { - int part = s390_single_qi (operands[1], DImode, 0); - operands[1] = GEN_INT (s390_extract_qi (operands[1], DImode, part)); + int part = s390_single_part (operands[1], DImode, QImode, 0); + operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0)); - operands[0] = gen_rtx_MEM (QImode, + operands[0] = gen_rtx_MEM (QImode, plus_constant (XEXP (operands[0], 0), part)); - return \"tm\\t%0,%b1\"; -}" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1"; +} + [(set_attr "op_type" "SI,SIY")]) (define_insn "*tmsi_mem" [(set (reg 33) - (compare (and:SI (match_operand:SI 0 "memory_operand" "Q") - (match_operand:SI 1 "immediate_operand" "n")) - (match_operand:SI 2 "immediate_operand" "n")))] + (compare (and:SI (match_operand:SI 0 "memory_operand" "Q,S") + (match_operand:SI 1 "immediate_operand" "n,n")) + (match_operand:SI 2 "immediate_operand" "n,n")))] "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0)) - && s390_single_qi (operands[1], SImode, 0) >= 0" - "* + && s390_single_part (operands[1], SImode, QImode, 0) >= 0" { - int part = s390_single_qi (operands[1], SImode, 0); - operands[1] = GEN_INT (s390_extract_qi (operands[1], SImode, part)); + int part = s390_single_part (operands[1], SImode, QImode, 0); + operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0)); - operands[0] = gen_rtx_MEM (QImode, + operands[0] = gen_rtx_MEM (QImode, plus_constant (XEXP (operands[0], 0), part)); - return \"tm\\t%0,%b1\"; -}" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1"; +} + [(set_attr "op_type" "SI")]) (define_insn "*tmhi_mem" [(set (reg 33) - (compare (and:SI (subreg:SI (match_operand:HI 0 "memory_operand" "Q") 0) - (match_operand:SI 1 "immediate_operand" "n")) - (match_operand:SI 2 "immediate_operand" "n")))] + (compare (and:SI (subreg:SI (match_operand:HI 0 "memory_operand" "Q,S") 0) + (match_operand:SI 1 "immediate_operand" "n,n")) + (match_operand:SI 2 "immediate_operand" "n,n")))] "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0)) - && s390_single_qi (operands[1], HImode, 0) >= 0" - "* + && s390_single_part (operands[1], HImode, QImode, 0) >= 0" { - int part = s390_single_qi (operands[1], HImode, 0); - operands[1] = GEN_INT (s390_extract_qi (operands[1], HImode, part)); + int part = s390_single_part (operands[1], HImode, QImode, 0); + operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0)); - operands[0] = gen_rtx_MEM (QImode, + operands[0] = gen_rtx_MEM (QImode, plus_constant (XEXP (operands[0], 0), part)); - return \"tm\\t%0,%b1\"; -}" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1"; +} + [(set_attr "op_type" "SI")]) (define_insn "*tmqi_mem" [(set (reg 33) - (compare (and:SI (subreg:SI (match_operand:QI 0 "memory_operand" "Q") 0) - (match_operand:SI 1 "immediate_operand" "n")) - (match_operand:SI 2 "immediate_operand" "n")))] + (compare (and:SI (subreg:SI (match_operand:QI 0 "memory_operand" "Q,S") 0) + (match_operand:SI 1 "immediate_operand" "n,n")) + (match_operand:SI 2 "immediate_operand" "n,n")))] "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))" - "tm\\t%0,%b1" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + "@ + tm\t%0,%b1 + tmy\t%0,%b1" + [(set_attr "op_type" "SI,SIY")]) (define_insn "*tmdi_reg" [(set (reg 33) - (compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "d") - (match_operand:DI 1 "immediate_operand" "n")) - (match_operand:DI 2 "immediate_operand" "n")))] + (compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "d,d,d,d") + (match_operand:DI 1 "immediate_operand" + "N0HD0,N1HD0,N2HD0,N3HD0")) + (match_operand:DI 2 "immediate_operand" "n,n,n,n")))] "TARGET_64BIT && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 1)) - && s390_single_hi (operands[1], DImode, 0) >= 0" - "* -{ - int part = s390_single_hi (operands[1], DImode, 0); - operands[1] = GEN_INT (s390_extract_hi (operands[1], DImode, part)); - - switch (part) - { - case 0: return \"tmhh\\t%0,%x1\"; - case 1: return \"tmhl\\t%0,%x1\"; - case 2: return \"tmlh\\t%0,%x1\"; - case 3: return \"tmll\\t%0,%x1\"; - default: abort (); - } -}" + && s390_single_part (operands[1], DImode, HImode, 0) >= 0" + "@ + tmhh\t%0,%i1 + tmhl\t%0,%i1 + tmlh\t%0,%i1 + tmll\t%0,%i1" [(set_attr "op_type" "RI")]) (define_insn "*tmsi_reg" [(set (reg 33) - (compare (and:SI (match_operand:SI 0 "nonimmediate_operand" "d") - (match_operand:SI 1 "immediate_operand" "n")) - (match_operand:SI 2 "immediate_operand" "n")))] + (compare (and:SI (match_operand:SI 0 "nonimmediate_operand" "d,d") + (match_operand:SI 1 "immediate_operand" "N0HS0,N1HS0")) + (match_operand:SI 2 "immediate_operand" "n,n")))] "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 1)) - && s390_single_hi (operands[1], SImode, 0) >= 0" - "* -{ - int part = s390_single_hi (operands[1], SImode, 0); - operands[1] = GEN_INT (s390_extract_hi (operands[1], SImode, part)); - - switch (part) - { - case 0: return \"tmh\\t%0,%x1\"; - case 1: return \"tml\\t%0,%x1\"; - default: abort (); - } -}" + && s390_single_part (operands[1], SImode, HImode, 0) >= 0" + "@ + tmh\t%0,%i1 + tml\t%0,%i1" [(set_attr "op_type" "RI")]) (define_insn "*tmhi_full" @@ -444,7 +567,7 @@ (compare (match_operand:HI 0 "register_operand" "d") (match_operand:HI 1 "immediate_operand" "n")))] "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))" - "tml\\t%0,65535" + "tml\t%0,65535" [(set_attr "op_type" "RX")]) (define_insn "*tmqi_full" @@ -452,7 +575,7 @@ (compare (match_operand:QI 0 "register_operand" "d") (match_operand:QI 1 "immediate_operand" "n")))] "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))" - "tml\\t%0,255" + "tml\t%0,255" [(set_attr "op_type" "RI")]) @@ -466,7 +589,7 @@ (set (match_operand:DI 2 "register_operand" "=d") (sign_extend:DI (match_dup 0)))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "ltgfr\\t%2,%0" + "ltgfr\t%2,%0" [(set_attr "op_type" "RRE")]) (define_insn "*tstdi" @@ -476,7 +599,7 @@ (set (match_operand:DI 2 "register_operand" "=d") (match_dup 0))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "ltgr\\t%2,%0" + "ltgr\t%2,%0" [(set_attr "op_type" "RRE")]) (define_insn "*tstdi_cconly" @@ -484,7 +607,7 @@ (compare (match_operand:DI 0 "register_operand" "d") (match_operand:DI 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "ltgr\\t%0,%0" + "ltgr\t%0,%0" [(set_attr "op_type" "RRE")]) (define_insn "*tstdi_cconly_31" @@ -492,132 +615,138 @@ (compare (match_operand:DI 0 "register_operand" "d") (match_operand:DI 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && !TARGET_64BIT" - "srda\\t%0,0" - [(set_attr "op_type" "RS")]) + "srda\t%0,0" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) + (define_insn "*tstsi" [(set (reg 33) - (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q") + (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q,S") (match_operand:SI 1 "const0_operand" ""))) - (set (match_operand:SI 2 "register_operand" "=d,d") + (set (match_operand:SI 2 "register_operand" "=d,d,d") (match_dup 0))] "s390_match_ccmode(insn, CCSmode)" "@ - ltr\\t%2,%0 - icm\\t%2,15,%0" - [(set_attr "op_type" "RR,RS") - (set_attr "atype" "reg,mem")]) + ltr\t%2,%0 + icm\t%2,15,%0 + icmy\t%2,15,%0" + [(set_attr "op_type" "RR,RS,RSY")]) (define_insn "*tstsi_cconly" [(set (reg 33) - (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q") + (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q,S") (match_operand:SI 1 "const0_operand" ""))) - (clobber (match_scratch:SI 2 "=X,d"))] + (clobber (match_scratch:SI 2 "=X,d,d"))] "s390_match_ccmode(insn, CCSmode)" "@ - ltr\\t%0,%0 - icm\\t%2,15,%0" - [(set_attr "op_type" "RR,RS") - (set_attr "atype" "reg,mem")]) + ltr\t%0,%0 + icm\t%2,15,%0 + icmy\t%2,15,%0" + [(set_attr "op_type" "RR,RS,RSY")]) (define_insn "*tstsi_cconly2" [(set (reg 33) (compare (match_operand:SI 0 "register_operand" "d") (match_operand:SI 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode)" - "ltr\\t%0,%0" + "ltr\t%0,%0" [(set_attr "op_type" "RR")]) (define_insn "*tsthiCCT" [(set (reg 33) - (compare (match_operand:HI 0 "nonimmediate_operand" "?Q,d") + (compare (match_operand:HI 0 "nonimmediate_operand" "?Q,?S,d") (match_operand:HI 1 "const0_operand" ""))) - (set (match_operand:HI 2 "register_operand" "=d,0") + (set (match_operand:HI 2 "register_operand" "=d,d,0") (match_dup 0))] "s390_match_ccmode(insn, CCTmode)" "@ - icm\\t%2,3,%0 - tml\\t%0,65535" - [(set_attr "op_type" "RS,RI") - (set_attr "atype" "mem,reg")]) + icm\t%2,3,%0 + icmy\t%2,3,%0 + tml\t%0,65535" + [(set_attr "op_type" "RS,RSY,RI")]) (define_insn "*tsthiCCT_cconly" [(set (reg 33) - (compare (match_operand:HI 0 "nonimmediate_operand" "Q,d") + (compare (match_operand:HI 0 "nonimmediate_operand" "Q,S,d") (match_operand:HI 1 "const0_operand" ""))) - (clobber (match_scratch:HI 2 "=d,X"))] + (clobber (match_scratch:HI 2 "=d,d,X"))] "s390_match_ccmode(insn, CCTmode)" "@ - icm\\t%2,3,%0 - tml\\t%0,65535" - [(set_attr "op_type" "RS,RI") - (set_attr "atype" "mem,reg")]) + icm\t%2,3,%0 + icmy\t%2,3,%0 + tml\t%0,65535" + [(set_attr "op_type" "RS,RSY,RI")]) (define_insn "*tsthi" [(set (reg 33) - (compare (match_operand:HI 0 "s_operand" "Q") + (compare (match_operand:HI 0 "s_operand" "Q,S") (match_operand:HI 1 "const0_operand" ""))) - (set (match_operand:HI 2 "register_operand" "=d") + (set (match_operand:HI 2 "register_operand" "=d,d") (match_dup 0))] "s390_match_ccmode(insn, CCSmode)" - "icm\\t%2,3,%0" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%2,3,%0 + icmy\t%2,3,%0" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*tsthi_cconly" [(set (reg 33) - (compare (match_operand:HI 0 "s_operand" "Q") + (compare (match_operand:HI 0 "s_operand" "Q,S") (match_operand:HI 1 "const0_operand" ""))) - (clobber (match_scratch:HI 2 "=d"))] + (clobber (match_scratch:HI 2 "=d,d"))] "s390_match_ccmode(insn, CCSmode)" - "icm\\t%2,3,%0" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%2,3,%0 + icmy\t%2,3,%0" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*tstqiCCT" [(set (reg 33) - (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,d") + (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,?S,d") (match_operand:QI 1 "const0_operand" ""))) - (set (match_operand:QI 2 "register_operand" "=d,0") + (set (match_operand:QI 2 "register_operand" "=d,d,0") (match_dup 0))] "s390_match_ccmode(insn, CCTmode)" "@ - icm\\t%2,1,%0 - tml\\t%0,255" - [(set_attr "op_type" "RS,RI") - (set_attr "atype" "mem,reg")]) + icm\t%2,1,%0 + icmy\t%2,1,%0 + tml\t%0,255" + [(set_attr "op_type" "RS,RSY,RI")]) (define_insn "*tstqiCCT_cconly" [(set (reg 33) - (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,d") + (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,?S,d") (match_operand:QI 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCTmode)" "@ - cli\\t%0,0 - tml\\t%0,255" - [(set_attr "op_type" "SI,RI") - (set_attr "atype" "mem,reg")]) + cli\t%0,0 + cliy\t%0,0 + tml\t%0,255" + [(set_attr "op_type" "SI,SIY,RI")]) (define_insn "*tstqi" [(set (reg 33) - (compare (match_operand:QI 0 "s_operand" "Q") + (compare (match_operand:QI 0 "s_operand" "Q,S") (match_operand:QI 1 "const0_operand" ""))) - (set (match_operand:QI 2 "register_operand" "=d") + (set (match_operand:QI 2 "register_operand" "=d,d") (match_dup 0))] "s390_match_ccmode(insn, CCSmode)" - "icm\\t%2,1,%0" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%2,1,%0 + icmy\t%2,1,%0" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*tstqi_cconly" [(set (reg 33) - (compare (match_operand:QI 0 "s_operand" "Q") + (compare (match_operand:QI 0 "s_operand" "Q,S") (match_operand:QI 1 "const0_operand" ""))) - (clobber (match_scratch:QI 2 "=d"))] + (clobber (match_scratch:QI 2 "=d,d"))] "s390_match_ccmode(insn, CCSmode)" - "icm\\t%2,1,%0" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%2,1,%0 + icmy\t%2,1,%0" + [(set_attr "op_type" "RS,RSY")]) ; Compare (signed) instructions @@ -628,10 +757,9 @@ (match_operand:DI 0 "register_operand" "d,d")))] "s390_match_ccmode(insn, CCSRmode) && TARGET_64BIT" "@ - cgfr\\t%0,%1 - cgf\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + cgfr\t%0,%1 + cgf\t%0,%1" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*cmpdi_ccs" [(set (reg 33) @@ -639,33 +767,33 @@ (match_operand:DI 1 "general_operand" "d,K,m")))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" "@ - cgr\\t%0,%1 - cghi\\t%0,%c1 - cg\\t%0,%1" - [(set_attr "op_type" "RRE,RI,RXE") - (set_attr "atype" "reg,reg,mem")]) - + cgr\t%0,%1 + cghi\t%0,%c1 + cg\t%0,%1" + [(set_attr "op_type" "RRE,RI,RXY")]) + (define_insn "*cmpsi_ccs_sign" [(set (reg 33) - (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")) - (match_operand:SI 0 "register_operand" "d")))] + (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T")) + (match_operand:SI 0 "register_operand" "d,d")))] "s390_match_ccmode(insn, CCSRmode)" - "ch\\t%0,%1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + ch\t%0,%1 + chy\t%0,%1" + [(set_attr "op_type" "RX,RXY")]) (define_insn "*cmpsi_ccs" [(set (reg 33) - (compare (match_operand:SI 0 "register_operand" "d,d,d") - (match_operand:SI 1 "general_operand" "d,K,m")))] + (compare (match_operand:SI 0 "register_operand" "d,d,d,d") + (match_operand:SI 1 "general_operand" "d,K,R,T")))] "s390_match_ccmode(insn, CCSmode)" "@ - cr\\t%0,%1 - chi\\t%0,%c1 - c\\t%0,%1" - [(set_attr "op_type" "RR,RI,RX") - (set_attr "atype" "reg,reg,mem")]) - + cr\t%0,%1 + chi\t%0,%c1 + c\t%0,%1 + cy\t%0,%1" + [(set_attr "op_type" "RR,RI,RX,RXY")]) + ; Compare (unsigned) instructions @@ -675,10 +803,9 @@ (match_operand:DI 0 "register_operand" "d,d")))] "s390_match_ccmode(insn, CCURmode) && TARGET_64BIT" "@ - clgfr\\t%0,%1 - clgf\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + clgfr\t%0,%1 + clgf\t%0,%1" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*cmpdi_ccu" [(set (reg 33) @@ -686,84 +813,82 @@ (match_operand:DI 1 "general_operand" "d,m")))] "s390_match_ccmode(insn, CCUmode) && TARGET_64BIT" "@ - clgr\\t%0,%1 - clg\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + clgr\t%0,%1 + clg\t%0,%1" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*cmpsi_ccu" [(set (reg 33) - (compare (match_operand:SI 0 "register_operand" "d,d") - (match_operand:SI 1 "general_operand" "d,m")))] + (compare (match_operand:SI 0 "register_operand" "d,d,d") + (match_operand:SI 1 "general_operand" "d,R,T")))] "s390_match_ccmode(insn, CCUmode)" "@ - clr\\t%0,%1 - cl\\t%0,%1" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + clr\t%0,%1 + cl\t%0,%1 + cly\t%0,%1" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*cmphi_ccu" [(set (reg 33) - (compare (match_operand:HI 0 "register_operand" "d") - (match_operand:HI 1 "s_imm_operand" "Q")))] + (compare (match_operand:HI 0 "register_operand" "d,d") + (match_operand:HI 1 "s_imm_operand" "Q,S")))] "s390_match_ccmode(insn, CCUmode)" - "clm\\t%0,3,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + clm\t%0,3,%1 + clmy\t%0,3,%1" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*cmpqi_ccu" [(set (reg 33) - (compare (match_operand:QI 0 "register_operand" "d") - (match_operand:QI 1 "s_imm_operand" "Q")))] + (compare (match_operand:QI 0 "register_operand" "d,d") + (match_operand:QI 1 "s_imm_operand" "Q,S")))] "s390_match_ccmode(insn, CCUmode)" - "clm\\t%0,1,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + clm\t%0,1,%1 + clmy\t%0,1,%1" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*cli" [(set (reg 33) - (compare (match_operand:QI 0 "memory_operand" "Q") - (match_operand:QI 1 "immediate_operand" "n")))] + (compare (match_operand:QI 0 "memory_operand" "Q,S") + (match_operand:QI 1 "immediate_operand" "n,n")))] "s390_match_ccmode (insn, CCUmode)" - "cli\\t%0,%b1" - [(set_attr "op_type" "SI") - (set_attr "atype" "mem")]) + "@ + cli\t%0,%b1 + cliy\t%0,%b1" + [(set_attr "op_type" "SI,SIY")]) (define_insn "*cmpdi_ccu_mem" [(set (reg 33) (compare (match_operand:DI 0 "s_operand" "Q") (match_operand:DI 1 "s_imm_operand" "Q")))] "s390_match_ccmode(insn, CCUmode)" - "clc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "clc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*cmpsi_ccu_mem" [(set (reg 33) (compare (match_operand:SI 0 "s_operand" "Q") (match_operand:SI 1 "s_imm_operand" "Q")))] "s390_match_ccmode(insn, CCUmode)" - "clc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "clc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*cmphi_ccu_mem" [(set (reg 33) (compare (match_operand:HI 0 "s_operand" "Q") (match_operand:HI 1 "s_imm_operand" "Q")))] "s390_match_ccmode(insn, CCUmode)" - "clc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "clc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*cmpqi_ccu_mem" [(set (reg 33) (compare (match_operand:QI 0 "s_operand" "Q") (match_operand:QI 1 "s_imm_operand" "Q")))] "s390_match_ccmode(insn, CCUmode)" - "clc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "clc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SS")]) ; DF instructions @@ -773,38 +898,40 @@ (compare (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "ltdbr\\t%0,%0" - [(set_attr "op_type" "RRE")]) + "ltdbr\t%0,%0" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimpd")]) (define_insn "*cmpdf_ccs_0_ibm" [(set (reg 33) (compare (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "ltdr\\t%0,%0" - [(set_attr "op_type" "RR")]) + "ltdr\t%0,%0" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimpd")]) (define_insn "*cmpdf_ccs" [(set (reg 33) (compare (match_operand:DF 0 "register_operand" "f,f") - (match_operand:DF 1 "general_operand" "f,m")))] + (match_operand:DF 1 "general_operand" "f,R")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - cdbr\\t%0,%1 - cdb\\t%0,%1" + cdbr\t%0,%1 + cdb\t%0,%1" [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd")]) (define_insn "*cmpdf_ccs_ibm" [(set (reg 33) (compare (match_operand:DF 0 "register_operand" "f,f") - (match_operand:DF 1 "general_operand" "f,m")))] + (match_operand:DF 1 "general_operand" "f,R")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - cdr\\t%0,%1 - cd\\t%0,%1" + cdr\t%0,%1 + cd\t%0,%1" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd")]) ; SF instructions @@ -814,38 +941,40 @@ (compare (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "ltebr\\t%0,%0" - [(set_attr "op_type" "RRE")]) + "ltebr\t%0,%0" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimps")]) (define_insn "*cmpsf_ccs_0_ibm" [(set (reg 33) (compare (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "const0_operand" "")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "lter\\t%0,%0" - [(set_attr "op_type" "RR")]) + "lter\t%0,%0" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimps")]) (define_insn "*cmpsf_ccs" [(set (reg 33) (compare (match_operand:SF 0 "register_operand" "f,f") - (match_operand:SF 1 "general_operand" "f,m")))] + (match_operand:SF 1 "general_operand" "f,R")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - cebr\\t%0,%1 - ceb\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + cebr\t%0,%1 + ceb\t%0,%1" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimps")]) (define_insn "*cmpsf_ccs" [(set (reg 33) (compare (match_operand:SF 0 "register_operand" "f,f") - (match_operand:SF 1 "general_operand" "f,m")))] + (match_operand:SF 1 "general_operand" "f,R")))] "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - cer\\t%0,%1 - ce\\t%0,%1" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + cer\t%0,%1 + ce\t%0,%1" + [(set_attr "op_type" "RR,RX") + (set_attr "type" "fsimps")]) ;; @@ -857,17 +986,17 @@ ; (define_insn "movti" - [(set (match_operand:TI 0 "nonimmediate_operand" "=d,Q,d,o,Q") - (match_operand:TI 1 "general_operand" "Q,d,dKm,d,Q"))] + [(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o,Q") + (match_operand:TI 1 "general_operand" "QS,d,dKm,d,Q"))] "TARGET_64BIT" "@ - lmg\\t%0,%N0,%1 - stmg\\t%1,%N1,%0 + lmg\t%0,%N0,%1 + stmg\t%1,%N1,%0 # # - mvc\\t%O0(16,%R0),%1" - [(set_attr "op_type" "RSE,RSE,NN,NN,SS") - (set_attr "atype" "mem")]) + mvc\t%O0(16,%R0),%1" + [(set_attr "op_type" "RSY,RSY,NN,NN,SS") + (set_attr "type" "lm,stm,*,*,cs")]) (define_split [(set (match_operand:TI 0 "nonimmediate_operand" "") @@ -929,7 +1058,6 @@ [(set (match_operand:DI 0 "general_operand" "") (match_operand:DI 1 "general_operand" ""))] "" - " { /* Handle symbolic constants. */ if (TARGET_64BIT && SYMBOLIC_CONST (operands[1])) @@ -938,85 +1066,64 @@ /* During and after reload, we need to force constants to the literal pool ourselves, if necessary. */ if ((reload_in_progress || reload_completed) - && CONSTANT_P (operands[1]) + && CONSTANT_P (operands[1]) && (!legitimate_reload_constant_p (operands[1]) || FP_REG_P (operands[0]))) operands[1] = force_const_mem (DImode, operands[1]); -}") - -(define_insn "*movdi_lhi" - [(set (match_operand:DI 0 "register_operand" "=d") - (match_operand:DI 1 "immediate_operand" "K"))] - "TARGET_64BIT - && GET_CODE (operands[1]) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K') - && !FP_REG_P (operands[0])" - "lghi\\t%0,%h1" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) - -(define_insn "*movdi_lli" - [(set (match_operand:DI 0 "register_operand" "=d") - (match_operand:DI 1 "immediate_operand" "n"))] - "TARGET_64BIT && s390_single_hi (operands[1], DImode, 0) >= 0 - && !FP_REG_P (operands[0])" - "* -{ - int part = s390_single_hi (operands[1], DImode, 0); - operands[1] = GEN_INT (s390_extract_hi (operands[1], DImode, part)); - - switch (part) - { - case 0: return \"llihh\\t%0,%x1\"; - case 1: return \"llihl\\t%0,%x1\"; - case 2: return \"llilh\\t%0,%x1\"; - case 3: return \"llill\\t%0,%x1\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) +}) (define_insn "*movdi_larl" [(set (match_operand:DI 0 "register_operand" "=d") (match_operand:DI 1 "larl_operand" "X"))] "TARGET_64BIT && !FP_REG_P (operands[0])" - "larl\\t%0,%1" + "larl\t%0,%1" [(set_attr "op_type" "RIL") - (set_attr "atype" "reg") - (set_attr "type" "la")]) + (set_attr "type" "larl")]) (define_insn "*movdi_64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m,?Q") - (match_operand:DI 1 "general_operand" "d,m,d,*f,m,*f,?Q"))] + [(set (match_operand:DI 0 "nonimmediate_operand" + "=d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,?Q") + (match_operand:DI 1 "general_operand" + "K,N0HD0,N1HD0,N2HD0,N3HD0,L,d,m,d,*f,R,T,*f,*f,?Q"))] "TARGET_64BIT" "@ - lgr\\t%0,%1 - lg\\t%0,%1 - stg\\t%1,%0 - ldr\\t%0,%1 - ld\\t%0,%1 - std\\t%1,%0 - mvc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "RRE,RXE,RXE,RR,RX,RX,SS") - (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")]) + lghi\t%0,%h1 + llihh\t%0,%i1 + llihl\t%0,%i1 + llilh\t%0,%i1 + llill\t%0,%i1 + lay\t%0,%a1 + lgr\t%0,%1 + lg\t%0,%1 + stg\t%1,%0 + ldr\t%0,%1 + ld\t%0,%1 + ldy\t%0,%1 + std\t%1,%0 + stdy\t%1,%0 + mvc\t%O0(8,%R0),%1" + [(set_attr "op_type" "RI,RI,RI,RI,RI,RXY,RRE,RXY,RXY,RR,RX,RXY,RX,RXY,SS") + (set_attr "type" "*,*,*,*,*,la,lr,load,store,floadd,floadd,floadd, + fstored,fstored,cs")]) (define_insn "*movdi_31" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!m,Q") - (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,m,*f,Q"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,Q,d,o,!*f,!*f,!*f,!R,!T,Q") + (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,R,T,*f,*f,Q"))] "!TARGET_64BIT" "@ - lm\\t%0,%N0,%1 - stm\\t%1,%N1,%0 + lm\t%0,%N0,%1 + stm\t%1,%N1,%0 # # - ldr\\t%0,%1 - ld\\t%0,%1 - std\\t%1,%0 - mvc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "RS,RS,NN,NN,RR,RX,RX,SS") - (set_attr "atype" "mem,mem,*,*,reg,mem,mem,mem")]) + ldr\t%0,%1 + ld\t%0,%1 + ldy\t%0,%1 + std\t%1,%0 + stdy\t%1,%0 + mvc\t%O0(8,%R0),%1" + [(set_attr "op_type" "RS,RS,NN,NN,RR,RX,RXY,RX,RXY,SS") + (set_attr "type" "lm,stm,*,*,floadd,floadd,floadd,fstored,fstored,cs")]) (define_split [(set (match_operand:DI 0 "nonimmediate_operand" "") @@ -1083,6 +1190,52 @@ [(set (match_dup 0) (match_dup 2))] "operands[2] = get_pool_constant (operands[1]);") +(define_insn "*la_64" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (match_operand:QI 1 "address_operand" "U,W"))] + "TARGET_64BIT" + "@ + la\t%0,%a1 + lay\t%0,%a1" + [(set_attr "op_type" "RX,RXY") + (set_attr "type" "la")]) + +(define_peephole2 + [(parallel + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:QI 1 "address_operand" "")) + (clobber (reg:CC 33))])] + "TARGET_64BIT + && strict_memory_address_p (VOIDmode, operands[1]) + && preferred_la_operand_p (operands[1])" + [(set (match_dup 0) (match_dup 1))] + "") + +(define_peephole2 + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "")) + (parallel + [(set (match_dup 0) + (plus:DI (match_dup 0) + (match_operand:DI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 33))])] + "TARGET_64BIT + && !reg_overlap_mentioned_p (operands[0], operands[2]) + && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (DImode, operands[1], operands[2])) + && preferred_la_operand_p (gen_rtx_PLUS (DImode, operands[1], operands[2]))" + [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))] + "") + +(define_expand "reload_indi" + [(parallel [(match_operand:DI 0 "register_operand" "=a") + (match_operand:DI 1 "s390_plus_operand" "") + (match_operand:DI 2 "register_operand" "=&a")])] + "TARGET_64BIT" +{ + s390_expand_plus_operand (operands[0], operands[1], operands[2]); + DONE; +}) + ; ; movsi instruction pattern(s). ; @@ -1091,14 +1244,13 @@ [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] "" - " { /* Handle symbolic constants. */ if (!TARGET_64BIT && SYMBOLIC_CONST (operands[1])) emit_symbolic_move (operands); - /* expr.c tries to load an effective address using - force_reg. This fails because we don't have a + /* expr.c tries to load an effective address using + force_reg. This fails because we don't have a generic load_address pattern. Convert the move to a proper arithmetic operation instead, unless it is guaranteed to be OK. */ @@ -1113,54 +1265,61 @@ /* During and after reload, we need to force constants to the literal pool ourselves, if necessary. */ if ((reload_in_progress || reload_completed) - && CONSTANT_P (operands[1]) + && CONSTANT_P (operands[1]) && (!legitimate_reload_constant_p (operands[1]) || FP_REG_P (operands[0]))) operands[1] = force_const_mem (SImode, operands[1]); -}") - -(define_insn "*movsi_lhi" - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:SI 1 "immediate_operand" "K"))] - "GET_CODE (operands[1]) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K') - && !FP_REG_P (operands[0])" - "lhi\\t%0,%h1" - [(set_attr "op_type" "RI")]) +}) -(define_insn "*movsi_lli" +(define_insn "*movsi_larl" [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:SI 1 "immediate_operand" "n"))] - "TARGET_64BIT && s390_single_hi (operands[1], SImode, 0) >= 0 + (match_operand:SI 1 "larl_operand" "X"))] + "!TARGET_64BIT && TARGET_CPU_ZARCH && !FP_REG_P (operands[0])" - "* -{ - int part = s390_single_hi (operands[1], SImode, 0); - operands[1] = GEN_INT (s390_extract_hi (operands[1], SImode, part)); - - switch (part) - { - case 0: return \"llilh\\t%0,%x1\"; - case 1: return \"llill\\t%0,%x1\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI")]) - -(define_insn "*movsi" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,m,!*f,!*f,!m,?Q") - (match_operand:SI 1 "general_operand" "d,m,d,*f,m,*f,?Q"))] - "" - "@ - lr\\t%0,%1 - l\\t%0,%1 - st\\t%1,%0 - ler\\t%0,%1 - le\\t%0,%1 - ste\\t%1,%0 - mvc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "RR,RX,RX,RR,RX,RX,SS") - (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")]) + "larl\t%0,%1" + [(set_attr "op_type" "RIL") + (set_attr "type" "larl")]) + +(define_insn "*movsi_zarch" + [(set (match_operand:SI 0 "nonimmediate_operand" + "=d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,?Q") + (match_operand:SI 1 "general_operand" + "K,N0HS0,N1HS0,L,d,R,T,d,d,*f,R,T,*f,*f,?Q"))] + "TARGET_ZARCH" + "@ + lhi\t%0,%h1 + llilh\t%0,%i1 + llill\t%0,%i1 + lay\t%0,%a1 + lr\t%0,%1 + l\t%0,%1 + ly\t%0,%1 + st\t%1,%0 + sty\t%1,%0 + ler\t%0,%1 + le\t%0,%1 + ley\t%0,%1 + ste\t%1,%0 + stey\t%1,%0 + mvc\t%O0(4,%R0),%1" + [(set_attr "op_type" "RI,RI,RI,RXY,RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS") + (set_attr "type" "*,*,*,la,lr,load,load,store,store,floads,floads,floads,fstores,fstores,cs")]) + +(define_insn "*movsi_esa" + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,?Q") + (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,?Q"))] + "!TARGET_ZARCH" + "@ + lhi\t%0,%h1 + lr\t%0,%1 + l\t%0,%1 + st\t%1,%0 + ler\t%0,%1 + le\t%0,%1 + ste\t%1,%0 + mvc\t%O0(4,%R0),%1" + [(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,SS") + (set_attr "type" "*,lr,load,store,floads,floads,fstores,cs")]) (define_peephole2 [(set (match_operand:SI 0 "register_operand" "") @@ -1173,22 +1332,125 @@ [(set (match_dup 0) (match_dup 2))] "operands[2] = get_pool_constant (operands[1]);") +(define_insn "*la_31" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (match_operand:QI 1 "address_operand" "U,W"))] + "!TARGET_64BIT && legitimate_la_operand_p (operands[1])" + "@ + la\t%0,%a1 + lay\t%0,%a1" + [(set_attr "op_type" "RX,RXY") + (set_attr "type" "la")]) + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:QI 1 "address_operand" "")) + (clobber (reg:CC 33))])] + "!TARGET_64BIT + && strict_memory_address_p (VOIDmode, operands[1]) + && preferred_la_operand_p (operands[1])" + [(set (match_dup 0) (match_dup 1))] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (parallel + [(set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 33))])] + "!TARGET_64BIT + && !reg_overlap_mentioned_p (operands[0], operands[2]) + && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (SImode, operands[1], operands[2])) + && preferred_la_operand_p (gen_rtx_PLUS (SImode, operands[1], operands[2]))" + [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))] + "") + +(define_insn "*la_31_and" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (and:SI (match_operand:QI 1 "address_operand" "U,W") + (const_int 2147483647)))] + "!TARGET_64BIT" + "@ + la\t%0,%a1 + lay\t%0,%a1" + [(set_attr "op_type" "RX,RXY") + (set_attr "type" "la")]) + +(define_insn_and_split "*la_31_and_cc" + [(set (match_operand:SI 0 "register_operand" "=d") + (and:SI (match_operand:QI 1 "address_operand" "p") + (const_int 2147483647))) + (clobber (reg:CC 33))] + "!TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (and:SI (match_dup 1) (const_int 2147483647)))] + "" + [(set_attr "op_type" "RX") + (set_attr "type" "la")]) + +(define_insn "force_la_31" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (match_operand:QI 1 "address_operand" "U,W")) + (use (const_int 0))] + "!TARGET_64BIT" + "@ + la\t%0,%a1 + lay\t%0,%a1" + [(set_attr "op_type" "RX") + (set_attr "type" "la")]) + +(define_expand "reload_insi" + [(parallel [(match_operand:SI 0 "register_operand" "=a") + (match_operand:SI 1 "s390_plus_operand" "") + (match_operand:SI 2 "register_operand" "=&a")])] + "!TARGET_64BIT" +{ + s390_expand_plus_operand (operands[0], operands[1], operands[2]); + DONE; +}) + ; ; movhi instruction pattern(s). ; -(define_insn "movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,?Q") - (match_operand:HI 1 "general_operand" "d,n,m,d,?Q"))] +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" +{ + /* Make it explicit that loading a register from memory + always sign-extends (at least) to SImode. */ + if (optimize && !no_new_pseudos + && register_operand (operands[0], VOIDmode) + && GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) != ADDRESSOF) + { + rtx tmp = gen_reg_rtx (SImode); + rtx ext = gen_rtx_SIGN_EXTEND (SImode, operands[1]); + emit_insn (gen_rtx_SET (VOIDmode, tmp, ext)); + operands[1] = gen_lowpart (HImode, tmp); + } +}) + +(define_insn "*movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,T,?Q") + (match_operand:HI 1 "general_operand" "d,n,R,T,d,d,?Q"))] "" "@ - lr\\t%0,%1 - lhi\\t%0,%h1 - lh\\t%0,%1 - sth\\t%1,%0 - mvc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "RR,RI,RX,RX,SS") - (set_attr "atype" "reg,reg,mem,mem,mem")]) + lr\t%0,%1 + lhi\t%0,%h1 + lh\t%0,%1 + lhy\t%0,%1 + sth\t%1,%0 + sthy\t%1,%0 + mvc\t%O0(2,%R0),%1" + [(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SS") + (set_attr "type" "lr,*,*,*,store,store,cs")]) (define_peephole2 [(set (match_operand:HI 0 "register_operand" "") @@ -1204,34 +1466,41 @@ ; movqi instruction pattern(s). ; -(define_insn "movqi_64" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q,?Q") - (match_operand:QI 1 "general_operand" "d,n,m,d,n,?Q"))] - "TARGET_64BIT" - "@ - lr\\t%0,%1 - lhi\\t%0,%b1 - llgc\\t%0,%1 - stc\\t%1,%0 - mvi\\t%0,%b1 - mvc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "RR,RI,RXE,RX,SI,SS") - (set_attr "atype" "reg,reg,mem,mem,mem,mem")]) - +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" +{ + /* On z/Architecture, zero-extending from memory to register + is just as fast as a QImode load. */ + if (TARGET_ZARCH && optimize && !no_new_pseudos + && register_operand (operands[0], VOIDmode) + && GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) != ADDRESSOF) + { + rtx tmp = gen_reg_rtx (word_mode); + rtx ext = gen_rtx_ZERO_EXTEND (word_mode, operands[1]); + emit_insn (gen_rtx_SET (VOIDmode, tmp, ext)); + operands[1] = gen_lowpart (QImode, tmp); + } +}) -(define_insn "movqi" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,Q,?Q") - (match_operand:QI 1 "general_operand" "d,n,m,d,n,?Q"))] +(define_insn "*movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,T,Q,S,?Q") + (match_operand:QI 1 "general_operand" "d,n,R,T,d,d,n,n,?Q"))] "" "@ - lr\\t%0,%1 - lhi\\t%0,%b1 - ic\\t%0,%1 - stc\\t%1,%0 - mvi\\t%0,%b1 - mvc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "RR,RI,RX,RX,SI,SS") - (set_attr "atype" "reg,reg,mem,mem,mem,mem")]) + lr\t%0,%1 + lhi\t%0,%b1 + ic\t%0,%1 + icy\t%0,%1 + stc\t%1,%0 + stcy\t%1,%0 + mvi\t%0,%b1 + mviy\t%0,%b1 + mvc\t%O0(1,%R0),%1" + [(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SI,SIY,SS") + (set_attr "type" "lr,*,*,*,store,store,store,store,cs")]) (define_peephole2 [(set (match_operand:QI 0 "nonimmediate_operand" "") @@ -1248,41 +1517,42 @@ ; (define_insn "*movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) - (match_operand:QI 1 "memory_operand" "m"))] + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d,d")) + (match_operand:QI 1 "memory_operand" "R,T"))] "" - "ic\\t%0,%1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + ic\t%0,%1 + icy\t%0,%1" + [(set_attr "op_type" "RX,RXY")]) ; ; movstricthi instruction pattern(s). ; (define_insn "*movstricthi" - [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) - (match_operand:HI 1 "s_imm_operand" "Q")) + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d,d")) + (match_operand:HI 1 "s_imm_operand" "Q,S")) (clobber (reg:CC 33))] "" - "icm\\t%0,3,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) - + "@ + icm\t%0,3,%1 + icmy\t%0,3,%1" + [(set_attr "op_type" "RS,RSY")]) ; ; movstrictsi instruction pattern(s). ; (define_insn "movstrictsi" - [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d")) - (match_operand:SI 1 "general_operand" "d,m"))] + [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d")) + (match_operand:SI 1 "general_operand" "d,R,T"))] "TARGET_64BIT" "@ - lr\\t%0,%1 - l\\t%0,%1" - [(set_attr "op_type" "RR,RS") - (set_attr "atype" "reg,mem")]) - + lr\t%0,%1 + l\t%0,%1 + ly\t%0,%1" + [(set_attr "op_type" "RR,RX,RXY") + (set_attr "type" "lr,load,load")]) ; ; movdf instruction pattern(s). @@ -1292,45 +1562,48 @@ [(set (match_operand:DF 0 "nonimmediate_operand" "") (match_operand:DF 1 "general_operand" ""))] "" - " { /* During and after reload, we need to force constants to the literal pool ourselves, if necessary. */ if ((reload_in_progress || reload_completed) && CONSTANT_P (operands[1])) operands[1] = force_const_mem (DFmode, operands[1]); -}") +}) (define_insn "*movdf_64" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,d,m,?Q") - (match_operand:DF 1 "general_operand" "f,m,f,d,m,d,?Q"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,d,m,?Q") + (match_operand:DF 1 "general_operand" "f,R,T,f,f,d,m,d,?Q"))] "TARGET_64BIT" "@ - ldr\\t%0,%1 - ld\\t%0,%1 - std\\t%1,%0 - lgr\\t%0,%1 - lg\\t%0,%1 - stg\\t%1,%0 - mvc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "RR,RX,RX,RRE,RXE,RXE,SS") - (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")]) + ldr\t%0,%1 + ld\t%0,%1 + ldy\t%0,%1 + std\t%1,%0 + stdy\t%1,%0 + lgr\t%0,%1 + lg\t%0,%1 + stg\t%1,%0 + mvc\t%O0(8,%R0),%1" + [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RRE,RXY,RXY,SS") + (set_attr "type" "floadd,floadd,floadd,fstored,fstored,lr,load,store,cs")]) (define_insn "*movdf_31" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,m,d,Q,d,o,Q") - (match_operand:DF 1 "general_operand" "f,m,f,Q,d,dKm,d,Q"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,Q,d,o,Q") + (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKm,d,Q"))] "!TARGET_64BIT" "@ - ldr\\t%0,%1 - ld\\t%0,%1 - std\\t%1,%0 - lm\\t%0,%N0,%1 - stm\\t%1,%N1,%0 + ldr\t%0,%1 + ld\t%0,%1 + ldy\t%0,%1 + std\t%1,%0 + stdy\t%1,%0 + lm\t%0,%N0,%1 + stm\t%1,%N1,%0 # # - mvc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "RR,RX,RX,RS,RS,NN,NN,SS") - (set_attr "atype" "reg,mem,mem,mem,mem,*,*,mem")]) + mvc\t%O0(8,%R0),%1" + [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RS,RS,NN,NN,SS") + (set_attr "type" "floadd,floadd,floadd,fstored,fstored,lm,stm,*,*,cs")]) (define_split [(set (match_operand:DF 0 "nonimmediate_operand" "") @@ -1393,41 +1666,47 @@ [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] "" - " { /* During and after reload, we need to force constants to the literal pool ourselves, if necessary. */ if ((reload_in_progress || reload_completed) && CONSTANT_P (operands[1])) operands[1] = force_const_mem (SFmode, operands[1]); -}") +}) (define_insn "*movsf" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,m,d,d,m,?Q") - (match_operand:SF 1 "general_operand" "f,m,f,d,m,d,?Q"))] + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,R,T,d,d,d,R,T,?Q") + (match_operand:SF 1 "general_operand" "f,R,T,f,f,d,R,T,d,d,?Q"))] "" "@ - ler\\t%0,%1 - le\\t%0,%1 - ste\\t%1,%0 - lr\\t%0,%1 - l\\t%0,%1 - st\\t%1,%0 - mvc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "RR,RX,RX,RR,RX,RX,SS") - (set_attr "atype" "reg,mem,mem,reg,mem,mem,mem")]) + ler\t%0,%1 + le\t%0,%1 + ley\t%0,%1 + ste\t%1,%0 + stey\t%1,%0 + lr\t%0,%1 + l\t%0,%1 + ly\t%0,%1 + st\t%1,%0 + sty\t%1,%0 + mvc\t%O0(4,%R0),%1" + [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS") + (set_attr "type" "floads,floads,floads,fstores,fstores,lr,load,load,store,store,cs")]) ; ; load_multiple pattern(s). ; +; ??? Due to reload problems with replacing registers inside match_parallel +; we currently support load_multiple/store_multiple only after reload. +; (define_expand "load_multiple" [(match_par_dup 3 [(set (match_operand 0 "" "") (match_operand 1 "" "")) (use (match_operand 2 "" ""))])] - "" - " + "reload_completed" { + enum machine_mode mode; int regno; int count; rtx from; @@ -1445,6 +1724,9 @@ count = INTVAL (operands[2]); regno = REGNO (operands[0]); + mode = GET_MODE (operands[0]); + if (mode != SImode && mode != word_mode) + FAIL; operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); if (no_new_pseudos) @@ -1475,61 +1757,48 @@ for (i = 0; i < count; i++) XVECEXP (operands[3], 0, i) - = gen_rtx_SET (VOIDmode, gen_rtx_REG (Pmode, regno + i), - change_address (operands[1], Pmode, - plus_constant (from, - off + i * UNITS_PER_WORD))); -}") + = gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, regno + i), + change_address (operands[1], mode, + plus_constant (from, off + i * GET_MODE_SIZE (mode)))); +}) (define_insn "*load_multiple_di" [(match_parallel 0 "load_multiple_operation" [(set (match_operand:DI 1 "register_operand" "=r") - (match_operand:DI 2 "s_operand" "Q"))])] - "" - "* + (match_operand:DI 2 "s_operand" "QS"))])] + "reload_completed && word_mode == DImode" { int words = XVECLEN (operands[0], 0); - - if (XVECLEN (operands[0], 0) == 1) - return \"lg\\t%1,0(%2)\"; - operands[0] = gen_rtx_REG (DImode, REGNO (operands[1]) + words - 1); - return \"lmg\\t%1,%0,%2\"; -}" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem") + return "lmg\t%1,%0,%2"; +} + [(set_attr "op_type" "RSY") (set_attr "type" "lm")]) (define_insn "*load_multiple_si" [(match_parallel 0 "load_multiple_operation" - [(set (match_operand:SI 1 "register_operand" "=r") - (match_operand:SI 2 "s_operand" "Q"))])] - "" - "* + [(set (match_operand:SI 1 "register_operand" "=r,r") + (match_operand:SI 2 "s_operand" "Q,S"))])] + "reload_completed" { int words = XVECLEN (operands[0], 0); - - if (XVECLEN (operands[0], 0) == 1) - return \"l\\t%1,0(%2)\"; - operands[0] = gen_rtx_REG (SImode, REGNO (operands[1]) + words - 1); - return \"lm\\t%1,%0,%2\"; -}" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem") + return which_alternative == 0 ? "lm\t%1,%0,%2" : "lmy\t%1,%0,%2"; +} + [(set_attr "op_type" "RS,RSY") (set_attr "type" "lm")]) ; -; store multiple pattern(s). +; store multiple pattern(s). ; (define_expand "store_multiple" [(match_par_dup 3 [(set (match_operand 0 "" "") (match_operand 1 "" "")) (use (match_operand 2 "" ""))])] - "" - " + "reload_completed" { + enum machine_mode mode; int regno; int count; rtx to; @@ -1547,6 +1816,9 @@ count = INTVAL (operands[2]); regno = REGNO (operands[1]); + mode = GET_MODE (operands[1]); + if (mode != SImode && mode != word_mode) + FAIL; operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); @@ -1570,7 +1842,7 @@ if (to == frame_pointer_rtx || to == arg_pointer_rtx) FAIL; } - else + else { to = force_reg (Pmode, XEXP (operands[0], 0)); off = 0; @@ -1579,49 +1851,36 @@ for (i = 0; i < count; i++) XVECEXP (operands[3], 0, i) = gen_rtx_SET (VOIDmode, - change_address (operands[0], Pmode, - plus_constant (to, - off + i * UNITS_PER_WORD)), - gen_rtx_REG (Pmode, regno + i)); -}") + change_address (operands[0], mode, + plus_constant (to, off + i * GET_MODE_SIZE (mode))), + gen_rtx_REG (mode, regno + i)); +}) (define_insn "*store_multiple_di" [(match_parallel 0 "store_multiple_operation" - [(set (match_operand:DI 1 "s_operand" "=Q") + [(set (match_operand:DI 1 "s_operand" "=QS") (match_operand:DI 2 "register_operand" "r"))])] - "" - "* + "reload_completed && word_mode == DImode" { int words = XVECLEN (operands[0], 0); - - if (XVECLEN (operands[0], 0) == 1) - return \"stg\\t%1,0(%2)\"; - operands[0] = gen_rtx_REG (DImode, REGNO (operands[2]) + words - 1); - return \"stmg\\t%2,%0,%1\"; -}" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem") + return "stmg\t%2,%0,%1"; +} + [(set_attr "op_type" "RSY") (set_attr "type" "stm")]) (define_insn "*store_multiple_si" [(match_parallel 0 "store_multiple_operation" - [(set (match_operand:SI 1 "s_operand" "=Q") - (match_operand:SI 2 "register_operand" "r"))])] - "" - "* + [(set (match_operand:SI 1 "s_operand" "=Q,S") + (match_operand:SI 2 "register_operand" "r,r"))])] + "reload_completed" { int words = XVECLEN (operands[0], 0); - - if (XVECLEN (operands[0], 0) == 1) - return \"st\\t%1,0(%2)\"; - operands[0] = gen_rtx_REG (SImode, REGNO (operands[2]) + words - 1); - return \"stm\\t%2,%0,%1\"; -}" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem") + return which_alternative == 0 ? "stm\t%2,%0,%1" : "stmy\t%2,%0,%1"; +} + [(set_attr "op_type" "RS,RSY") (set_attr "type" "stm")]) ;; @@ -1629,6 +1888,82 @@ ;; ; +; strlenM instruction pattern(s). +; + +(define_expand "strlendi" + [(set (reg:QI 0) (match_operand:QI 2 "immediate_operand" "")) + (parallel + [(set (match_dup 4) + (unspec:DI [(const_int 0) + (match_operand:BLK 1 "memory_operand" "") + (reg:QI 0) + (match_operand 3 "immediate_operand" "")] UNSPEC_SRST)) + (clobber (scratch:DI)) + (clobber (reg:CC 33))]) + (parallel + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_dup 4) (match_dup 5))) + (clobber (reg:CC 33))])] + "TARGET_64BIT" +{ + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); + emit_move_insn (operands[5], force_operand (XEXP (operands[1], 0), NULL_RTX)); + operands[1] = replace_equiv_address (operands[1], operands[5]); +}) + +(define_insn "*strlendi" + [(set (match_operand:DI 0 "register_operand" "=a") + (unspec:DI [(match_operand:DI 2 "general_operand" "0") + (mem:BLK (match_operand:DI 3 "register_operand" "1")) + (reg:QI 0) + (match_operand 4 "immediate_operand" "")] UNSPEC_SRST)) + (clobber (match_scratch:DI 1 "=a")) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "srst\t%0,%1\;jo\t.-4" + [(set_attr "op_type" "NN") + (set_attr "type" "vs") + (set_attr "length" "8")]) + +(define_expand "strlensi" + [(set (reg:QI 0) (match_operand:QI 2 "immediate_operand" "")) + (parallel + [(set (match_dup 4) + (unspec:SI [(const_int 0) + (match_operand:BLK 1 "memory_operand" "") + (reg:QI 0) + (match_operand 3 "immediate_operand" "")] UNSPEC_SRST)) + (clobber (scratch:SI)) + (clobber (reg:CC 33))]) + (parallel + [(set (match_operand:SI 0 "register_operand" "") + (minus:SI (match_dup 4) (match_dup 5))) + (clobber (reg:CC 33))])] + "!TARGET_64BIT" +{ + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); + emit_move_insn (operands[5], force_operand (XEXP (operands[1], 0), NULL_RTX)); + operands[1] = replace_equiv_address (operands[1], operands[5]); +}) + +(define_insn "*strlensi" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec:SI [(match_operand:SI 2 "general_operand" "0") + (mem:BLK (match_operand:SI 3 "register_operand" "1")) + (reg:QI 0) + (match_operand 4 "immediate_operand" "")] UNSPEC_SRST)) + (clobber (match_scratch:SI 1 "=a")) + (clobber (reg:CC 33))] + "!TARGET_64BIT" + "srst\t%0,%1\;jo\t.-4" + [(set_attr "op_type" "NN") + (set_attr "type" "vs") + (set_attr "length" "8")]) + +; ; movstrM instruction pattern(s). ; @@ -1651,98 +1986,103 @@ ; Move a block that is up to 256 bytes in length. ; The block length is taken as (operands[2] % 256) + 1. -(define_insn "movstr_short_64" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q")) - (use (match_operand:DI 2 "nonmemory_operand" "n,a")) - (clobber (match_scratch:DI 3 "=X,&a"))] - "TARGET_64BIT" - "* -{ - switch (which_alternative) - { - case 0: - return \"mvc\\t%O0(%b2+1,%R0),%1\"; - - case 1: - output_asm_insn (\"bras\\t%3,.+10\", operands); - output_asm_insn (\"mvc\\t%O0(1,%R0),%1\", operands); - return \"ex\\t%2,0(%3)\"; - - default: - abort (); - } -}" - [(set_attr "op_type" "SS,NN") - (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") - (set_attr "length" "*,14")]) +(define_expand "movstr_short" + [(parallel + [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand 2 "nonmemory_operand" "")) + (clobber (match_dup 3))])] + "" + "operands[3] = gen_rtx_SCRATCH (Pmode);") -(define_insn "movstr_short_31" +(define_insn "*movstr_short" [(set (match_operand:BLK 0 "memory_operand" "=Q,Q") (match_operand:BLK 1 "memory_operand" "Q,Q")) - (use (match_operand:SI 2 "nonmemory_operand" "n,a")) - (clobber (match_scratch:SI 3 "=X,&a"))] - "!TARGET_64BIT" - "* + (use (match_operand 2 "nonmemory_operand" "n,a")) + (clobber (match_scratch 3 "=X,&a"))] + "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) + && GET_MODE (operands[3]) == Pmode" { switch (which_alternative) { case 0: - return \"mvc\\t%O0(%b2+1,%R0),%1\"; + return "mvc\t%O0(%b2+1,%R0),%1"; case 1: - output_asm_insn (\"bras\\t%3,.+10\", operands); - output_asm_insn (\"mvc\\t%O0(1,%R0),%1\", operands); - return \"ex\\t%2,0(%3)\"; + output_asm_insn ("bras\t%3,.+10", operands); + output_asm_insn ("mvc\t%O0(1,%R0),%1", operands); + return "ex\t%2,0(%3)"; default: abort (); } -}" +} [(set_attr "op_type" "SS,NN") (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") + (set_attr "atype" "*,agen") (set_attr "length" "*,14")]) ; Move a block of arbitrary length. -(define_insn "movstr_long_64" - [(set (match_operand:TI 0 "register_operand" "=d") - (ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0") - (lshiftrt:TI (match_dup 2) (const_int 64))) - (const_int 64))) - (set (match_operand:TI 1 "register_operand" "=d") - (ashift:TI (plus:TI (match_operand:TI 3 "register_operand" "1") - (lshiftrt:TI (match_dup 3) (const_int 64))) - (const_int 64))) - (set (mem:BLK (subreg:DI (match_dup 2) 0)) - (mem:BLK (subreg:DI (match_dup 3) 0))) +(define_expand "movstr_long" + [(parallel + [(clobber (match_dup 2)) + (clobber (match_dup 3)) + (set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand 2 "general_operand" "")) + (use (match_dup 3)) + (clobber (reg:CC 33))])] + "" +{ + enum machine_mode dword_mode = word_mode == DImode ? TImode : DImode; + rtx reg0 = gen_reg_rtx (dword_mode); + rtx reg1 = gen_reg_rtx (dword_mode); + rtx addr0 = gen_lowpart (Pmode, gen_highpart (word_mode, reg0)); + rtx addr1 = gen_lowpart (Pmode, gen_highpart (word_mode, reg1)); + rtx len0 = gen_lowpart (Pmode, reg0); + rtx len1 = gen_lowpart (Pmode, reg1); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, reg0)); + emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len0, operands[2]); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); + emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (len1, operands[2]); + + operands[0] = replace_equiv_address_nv (operands[0], addr0); + operands[1] = replace_equiv_address_nv (operands[1], addr1); + operands[2] = reg0; + operands[3] = reg1; +}) + +(define_insn "*movstr_long_64" + [(clobber (match_operand:TI 0 "register_operand" "=d")) + (clobber (match_operand:TI 1 "register_operand" "=d")) + (set (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0)) + (mem:BLK (subreg:DI (match_operand:TI 3 "register_operand" "1") 0))) + (use (match_dup 2)) + (use (match_dup 3)) (clobber (reg:CC 33))] "TARGET_64BIT" - "mvcle\\t%0,%1,0\;jo\\t.-4" + "mvcle\t%0,%1,0\;jo\t.-4" [(set_attr "op_type" "NN") (set_attr "type" "vs") - (set_attr "atype" "mem") (set_attr "length" "8")]) -(define_insn "movstr_long_31" - [(set (match_operand:DI 0 "register_operand" "=d") - (ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0") - (lshiftrt:DI (match_dup 2) (const_int 32))) - (const_int 32))) - (set (match_operand:DI 1 "register_operand" "=d") - (ashift:DI (plus:DI (match_operand:DI 3 "register_operand" "1") - (lshiftrt:DI (match_dup 3) (const_int 32))) - (const_int 32))) - (set (mem:BLK (subreg:SI (match_dup 2) 0)) - (mem:BLK (subreg:SI (match_dup 3) 0))) +(define_insn "*movstr_long_31" + [(clobber (match_operand:DI 0 "register_operand" "=d")) + (clobber (match_operand:DI 1 "register_operand" "=d")) + (set (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0)) + (mem:BLK (subreg:SI (match_operand:DI 3 "register_operand" "1") 0))) + (use (match_dup 2)) + (use (match_dup 3)) (clobber (reg:CC 33))] "!TARGET_64BIT" - "mvcle\\t%0,%1,0\;jo\\t.-4" + "mvcle\t%0,%1,0\;jo\t.-4" [(set_attr "op_type" "NN") (set_attr "type" "vs") - (set_attr "atype" "mem") (set_attr "length" "8")]) ; @@ -1766,184 +2106,202 @@ "s390_expand_clrstr (operands[0], operands[1]); DONE;") ; Clear a block that is up to 256 bytes in length. -; The block length is taken as (operands[2] % 256) + 1. +; The block length is taken as (operands[1] % 256) + 1. -(define_insn "clrstr_short_64" +(define_expand "clrstr_short" + [(parallel + [(set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand 1 "nonmemory_operand" "")) + (clobber (match_dup 2)) + (clobber (reg:CC 33))])] + "" + "operands[2] = gen_rtx_SCRATCH (Pmode);") + +(define_insn "*clrstr_short" [(set (match_operand:BLK 0 "memory_operand" "=Q,Q") (const_int 0)) - (use (match_operand:DI 1 "nonmemory_operand" "n,a")) - (clobber (match_scratch:DI 2 "=X,&a")) + (use (match_operand 1 "nonmemory_operand" "n,a")) + (clobber (match_scratch 2 "=X,&a")) (clobber (reg:CC 33))] - "TARGET_64BIT" - "* + "(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode) + && GET_MODE (operands[2]) == Pmode" { switch (which_alternative) { case 0: - return \"xc\\t%O0(%b1+1,%R0),%0\"; + return "xc\t%O0(%b1+1,%R0),%0"; case 1: - output_asm_insn (\"bras\\t%2,.+10\", operands); - output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands); - return \"ex\\t%1,0(%2)\"; + output_asm_insn ("bras\t%2,.+10", operands); + output_asm_insn ("xc\t%O0(1,%R0),%0", operands); + return "ex\t%1,0(%2)"; default: abort (); } -}" +} [(set_attr "op_type" "SS,NN") (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") + (set_attr "atype" "*,agen") (set_attr "length" "*,14")]) -(define_insn "clrstr_short_31" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q") - (const_int 0)) - (use (match_operand:SI 1 "nonmemory_operand" "n,a")) - (clobber (match_scratch:SI 2 "=X,&a")) - (clobber (reg:CC 33))] - "!TARGET_64BIT" - "* +; Clear a block of arbitrary length. + +(define_expand "clrstr_long" + [(parallel + [(clobber (match_dup 1)) + (set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand 1 "general_operand" "")) + (use (match_dup 2)) + (clobber (reg:CC 33))])] + "" { - switch (which_alternative) - { - case 0: - return \"xc\\t%O0(%b1+1,%R0),%0\"; + enum machine_mode dword_mode = word_mode == DImode ? TImode : DImode; + rtx reg0 = gen_reg_rtx (dword_mode); + rtx reg1 = gen_reg_rtx (dword_mode); + rtx addr0 = gen_lowpart (Pmode, gen_highpart (word_mode, reg0)); + rtx len0 = gen_lowpart (Pmode, reg0); - case 1: - output_asm_insn (\"bras\\t%2,.+10\", operands); - output_asm_insn (\"xc\\t%O0(1,%R0),%0\", operands); - return \"ex\\t%1,0(%2)\"; + emit_insn (gen_rtx_CLOBBER (VOIDmode, reg0)); + emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len0, operands[1]); - default: - abort (); - } -}" - [(set_attr "op_type" "SS,NN") - (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") - (set_attr "length" "*,14")]) + emit_move_insn (reg1, const0_rtx); -; Clear a block of arbitrary length. + operands[0] = replace_equiv_address_nv (operands[0], addr0); + operands[1] = reg0; + operands[2] = reg1; +}) -(define_insn "clrstr_long_64" - [(set (match_operand:TI 0 "register_operand" "=d") - (ashift:TI (plus:TI (match_operand:TI 2 "register_operand" "0") - (lshiftrt:TI (match_dup 2) (const_int 64))) - (const_int 64))) - (set (mem:BLK (subreg:DI (match_dup 2) 0)) +(define_insn "*clrstr_long_64" + [(clobber (match_operand:TI 0 "register_operand" "=d")) + (set (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0)) (const_int 0)) + (use (match_dup 2)) (use (match_operand:TI 1 "register_operand" "d")) (clobber (reg:CC 33))] "TARGET_64BIT" - "mvcle\\t%0,%1,0\;jo\\t.-4" + "mvcle\t%0,%1,0\;jo\t.-4" [(set_attr "op_type" "NN") - (set_attr "atype" "mem") (set_attr "type" "vs") (set_attr "length" "8")]) -(define_insn "clrstr_long_31" - [(set (match_operand:DI 0 "register_operand" "=d") - (ashift:DI (plus:DI (match_operand:DI 2 "register_operand" "0") - (lshiftrt:DI (match_dup 2) (const_int 32))) - (const_int 32))) - (set (mem:BLK (subreg:SI (match_dup 2) 0)) +(define_insn "*clrstr_long_31" + [(clobber (match_operand:DI 0 "register_operand" "=d")) + (set (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0)) (const_int 0)) + (use (match_dup 2)) (use (match_operand:DI 1 "register_operand" "d")) (clobber (reg:CC 33))] "!TARGET_64BIT" - "mvcle\\t%0,%1,0\;jo\\t.-4" + "mvcle\t%0,%1,0\;jo\t.-4" [(set_attr "op_type" "NN") - (set_attr "atype" "mem") (set_attr "type" "vs") (set_attr "length" "8")]) ; -; cmpstrM instruction pattern(s). +; cmpmemM instruction pattern(s). ; -(define_expand "cmpstrdi" +(define_expand "cmpmemdi" [(set (match_operand:DI 0 "register_operand" "") (compare:DI (match_operand:BLK 1 "memory_operand" "") (match_operand:BLK 2 "memory_operand" "") ) ) (use (match_operand:DI 3 "general_operand" "")) (use (match_operand:DI 4 "" ""))] "TARGET_64BIT" - "s390_expand_cmpstr (operands[0], operands[1], + "s390_expand_cmpmem (operands[0], operands[1], operands[2], operands[3]); DONE;") -(define_expand "cmpstrsi" +(define_expand "cmpmemsi" [(set (match_operand:SI 0 "register_operand" "") (compare:SI (match_operand:BLK 1 "memory_operand" "") (match_operand:BLK 2 "memory_operand" "") ) ) (use (match_operand:SI 3 "general_operand" "")) (use (match_operand:SI 4 "" ""))] "" - "s390_expand_cmpstr (operands[0], operands[1], + "s390_expand_cmpmem (operands[0], operands[1], operands[2], operands[3]); DONE;") ; Compare a block that is up to 256 bytes in length. ; The block length is taken as (operands[2] % 256) + 1. -(define_insn "cmpstr_short_64" - [(set (reg:CCS 33) - (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q"))) - (use (match_operand:DI 2 "nonmemory_operand" "n,a")) - (clobber (match_scratch:DI 3 "=X,&a"))] - "TARGET_64BIT" - "* -{ - switch (which_alternative) - { - case 0: - return \"clc\\t%O0(%b2+1,%R0),%1\"; - - case 1: - output_asm_insn (\"bras\\t%3,.+10\", operands); - output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands); - return \"ex\\t%2,0(%3)\"; - - default: - abort (); - } -}" - [(set_attr "op_type" "SS,NN") - (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") - (set_attr "length" "*,14")]) +(define_expand "cmpmem_short" + [(parallel + [(set (reg:CCS 33) + (compare:CCS (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" ""))) + (use (match_operand 2 "nonmemory_operand" "")) + (clobber (match_dup 3))])] + "" + "operands[3] = gen_rtx_SCRATCH (Pmode);") -(define_insn "cmpstr_short_31" +(define_insn "*cmpmem_short" [(set (reg:CCS 33) (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q") (match_operand:BLK 1 "memory_operand" "Q,Q"))) - (use (match_operand:SI 2 "nonmemory_operand" "n,a")) - (clobber (match_scratch:SI 3 "=X,&a"))] - "!TARGET_64BIT" - "* + (use (match_operand 2 "nonmemory_operand" "n,a")) + (clobber (match_scratch 3 "=X,&a"))] + "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) + && GET_MODE (operands[3]) == Pmode" { switch (which_alternative) { case 0: - return \"clc\\t%O0(%b2+1,%R0),%1\"; + return "clc\t%O0(%b2+1,%R0),%1"; case 1: - output_asm_insn (\"bras\\t%3,.+10\", operands); - output_asm_insn (\"clc\\t%O0(1,%R0),%1\", operands); - return \"ex\\t%2,0(%3)\"; + output_asm_insn ("bras\t%3,.+10", operands); + output_asm_insn ("clc\t%O0(1,%R0),%1", operands); + return "ex\t%2,0(%3)"; default: abort (); } -}" +} [(set_attr "op_type" "SS,NN") (set_attr "type" "cs,cs") - (set_attr "atype" "mem,mem") + (set_attr "atype" "*,agen") (set_attr "length" "*,14")]) ; Compare a block of arbitrary length. -(define_insn "cmpstr_long_64" +(define_expand "cmpmem_long" + [(parallel + [(clobber (match_dup 2)) + (clobber (match_dup 3)) + (set (reg:CCS 33) + (compare:CCS (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" ""))) + (use (match_operand 2 "general_operand" "")) + (use (match_dup 3))])] + "" +{ + enum machine_mode dword_mode = word_mode == DImode ? TImode : DImode; + rtx reg0 = gen_reg_rtx (dword_mode); + rtx reg1 = gen_reg_rtx (dword_mode); + rtx addr0 = gen_lowpart (Pmode, gen_highpart (word_mode, reg0)); + rtx addr1 = gen_lowpart (Pmode, gen_highpart (word_mode, reg1)); + rtx len0 = gen_lowpart (Pmode, reg0); + rtx len1 = gen_lowpart (Pmode, reg1); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, reg0)); + emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len0, operands[2]); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); + emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (len1, operands[2]); + + operands[0] = replace_equiv_address_nv (operands[0], addr0); + operands[1] = replace_equiv_address_nv (operands[1], addr1); + operands[2] = reg0; + operands[3] = reg1; +}) + +(define_insn "*cmpmem_long_64" [(clobber (match_operand:TI 0 "register_operand" "=d")) (clobber (match_operand:TI 1 "register_operand" "=d")) (set (reg:CCS 33) @@ -1952,12 +2310,12 @@ (use (match_dup 2)) (use (match_dup 3))] "TARGET_64BIT" - "clcl\\t%0,%1" - [(set_attr "op_type" "RR") - (set_attr "atype" "mem") - (set_attr "type" "vs")]) + "clcle\t%0,%1,0\;jo\t.-4" + [(set_attr "op_type" "NN") + (set_attr "type" "vs") + (set_attr "length" "8")]) -(define_insn "cmpstr_long_31" +(define_insn "*cmpmem_long_31" [(clobber (match_operand:DI 0 "register_operand" "=d")) (clobber (match_operand:DI 1 "register_operand" "=d")) (set (reg:CCS 33) @@ -1966,10 +2324,10 @@ (use (match_dup 2)) (use (match_dup 3))] "!TARGET_64BIT" - "clcl\\t%0,%1" - [(set_attr "op_type" "RR") - (set_attr "atype" "mem") - (set_attr "type" "vs")]) + "clcle\t%0,%1,0\;jo\t.-4" + [(set_attr "op_type" "NN") + (set_attr "type" "vs") + (set_attr "length" "8")]) ; Convert condition code to integer in range (-1, 0, 1) @@ -1977,34 +2335,30 @@ [(set (match_operand:SI 0 "register_operand" "=d") (compare:SI (reg:CCS 33) (const_int 0)))] "" - "* { - output_asm_insn (\"lhi\\t%0,1\", operands); - output_asm_insn (\"jh\\t.+12\", operands); - output_asm_insn (\"jl\\t.+6\", operands); - output_asm_insn (\"sr\\t%0,%0\", operands); - return \"lcr\\t%0,%0\"; -}" + output_asm_insn ("lhi\t%0,1", operands); + output_asm_insn ("jh\t.+12", operands); + output_asm_insn ("jl\t.+6", operands); + output_asm_insn ("sr\t%0,%0", operands); + return "lcr\t%0,%0"; +} [(set_attr "op_type" "NN") (set_attr "length" "16") - (set_attr "atype" "reg") (set_attr "type" "other")]) (define_insn "cmpint_di" [(set (match_operand:DI 0 "register_operand" "=d") (compare:DI (reg:CCS 33) (const_int 0)))] "TARGET_64BIT" - "* { - output_asm_insn (\"lghi\\t%0,1\", operands); - output_asm_insn (\"jh\\t.+12\", operands); - output_asm_insn (\"jl\\t.+6\", operands); - output_asm_insn (\"sgr\\t%0,%0\", operands); - return \"lcgr\\t%0,%0\"; -}" + output_asm_insn ("lghi\t%0,1", operands); + output_asm_insn ("jh\t.+16", operands); + output_asm_insn ("jl\t.+8", operands); + output_asm_insn ("sgr\t%0,%0", operands); + return "lcgr\t%0,%0"; +} [(set_attr "op_type" "NN") - (set_attr "length" "22") - (set_attr "atype" "reg") + (set_attr "length" "20") (set_attr "type" "other")]) @@ -2013,40 +2367,42 @@ ;; (define_insn "*sethighqisi" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:QI 1 "s_operand" "Q")] 10)) + [(set (match_operand:SI 0 "register_operand" "=d,d") + (unspec:SI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH)) (clobber (reg:CC 33))] "" - "icm\\t%0,8,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%0,8,%1 + icmy\t%0,8,%1" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*sethighhisi" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:HI 1 "s_operand" "Q")] 10)) + [(set (match_operand:SI 0 "register_operand" "=d,d") + (unspec:SI [(match_operand:HI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH)) (clobber (reg:CC 33))] "" - "icm\\t%0,12,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%0,12,%1 + icmy\t%0,12,%1" + [(set_attr "op_type" "RS,RSY")]) (define_insn "*sethighqidi_64" [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:QI 1 "s_operand" "Q")] 10)) + (unspec:DI [(match_operand:QI 1 "s_operand" "QS")] UNSPEC_SETHIGH)) (clobber (reg:CC 33))] "TARGET_64BIT" - "icmh\\t%0,8,%1" - [(set_attr "op_type" "RSE") - (set_attr "atype" "mem")]) + "icmh\t%0,8,%1" + [(set_attr "op_type" "RSY")]) (define_insn "*sethighqidi_31" - [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:QI 1 "s_operand" "Q")] 10)) + [(set (match_operand:DI 0 "register_operand" "=d,d") + (unspec:DI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH)) (clobber (reg:CC 33))] "!TARGET_64BIT" - "icm\\t%0,8,%1" - [(set_attr "op_type" "RS") - (set_attr "atype" "mem")]) + "@ + icm\t%0,8,%1 + icmy\t%0,8,%1" + [(set_attr "op_type" "RS,RSY")]) (define_insn_and_split "*extractqi" [(set (match_operand:SI 0 "register_operand" "=d") @@ -2059,15 +2415,14 @@ "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] 10)) + [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) (clobber (reg:CC 33))]) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] - " { operands[2] = GEN_INT (32 - INTVAL (operands[2])); operands[1] = change_address (operands[1], QImode, 0); -}" - [(set_attr "atype" "mem")]) +} + [(set_attr "atype" "agen")]) (define_insn_and_split "*extracthi" [(set (match_operand:SI 0 "register_operand" "=d") @@ -2080,15 +2435,14 @@ "#" "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] 10)) + [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) (clobber (reg:CC 33))]) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] - " { operands[2] = GEN_INT (32 - INTVAL (operands[2])); operands[1] = change_address (operands[1], HImode, 0); -}" - [(set_attr "atype" "mem")]) +} + [(set_attr "atype" "agen")]) ; ; extendsidi2 instruction pattern(s). @@ -2116,10 +2470,9 @@ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m")))] "TARGET_64BIT" "@ - lgfr\\t%0,%1 - lgf\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + lgfr\t%0,%1 + lgf\t%0,%1" + [(set_attr "op_type" "RRE,RXY")]) ; ; extendhidi2 instruction pattern(s). @@ -2142,7 +2495,7 @@ { operands[1] = gen_lowpart (DImode, operands[1]); emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (48))); - emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (48))); + emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (48))); DONE; } } @@ -2152,9 +2505,8 @@ [(set (match_operand:DI 0 "register_operand" "=d") (sign_extend:DI (match_operand:HI 1 "memory_operand" "m")))] "TARGET_64BIT" - "lgh\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "lgh\t%0,%1" + [(set_attr "op_type" "RXY")]) ; ; extendqidi2 instruction pattern(s). @@ -2177,18 +2529,28 @@ { operands[1] = gen_lowpart (DImode, operands[1]); emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (56))); - emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (56))); + emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (56))); DONE; } } ") -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (sign_extend:DI (match_operand:QI 1 "s_operand" "")))] - "TARGET_64BIT && !reload_completed" +(define_insn "*extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_64BIT && TARGET_LONG_DISPLACEMENT" + "lgb\t%0,%1" + [(set_attr "op_type" "RXY")]) + +(define_insn_and_split "*extendqidi2_short_displ" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (match_operand:QI 1 "s_operand" "Q"))) + (clobber (reg:CC 33))] + "TARGET_64BIT && !TARGET_LONG_DISPLACEMENT" + "#" + "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:DI [(match_dup 1)] 10)) + [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_SETHIGH)) (clobber (reg:CC 33))]) (parallel [(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 56))) @@ -2207,18 +2569,19 @@ { operands[1] = gen_lowpart (SImode, operands[1]); emit_insn (gen_ashlsi3 (operands[0], operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (16))); + emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (16))); DONE; } ") (define_insn "*extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=d") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + [(set (match_operand:SI 0 "register_operand" "=d,d") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T")))] "" - "lh\\t%0,%1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + lh\t%0,%1 + lhy\t%0,%1" + [(set_attr "op_type" "RX,RXY")]) ; ; extendqisi2 instruction pattern(s). @@ -2232,17 +2595,27 @@ { operands[1] = gen_lowpart (SImode, operands[1]); emit_insn (gen_ashlsi3 (operands[0], operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (24))); + emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (24))); DONE; } ") -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (sign_extend:SI (match_operand:QI 1 "s_operand" "")))] - "!reload_completed" +(define_insn "*extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "TARGET_LONG_DISPLACEMENT" + "lb\t%0,%1" + [(set_attr "op_type" "RXY")]) + +(define_insn_and_split "*extendsiqi2_short_displ" + [(set (match_operand:SI 0 "register_operand" "=d") + (sign_extend:SI (match_operand:QI 1 "s_operand" "Q"))) + (clobber (reg:CC 33))] + "!TARGET_LONG_DISPLACEMENT" + "#" + "&& reload_completed" [(parallel - [(set (match_dup 0) (unspec:SI [(match_dup 1)] 10)) + [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH)) (clobber (reg:CC 33))]) (parallel [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 24))) @@ -2279,10 +2652,9 @@ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m")))] "TARGET_64BIT" "@ - llgfr\\t%0,%1 - llgf\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + llgfr\t%0,%1 + llgf\t%0,%1" + [(set_attr "op_type" "RRE,RXY")]) ; ; zero_extendhidi2 instruction pattern(s). @@ -2305,7 +2677,7 @@ { operands[1] = gen_lowpart (DImode, operands[1]); emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (48))); - emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (48))); + emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (48))); DONE; } } @@ -2315,9 +2687,75 @@ [(set (match_operand:DI 0 "register_operand" "=d") (zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))] "TARGET_64BIT" - "llgh\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "llgh\t%0,%1" + [(set_attr "op_type" "RXY")]) + +; +; LLGT-type instructions (zero-extend from 31 bit to 64 bit). +; + +(define_insn "*llgt_sisi" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "d,m") + (const_int 2147483647)))] + "TARGET_64BIT" + "@ + llgtr\t%0,%1 + llgt\t%0,%1" + [(set_attr "op_type" "RRE,RXE")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "") + (const_int 2147483647))) + (clobber (reg:CC 33))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 0) + (and:SI (match_dup 1) + (const_int 2147483647)))] + "") + +(define_insn "*llgt_didi" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o") + (const_int 2147483647)))] + "TARGET_64BIT" + "@ + llgtr\t%0,%1 + llgt\t%0,%N1" + [(set_attr "op_type" "RRE,RXE")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "") + (const_int 2147483647))) + (clobber (reg:CC 33))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 0) + (and:DI (match_dup 1) + (const_int 2147483647)))] + "") + +(define_insn "*llgt_sidi" + [(set (match_operand:DI 0 "register_operand" "=d") + (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0) + (const_int 2147483647)))] + "TARGET_64BIT" + "llgt\t%0,%1" + [(set_attr "op_type" "RXE")]) + +(define_insn_and_split "*llgt_sidi_split" + [(set (match_operand:DI 0 "register_operand" "=d") + (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0) + (const_int 2147483647))) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (and:DI (subreg:DI (match_dup 1) 0) + (const_int 2147483647)))] + "") ; ; zero_extendqidi2 instruction pattern(s) @@ -2340,7 +2778,7 @@ { operands[1] = gen_lowpart (DImode, operands[1]); emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (56))); - emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (56))); + emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (56))); DONE; } } @@ -2350,9 +2788,8 @@ [(set (match_operand:DI 0 "register_operand" "=d") (zero_extend:DI (match_operand:QI 1 "memory_operand" "m")))] "TARGET_64BIT" - "llgc\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "llgc\t%0,%1" + [(set_attr "op_type" "RXY")]) ; ; zero_extendhisi2 instruction pattern(s). @@ -2374,13 +2811,12 @@ [(set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] "TARGET_64BIT" - "llgh\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "llgh\t%0,%1" + [(set_attr "op_type" "RXY")]) (define_insn_and_split "*zero_extendhisi2_31" [(set (match_operand:SI 0 "register_operand" "=&d") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "Q"))) + (zero_extend:SI (match_operand:HI 1 "s_operand" "QS"))) (clobber (reg:CC 33))] "!TARGET_64BIT" "#" @@ -2390,8 +2826,8 @@ [(set (strict_low_part (match_dup 2)) (match_dup 1)) (clobber (reg:CC 33))])] "operands[2] = gen_lowpart (HImode, operands[0]);" - [(set_attr "atype" "mem")]) - + [(set_attr "atype" "agen")]) + ; ; zero_extendqisi2 instruction pattern(s). ; @@ -2411,22 +2847,21 @@ (define_insn "*zero_extendqisi2_64" [(set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_64BIT" - "llgc\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "TARGET_ZARCH" + "llgc\t%0,%1" + [(set_attr "op_type" "RXY")]) (define_insn_and_split "*zero_extendqisi2_31" [(set (match_operand:SI 0 "register_operand" "=&d") (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "!TARGET_64BIT" + "!TARGET_ZARCH" "#" "&& reload_completed" [(set (match_dup 0) (const_int 0)) (set (strict_low_part (match_dup 2)) (match_dup 1))] "operands[2] = gen_lowpart (QImode, operands[0]);" - [(set_attr "atype" "mem")]) - + [(set_attr "atype" "agen")]) + ; ; zero_extendqihi2 instruction pattern(s). ; @@ -2434,7 +2869,7 @@ (define_expand "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "register_operand" "")))] - "TARGET_64BIT" + "TARGET_ZARCH" " { operands[1] = gen_lowpart (HImode, operands[1]); @@ -2446,21 +2881,20 @@ (define_insn "*zero_extendqihi2_64" [(set (match_operand:HI 0 "register_operand" "=d") (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_64BIT" - "llgc\\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "TARGET_ZARCH" + "llgc\t%0,%1" + [(set_attr "op_type" "RXY")]) (define_insn_and_split "*zero_extendqihi2_31" [(set (match_operand:HI 0 "register_operand" "=&d") (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))] - "!TARGET_64BIT" + "!TARGET_ZARCH" "#" "&& reload_completed" [(set (match_dup 0) (const_int 0)) (set (strict_low_part (match_dup 2)) (match_dup 1))] "operands[2] = gen_lowpart (QImode, operands[0]);" - [(set_attr "atype" "mem")]) + [(set_attr "atype" "agen")]) ; @@ -2471,20 +2905,19 @@ [(set (match_operand:DI 0 "register_operand" "") (unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); rtx temp = gen_reg_rtx (DFmode); operands[1] = force_reg (DFmode, operands[1]); - emit_insn (gen_cmpdf (operands[1], + emit_insn (gen_cmpdf (operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"9223372036854775808.0\", DFmode), DFmode))); + REAL_VALUE_ATOF ("9223372036854775808.0", DFmode), DFmode))); emit_jump_insn (gen_blt (label1)); emit_insn (gen_subdf3 (temp, operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"18446744073709551616.0\", DFmode), DFmode))); + REAL_VALUE_ATOF ("18446744073709551616.0", DFmode), DFmode))); emit_insn (gen_fix_truncdfdi2_ieee (operands[0], temp, GEN_INT(7))); emit_jump (label2); @@ -2492,28 +2925,27 @@ emit_insn (gen_fix_truncdfdi2_ieee (operands[0], operands[1], GEN_INT(5))); emit_label (label2); DONE; -}") +}) (define_expand "fix_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "") (fix:DI (match_operand:DF 1 "nonimmediate_operand" "")))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { operands[1] = force_reg (DFmode, operands[1]); emit_insn (gen_fix_truncdfdi2_ieee (operands[0], operands[1], GEN_INT(5))); DONE; -}") +}) (define_insn "fix_truncdfdi2_ieee" [(set (match_operand:DI 0 "register_operand" "=d") (fix:DI (match_operand:DF 1 "register_operand" "f"))) - (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] 1) + (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] UNSPEC_ROUND) (clobber (reg:CC 33))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cgdbr\\t%0,%h2,%1" + "cgdbr\t%0,%h2,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other")]) + (set_attr "type" "ftoi")]) ; ; fixuns_truncdfsi2 and fix_truncdfsi2 instruction pattern(s). @@ -2523,20 +2955,19 @@ [(set (match_operand:SI 0 "register_operand" "") (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); rtx temp = gen_reg_rtx (DFmode); operands[1] = force_reg (DFmode,operands[1]); - emit_insn (gen_cmpdf (operands[1], + emit_insn (gen_cmpdf (operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"2147483648.0\", DFmode), DFmode))); + REAL_VALUE_ATOF ("2147483648.0", DFmode), DFmode))); emit_jump_insn (gen_blt (label1)); emit_insn (gen_subdf3 (temp, operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"4294967296.0\", DFmode), DFmode))); + REAL_VALUE_ATOF ("4294967296.0", DFmode), DFmode))); emit_insn (gen_fix_truncdfsi2_ieee (operands[0], temp, GEN_INT (7))); emit_jump (label2); @@ -2544,42 +2975,41 @@ emit_insn (gen_fix_truncdfsi2_ieee (operands[0], operands[1], GEN_INT (5))); emit_label (label2); DONE; -}") +}) (define_expand "fix_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "") (fix:SI (match_operand:DF 1 "nonimmediate_operand" "")))] "TARGET_HARD_FLOAT" - " { - if (TARGET_IBM_FLOAT) + if (TARGET_IBM_FLOAT) { /* This is the algorithm from POP chapter A.5.7.2. */ - rtx temp = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD); + rtx temp = assign_stack_local (BLKmode, 8, BITS_PER_WORD); rtx two31r = s390_gen_rtx_const_DI (0x4f000000, 0x08000000); rtx two32 = s390_gen_rtx_const_DI (0x4e000001, 0x00000000); operands[1] = force_reg (DFmode, operands[1]); - emit_insn (gen_fix_truncdfsi2_ibm (operands[0], operands[1], + emit_insn (gen_fix_truncdfsi2_ibm (operands[0], operands[1], two31r, two32, temp)); - } - else + } + else { operands[1] = force_reg (DFmode, operands[1]); emit_insn (gen_fix_truncdfsi2_ieee (operands[0], operands[1], GEN_INT (5))); } DONE; -}") +}) (define_insn "fix_truncdfsi2_ieee" [(set (match_operand:SI 0 "register_operand" "=d") (fix:SI (match_operand:DF 1 "register_operand" "f"))) - (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] 1) + (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] UNSPEC_ROUND) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cfdbr\\t%0,%h2,%1" + "cfdbr\t%0,%h2,%1" [(set_attr "op_type" "RRE") (set_attr "type" "other" )]) @@ -2591,16 +3021,16 @@ (use (match_operand:BLK 4 "memory_operand" "m")) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "* { - output_asm_insn (\"sd\\t%1,%2\", operands); - output_asm_insn (\"aw\\t%1,%3\", operands); - output_asm_insn (\"std\\t%1,%4\", operands); - output_asm_insn (\"xi\\t%N4,128\", operands); - return \"l\\t%0,%N4\"; -}" + output_asm_insn ("sd\t%1,%2", operands); + output_asm_insn ("aw\t%1,%3", operands); + output_asm_insn ("std\t%1,%4", operands); + output_asm_insn ("xi\t%N4,128", operands); + return "l\t%0,%N4"; +} [(set_attr "op_type" "NN") - (set_attr "type" "other") + (set_attr "type" "ftoi") + (set_attr "atype" "agen") (set_attr "length" "20")]) ; @@ -2611,21 +3041,20 @@ [(set (match_operand:DI 0 "register_operand" "") (unsigned_fix:DI (match_operand:SF 1 "register_operand" "")))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); rtx temp = gen_reg_rtx (SFmode); operands[1] = force_reg (SFmode, operands[1]); - emit_insn (gen_cmpsf (operands[1], + emit_insn (gen_cmpsf (operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"9223372036854775808.0\", SFmode), SFmode))); + REAL_VALUE_ATOF ("9223372036854775808.0", SFmode), SFmode))); emit_jump_insn (gen_blt (label1)); emit_insn (gen_subsf3 (temp, operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"18446744073709551616.0\", SFmode), SFmode))); + REAL_VALUE_ATOF ("18446744073709551616.0", SFmode), SFmode))); emit_insn (gen_fix_truncsfdi2_ieee (operands[0], temp, GEN_INT(7))); emit_jump (label2); @@ -2633,28 +3062,27 @@ emit_insn (gen_fix_truncsfdi2_ieee (operands[0], operands[1], GEN_INT(5))); emit_label (label2); DONE; -}") +}) (define_expand "fix_truncsfdi2" [(set (match_operand:DI 0 "register_operand" "") (fix:DI (match_operand:SF 1 "nonimmediate_operand" "")))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { operands[1] = force_reg (SFmode, operands[1]); emit_insn (gen_fix_truncsfdi2_ieee (operands[0], operands[1], GEN_INT(5))); DONE; -}") +}) (define_insn "fix_truncsfdi2_ieee" [(set (match_operand:DI 0 "register_operand" "=d") (fix:DI (match_operand:SF 1 "register_operand" "f"))) - (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] 1) + (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] UNSPEC_ROUND) (clobber (reg:CC 33))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cgebr\\t%0,%h2,%1" + "cgebr\t%0,%h2,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other")]) + (set_attr "type" "ftoi")]) ; ; fixuns_truncsfsi2 and fix_truncsfsi2 instruction pattern(s). @@ -2664,7 +3092,6 @@ [(set (match_operand:SI 0 "register_operand" "") (unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - " { rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); @@ -2673,11 +3100,11 @@ operands[1] = force_reg (SFmode, operands[1]); emit_insn (gen_cmpsf (operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"2147483648.0\", SFmode), SFmode))); + REAL_VALUE_ATOF ("2147483648.0", SFmode), SFmode))); emit_jump_insn (gen_blt (label1)); emit_insn (gen_subsf3 (temp, operands[1], CONST_DOUBLE_FROM_REAL_VALUE ( - REAL_VALUE_ATOF (\"4294967296.0\", SFmode), SFmode))); + REAL_VALUE_ATOF ("4294967296.0", SFmode), SFmode))); emit_insn (gen_fix_truncsfsi2_ieee (operands[0], temp, GEN_INT (7))); emit_jump (label2); @@ -2685,13 +3112,12 @@ emit_insn (gen_fix_truncsfsi2_ieee (operands[0], operands[1], GEN_INT (5))); emit_label (label2); DONE; -}") +}) (define_expand "fix_truncsfsi2" [(set (match_operand:SI 0 "register_operand" "") (fix:SI (match_operand:SF 1 "nonimmediate_operand" "")))] "TARGET_HARD_FLOAT" - " { if (TARGET_IBM_FLOAT) { @@ -2707,17 +3133,17 @@ } DONE; -}") +}) (define_insn "fix_truncsfsi2_ieee" [(set (match_operand:SI 0 "register_operand" "=d") (fix:SI (match_operand:SF 1 "register_operand" "f"))) - (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] 1) + (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] UNSPEC_ROUND) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cfebr\\t%0,%h2,%1" + "cfebr\t%0,%h2,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other")]) + (set_attr "type" "ftoi")]) ; ; floatdidf2 instruction pattern(s). @@ -2728,9 +3154,9 @@ (float:DF (match_operand:DI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cdgbr\\t%0,%1" + "cdgbr\t%0,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other" )]) + (set_attr "type" "itof" )]) ; ; floatdisf2 instruction pattern(s). @@ -2741,9 +3167,9 @@ (float:SF (match_operand:DI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cegbr\\t%0,%1" + "cegbr\t%0,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other" )]) + (set_attr "type" "itof" )]) ; ; floatsidf2 instruction pattern(s). @@ -2755,28 +3181,27 @@ (float:DF (match_operand:SI 1 "register_operand" ""))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" - " { - if (TARGET_IBM_FLOAT) + if (TARGET_IBM_FLOAT) { /* This is the algorithm from POP chapter A.5.7.1. */ - rtx temp = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD); - rtx two31 = s390_gen_rtx_const_DI (0x4e000000, 0x80000000); + rtx temp = assign_stack_local (BLKmode, 8, BITS_PER_WORD); + rtx two31 = s390_gen_rtx_const_DI (0x4e000000, 0x80000000); emit_insn (gen_floatsidf2_ibm (operands[0], operands[1], two31, temp)); DONE; } -}") +}) (define_insn "floatsidf2_ieee" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:SI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cdfbr\\t%0,%1" + "cdfbr\t%0,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other" )]) + (set_attr "type" "itof" )]) (define_insn "floatsidf2_ibm" [(set (match_operand:DF 0 "register_operand" "=f") @@ -2785,16 +3210,16 @@ (use (match_operand:BLK 3 "memory_operand" "m")) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "* { - output_asm_insn (\"st\\t%1,%N3\", operands); - output_asm_insn (\"xi\\t%N3,128\", operands); - output_asm_insn (\"mvc\\t%O3(4,%R3),%2\", operands); - output_asm_insn (\"ld\\t%0,%3\", operands); - return \"sd\\t%0,%2\"; -}" + output_asm_insn ("st\t%1,%N3", operands); + output_asm_insn ("xi\t%N3,128", operands); + output_asm_insn ("mvc\t%O3(4,%R3),%2", operands); + output_asm_insn ("ld\t%0,%3", operands); + return "sd\t%0,%2"; +} [(set_attr "op_type" "NN") (set_attr "type" "other" ) + (set_attr "atype" "agen") (set_attr "length" "20")]) ; @@ -2807,7 +3232,6 @@ (float:SF (match_operand:SI 1 "register_operand" ""))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" - " { if (TARGET_IBM_FLOAT) { @@ -2817,16 +3241,16 @@ emit_insn (gen_truncdfsf2 (operands[0], temp)); DONE; } -}") +}) (define_insn "floatsisf2_ieee" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:SI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "cefbr\\t%0,%1" + "cefbr\t%0,%1" [(set_attr "op_type" "RRE") - (set_attr "type" "other" )]) + (set_attr "type" "itof" )]) ; ; truncdfsf2 instruction pattern(s). @@ -2842,18 +3266,18 @@ [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "general_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "ledbr\\t%0,%1" + "ledbr\t%0,%1" [(set_attr "op_type" "RRE")]) (define_insn "truncdfsf2_ibm" [(set (match_operand:SF 0 "register_operand" "=f,f") - (float_truncate:SF (match_operand:DF 1 "general_operand" "f,m")))] + (float_truncate:SF (match_operand:DF 1 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - lrer\\t%0,%1 - le\\t%0,%1" + lrer\t%0,%1 + le\t%0,%1" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "floads,floads")]) ; ; extendsfdf2 instruction pattern(s). @@ -2863,41 +3287,42 @@ [(set (match_operand:DF 0 "register_operand" "") (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))] "TARGET_HARD_FLOAT" - " { if (TARGET_IBM_FLOAT) { emit_insn (gen_extendsfdf2_ibm (operands[0], operands[1])); DONE; } -}") +}) (define_insn "extendsfdf2_ieee" [(set (match_operand:DF 0 "register_operand" "=f,f") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m")))] + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - ldebr\\t%0,%1 - ldeb\\t%0,%1" - [(set_attr "op_type" "RRE,RXE")]) + ldebr\t%0,%1 + ldeb\t%0,%1" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "floads,floads")]) (define_insn "extendsfdf2_ibm" [(set (match_operand:DF 0 "register_operand" "=f,f") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m"))) + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - sdr\\t%0,%0\;ler\\t%0,%1 - sdr\\t%0,%0\;le\\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem") - (set_attr "type" "o2,o2")]) + sdr\t%0,%0\;ler\t%0,%1 + sdr\t%0,%0\;le\t%0,%1" + [(set_attr "op_type" "NN,NN") + (set_attr "atype" "reg,agen") + (set_attr "length" "4,6") + (set_attr "type" "o2,o2")]) ;; -;; ARITHMETRIC OPERATIONS +;; ARITHMETIC OPERATIONS ;; -; arithmetric operations set the ConditionCode, +; arithmetic operations set the ConditionCode, ; because of unpredictable Bits in Register for Halfword and Byte ; the ConditionCode can be set wrong in operations for Halfword and Byte @@ -2916,13 +3341,12 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - agfr\\t%0,%2 - agf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + agfr\t%0,%2 + agf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_zero_cc" - [(set (reg 33) + [(set (reg 33) (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m")) (match_operand:DI 1 "register_operand" "0,0")) (const_int 0))) @@ -2930,23 +3354,21 @@ (plus:DI (zero_extend:DI (match_dup 2)) (match_dup 1)))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - algfr\\t%0,%2 - algf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algfr\t%0,%2 + algf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_zero_cconly" - [(set (reg 33) + [(set (reg 33) (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m")) (match_operand:DI 1 "register_operand" "0,0")) (const_int 0))) (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - algfr\\t%0,%2 - algf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algfr\t%0,%2 + algf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_zero" [(set (match_operand:DI 0 "register_operand" "=d,d") @@ -2955,27 +3377,75 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - algfr\\t%0,%2 - algf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algfr\t%0,%2 + algf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_imm_cc" - [(set (reg 33) + [(set (reg 33) (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "0") (match_operand:DI 2 "const_int_operand" "K")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=d") (plus:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && s390_match_ccmode (insn, CCAmode) - && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" - "aghi\\t%0,%h2" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) + "TARGET_64BIT + && s390_match_ccmode (insn, CCAmode) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\")" + "aghi\t%0,%h2" + [(set_attr "op_type" "RI")]) + +(define_insn "*adddi3_carry1_cc" + [(set (reg 33) + (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 1))) + (set (match_operand:DI 0 "register_operand" "=d,d") + (plus:DI (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT" + "@ + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*adddi3_carry1_cconly" + [(set (reg 33) + (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 1))) + (clobber (match_scratch:DI 0 "=d,d"))] + "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT" + "@ + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*adddi3_carry2_cc" + [(set (reg 33) + (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 2))) + (set (match_operand:DI 0 "register_operand" "=d,d") + (plus:DI (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT" + "@ + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*adddi3_carry2_cconly" + [(set (reg 33) + (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 2))) + (clobber (match_scratch:DI 0 "=d,d"))] + "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT" + "@ + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_cc" - [(set (reg 33) + [(set (reg 33) (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "general_operand" "d,m")) (const_int 0))) @@ -2983,35 +3453,32 @@ (plus:DI (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - algr\\t%0,%2 - alg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_cconly" - [(set (reg 33) + [(set (reg 33) (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") (match_operand:DI 2 "general_operand" "d,m")) (const_int 0))) (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - algr\\t%0,%2 - alg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_cconly2" - [(set (reg 33) + [(set (reg 33) (compare (match_operand:DI 1 "nonimmediate_operand" "%0,0") (neg:SI (match_operand:DI 2 "general_operand" "d,m")))) (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode(insn, CCLmode) && TARGET_64BIT" "@ - algr\\t%0,%2 - alg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + algr\t%0,%2 + alg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*adddi3_64" [(set (match_operand:DI 0 "register_operand" "=d,d,d") @@ -3020,18 +3487,42 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - agr\\t%0,%2 - aghi\\t%0,%h2 - ag\\t%0,%2" - [(set_attr "op_type" "RRE,RI,RXE") - (set_attr "atype" "reg,reg,mem")]) + agr\t%0,%2 + aghi\t%0,%h2 + ag\t%0,%2" + [(set_attr "op_type" "RRE,RI,RXY")]) + +(define_insn_and_split "*adddi3_31z" + [(set (match_operand:DI 0 "register_operand" "=&d") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "general_operand" "do") ) ) + (clobber (reg:CC 33))] + "!TARGET_64BIT && TARGET_CPU_ZARCH" + "#" + "&& reload_completed" + [(parallel + [(set (reg:CCL1 33) + (compare:CCL1 (plus:SI (match_dup 7) (match_dup 8)) + (match_dup 7))) + (set (match_dup 6) (plus:SI (match_dup 7) (match_dup 8)))]) + (parallel + [(set (match_dup 3) (plus:SI (plus:SI (match_dup 4) (match_dup 5)) + (ltu:SI (reg:CCL1 33) (const_int 0)))) + (clobber (reg:CC 33))])] + "operands[3] = operand_subword (operands[0], 0, 0, DImode); + operands[4] = operand_subword (operands[1], 0, 0, DImode); + operands[5] = operand_subword (operands[2], 0, 0, DImode); + operands[6] = operand_subword (operands[0], 1, 0, DImode); + operands[7] = operand_subword (operands[1], 1, 0, DImode); + operands[8] = operand_subword (operands[2], 1, 0, DImode);" + [(set_attr "op_type" "NN")]) (define_insn_and_split "*adddi3_31" [(set (match_operand:DI 0 "register_operand" "=&d") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "general_operand" "do") ) ) (clobber (reg:CC 33))] - "!TARGET_64BIT" + "!TARGET_CPU_ZARCH" "#" "&& reload_completed" [(parallel @@ -3068,277 +3559,138 @@ "" "") -(define_insn "*la_64" - [(set (match_operand:DI 0 "register_operand" "=d") - (match_operand:QI 1 "address_operand" "p"))] - "TARGET_64BIT" - "la\\t%0,%a1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem") - (set_attr "type" "la")]) - -(define_peephole2 - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:QI 1 "address_operand" "")) - (clobber (reg:CC 33))])] - "TARGET_64BIT - && strict_memory_address_p (VOIDmode, operands[1]) - && preferred_la_operand_p (operands[1])" - [(set (match_dup 0) (match_dup 1))] - "") - -(define_peephole2 - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "register_operand" "")) - (parallel - [(set (match_dup 0) - (plus:DI (match_dup 0) - (match_operand:DI 2 "nonmemory_operand" ""))) - (clobber (reg:CC 33))])] - "TARGET_64BIT - && !reg_overlap_mentioned_p (operands[0], operands[2]) - && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (DImode, operands[1], operands[2])) - && preferred_la_operand_p (gen_rtx_PLUS (DImode, operands[1], operands[2]))" - [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))] - "") - -(define_expand "reload_indi" - [(parallel [(match_operand:DI 0 "register_operand" "=a") - (match_operand:DI 1 "s390_plus_operand" "") - (match_operand:DI 2 "register_operand" "=&a")])] - "TARGET_64BIT" - " -{ - s390_expand_plus_operand (operands[0], operands[1], operands[2]); - DONE; -}") - - ; ; addsi3 instruction pattern(s). ; (define_insn "*addsi3_imm_cc" - [(set (reg 33) + [(set (reg 33) (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "const_int_operand" "K")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=d") (plus:SI (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCAmode) - && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" - "ahi\\t%0,%h2" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\")" + "ahi\t%0,%h2" + [(set_attr "op_type" "RI")]) (define_insn "*addsi3_carry1_cc" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 1))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode)" + "s390_match_ccmode (insn, CCL1mode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_carry1_cconly" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 1))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode (insn, CCL1mode)" + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCL1mode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_carry2_cc" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 2))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode)" + "s390_match_ccmode (insn, CCL1mode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_carry2_cconly" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 2))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode (insn, CCL1mode)" + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCL1mode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_cc" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCLmode)" + "s390_match_ccmode (insn, CCLmode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_cconly" - [(set (reg 33) - (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + [(set (reg 33) + (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode (insn, CCLmode)" + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCLmode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_cconly2" - [(set (reg 33) - (compare (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (neg:SI (match_operand:SI 2 "general_operand" "d,m")))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode(insn, CCLmode)" + [(set (reg 33) + (compare (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (neg:SI (match_operand:SI 2 "general_operand" "d,R,T")))) + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCLmode)" "@ - alr\\t%0,%2 - al\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + alr\t%0,%2 + al\t%0,%2 + aly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*addsi3_sign" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (sign_extend:SI (match_operand:HI 2 "memory_operand" "m")))) - (clobber (reg:CC 33))] - "" - "ah\\t%0,%2" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) - -(define_insn "*addsi3_sub" - [(set (match_operand:SI 0 "register_operand" "=d") - (plus:SI (match_operand:SI 1 "register_operand" "0") - (subreg:SI (match_operand:HI 2 "memory_operand" "m") 0))) + [(set (match_operand:SI 0 "register_operand" "=d,d") + (plus:SI (match_operand:SI 1 "register_operand" "0,0") + (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T")))) (clobber (reg:CC 33))] "" - "ah\\t%0,%2" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + ah\t%0,%2 + ahy\t%0,%2" + [(set_attr "op_type" "RX,RXY")]) (define_insn "addsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d,d") - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:SI 2 "general_operand" "d,K,m"))) + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0") + (match_operand:SI 2 "general_operand" "d,K,R,T"))) (clobber (reg:CC 33))] "" "@ - ar\\t%0,%2 - ahi\\t%0,%h2 - a\\t%0,%2" - [(set_attr "op_type" "RR,RI,RX") - (set_attr "atype" "reg,reg,mem")]) - -(define_insn "*la_31" - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:QI 1 "address_operand" "p"))] - "!TARGET_64BIT && legitimate_la_operand_p (operands[1])" - "la\\t%0,%a1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem") - (set_attr "type" "la")]) - -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:QI 1 "address_operand" "")) - (clobber (reg:CC 33))])] - "!TARGET_64BIT - && strict_memory_address_p (VOIDmode, operands[1]) - && preferred_la_operand_p (operands[1])" - [(set (match_dup 0) (match_dup 1))] - "") - -(define_peephole2 - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "register_operand" "")) - (parallel - [(set (match_dup 0) - (plus:SI (match_dup 0) - (match_operand:SI 2 "nonmemory_operand" ""))) - (clobber (reg:CC 33))])] - "!TARGET_64BIT - && !reg_overlap_mentioned_p (operands[0], operands[2]) - && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (SImode, operands[1], operands[2])) - && preferred_la_operand_p (gen_rtx_PLUS (SImode, operands[1], operands[2]))" - [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))] - "") - -(define_insn "*la_31_and" - [(set (match_operand:SI 0 "register_operand" "=d") - (and:SI (match_operand:QI 1 "address_operand" "p") - (const_int 2147483647)))] - "!TARGET_64BIT" - "la\\t%0,%a1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem") - (set_attr "type" "la")]) - -(define_insn_and_split "*la_31_and_cc" - [(set (match_operand:SI 0 "register_operand" "=d") - (and:SI (match_operand:QI 1 "address_operand" "p") - (const_int 2147483647))) - (clobber (reg:CC 33))] - "!TARGET_64BIT" - "#" - "&& reload_completed" - [(set (match_dup 0) - (and:SI (match_dup 1) (const_int 2147483647)))] - "" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem") - (set_attr "type" "la")]) - -(define_insn "force_la_31" - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:QI 1 "address_operand" "p")) - (use (const_int 0))] - "!TARGET_64BIT" - "la\\t%0,%a1" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem") - (set_attr "type" "la")]) - -(define_expand "reload_insi" - [(parallel [(match_operand:SI 0 "register_operand" "=a") - (match_operand:SI 1 "s390_plus_operand" "") - (match_operand:SI 2 "register_operand" "=&a")])] - "!TARGET_64BIT" - " -{ - s390_expand_plus_operand (operands[0], operands[1], operands[2]); - DONE; -}") - + ar\t%0,%2 + ahi\t%0,%h2 + a\t%0,%2 + ay\t%0,%2" + [(set_attr "op_type" "RR,RI,RX,RXY")]) ; ; adddf3 instruction pattern(s). @@ -3348,7 +3700,7 @@ [(parallel [(set (match_operand:DF 0 "register_operand" "=f,f") (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" "") @@ -3356,26 +3708,53 @@ (define_insn "*adddf3" [(set (match_operand:DF 0 "register_operand" "=f,f") (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - adbr\\t%0,%2 - adb\\t%0,%2" + adbr\t%0,%2 + adb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimpd,fsimpd")]) + +(define_insn "*adddf3_cc" + [(set (reg 33) + (compare (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "general_operand" "f,R")) + (match_operand:DF 3 "const0_operand" ""))) + (set (match_operand:DF 0 "register_operand" "=f,f") + (plus:DF (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + adbr\t%0,%2 + adb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd,fsimpd")]) + +(define_insn "*adddf3_cconly" + [(set (reg 33) + (compare (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "general_operand" "f,R")) + (match_operand:DF 3 "const0_operand" ""))) + (clobber (match_scratch:DF 0 "=f,f"))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + adbr\t%0,%2 + adb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimpd,fsimpd")]) (define_insn "*adddf3_ibm" [(set (match_operand:DF 0 "register_operand" "=f,f") (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - adr\\t%0,%2 - ad\\t%0,%2" + adr\t%0,%2 + ad\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd,fsimpd")]) ; ; addsf3 instruction pattern(s). @@ -3385,7 +3764,7 @@ [(parallel [(set (match_operand:SF 0 "register_operand" "=f,f") (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" "") @@ -3393,26 +3772,53 @@ (define_insn "*addsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - aebr\\t%0,%2 - aeb\\t%0,%2" + aebr\t%0,%2 + aeb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimps,fsimps")]) + +(define_insn "*addsf3_cc" + [(set (reg 33) + (compare (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") + (match_operand:SF 2 "general_operand" "f,R")) + (match_operand:SF 3 "const0_operand" ""))) + (set (match_operand:SF 0 "register_operand" "=f,f") + (plus:SF (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + aebr\t%0,%2 + aeb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimps,fsimps")]) + +(define_insn "*addsf3_cconly" + [(set (reg 33) + (compare (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") + (match_operand:SF 2 "general_operand" "f,R")) + (match_operand:SF 3 "const0_operand" ""))) + (clobber (match_scratch:SF 0 "=f,f"))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + aebr\t%0,%2 + aeb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimps,fsimps")]) (define_insn "*addsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - aer\\t%0,%2 - ae\\t%0,%2" + aer\t%0,%2 + ae\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimps,fsimps")]) ;; @@ -3430,13 +3836,12 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - sgfr\\t%0,%2 - sgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + sgfr\t%0,%2 + sgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_zero_cc" - [(set (reg 33) + [(set (reg 33) (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))) (const_int 0))) @@ -3444,23 +3849,21 @@ (minus:DI (match_dup 1) (zero_extend:DI (match_dup 2))))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - slgfr\\t%0,%2 - slgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + slgfr\t%0,%2 + slgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_zero_cconly" - [(set (reg 33) + [(set (reg 33) (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))) (const_int 0))) (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - slgfr\\t%0,%2 - slgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + slgfr\t%0,%2 + slgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_zero" [(set (match_operand:DI 0 "register_operand" "=d,d") @@ -3469,10 +3872,34 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - slgfr\\t%0,%2 - slgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + slgfr\t%0,%2 + slgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subdi3_borrow_cc" + [(set (reg 33) + (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 1))) + (set (match_operand:DI 0 "register_operand" "=d,d") + (minus:DI (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCL2mode) && TARGET_64BIT" + "@ + slgr\t%0,%2 + slg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subdi3_borrow_cconly" + [(set (reg 33) + (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_dup 1))) + (clobber (match_scratch:DI 0 "=d,d"))] + "s390_match_ccmode (insn, CCL2mode) && TARGET_64BIT" + "@ + slgr\t%0,%2 + slg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_cc" [(set (reg 33) @@ -3481,12 +3908,11 @@ (const_int 0))) (set (match_operand:DI 0 "register_operand" "=d,d") (minus:DI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCLmode)" + "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - slgr\\t%0,%2 - slg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + slgr\t%0,%2 + slg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_cconly" [(set (reg 33) @@ -3494,12 +3920,11 @@ (match_operand:DI 2 "general_operand" "d,m")) (const_int 0))) (clobber (match_scratch:DI 0 "=d,d"))] - "s390_match_ccmode (insn, CCLmode)" + "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" "@ - slgr\\t%0,%2 - slg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + slgr\t%0,%2 + slg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*subdi3_64" [(set (match_operand:DI 0 "register_operand" "=d,d") @@ -3508,17 +3933,41 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - sgr\\t%0,%2 - sg\\t%0,%2" - [(set_attr "op_type" "RRE,RRE") - (set_attr "atype" "reg,mem")]) + sgr\t%0,%2 + sg\t%0,%2" + [(set_attr "op_type" "RRE,RRE")]) + +(define_insn_and_split "*subdi3_31z" + [(set (match_operand:DI 0 "register_operand" "=&d") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "general_operand" "do") ) ) + (clobber (reg:CC 33))] + "!TARGET_64BIT && TARGET_CPU_ZARCH" + "#" + "&& reload_completed" + [(parallel + [(set (reg:CCL2 33) + (compare:CCL2 (minus:SI (match_dup 7) (match_dup 8)) + (match_dup 7))) + (set (match_dup 6) (minus:SI (match_dup 7) (match_dup 8)))]) + (parallel + [(set (match_dup 3) (minus:SI (minus:SI (match_dup 4) (match_dup 5)) + (gtu:SI (reg:CCL2 33) (const_int 0)))) + (clobber (reg:CC 33))])] + "operands[3] = operand_subword (operands[0], 0, 0, DImode); + operands[4] = operand_subword (operands[1], 0, 0, DImode); + operands[5] = operand_subword (operands[2], 0, 0, DImode); + operands[6] = operand_subword (operands[0], 1, 0, DImode); + operands[7] = operand_subword (operands[1], 1, 0, DImode); + operands[8] = operand_subword (operands[2], 1, 0, DImode);" + [(set_attr "op_type" "NN")]) (define_insn_and_split "*subdi3_31" [(set (match_operand:DI 0 "register_operand" "=&d") (minus:DI (match_operand:DI 1 "register_operand" "0") (match_operand:DI 2 "general_operand" "do") ) ) (clobber (reg:CC 33))] - "!TARGET_64BIT" + "!TARGET_CPU_ZARCH" "#" "&& reload_completed" [(parallel @@ -3561,89 +4010,80 @@ (define_insn "*subsi3_borrow_cc" [(set (reg 33) - (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 1))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (minus:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCL2mode)" + "s390_match_ccmode (insn, CCL2mode)" "@ - slr\\t%0,%2 - sl\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + slr\t%0,%2 + sl\t%0,%2 + sly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*subsi3_borrow_cconly" [(set (reg 33) - (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (match_dup 1))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode(insn, CCL2mode)" + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCL2mode)" "@ - slr\\t%0,%2 - sl\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + slr\t%0,%2 + sl\t%0,%2 + sly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*subsi3_cc" [(set (reg 33) - (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (minus:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCLmode)" + "s390_match_ccmode (insn, CCLmode)" "@ - slr\\t%0,%2 - sl\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + slr\t%0,%2 + sl\t%0,%2 + sly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*subsi3_cconly" [(set (reg 33) - (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] - "s390_match_ccmode(insn, CCLmode)" + (clobber (match_scratch:SI 0 "=d,d,d"))] + "s390_match_ccmode (insn, CCLmode)" "@ - slr\\t%0,%2 - sl\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + slr\t%0,%2 + sl\t%0,%2 + sly\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*subsi3_sign" - [(set (match_operand:SI 0 "register_operand" "=d") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (sign_extend:SI (match_operand:HI 2 "memory_operand" "m")))) - (clobber (reg:CC 33))] - "" - "sh\\t%0,%2" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) - -(define_insn "*subsi3_sub" - [(set (match_operand:SI 0 "register_operand" "=d") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (subreg:SI (match_operand:HI 2 "memory_operand" "m") 0))) + [(set (match_operand:SI 0 "register_operand" "=d,d") + (minus:SI (match_operand:SI 1 "register_operand" "0,0") + (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T")))) (clobber (reg:CC 33))] "" - "sh\\t%0,%2" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + sh\t%0,%2 + shy\t%0,%2" + [(set_attr "op_type" "RX,RXY")]) (define_insn "subsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (minus:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "general_operand" "d,m"))) + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (minus:SI (match_operand:SI 1 "register_operand" "0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T"))) (clobber (reg:CC 33))] "" "@ - sr\\t%0,%2 - s\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + sr\t%0,%2 + s\t%0,%2 + sy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) ; @@ -3654,7 +4094,7 @@ [(parallel [(set (match_operand:DF 0 "register_operand" "=f,f") (minus:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" "") @@ -3662,26 +4102,53 @@ (define_insn "*subdf3" [(set (match_operand:DF 0 "register_operand" "=f,f") (minus:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - sdbr\\t%0,%2 - sdb\\t%0,%2" + sdbr\t%0,%2 + sdb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimpd,fsimpd")]) + +(define_insn "*subdf3_cc" + [(set (reg 33) + (compare (minus:DF (match_operand:DF 1 "nonimmediate_operand" "0,0") + (match_operand:DF 2 "general_operand" "f,R")) + (match_operand:DF 3 "const0_operand" ""))) + (set (match_operand:DF 0 "register_operand" "=f,f") + (plus:DF (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + sdbr\t%0,%2 + sdb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd,fsimpd")]) + +(define_insn "*subdf3_cconly" + [(set (reg 33) + (compare (minus:DF (match_operand:DF 1 "nonimmediate_operand" "0,0") + (match_operand:DF 2 "general_operand" "f,R")) + (match_operand:DF 3 "const0_operand" ""))) + (clobber (match_scratch:DF 0 "=f,f"))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + sdbr\t%0,%2 + sdb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimpd,fsimpd")]) (define_insn "*subdf3_ibm" [(set (match_operand:DF 0 "register_operand" "=f,f") (minus:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) + (match_operand:DF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - sdr\\t%0,%2 - sd\\t%0,%2" + sdr\t%0,%2 + sd\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimpd,fsimpd")]) ; ; subsf3 instruction pattern(s). @@ -3691,7 +4158,7 @@ [(parallel [(set (match_operand:SF 0 "register_operand" "=f,f") (minus:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))])] "TARGET_HARD_FLOAT" "") @@ -3699,26 +4166,174 @@ (define_insn "*subsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (minus:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - sebr\\t%0,%2 - seb\\t%0,%2" + sebr\t%0,%2 + seb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimps,fsimps")]) + +(define_insn "*subsf3_cc" + [(set (reg 33) + (compare (minus:SF (match_operand:SF 1 "nonimmediate_operand" "0,0") + (match_operand:SF 2 "general_operand" "f,R")) + (match_operand:SF 3 "const0_operand" ""))) + (set (match_operand:SF 0 "register_operand" "=f,f") + (minus:SF (match_dup 1) (match_dup 2)))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + sebr\t%0,%2 + seb\t%0,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fsimps,fsimps")]) + +(define_insn "*subsf3_cconly" + [(set (reg 33) + (compare (minus:SF (match_operand:SF 1 "nonimmediate_operand" "0,0") + (match_operand:SF 2 "general_operand" "f,R")) + (match_operand:SF 3 "const0_operand" ""))) + (clobber (match_scratch:SF 0 "=f,f"))] + "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "@ + sebr\t%0,%2 + seb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimps,fsimps")]) (define_insn "*subsf3_ibm" [(set (match_operand:SF 0 "register_operand" "=f,f") (minus:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) + (match_operand:SF 2 "general_operand" "f,R"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - ser\\t%0,%2 - se\\t%0,%2" + ser\t%0,%2 + se\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fsimps,fsimps")]) + + +;; +;;- Conditional add/subtract instructions. +;; + +; +; adddicc instruction pattern(s). +; + +(define_insn "*adddi3_alc_cc" + [(set (reg 33) + (compare + (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_operand:DI 3 "s390_alc_comparison" "")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=d,d") + (plus:DI (plus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" + "@ + alcgr\\t%0,%2 + alcg\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*adddi3_alc" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_operand:DI 3 "s390_alc_comparison" ""))) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "@ + alcgr\\t%0,%2 + alcg\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subdi3_slb_cc" + [(set (reg 33) + (compare + (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_operand:DI 3 "s390_slb_comparison" "")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=d,d") + (minus:DI (minus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT" + "@ + slbgr\\t%0,%2 + slbg\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subdi3_slb" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "general_operand" "d,m")) + (match_operand:DI 3 "s390_slb_comparison" ""))) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "@ + slbgr\\t%0,%2 + slbg\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +; +; addsicc instruction pattern(s). +; + +(define_insn "*addsi3_alc_cc" + [(set (reg 33) + (compare + (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "d,m")) + (match_operand:SI 3 "s390_alc_comparison" "")) + (const_int 0))) + (set (match_operand:SI 0 "register_operand" "=d,d") + (plus:SI (plus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" + "@ + alcr\\t%0,%2 + alc\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*addsi3_alc" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "d,m")) + (match_operand:SI 3 "s390_alc_comparison" ""))) + (clobber (reg:CC 33))] + "TARGET_CPU_ZARCH" + "@ + alcr\\t%0,%2 + alc\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subsi3_slb_cc" + [(set (reg 33) + (compare + (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "d,m")) + (match_operand:SI 3 "s390_slb_comparison" "")) + (const_int 0))) + (set (match_operand:SI 0 "register_operand" "=d,d") + (minus:SI (minus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" + "@ + slbr\\t%0,%2 + slb\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) + +(define_insn "*subsi3_slb" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "d,m")) + (match_operand:SI 3 "s390_slb_comparison" ""))) + (clobber (reg:CC 33))] + "TARGET_CPU_ZARCH" + "@ + slbr\\t%0,%2 + slb\\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) ;; @@ -3735,160 +4350,196 @@ (match_operand:DI 1 "register_operand" "0,0")))] "TARGET_64BIT" "@ - msgfr\\t%0,%2 - msgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem") + msgfr\t%0,%2 + msgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY") (set_attr "type" "imul")]) - (define_insn "muldi3" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") (match_operand:DI 2 "general_operand" "d,K,m")))] "TARGET_64BIT" "@ - msgr\\t%0,%2 - mghi\\t%0,%h2 - msg\\t%0,%2" - [(set_attr "op_type" "RRE,RI,RXE") - (set_attr "atype" "reg,reg,mem") + msgr\t%0,%2 + mghi\t%0,%h2 + msg\t%0,%2" + [(set_attr "op_type" "RRE,RI,RXY") (set_attr "type" "imul")]) ; ; mulsi3 instruction pattern(s). ; +(define_insn "*mulsi3_sign" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (sign_extend:SI (match_operand:HI 2 "memory_operand" "R")) + (match_operand:SI 1 "register_operand" "0")))] + "" + "mh\t%0,%2" + [(set_attr "op_type" "RX") + (set_attr "type" "imul")]) + (define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d,d") - (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:SI 2 "general_operand" "d,K,m")))] + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0") + (match_operand:SI 2 "general_operand" "d,K,R,T")))] "" "@ - msr\\t%0,%2 - mhi\\t%0,%h2 - ms\\t%0,%2" - [(set_attr "op_type" "RRE,RI,RX") - (set_attr "atype" "reg,reg,mem") + msr\t%0,%2 + mhi\t%0,%h2 + ms\t%0,%2 + msy\t%0,%2" + [(set_attr "op_type" "RRE,RI,RX,RXY") (set_attr "type" "imul")]) ; ; mulsidi3 instruction pattern(s). ; -(define_expand "mulsidi3" - [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")) - (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))))] +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (mult:DI (sign_extend:DI + (match_operand:SI 1 "register_operand" "%0,0")) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "d,R"))))] "!TARGET_64BIT" - " -{ - rtx insn; + "@ + mr\t%0,%2 + m\t%0,%2" + [(set_attr "op_type" "RR,RX") + (set_attr "type" "imul")]) - emit_insn (gen_zero_extendsidi2 (operands[0], operands[1])); - insn = emit_insn (gen_mulsi_6432 (operands[0], operands[0], operands[2])); +; +; umulsidi3 instruction pattern(s). +; - REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, - gen_rtx_MULT (DImode, - gen_rtx_SIGN_EXTEND (DImode, operands[1]), - gen_rtx_SIGN_EXTEND (DImode, operands[2])), - REG_NOTES (insn)); - DONE; -}") - -(define_insn "mulsi_6432" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (mult:DI (sign_extend:DI - (truncate:SI (match_operand:DI 1 "register_operand" "0,0"))) - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,m"))))] - "!TARGET_64BIT" - "@ - mr\\t%0,%2 - m\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem") +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "register_operand" "%0,0")) + (zero_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "d,m"))))] + "!TARGET_64BIT && TARGET_CPU_ZARCH" + "@ + mlr\t%0,%2 + ml\t%0,%2" + [(set_attr "op_type" "RRE,RXY") (set_attr "type" "imul")]) - + ; ; muldf3 instruction pattern(s). ; (define_expand "muldf3" - [(parallel - [(set (match_operand:DF 0 "register_operand" "=f,f") - (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))])] + [(set (match_operand:DF 0 "register_operand" "=f,f") + (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT" "") (define_insn "*muldf3" [(set (match_operand:DF 0 "register_operand" "=f,f") (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - mdbr\\t%0,%2 - mdb\\t%0,%2" + mdbr\t%0,%2 + mdb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fmul") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fmuld")]) (define_insn "*muldf3_ibm" [(set (match_operand:DF 0 "register_operand" "=f,f") (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - mdr\\t%0,%2 - md\\t%0,%2" + mdr\t%0,%2 + md\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "type" "fmul") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fmuld")]) + +(define_insn "*fmadddf" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "%f,f") + (match_operand:DF 2 "nonimmediate_operand" "f,R")) + (match_operand:DF 3 "register_operand" "0,0")))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD" + "@ + madbr\t%0,%1,%2 + madb\t%0,%1,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fmuld")]) + +(define_insn "*fmsubdf" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "f,f") + (match_operand:DF 2 "nonimmediate_operand" "f,R")) + (match_operand:DF 3 "register_operand" "0,0")))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD" + "@ + msdbr\t%0,%1,%2 + msdb\t%0,%1,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fmuld")]) ; ; mulsf3 instruction pattern(s). ; (define_expand "mulsf3" - [(parallel - [(set (match_operand:SF 0 "register_operand" "=f,f") - (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))])] + [(set (match_operand:SF 0 "register_operand" "=f,f") + (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT" "") (define_insn "*mulsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - meebr\\t%0,%2 - meeb\\t%0,%2" + meebr\t%0,%2 + meeb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fmul") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fmuls")]) (define_insn "*mulsf3_ibm" [(set (match_operand:SF 0 "register_operand" "=f,f") (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - mer\\t%0,%2 - me\\t%0,%2" + mer\t%0,%2 + me\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "type" "fmul") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fmuls")]) +(define_insn "*fmaddsf" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f,f") + (match_operand:SF 2 "nonimmediate_operand" "f,R")) + (match_operand:SF 3 "register_operand" "0,0")))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD" + "@ + maebr\t%0,%1,%2 + maeb\t%0,%1,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fmuls")]) + +(define_insn "*fmsubsf" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "f,f") + (match_operand:SF 2 "nonimmediate_operand" "f,R")) + (match_operand:SF 3 "register_operand" "0,0")))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD" + "@ + msebr\t%0,%1,%2 + mseb\t%0,%1,%2" + [(set_attr "op_type" "RRE,RXE") + (set_attr "type" "fmuls")]) ;; ;;- Divide and modulo instructions. @@ -3900,31 +4551,20 @@ (define_expand "divmoddi4" [(parallel [(set (match_operand:DI 0 "general_operand" "") - (div:DI (match_operand:DI 1 "general_operand" "") + (div:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "general_operand" ""))) (set (match_operand:DI 3 "general_operand" "") (mod:DI (match_dup 1) (match_dup 2)))]) (clobber (match_dup 4))] "TARGET_64BIT" - " { - rtx insn, div_equal, mod_equal, equal; + rtx insn, div_equal, mod_equal; div_equal = gen_rtx_DIV (DImode, operands[1], operands[2]); mod_equal = gen_rtx_MOD (DImode, operands[1], operands[2]); - equal = gen_rtx_IOR (TImode, - gen_rtx_ZERO_EXTEND (TImode, div_equal), - gen_rtx_ASHIFT (TImode, - gen_rtx_ZERO_EXTEND (TImode, mod_equal), - GEN_INT (64))); operands[4] = gen_reg_rtx(TImode); - emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[4])); - emit_move_insn (gen_lowpart (DImode, operands[4]), operands[1]); - emit_move_insn (gen_highpart (DImode, operands[4]), const0_rtx); - insn = emit_insn (gen_divmodtidi3 (operands[4], operands[4], operands[2])); - REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); + emit_insn (gen_divmodtidi3 (operands[4], operands[1], operands[2])); insn = emit_move_insn (operands[0], gen_lowpart (DImode, operands[4])); REG_NOTES (insn) = @@ -3935,45 +4575,43 @@ gen_rtx_EXPR_LIST (REG_EQUAL, mod_equal, REG_NOTES (insn)); DONE; -}") +}) (define_insn "divmodtidi3" [(set (match_operand:TI 0 "register_operand" "=d,d") (ior:TI (zero_extend:TI - (div:DI (truncate:DI (match_operand:TI 1 "register_operand" "0,0")) + (div:DI (match_operand:DI 1 "register_operand" "0,0") (match_operand:DI 2 "general_operand" "d,m"))) (ashift:TI (zero_extend:TI - (mod:DI (truncate:DI (match_dup 1)) + (mod:DI (match_dup 1) (match_dup 2))) (const_int 64))))] "TARGET_64BIT" "@ - dsgr\\t%0,%2 - dsg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "idiv") - (set_attr "atype" "reg,mem")]) + dsgr\t%0,%2 + dsg\t%0,%2" + [(set_attr "op_type" "RRE,RXY") + (set_attr "type" "idiv")]) (define_insn "divmodtisi3" [(set (match_operand:TI 0 "register_operand" "=d,d") (ior:TI (zero_extend:TI - (div:DI (truncate:DI (match_operand:TI 1 "register_operand" "0,0")) + (div:DI (match_operand:DI 1 "register_operand" "0,0") (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "d,m")))) (ashift:TI (zero_extend:TI - (mod:DI (truncate:DI (match_dup 1)) + (mod:DI (match_dup 1) (sign_extend:DI (match_dup 2)))) (const_int 64))))] "TARGET_64BIT" "@ - dsgfr\\t%0,%2 - dsgf\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "idiv") - (set_attr "atype" "reg,mem")]) + dsgfr\t%0,%2 + dsgf\t%0,%2" + [(set_attr "op_type" "RRE,RXY") + (set_attr "type" "idiv")]) ; ; udivmoddi4 instruction pattern(s). @@ -3987,7 +4625,6 @@ (umod:DI (match_dup 1) (match_dup 2)))]) (clobber (match_dup 4))] "TARGET_64BIT" - " { rtx insn, div_equal, mod_equal, equal; @@ -4016,11 +4653,11 @@ gen_rtx_EXPR_LIST (REG_EQUAL, mod_equal, REG_NOTES (insn)); DONE; -}") +}) (define_insn "udivmodtidi3" [(set (match_operand:TI 0 "register_operand" "=d,d") - (ior:TI (zero_extend:TI + (ior:TI (zero_extend:TI (truncate:DI (udiv:TI (match_operand:TI 1 "register_operand" "0,0") (zero_extend:TI @@ -4032,11 +4669,10 @@ (const_int 64))))] "TARGET_64BIT" "@ - dlgr\\t%0,%2 - dlg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "idiv") - (set_attr "atype" "reg,mem")]) + dlgr\t%0,%2 + dlg\t%0,%2" + [(set_attr "op_type" "RRE,RXY") + (set_attr "type" "idiv")]) ; ; divmodsi4 instruction pattern(s). @@ -4050,7 +4686,6 @@ (mod:SI (match_dup 1) (match_dup 2)))]) (clobber (match_dup 4))] "!TARGET_64BIT" - " { rtx insn, div_equal, mod_equal, equal; @@ -4077,40 +4712,94 @@ gen_rtx_EXPR_LIST (REG_EQUAL, mod_equal, REG_NOTES (insn)); DONE; -}") +}) (define_insn "divmoddisi3" [(set (match_operand:DI 0 "register_operand" "=d,d") (ior:DI (zero_extend:DI (truncate:SI (div:DI (match_operand:DI 1 "register_operand" "0,0") - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,m"))))) + (sign_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "d,R"))))) (ashift:DI (zero_extend:DI (truncate:SI - (mod:DI (match_dup 1) (sign_extend:SI (match_dup 2))))) + (mod:DI (match_dup 1) (sign_extend:DI (match_dup 2))))) (const_int 32))))] "!TARGET_64BIT" "@ - dr\\t%0,%2 - d\\t%0,%2" + dr\t%0,%2 + d\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "type" "idiv") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "idiv")]) ; ; udivsi3 and umodsi3 instruction pattern(s). ; +(define_expand "udivmodsi4" + [(parallel [(set (match_operand:SI 0 "general_operand" "") + (udiv:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (match_operand:SI 3 "general_operand" "") + (umod:SI (match_dup 1) (match_dup 2)))]) + (clobber (match_dup 4))] + "!TARGET_64BIT && TARGET_CPU_ZARCH" +{ + rtx insn, div_equal, mod_equal, equal; + + div_equal = gen_rtx_UDIV (SImode, operands[1], operands[2]); + mod_equal = gen_rtx_UMOD (SImode, operands[1], operands[2]); + equal = gen_rtx_IOR (DImode, + gen_rtx_ZERO_EXTEND (DImode, div_equal), + gen_rtx_ASHIFT (DImode, + gen_rtx_ZERO_EXTEND (DImode, mod_equal), + GEN_INT (32))); + + operands[4] = gen_reg_rtx(DImode); + emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[4])); + emit_move_insn (gen_lowpart (SImode, operands[4]), operands[1]); + emit_move_insn (gen_highpart (SImode, operands[4]), const0_rtx); + insn = emit_insn (gen_udivmoddisi3 (operands[4], operands[4], operands[2])); + REG_NOTES (insn) = + gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); + + insn = emit_move_insn (operands[0], gen_lowpart (SImode, operands[4])); + REG_NOTES (insn) = + gen_rtx_EXPR_LIST (REG_EQUAL, div_equal, REG_NOTES (insn)); + + insn = emit_move_insn (operands[3], gen_highpart (SImode, operands[4])); + REG_NOTES (insn) = + gen_rtx_EXPR_LIST (REG_EQUAL, mod_equal, REG_NOTES (insn)); + + DONE; +}) + +(define_insn "udivmoddisi3" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (ior:DI (zero_extend:DI + (truncate:SI + (udiv:DI (match_operand:DI 1 "register_operand" "0,0") + (zero_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "d,m"))))) + (ashift:DI + (zero_extend:DI + (truncate:SI + (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2))))) + (const_int 32))))] + "!TARGET_64BIT && TARGET_CPU_ZARCH" + "@ + dlr\t%0,%2 + dl\t%0,%2" + [(set_attr "op_type" "RRE,RXY") + (set_attr "type" "idiv")]) (define_expand "udivsi3" [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "general_operand" "") (match_operand:SI 2 "general_operand" ""))) (clobber (match_dup 3))] - "!TARGET_64BIT" - " + "!TARGET_64BIT && !TARGET_CPU_ZARCH" { rtx insn, udiv_equal, umod_equal, equal; @@ -4139,32 +4828,32 @@ } else { - operands[2] = force_reg (SImode, operands[2]); - operands[2] = make_safe_from (operands[2], operands[0]); + operands[2] = force_reg (SImode, operands[2]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_insn (gen_zero_extendsidi2 (operands[3], operands[1])); insn = emit_insn (gen_divmoddisi3 (operands[3], operands[3], operands[2])); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); - - insn = emit_move_insn (operands[0], + + insn = emit_move_insn (operands[0], gen_lowpart (SImode, operands[3])); REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_EXPR_LIST (REG_EQUAL, udiv_equal, REG_NOTES (insn)); } } else - { + { rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); rtx label3 = gen_label_rtx (); - operands[1] = force_reg (SImode, operands[1]); - operands[1] = make_safe_from (operands[1], operands[0]); - operands[2] = force_reg (SImode, operands[2]); - operands[2] = make_safe_from (operands[2], operands[0]); + operands[1] = force_reg (SImode, operands[1]); + operands[1] = make_safe_from (operands[1], operands[0]); + operands[2] = force_reg (SImode, operands[2]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_move_insn (operands[0], const0_rtx); emit_insn (gen_cmpsi (operands[2], operands[1])); @@ -4178,11 +4867,11 @@ operands[2])); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); - - insn = emit_move_insn (operands[0], + + insn = emit_move_insn (operands[0], gen_lowpart (SImode, operands[3])); REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_EXPR_LIST (REG_EQUAL, udiv_equal, REG_NOTES (insn)); emit_jump (label3); emit_label (label1); @@ -4192,17 +4881,16 @@ emit_move_insn (operands[0], const1_rtx); emit_label (label3); } - emit_move_insn (operands[0], operands[0]); + emit_move_insn (operands[0], operands[0]); DONE; -}") +}) (define_expand "umodsi3" [(set (match_operand:SI 0 "register_operand" "=d") (umod:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "nonimmediate_operand" ""))) (clobber (match_dup 3))] - "!TARGET_64BIT" - " + "!TARGET_64BIT && !TARGET_CPU_ZARCH" { rtx insn, udiv_equal, umod_equal, equal; @@ -4232,19 +4920,19 @@ } else { - operands[2] = force_reg (SImode, operands[2]); - operands[2] = make_safe_from (operands[2], operands[0]); + operands[2] = force_reg (SImode, operands[2]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_insn (gen_zero_extendsidi2 (operands[3], operands[1])); insn = emit_insn (gen_divmoddisi3 (operands[3], operands[3], operands[2])); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); - - insn = emit_move_insn (operands[0], + + insn = emit_move_insn (operands[0], gen_highpart (SImode, operands[3])); REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_EXPR_LIST (REG_EQUAL, umod_equal, REG_NOTES (insn)); } } @@ -4254,12 +4942,12 @@ rtx label2 = gen_label_rtx (); rtx label3 = gen_label_rtx (); - operands[1] = force_reg (SImode, operands[1]); - operands[1] = make_safe_from (operands[1], operands[0]); - operands[2] = force_reg (SImode, operands[2]); - operands[2] = make_safe_from (operands[2], operands[0]); + operands[1] = force_reg (SImode, operands[1]); + operands[1] = make_safe_from (operands[1], operands[0]); + operands[2] = force_reg (SImode, operands[2]); + operands[2] = make_safe_from (operands[2], operands[0]); - emit_move_insn(operands[0], operands[1]); + emit_move_insn(operands[0], operands[1]); emit_insn (gen_cmpsi (operands[2], operands[1])); emit_jump_insn (gen_bgtu (label3)); emit_insn (gen_cmpsi (operands[2], const1_rtx)); @@ -4271,11 +4959,11 @@ operands[2])); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, equal, REG_NOTES (insn)); - - insn = emit_move_insn (operands[0], + + insn = emit_move_insn (operands[0], gen_highpart (SImode, operands[3])); REG_NOTES (insn) = - gen_rtx_EXPR_LIST (REG_EQUAL, + gen_rtx_EXPR_LIST (REG_EQUAL, umod_equal, REG_NOTES (insn)); emit_jump (label3); emit_label (label1); @@ -4286,85 +4974,73 @@ emit_label (label3); } DONE; -}") +}) ; ; divdf3 instruction pattern(s). ; (define_expand "divdf3" - [(parallel - [(set (match_operand:DF 0 "register_operand" "=f,f") - (div:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))])] + [(set (match_operand:DF 0 "register_operand" "=f,f") + (div:DF (match_operand:DF 1 "register_operand" "0,0") + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT" "") (define_insn "*divdf3" [(set (match_operand:DF 0 "register_operand" "=f,f") (div:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - ddbr\\t%0,%2 - ddb\\t%0,%2" + ddbr\t%0,%2 + ddb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fdiv") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fdivd")]) (define_insn "*divdf3_ibm" [(set (match_operand:DF 0 "register_operand" "=f,f") (div:DF (match_operand:DF 1 "register_operand" "0,0") - (match_operand:DF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:DF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - ddr\\t%0,%2 - dd\\t%0,%2" + ddr\t%0,%2 + dd\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "type" "fdiv") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fdivd")]) ; ; divsf3 instruction pattern(s). ; (define_expand "divsf3" - [(parallel - [(set (match_operand:SF 0 "register_operand" "=f,f") - (div:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))])] + [(set (match_operand:SF 0 "register_operand" "=f,f") + (div:SF (match_operand:SF 1 "register_operand" "0,0") + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT" "") (define_insn "*divsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (div:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - debr\\t%0,%2 - deb\\t%0,%2" + debr\t%0,%2 + deb\t%0,%2" [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fdiv") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fdivs")]) (define_insn "*divsf3" [(set (match_operand:SF 0 "register_operand" "=f,f") (div:SF (match_operand:SF 1 "register_operand" "0,0") - (match_operand:SF 2 "general_operand" "f,m"))) - (clobber (reg:CC 33))] + (match_operand:SF 2 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" "@ - der\\t%0,%2 - de\\t%0,%2" + der\t%0,%2 + de\t%0,%2" [(set_attr "op_type" "RR,RX") - (set_attr "type" "fdiv") - (set_attr "atype" "reg,mem")]) + (set_attr "type" "fdivs")]) ;; @@ -4384,10 +5060,9 @@ (and:DI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - ngr\\t%0,%2 - ng\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + ngr\t%0,%2 + ng\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*anddi3_cconly" [(set (reg 33) @@ -4397,45 +5072,27 @@ (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - ngr\\t%0,%2 - ng\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) - -(define_insn "*anddi3_ni" - [(set (match_operand:DI 0 "register_operand" "=d") - (and:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:DI 2 "immediate_operand" "n"))) - (clobber (reg:CC 33))] - "TARGET_64BIT && s390_single_hi (operands[2], DImode, -1) >= 0" - "* -{ - int part = s390_single_hi (operands[2], DImode, -1); - operands[2] = GEN_INT (s390_extract_hi (operands[2], DImode, part)); - - switch (part) - { - case 0: return \"nihh\\t%0,%x2\"; - case 1: return \"nihl\\t%0,%x2\"; - case 2: return \"nilh\\t%0,%x2\"; - case 3: return \"nill\\t%0,%x2\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) + ngr\t%0,%2 + ng\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "anddi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "general_operand" "d,m"))) - (clobber (reg:CC 33))] - "TARGET_64BIT" - "@ - ngr\\t%0,%2 - ng\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + [(set (match_operand:DI 0 "register_operand" "=d,d,d,d,d,d,d,d") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o,0,0,0,0,0,0") + (match_operand:DI 2 "general_operand" + "M,M,N0HDF,N1HDF,N2HDF,N3HDF,d,m"))) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "@ + # + # + nihh\t%0,%j2 + nihl\t%0,%j2 + nilh\t%0,%j2 + nill\t%0,%j2 + ngr\t%0,%2 + ng\t%0,%2" + [(set_attr "op_type" "RRE,RXE,RI,RI,RI,RI,RRE,RXY")]) (define_insn "*anddi3_ss" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4443,9 +5100,8 @@ (match_operand:DI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "nc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*anddi3_ss_inv" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4453,9 +5109,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "nc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; andsi3 instruction pattern(s). @@ -4463,63 +5118,66 @@ (define_insn "*andsi3_cc" [(set (reg 33) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (and:SI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode)" "@ - nr\\t%0,%2 - n\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + nr\t%0,%2 + n\t%0,%2 + ny\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*andsi3_cconly" [(set (reg 33) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] + (clobber (match_scratch:SI 0 "=d,d,d"))] "s390_match_ccmode(insn, CCTmode)" "@ - nr\\t%0,%2 - n\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + nr\t%0,%2 + n\t%0,%2 + ny\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) -(define_insn "*andsi3_ni" - [(set (match_operand:SI 0 "register_operand" "=d") - (and:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "immediate_operand" "n"))) - (clobber (reg:CC 33))] - "TARGET_64BIT && s390_single_hi (operands[2], SImode, -1) >= 0" - "* -{ - int part = s390_single_hi (operands[2], SImode, -1); - operands[2] = GEN_INT (s390_extract_hi (operands[2], SImode, part)); - - switch (part) - { - case 0: return \"nilh\\t%0,%x2\"; - case 1: return \"nill\\t%0,%x2\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) +(define_expand "andsi3" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 33))])] + "" + "") -(define_insn "andsi3" +(define_insn "*andsi3_zarch" + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d,d,d") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "d,o,0,0,0,0,0") + (match_operand:SI 2 "general_operand" "M,M,N0HSF,N1HSF,d,R,T"))) + (clobber (reg:CC 33))] + "TARGET_ZARCH" + "@ + # + # + nilh\t%0,%j2 + nill\t%0,%j2 + nr\t%0,%2 + n\t%0,%2 + ny\t%0,%2" + [(set_attr "op_type" "RRE,RXE,RI,RI,RR,RX,RXY")]) + +(define_insn "*andsi3_esa" [(set (match_operand:SI 0 "register_operand" "=d,d") (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m"))) + (match_operand:SI 2 "general_operand" "d,R"))) (clobber (reg:CC 33))] - "" + "!TARGET_ZARCH" "@ - nr\\t%0,%2 - n\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + nr\t%0,%2 + n\t%0,%2" + [(set_attr "op_type" "RR,RX")]) (define_insn "*andsi3_ss" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -4527,9 +5185,8 @@ (match_operand:SI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "nc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*andsi3_ss_inv" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -4537,9 +5194,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "nc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; andhi3 instruction pattern(s). @@ -4550,12 +5206,11 @@ (and:HI (match_operand:HI 1 "register_operand" "%0,0") (match_operand:HI 2 "nonmemory_operand" "d,n"))) (clobber (reg:CC 33))] - "TARGET_64BIT" + "TARGET_ZARCH" "@ - nr\\t%0,%2 - nill\\t%0,%x2" - [(set_attr "op_type" "RR,RI") - (set_attr "atype" "reg")]) + nr\t%0,%2 + nill\t%0,%x2" + [(set_attr "op_type" "RR,RI")]) (define_insn "andhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -4563,9 +5218,8 @@ (match_operand:HI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "nr\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "nr\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*andhi3_ss" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -4573,9 +5227,8 @@ (match_operand:HI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "nc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*andhi3_ss_inv" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -4583,9 +5236,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "nc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "nc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; andqi3 instruction pattern(s). @@ -4596,12 +5248,11 @@ (and:QI (match_operand:QI 1 "register_operand" "%0,0") (match_operand:QI 2 "nonmemory_operand" "d,n"))) (clobber (reg:CC 33))] - "TARGET_64BIT" + "TARGET_ZARCH" "@ - nr\\t%0,%2 - nill\\t%0,%b2" - [(set_attr "op_type" "RR,RI") - (set_attr "atype" "reg")]) + nr\t%0,%2 + nill\t%0,%b2" + [(set_attr "op_type" "RR,RI")]) (define_insn "andqi3" [(set (match_operand:QI 0 "register_operand" "=d") @@ -4609,33 +5260,32 @@ (match_operand:QI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "nr\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "nr\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*andqi3_ss" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") (and:QI (match_dup 0) - (match_operand:QI 1 "s_imm_operand" "n,Q"))) + (match_operand:QI 1 "s_imm_operand" "n,n,Q"))) (clobber (reg:CC 33))] "" "@ - ni\\t%0,%b1 - nc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "mem")]) + ni\t%0,%b1 + niy\t%0,%b1 + nc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) (define_insn "*andqi3_ss_inv" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") - (and:QI (match_operand:QI 1 "s_imm_operand" "n,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") + (and:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q") (match_dup 0))) (clobber (reg:CC 33))] "" "@ - ni\\t%0,%b1 - nc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "mem")]) + ni\t%0,%b1 + niy\t%0,%b1 + nc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) ;; @@ -4655,10 +5305,9 @@ (ior:DI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - ogr\\t%0,%2 - og\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + ogr\t%0,%2 + og\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*iordi3_cconly" [(set (reg 33) @@ -4668,45 +5317,24 @@ (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - ogr\\t%0,%2 - og\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) - -(define_insn "*iordi3_oi" - [(set (match_operand:DI 0 "register_operand" "=d") - (ior:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:DI 2 "immediate_operand" "n"))) - (clobber (reg:CC 33))] - "TARGET_64BIT && s390_single_hi (operands[2], DImode, 0) >= 0" - "* -{ - int part = s390_single_hi (operands[2], DImode, 0); - operands[2] = GEN_INT (s390_extract_hi (operands[2], DImode, part)); - - switch (part) - { - case 0: return \"oihh\\t%0,%x2\"; - case 1: return \"oihl\\t%0,%x2\"; - case 2: return \"oilh\\t%0,%x2\"; - case 3: return \"oill\\t%0,%x2\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) + ogr\t%0,%2 + og\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "iordi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "general_operand" "d,m"))) + [(set (match_operand:DI 0 "register_operand" "=d,d,d,d,d,d") + (ior:DI (match_operand:DI 1 "nonimmediate_operand" "0,0,0,0,0,0") + (match_operand:DI 2 "general_operand" "N0HD0,N1HD0,N2HD0,N3HD0,d,m"))) (clobber (reg:CC 33))] "TARGET_64BIT" "@ - ogr\\t%0,%2 - og\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + oihh\t%0,%i2 + oihl\t%0,%i2 + oilh\t%0,%i2 + oill\t%0,%i2 + ogr\t%0,%2 + og\t%0,%2" + [(set_attr "op_type" "RI,RI,RI,RI,RRE,RXY")]) (define_insn "*iordi3_ss" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4714,9 +5342,8 @@ (match_operand:DI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "oc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*iordi3_ss_inv" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4724,9 +5351,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "oc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; iorsi3 instruction pattern(s). @@ -4734,63 +5360,64 @@ (define_insn "*iorsi3_cc" [(set (reg 33) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (ior:SI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode)" "@ - or\\t%0,%2 - o\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + or\t%0,%2 + o\t%0,%2 + oy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*iorsi3_cconly" [(set (reg 33) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] + (clobber (match_scratch:SI 0 "=d,d,d"))] "s390_match_ccmode(insn, CCTmode)" "@ - or\\t%0,%2 - o\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + or\t%0,%2 + o\t%0,%2 + oy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) -(define_insn "*iorsi3_oi" - [(set (match_operand:SI 0 "register_operand" "=d") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "immediate_operand" "n"))) - (clobber (reg:CC 33))] - "TARGET_64BIT && s390_single_hi (operands[2], SImode, 0) >= 0" - "* -{ - int part = s390_single_hi (operands[2], SImode, 0); - operands[2] = GEN_INT (s390_extract_hi (operands[2], SImode, part)); +(define_expand "iorsi3" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 33))])] + "" + "") - switch (part) - { - case 0: return \"oilh\\t%0,%x2\"; - case 1: return \"oill\\t%0,%x2\"; - default: abort (); - } -}" - [(set_attr "op_type" "RI") - (set_attr "atype" "reg")]) +(define_insn "iorsi3_zarch" + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0,0,0,0,0") + (match_operand:SI 2 "general_operand" "N0HS0,N1HS0,d,R,T"))) + (clobber (reg:CC 33))] + "TARGET_ZARCH" + "@ + oilh\t%0,%i2 + oill\t%0,%i2 + or\t%0,%2 + o\t%0,%2 + oy\t%0,%2" + [(set_attr "op_type" "RI,RI,RR,RX,RXY")]) -(define_insn "iorsi3" +(define_insn "iorsi3_esa" [(set (match_operand:SI 0 "register_operand" "=d,d") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m"))) + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "d,R"))) (clobber (reg:CC 33))] - "" + "!TARGET_ZARCH" "@ - or\\t%0,%2 - o\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + or\t%0,%2 + o\t%0,%2" + [(set_attr "op_type" "RR,RX")]) (define_insn "*iorsi3_ss" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -4798,9 +5425,8 @@ (match_operand:SI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "oc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*iorsi3_ss_inv" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -4808,9 +5434,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "oc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; iorhi3 instruction pattern(s). @@ -4821,12 +5446,11 @@ (ior:HI (match_operand:HI 1 "register_operand" "%0,0") (match_operand:HI 2 "nonmemory_operand" "d,n"))) (clobber (reg:CC 33))] - "TARGET_64BIT" + "TARGET_ZARCH" "@ - or\\t%0,%2 - oill\\t%0,%x2" - [(set_attr "op_type" "RR,RI") - (set_attr "atype" "reg")]) + or\t%0,%2 + oill\t%0,%x2" + [(set_attr "op_type" "RR,RI")]) (define_insn "iorhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -4834,9 +5458,8 @@ (match_operand:HI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "or\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "or\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*iorhi3_ss" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -4844,9 +5467,8 @@ (match_operand:HI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "oc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*iorhi3_ss_inv" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -4854,9 +5476,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "oc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "oc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; iorqi3 instruction pattern(s). @@ -4867,12 +5488,11 @@ (ior:QI (match_operand:QI 1 "register_operand" "%0,0") (match_operand:QI 2 "nonmemory_operand" "d,n"))) (clobber (reg:CC 33))] - "TARGET_64BIT" + "TARGET_ZARCH" "@ - or\\t%0,%2 - oill\\t%0,%b2" - [(set_attr "op_type" "RR,RI") - (set_attr "atype" "reg")]) + or\t%0,%2 + oill\t%0,%b2" + [(set_attr "op_type" "RR,RI")]) (define_insn "iorqi3" [(set (match_operand:QI 0 "register_operand" "=d") @@ -4880,33 +5500,32 @@ (match_operand:QI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "or\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "or\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*iorqi3_ss" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") (ior:QI (match_dup 0) - (match_operand:QI 1 "s_imm_operand" "n,Q"))) + (match_operand:QI 1 "s_imm_operand" "n,n,Q"))) (clobber (reg:CC 33))] "" "@ - oi\\t%0,%b1 - oc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "reg,mem")]) + oi\t%0,%b1 + oiy\t%0,%b1 + oc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) (define_insn "*iorqi3_ss_inv" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") - (ior:QI (match_operand:QI 1 "s_imm_operand" "n,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") + (ior:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q") (match_dup 0))) (clobber (reg:CC 33))] "" "@ - oi\\t%0,%b1 - oc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "reg,mem")]) + oi\t%0,%b1 + oiy\t%0,%b1 + oc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) ;; @@ -4926,10 +5545,9 @@ (xor:DI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - xgr\\t%0,%2 - xg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + xgr\t%0,%2 + xg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*xordi3_cconly" [(set (reg 33) @@ -4939,10 +5557,9 @@ (clobber (match_scratch:DI 0 "=d,d"))] "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT" "@ - xgr\\t%0,%2 - xr\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + xgr\t%0,%2 + xr\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "xordi3" [(set (match_operand:DI 0 "register_operand" "=d,d") @@ -4951,10 +5568,9 @@ (clobber (reg:CC 33))] "TARGET_64BIT" "@ - xgr\\t%0,%2 - xg\\t%0,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "atype" "reg,mem")]) + xgr\t%0,%2 + xg\t%0,%2" + [(set_attr "op_type" "RRE,RXY")]) (define_insn "*xordi3_ss" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4962,9 +5578,8 @@ (match_operand:DI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "xc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*xordi3_ss_inv" [(set (match_operand:DI 0 "s_operand" "=Q") @@ -4972,9 +5587,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "xc\\t%O0(8,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(8,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; xorsi3 instruction pattern(s). @@ -4982,42 +5596,42 @@ (define_insn "*xorsi3_cc" [(set (reg 33) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d,d,d") (xor:SI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCTmode)" "@ - xr\\t%0,%2 - x\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + xr\t%0,%2 + x\t%0,%2 + xy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*xorsi3_cconly" [(set (reg 33) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m")) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] + (clobber (match_scratch:SI 0 "=d,d,d"))] "s390_match_ccmode(insn, CCTmode)" "@ - xr\\t%0,%2 - x\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + xr\t%0,%2 + x\t%0,%2 + xy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "xorsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "d,m"))) + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:SI 2 "general_operand" "d,R,T"))) (clobber (reg:CC 33))] "" "@ - xr\\t%0,%2 - x\\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "atype" "reg,mem")]) + xr\t%0,%2 + x\t%0,%2 + xy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY")]) (define_insn "*xorsi3_ss" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -5025,9 +5639,8 @@ (match_operand:SI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "xc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*xorsi3_ss_inv" [(set (match_operand:SI 0 "s_operand" "=Q") @@ -5035,9 +5648,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "xc\\t%O0(4,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(4,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; xorhi3 instruction pattern(s). @@ -5049,9 +5661,8 @@ (match_operand:HI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "xr\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "xr\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*xorhi3_ss" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -5059,9 +5670,8 @@ (match_operand:HI 1 "s_imm_operand" "Q"))) (clobber (reg:CC 33))] "" - "xc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) (define_insn "*xorhi3_ss_inv" [(set (match_operand:HI 0 "s_operand" "=Q") @@ -5069,9 +5679,8 @@ (match_dup 0))) (clobber (reg:CC 33))] "" - "xc\\t%O0(2,%R0),%1" - [(set_attr "op_type" "SS") - (set_attr "atype" "mem")]) + "xc\t%O0(2,%R0),%1" + [(set_attr "op_type" "SS")]) ; ; xorqi3 instruction pattern(s). @@ -5083,33 +5692,32 @@ (match_operand:QI 2 "nonmemory_operand" "d"))) (clobber (reg:CC 33))] "" - "xr\\t%0,%2" - [(set_attr "op_type" "RR") - (set_attr "atype" "reg")]) + "xr\t%0,%2" + [(set_attr "op_type" "RR")]) (define_insn "*xorqi3_ss" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") (xor:QI (match_dup 0) - (match_operand:QI 1 "s_imm_operand" "n,Q"))) + (match_operand:QI 1 "s_imm_operand" "n,n,Q"))) (clobber (reg:CC 33))] "" "@ - xi\\t%0,%b1 - xc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "mem")]) + xi\t%0,%b1 + xiy\t%0,%b1 + xc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) (define_insn "*xorqi3_ss_inv" - [(set (match_operand:QI 0 "s_operand" "=Q,Q") - (xor:QI (match_operand:QI 1 "s_imm_operand" "n,Q") + [(set (match_operand:QI 0 "s_operand" "=Q,S,Q") + (xor:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q") (match_dup 0))) (clobber (reg:CC 33))] "" "@ - xi\\t%0,%b1 - xc\\t%O0(1,%R0),%1" - [(set_attr "op_type" "SI,SS") - (set_attr "atype" "mem")]) + xi\t%0,%b1 + xiy\t%0,%b1 + xc\t%O0(1,%R0),%1" + [(set_attr "op_type" "SI,SIY,SS")]) ;; @@ -5133,7 +5741,7 @@ (neg:DI (match_operand:DI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_64BIT" - "lcgr\\t%0,%1" + "lcgr\t%0,%1" [(set_attr "op_type" "RR")]) (define_insn "*negdi2_31" @@ -5141,18 +5749,17 @@ (neg:DI (match_operand:DI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "!TARGET_64BIT" - "* { rtx xop[1]; xop[0] = gen_label_rtx (); - output_asm_insn (\"lcr\\t%0,%1\", operands); - output_asm_insn (\"lcr\\t%N0,%N1\", operands); - output_asm_insn (\"je\\t%l0\", xop); - output_asm_insn (\"bctr\\t%0,0\", operands); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + output_asm_insn ("lcr\t%0,%1", operands); + output_asm_insn ("lcr\t%N0,%N1", operands); + output_asm_insn ("je\t%l0", xop); + output_asm_insn ("bctr\t%0,0", operands); + targetm.asm_out.internal_label (asm_out_file, "L", CODE_LABEL_NUMBER (xop[0])); - return \"\"; -}" + return ""; +} [(set_attr "op_type" "NN") (set_attr "type" "other") (set_attr "length" "10")]) @@ -5166,7 +5773,7 @@ (neg:SI (match_operand:SI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "" - "lcr\\t%0,%1" + "lcr\t%0,%1" [(set_attr "op_type" "RR")]) ; @@ -5186,16 +5793,18 @@ (neg:DF (match_operand:DF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "lcdbr\\t%0,%1" - [(set_attr "op_type" "RRE")]) + "lcdbr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimpd")]) (define_insn "*negdf2_ibm" [(set (match_operand:DF 0 "register_operand" "=f") (neg:DF (match_operand:DF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "lcdr\\t%0,%1" - [(set_attr "op_type" "RR")]) + "lcdr\t%0,%1" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimpd")]) ; ; negsf2 instruction pattern(s). @@ -5214,16 +5823,18 @@ (neg:SF (match_operand:SF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "lcebr\\t%0,%1" - [(set_attr "op_type" "RRE")]) + "lcebr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimps")]) (define_insn "*negsf2" [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "lcer\\t%0,%1" - [(set_attr "op_type" "RR")]) + "lcer\t%0,%1" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimps")]) ;; @@ -5239,7 +5850,7 @@ (abs:DI (match_operand:DI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "TARGET_64BIT" - "lpgr\\t%0,%1" + "lpgr\t%0,%1" [(set_attr "op_type" "RRE")]) ; @@ -5251,7 +5862,7 @@ (abs:SI (match_operand:SI 1 "register_operand" "d"))) (clobber (reg:CC 33))] "" - "lpr\\t%0,%1" + "lpr\t%0,%1" [(set_attr "op_type" "RR")]) ; @@ -5271,16 +5882,18 @@ (abs:DF (match_operand:DF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "lpdbr\\t%0,%1" - [(set_attr "op_type" "RRE")]) + "lpdbr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimpd")]) (define_insn "*absdf2_ibm" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "lpdr\\t%0,%1" - [(set_attr "op_type" "RR")]) + "lpdr\t%0,%1" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimpd")]) ; ; abssf2 instruction pattern(s). @@ -5299,16 +5912,64 @@ (abs:SF (match_operand:SF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" - "lpebr\\t%0,%1" - [(set_attr "op_type" "RRE")]) + "lpebr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimps")]) (define_insn "*abssf2_ibm" [(set (match_operand:SF 0 "register_operand" "=f") (abs:SF (match_operand:SF 1 "register_operand" "f"))) (clobber (reg:CC 33))] "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT" - "lper\\t%0,%1" - [(set_attr "op_type" "RR")]) + "lper\t%0,%1" + [(set_attr "op_type" "RR") + (set_attr "type" "fsimps")]) + +;; +;;- Negated absolute value instructions +;; + +; +; Integer +; + +(define_insn "*negabssi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (neg:SI (abs:SI (match_operand:SI 1 "register_operand" "d")))) + (clobber (reg:CC 33))] + "" + "lnr\t%0,%1" + [(set_attr "op_type" "RR")]) + +(define_insn "*negabsdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (neg:DI (abs:DI (match_operand:DI 1 "register_operand" "d")))) + (clobber (reg:CC 33))] + "TARGET_64BIT" + "lngr\t%0,%1" + [(set_attr "op_type" "RRE")]) + +; +; Floating point +; + +(define_insn "*negabssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (abs:SF (match_operand:SF 1 "register_operand" "f")))) + (clobber (reg:CC 33))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "lnebr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimps")]) + +(define_insn "*negabsdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (abs:DF (match_operand:DF 1 "register_operand" "f")))) + (clobber (reg:CC 33))] + "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" + "lndbr\t%0,%1" + [(set_attr "op_type" "RRE") + (set_attr "type" "fsimpd")]) ;; ;;- Square root instructions. @@ -5320,12 +5981,12 @@ (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f,f") - (sqrt:DF (match_operand:DF 1 "general_operand" "f,m")))] + (sqrt:DF (match_operand:DF 1 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - sqdbr\\t%0,%1 - sqdb\\t%0,%1" - [(set_attr "op_type" "RRE,RSE")]) + sqdbr\t%0,%1 + sqdb\t%0,%1" + [(set_attr "op_type" "RRE,RXE")]) ; ; sqrtsf2 instruction pattern(s). @@ -5333,12 +5994,12 @@ (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f,f") - (sqrt:SF (match_operand:SF 1 "general_operand" "f,m")))] + (sqrt:SF (match_operand:SF 1 "general_operand" "f,R")))] "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT" "@ - sqebr\\t%0,%1 - sqeb\\t%0,%1" - [(set_attr "op_type" "RRE,RSE")]) + sqebr\t%0,%1 + sqeb\t%0,%1" + [(set_attr "op_type" "RRE,RXE")]) ;; ;;- One complement instructions. @@ -5347,7 +6008,7 @@ ; ; one_cmpldi2 instruction pattern(s). ; - + (define_expand "one_cmpldi2" [(parallel [(set (match_operand:DI 0 "register_operand" "") @@ -5356,11 +6017,11 @@ (clobber (reg:CC 33))])] "TARGET_64BIT" "") - + ; ; one_cmplsi2 instruction pattern(s). ; - + (define_expand "one_cmplsi2" [(parallel [(set (match_operand:SI 0 "register_operand" "") @@ -5369,11 +6030,11 @@ (clobber (reg:CC 33))])] "" "") - + ; ; one_cmplhi2 instruction pattern(s). ; - + (define_expand "one_cmplhi2" [(parallel [(set (match_operand:HI 0 "register_operand" "") @@ -5382,11 +6043,11 @@ (clobber (reg:CC 33))])] "" "") - + ; ; one_cmplqi2 instruction pattern(s). ; - + (define_expand "one_cmplqi2" [(parallel [(set (match_operand:QI 0 "register_operand" "") @@ -5406,28 +6067,26 @@ ; (define_insn "rotldi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (rotate:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:DI 0 "register_operand" "=d") + (rotate:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")))] "TARGET_64BIT" - "@ - rllg\\t%0,%1,%c2 - rllg\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + "rllg\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) ; ; rotlsi3 instruction pattern(s). ; (define_insn "rotlsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (rotate:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] - "TARGET_64BIT" - "@ - rll\\t%0,%1,%c2 - rll\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + [(set (match_operand:SI 0 "register_operand" "=d") + (rotate:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")))] + "TARGET_CPU_ZARCH" + "rll\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) ;; @@ -5441,29 +6100,27 @@ (define_expand "ashldi3" [(set (match_operand:DI 0 "register_operand" "") (ashift:DI (match_operand:DI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] + (match_operand:SI 2 "shift_count_operand" "")))] "" "") (define_insn "*ashldi3_31" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashift:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:DI 0 "register_operand" "=d") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")))] "!TARGET_64BIT" - "@ - sldl\\t%0,%c2 - sldl\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "sldl\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "*ashldi3_64" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashift:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:DI 0 "register_operand" "=d") + (ashift:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")))] "TARGET_64BIT" - "@ - sllg\\t%0,%1,%2 - sllg\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + "sllg\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) ; ; ashrdi3 instruction pattern(s). @@ -5473,96 +6130,90 @@ [(parallel [(set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" ""))) + (match_operand:SI 2 "shift_count_operand" ""))) (clobber (reg:CC 33))])] "" "") (define_insn "*ashrdi3_cc_31" [(set (reg 33) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d") + (set (match_operand:DI 0 "register_operand" "=d") (ashiftrt:DI (match_dup 1) (match_dup 2)))] "!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)" - "@ - srda\\t%0,%c2 - srda\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "srda\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "*ashrdi3_cconly_31" [(set (reg 33) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d"))] + (clobber (match_scratch:DI 0 "=d"))] "!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)" - "@ - srda\\t%0,%c2 - srda\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "srda\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "*ashrdi3_31" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a"))) + [(set (match_operand:DI 0 "register_operand" "=d") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y"))) (clobber (reg:CC 33))] "!TARGET_64BIT" - "@ - srda\\t%0,%c2 - srda\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "srda\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "*ashrdi3_cc_64" [(set (reg 33) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d") + (set (match_operand:DI 0 "register_operand" "=d") (ashiftrt:DI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "@ - srag\\t%0,%1,%c2 - srag\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + "srag\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) (define_insn "*ashrdi3_cconly_64" [(set (reg 33) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d"))] + (clobber (match_scratch:DI 0 "=d"))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "@ - srag\\t%0,%1,%c2 - srag\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + "srag\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) (define_insn "*ashrdi3_64" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a"))) + [(set (match_operand:DI 0 "register_operand" "=d") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y"))) (clobber (reg:CC 33))] "TARGET_64BIT" - "@ - srag\\t%0,%1,%c2 - srag\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE")]) + "srag\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) + ; ; ashlsi3 instruction pattern(s). ; (define_insn "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (ashift:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")))] "" - "@ - sll\\t%0,%c2 - sll\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "sll\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) ; ; ashrsi3 instruction pattern(s). @@ -5570,39 +6221,37 @@ (define_insn "*ashrsi3_cc" [(set (reg 33) - (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d") + (set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_dup 1) (match_dup 2)))] "s390_match_ccmode(insn, CCSmode)" - "@ - sra\\t%0,%c2 - sra\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "sra\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) + (define_insn "*ashrsi3_cconly" [(set (reg 33) - (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")) + (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")) (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d"))] + (clobber (match_scratch:SI 0 "=d"))] "s390_match_ccmode(insn, CCSmode)" - "@ - sra\\t%0,%c2 - sra\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "sra\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a"))) + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y"))) (clobber (reg:CC 33))] "" - "@ - sra\\t%0,%c2 - sra\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "sra\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) ;; @@ -5616,43 +6265,40 @@ (define_expand "lshrdi3" [(set (match_operand:DI 0 "register_operand" "") (lshiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] + (match_operand:SI 2 "shift_count_operand" "")))] "" "") (define_insn "*lshrdi3_31" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:DI 0 "register_operand" "=d") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")))] "!TARGET_64BIT" - "@ - srdl\\t%0,%c2 - srdl\\t%0,0(%2)" - [(set_attr "op_type" "RS,RS")]) + "srdl\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) (define_insn "*lshrdi3_64" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "d,d") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:DI 0 "register_operand" "=d") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "shift_count_operand" "Y")))] "TARGET_64BIT" - "@ - srlg\\t%0,%1,%c2 - srlg\\t%0,%1,0(%2)" - [(set_attr "op_type" "RSE,RSE")]) + "srlg\t%0,%1,%Y2" + [(set_attr "op_type" "RSE") + (set_attr "atype" "reg")]) ; ; lshrsi3 instruction pattern(s). ; (define_insn "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:SI 2 "nonmemory_operand" "J,a")))] + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "shift_count_operand" "Y")))] "" - "@ - srl\\t%0,%c2 - srl\\t%0,0(%2)" - [(set_attr "op_type" "RS")]) + "srl\t%0,%Y2" + [(set_attr "op_type" "RS") + (set_attr "atype" "reg")]) ;; @@ -5666,7 +6312,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bne" [(set (reg:CCZ 33) (compare:CCZ (match_dup 1) (match_dup 2))) @@ -5675,7 +6321,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bgt" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5684,7 +6330,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bgtu" [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2))) @@ -5693,7 +6339,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "blt" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5702,7 +6348,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bltu" [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2))) @@ -5711,7 +6357,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bge" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5720,7 +6366,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bgeu" [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2))) @@ -5729,7 +6375,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "ble" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5738,7 +6384,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bleu" [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2))) @@ -5747,7 +6393,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bunordered" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5756,7 +6402,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bordered" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5765,7 +6411,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "buneq" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5774,7 +6420,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bungt" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5783,7 +6429,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bunlt" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5792,7 +6438,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bunge" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5801,7 +6447,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bunle" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5810,7 +6456,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") (define_expand "bltgt" [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2))) @@ -5819,7 +6465,7 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }") + "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;") ;; @@ -5828,25 +6474,25 @@ (define_insn "cjump" [(set (pc) - (if_then_else + (if_then_else (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" - "* { if (get_attr_length (insn) == 4) - return \"j%C1\\t%l0\"; - else if (TARGET_64BIT) - return \"jg%C1\\t%l0\"; + return "j%C1\t%l0"; + else if (TARGET_CPU_ZARCH) + return "jg%C1\t%l0"; else abort (); -}" +} [(set_attr "op_type" "RI") + (set_attr "type" "branch") (set (attr "length") (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) (const_int 4) - (ne (symbol_ref "TARGET_64BIT") (const_int 0)) + (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0)) (const_int 6) (eq (symbol_ref "flag_pic") (const_int 0)) (const_int 6)] (const_int 8)))]) @@ -5855,20 +6501,20 @@ [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)]) - (match_operand 0 "address_operand" "p") + (match_operand 0 "address_operand" "U") (pc)))] "" - "* { if (get_attr_op_type (insn) == OP_TYPE_RR) - return \"b%C1r\\t%0\"; + return "b%C1r\t%0"; else - return \"b%C1\\t%a0\"; -}" - [(set (attr "op_type") + return "b%C1\t%a0"; +} + [(set (attr "op_type") (if_then_else (match_operand 0 "register_operand" "") (const_string "RR") (const_string "RX"))) - (set_attr "atype" "mem")]) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) ;; @@ -5879,23 +6525,23 @@ [(set (pc) (if_then_else (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)]) - (pc) + (pc) (label_ref (match_operand 0 "" ""))))] "" - "* -{ +{ if (get_attr_length (insn) == 4) - return \"j%D1\\t%l0\"; - else if (TARGET_64BIT) - return \"jg%D1\\t%l0\"; + return "j%D1\t%l0"; + else if (TARGET_CPU_ZARCH) + return "jg%D1\t%l0"; else abort (); -}" +} [(set_attr "op_type" "RI") + (set_attr "type" "branch") (set (attr "length") (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) (const_int 4) - (ne (symbol_ref "TARGET_64BIT") (const_int 0)) + (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0)) (const_int 6) (eq (symbol_ref "flag_pic") (const_int 0)) (const_int 6)] (const_int 8)))]) @@ -5905,19 +6551,19 @@ (if_then_else (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)]) (pc) - (match_operand 0 "address_operand" "p")))] + (match_operand 0 "address_operand" "U")))] "" - "* { if (get_attr_op_type (insn) == OP_TYPE_RR) - return \"b%D1r\\t%0\"; + return "b%D1r\t%0"; else - return \"b%D1\\t%a0\"; -}" - [(set (attr "op_type") + return "b%D1\t%a0"; +} + [(set (attr "op_type") (if_then_else (match_operand 0 "register_operand" "") (const_string "RR") (const_string "RX"))) - (set_attr "atype" "mem")]) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) ;; ;;- Trap instructions. @@ -5926,8 +6572,9 @@ (define_insn "trap" [(trap_if (const_int 1) (const_int 0))] "" - "j\\t.+2" - [(set_attr "op_type" "RX")]) + "j\t.+2" + [(set_attr "op_type" "RX") + (set_attr "type" "branch")]) (define_expand "conditional_trap" [(set (match_dup 2) (match_dup 3)) @@ -5935,31 +6582,31 @@ [(match_dup 2) (const_int 0)]) (match_operand:SI 1 "general_operand" ""))] "" - " { enum machine_mode ccmode; - if (operands[1] != const0_rtx) FAIL; + if (operands[1] != const0_rtx) FAIL; - ccmode = s390_select_ccmode (GET_CODE (operands[0]), - s390_compare_op0, s390_compare_op1); + ccmode = s390_select_ccmode (GET_CODE (operands[0]), + s390_compare_op0, s390_compare_op1); operands[2] = gen_rtx_REG (ccmode, 33); operands[3] = gen_rtx_COMPARE (ccmode, s390_compare_op0, s390_compare_op1); -}") +}) (define_insn "*trap" [(trap_if (match_operator 0 "comparison_operator" [(reg 33) (const_int 0)]) (const_int 0))] "" - "j%C0\\t.+2"; - [(set_attr "op_type" "RX")]) + "j%C0\t.+2"; + [(set_attr "op_type" "RI") + (set_attr "type" "branch")]) ;; ;;- Loop instructions. ;; ;; This is all complicated by the fact that since this is a jump insn ;; we must handle our own output reloads. - + (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo (use (match_operand 1 "" "")) ; iterations; zero if unknown @@ -5967,7 +6614,6 @@ (use (match_operand 3 "" "")) ; loop level (use (match_operand 4 "" ""))] ; label "" - " { if (GET_MODE (operands[0]) == SImode) emit_jump_insn (gen_doloop_si (operands[4], operands[0], operands[0])); @@ -5977,7 +6623,7 @@ FAIL; DONE; -}") +}) (define_insn "doloop_si" [(set (pc) @@ -5991,20 +6637,22 @@ (clobber (match_scratch:SI 3 "=X,&d")) (clobber (reg:CC 33))] "" - "* { if (which_alternative != 0) - return \"#\"; + return "#"; else if (get_attr_length (insn) == 4) - return \"brct\\t%1,%l0\"; + return "brct\t%1,%l0"; + else if (TARGET_CPU_ZARCH) + return "ahi\t%1,-1\;jgne\t%l0"; else abort (); -}" +} [(set_attr "op_type" "RI") + (set_attr "type" "branch") (set (attr "length") (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) (const_int 4) - (ne (symbol_ref "TARGET_64BIT") (const_int 0)) + (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0)) (const_int 10) (eq (symbol_ref "flag_pic") (const_int 0)) (const_int 6)] (const_int 8)))]) @@ -6014,24 +6662,24 @@ (if_then_else (ne (match_operand:SI 1 "register_operand" "d,d") (const_int 1)) - (match_operand 0 "address_operand" "p,p") + (match_operand 0 "address_operand" "U,U") (pc))) (set (match_operand:SI 2 "register_operand" "=1,?*m*d") (plus:SI (match_dup 1) (const_int -1))) (clobber (match_scratch:SI 3 "=X,&d")) (clobber (reg:CC 33))] "" - "* { if (get_attr_op_type (insn) == OP_TYPE_RR) - return \"bctr\\t%1,%0\"; + return "bctr\t%1,%0"; else - return \"bct\\t%1,%a0\"; -}" - [(set (attr "op_type") + return "bct\t%1,%a0"; +} + [(set (attr "op_type") (if_then_else (match_operand 0 "register_operand" "") (const_string "RR") (const_string "RX"))) - (set_attr "atype" "mem")]) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) (define_split [(set (pc) @@ -6069,43 +6717,19 @@ (clobber (match_scratch:DI 3 "=X,&d")) (clobber (reg:CC 33))] "TARGET_64BIT" - "* { if (which_alternative != 0) - return \"#\"; + return "#"; else if (get_attr_length (insn) == 4) - return \"brctg\\t%1,%l0\"; + return "brctg\t%1,%l0"; else - abort (); -}" + return "aghi\t%1,-1\;jgne\t%l0"; +} [(set_attr "op_type" "RI") + (set_attr "type" "branch") (set (attr "length") (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 12)))]) - -(define_insn "*doloop_di_long" - [(set (pc) - (if_then_else - (ne (match_operand:DI 1 "register_operand" "d,d") - (const_int 1)) - (match_operand 0 "address_operand" "p,p") - (pc))) - (set (match_operand:DI 2 "register_operand" "=1,?*m*d") - (plus:DI (match_dup 1) (const_int -1))) - (clobber (match_scratch:DI 3 "=X,&d")) - (clobber (reg:CC 33))] - "" - "* -{ - if (get_attr_op_type (insn) == OP_TYPE_RRE) - return \"bctgr\\t%1,%0\"; - else - return \"bctg\\t%1,%a0\"; -}" - [(set (attr "op_type") - (if_then_else (match_operand 0 "register_operand" "") - (const_string "RRE") (const_string "RXE"))) - (set_attr "atype" "mem")]) + (const_int 4) (const_int 10)))]) (define_split [(set (pc) @@ -6142,20 +6766,20 @@ (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" - "* { if (get_attr_length (insn) == 4) - return \"j\\t%l0\"; - else if (TARGET_64BIT) - return \"jg\\t%l0\"; + return "j\t%l0"; + else if (TARGET_CPU_ZARCH) + return "jg\t%l0"; else abort (); -}" +} [(set_attr "op_type" "RI") + (set_attr "type" "branch") (set (attr "length") (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) (const_int 4) - (ne (symbol_ref "TARGET_64BIT") (const_int 0)) + (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0)) (const_int 6) (eq (symbol_ref "flag_pic") (const_int 0)) (const_int 6)] (const_int 8)))]) @@ -6165,39 +6789,39 @@ ; (define_insn "indirect_jump" - [(set (pc) (match_operand 0 "address_operand" "p"))] + [(set (pc) (match_operand 0 "address_operand" "U"))] "" - "* { if (get_attr_op_type (insn) == OP_TYPE_RR) - return \"br\\t%0\"; + return "br\t%0"; else - return \"b\\t%a0\"; -}" - [(set (attr "op_type") + return "b\t%a0"; +} + [(set (attr "op_type") (if_then_else (match_operand 0 "register_operand" "") (const_string "RR") (const_string "RX"))) - (set_attr "atype" "mem")]) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) ; ; casesi instruction pattern(s). ; (define_insn "casesi_jump" - [(set (pc) (match_operand 0 "address_operand" "p")) + [(set (pc) (match_operand 0 "address_operand" "U")) (use (label_ref (match_operand 1 "" "")))] "" - "* { if (get_attr_op_type (insn) == OP_TYPE_RR) - return \"br\\t%0\"; + return "br\t%0"; else - return \"b\\t%a0\"; -}" - [(set (attr "op_type") + return "b\t%a0"; +} + [(set (attr "op_type") (if_then_else (match_operand 0 "register_operand" "") (const_string "RR") (const_string "RX"))) - (set_attr "atype" "mem")]) + (set_attr "type" "branch") + (set_attr "atype" "agen")]) (define_expand "casesi" [(match_operand:SI 0 "general_operand" "") @@ -6206,7 +6830,6 @@ (label_ref (match_operand 3 "" "")) (label_ref (match_operand 4 "" ""))] "" - " { rtx index = gen_reg_rtx (SImode); rtx base = gen_reg_rtx (Pmode); @@ -6237,7 +6860,7 @@ emit_jump_insn (gen_casesi_jump (target, operands[3])); DONE; -}") +}) ;; @@ -6256,7 +6879,6 @@ (match_operand 1 "" "") (match_operand 2 "" "")])] "" - " { int i; @@ -6275,13 +6897,13 @@ emit_insn (gen_blockage ()); DONE; -}") +}) ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and ;; all of memory. This blocks insns from being moved across this point. (define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] "" "" [(set_attr "type" "none") @@ -6298,9 +6920,8 @@ (match_operand 1 "" "")) (use (match_operand 2 "" ""))] "" - " { - int plt_call = 0; + bool plt_call = false; rtx insn; /* Direct function calls need special treatment. */ @@ -6310,22 +6931,22 @@ /* When calling a global routine in PIC mode, we must replace the symbol itself with the PLT stub. */ - if (flag_pic && !SYMBOL_REF_FLAG (sym)) + if (flag_pic && !SYMBOL_REF_LOCAL_P (sym)) { - sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113); + sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT); sym = gen_rtx_CONST (Pmode, sym); - - plt_call = 1; + plt_call = true; } - /* Unless we can use the bras(l) insn, force the + /* Unless we can use the bras(l) insn, force the routine address into a register. */ - if (!TARGET_SMALL_EXEC && !TARGET_64BIT) - { - rtx target = gen_reg_rtx (Pmode); - emit_move_insn (target, sym); - sym = target; - } + if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH) + { + if (flag_pic) + sym = legitimize_pic_address (sym, 0); + else + sym = force_reg (Pmode, sym); + } operands[0] = gen_rtx_MEM (QImode, sym); } @@ -6334,14 +6955,12 @@ insn = emit_call_insn (gen_call_exp (operands[0], operands[1], gen_rtx_REG (Pmode, RETURN_REGNUM))); - /* In 31-bit, we must load the GOT register even if the - compiler doesn't know about it, because the PLT glue - code uses it. In 64-bit, this is not necessary. */ - if (plt_call && !TARGET_64BIT) + /* 31-bit PLT stubs use the GOT register implicitly. */ + if (!TARGET_64BIT && plt_call) use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); - + DONE; -}") +}) (define_expand "call_exp" [(parallel [(call (match_operand 0 "" "") @@ -6350,64 +6969,40 @@ "" "") -(define_insn "brasl" - [(call (mem:QI (match_operand:DI 0 "bras_sym_operand" "X")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:DI 2 "register_operand" "=r"))] - "TARGET_64BIT" - "brasl\\t%2,%0" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr")]) - -(define_insn "bras" - [(call (mem:QI (match_operand:SI 0 "bras_sym_operand" "X")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:SI 2 "register_operand" "=r"))] - "TARGET_SMALL_EXEC" - "bras\\t%2,%0" +(define_insn "*bras" + [(call (mem:QI (match_operand 0 "bras_sym_operand" "X")) + (match_operand 1 "const_int_operand" "n")) + (clobber (match_operand 2 "register_operand" "=r"))] + "TARGET_SMALL_EXEC && GET_MODE (operands[2]) == Pmode" + "bras\t%2,%0" [(set_attr "op_type" "RI") (set_attr "type" "jsr")]) -(define_insn "basr_64" - [(call (mem:QI (match_operand:DI 0 "register_operand" "a")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:DI 2 "register_operand" "=r"))] - "TARGET_64BIT" - "basr\\t%2,%0" - [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "basr_31" - [(call (mem:QI (match_operand:SI 0 "register_operand" "a")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:SI 2 "register_operand" "=r"))] - "!TARGET_64BIT" - "basr\\t%2,%0" - [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_64" - [(call (mem:QI (match_operand:QI 0 "address_operand" "p")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:DI 2 "register_operand" "=r"))] - "TARGET_64BIT" - "bas\\t%2,%a0" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_31" - [(call (mem:QI (match_operand:QI 0 "address_operand" "p")) - (match_operand:SI 1 "const_int_operand" "n")) - (clobber (match_operand:SI 2 "register_operand" "=r"))] - "!TARGET_64BIT" - "bas\\t%2,%a0" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) +(define_insn "*brasl" + [(call (mem:QI (match_operand 0 "bras_sym_operand" "X")) + (match_operand 1 "const_int_operand" "n")) + (clobber (match_operand 2 "register_operand" "=r"))] + "TARGET_CPU_ZARCH && GET_MODE (operands[2]) == Pmode" + "brasl\t%2,%0" + [(set_attr "op_type" "RIL") + (set_attr "type" "jsr")]) +(define_insn "*basr" + [(call (mem:QI (match_operand 0 "address_operand" "U")) + (match_operand 1 "const_int_operand" "n")) + (clobber (match_operand 2 "register_operand" "=r"))] + "GET_MODE (operands[2]) == Pmode" +{ + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "basr\t%2,%0"; + else + return "bas\t%2,%a0"; +} + [(set (attr "op_type") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "RR") (const_string "RX"))) + (set_attr "type" "jsr") + (set_attr "atype" "agen")]) ; ; call_value instruction pattern(s). @@ -6419,9 +7014,8 @@ (match_operand 2 "" ""))) (use (match_operand 3 "" ""))] "" - " { - int plt_call = 0; + bool plt_call = false; rtx insn; /* Direct function calls need special treatment. */ @@ -6431,21 +7025,21 @@ /* When calling a global routine in PIC mode, we must replace the symbol itself with the PLT stub. */ - if (flag_pic && !SYMBOL_REF_FLAG (sym)) + if (flag_pic && !SYMBOL_REF_LOCAL_P (sym)) { - sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113); + sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT); sym = gen_rtx_CONST (Pmode, sym); - - plt_call = 1; + plt_call = true; } - /* Unless we can use the bras(l) insn, force the + /* Unless we can use the bras(l) insn, force the routine address into a register. */ - if (!TARGET_SMALL_EXEC && !TARGET_64BIT) + if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH) { - rtx target = gen_reg_rtx (Pmode); - emit_move_insn (target, sym); - sym = target; + if (flag_pic) + sym = legitimize_pic_address (sym, 0); + else + sym = force_reg (Pmode, sym); } operands[1] = gen_rtx_MEM (QImode, sym); @@ -6456,14 +7050,12 @@ gen_call_value_exp (operands[0], operands[1], operands[2], gen_rtx_REG (Pmode, RETURN_REGNUM))); - /* In 31-bit, we must load the GOT register even if the - compiler doesn't know about it, because the PLT glue - code uses it. In 64-bit, this is not necessary. */ - if (plt_call && !TARGET_64BIT) + /* 31-bit PLT stubs use the GOT register implicitly. */ + if (!TARGET_64BIT && plt_call) use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); - + DONE; -}") +}) (define_expand "call_value_exp" [(parallel [(set (match_operand 0 "" "") @@ -6473,68 +7065,43 @@ "" "") -(define_insn "brasl_r" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:DI 1 "bras_sym_operand" "X")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r"))] - "TARGET_64BIT" - "brasl\\t%3,%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr")]) - -(define_insn "bras_r" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:SI 1 "bras_sym_operand" "X")) +(define_insn "*bras_r" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r"))] - "TARGET_SMALL_EXEC" - "bras\\t%3,%1" + (clobber (match_operand 3 "register_operand" "=r"))] + "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode" + "bras\t%3,%1" [(set_attr "op_type" "RI") (set_attr "type" "jsr")]) -(define_insn "basr_r_64" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:DI 1 "register_operand" "a")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r"))] - "TARGET_64BIT" - "basr\\t%3,%1" - [(set_attr "op_type" "RR") +(define_insn "*brasl_r" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r"))] + "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode" + "brasl\t%3,%1" + [(set_attr "op_type" "RIL") (set_attr "type" "jsr")]) -(define_insn "basr_r_31" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:SI 1 "register_operand" "a")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r"))] - "!TARGET_64BIT" - "basr\\t%3,%1" - [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_r_64" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:QI 1 "address_operand" "p")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r"))] - "TARGET_64BIT" - "bas\\t%3,%a1" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_r_31" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:QI 1 "address_operand" "p")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r"))] - "!TARGET_64BIT" - "bas\\t%3,%a1" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) +(define_insn "*basr_r" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "address_operand" "U")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r"))] + "GET_MODE (operands[3]) == Pmode" +{ + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "basr\t%3,%1"; + else + return "bas\t%3,%a1"; +} + [(set (attr "op_type") + (if_then_else (match_operand 1 "register_operand" "") + (const_string "RR") (const_string "RX"))) + (set_attr "type" "jsr") + (set_attr "atype" "agen")]) ;; ;;- Thread-local storage support. @@ -6545,10 +7112,10 @@ (unspec:DI [(const_int 0)] UNSPEC_TP))] "TARGET_64BIT" "@ - ear\\t%0,%%a0\;sllg\\t%0,%0,32\;ear\\t%0,%%a1 - stam\\t%%a0,%%a1,%0" + ear\t%0,%%a0\;sllg\t%0,%0,32\;ear\t%0,%%a1 + stam\t%%a0,%%a1,%0" [(set_attr "op_type" "NN,RS") - (set_attr "atype" "reg,mem") + (set_attr "atype" "reg,*") (set_attr "type" "o3,*") (set_attr "length" "14,*")]) @@ -6557,20 +7124,19 @@ (unspec:SI [(const_int 0)] UNSPEC_TP))] "!TARGET_64BIT" "@ - ear\\t%0,%%a0 - stam\\t%%a0,%%a0,%0" - [(set_attr "op_type" "RRE,RS") - (set_attr "atype" "reg,mem")]) + ear\t%0,%%a0 + stam\t%%a0,%%a0,%0" + [(set_attr "op_type" "RRE,RS")]) (define_insn "set_tp_64" [(unspec_volatile [(match_operand:DI 0 "general_operand" "??d,Q")] UNSPECV_SET_TP) (clobber (match_scratch:SI 1 "=d,X"))] "TARGET_64BIT" "@ - sar\\t%%a1,%0\;srlg\\t%1,%0,32\;sar\\t%%a0,%1 - lam\\t%%a0,%%a1,%0" + sar\t%%a1,%0\;srlg\t%1,%0,32\;sar\t%%a0,%1 + lam\t%%a0,%%a1,%0" [(set_attr "op_type" "NN,RS") - (set_attr "atype" "reg,mem") + (set_attr "atype" "reg,*") (set_attr "type" "o3,*") (set_attr "length" "14,*")]) @@ -6578,37 +7144,35 @@ [(unspec_volatile [(match_operand:SI 0 "general_operand" "d,Q")] UNSPECV_SET_TP)] "!TARGET_64BIT" "@ - sar\\t%%a0,%0 - lam\\t%%a0,%%a0,%0" - [(set_attr "op_type" "RRE,RS") - (set_attr "atype" "reg,mem")]) - + sar\t%%a0,%0 + lam\t%%a0,%%a0,%0" + [(set_attr "op_type" "RRE,RS")]) + (define_insn "*tls_load_64" [(set (match_operand:DI 0 "register_operand" "=d") (unspec:DI [(match_operand:DI 1 "memory_operand" "m") (match_operand:DI 2 "" "")] UNSPEC_TLS_LOAD))] "TARGET_64BIT" - "lg\\t%0,%1%J2" - [(set_attr "op_type" "RXE") - (set_attr "atype" "mem")]) + "lg\t%0,%1%J2" + [(set_attr "op_type" "RXE")]) (define_insn "*tls_load_31" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:SI 1 "memory_operand" "m") + [(set (match_operand:SI 0 "register_operand" "=d,d") + (unspec:SI [(match_operand:SI 1 "memory_operand" "R,T") (match_operand:SI 2 "" "")] UNSPEC_TLS_LOAD))] "!TARGET_64BIT" - "l\\t%0,%1%J2" - [(set_attr "op_type" "RX") - (set_attr "atype" "mem")]) + "@ + l\t%0,%1%J2 + ly\t%0,%1%J2" + [(set_attr "op_type" "RX,RXY")]) (define_expand "call_value_tls" [(set (match_operand 0 "" "") (call (const_int 0) (const_int 0))) (use (match_operand 1 "" ""))] "" - " { rtx insn, sym; @@ -6616,16 +7180,17 @@ abort (); sym = s390_tls_get_offset (); - sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), 113); + sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT); sym = gen_rtx_CONST (Pmode, sym); - /* Unless we can use the bras(l) insn, force the + /* Unless we can use the bras(l) insn, force the routine address into a register. */ - if (!TARGET_SMALL_EXEC && !TARGET_64BIT) + if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH) { - rtx target = gen_reg_rtx (Pmode); - emit_move_insn (target, sym); - sym = target; + if (flag_pic) + sym = legitimize_pic_address (sym, 0); + else + sym = force_reg (Pmode, sym); } sym = gen_rtx_MEM (QImode, sym); @@ -6643,7 +7208,7 @@ CONST_OR_PURE_CALL_P (insn) = 1; DONE; -}") +}) (define_expand "call_value_tls_exp" [(parallel [(set (match_operand 0 "" "") @@ -6654,74 +7219,46 @@ "" "") -(define_insn "brasl_tls" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:DI 1 "bras_sym_operand" "X")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r")) - (use (match_operand:DI 4 "" ""))] - "TARGET_64BIT" - "brasl\\t%3,%1%J4" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr")]) - -(define_insn "bras_tls" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:SI 1 "bras_sym_operand" "X")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r")) - (use (match_operand:SI 4 "" ""))] - "TARGET_SMALL_EXEC" - "bras\\t%3,%1%J4" +(define_insn "*bras_tls" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r")) + (use (match_operand 4 "" ""))] + "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode" + "bras\t%3,%1%J4" [(set_attr "op_type" "RI") (set_attr "type" "jsr")]) -(define_insn "basr_tls_64" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:DI 1 "register_operand" "a")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r")) - (use (match_operand:DI 4 "" ""))] - "TARGET_64BIT" - "basr\\t%3,%1%J4" - [(set_attr "op_type" "RR") +(define_insn "*brasl_tls" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r")) + (use (match_operand 4 "" ""))] + "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode" + "brasl\t%3,%1%J4" + [(set_attr "op_type" "RIL") (set_attr "type" "jsr")]) -(define_insn "basr_tls_31" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:SI 1 "register_operand" "a")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r")) - (use (match_operand:SI 4 "" ""))] - "!TARGET_64BIT" - "basr\\t%3,%1%J4" - [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_tls_64" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:QI 1 "address_operand" "p")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:DI 3 "register_operand" "=r")) - (use (match_operand:DI 4 "" ""))] - "TARGET_64BIT" - "bas\\t%3,%a1%J4" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) - -(define_insn "bas_tls_31" - [(set (match_operand 0 "register_operand" "=df") - (call (mem:QI (match_operand:QI 1 "address_operand" "p")) - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_operand:SI 3 "register_operand" "=r")) - (use (match_operand:SI 4 "" ""))] - "!TARGET_64BIT" - "bas\\t%3,%a1%J4" - [(set_attr "op_type" "RX") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) +(define_insn "*basr_tls" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand 1 "address_operand" "U")) + (match_operand 2 "const_int_operand" "n"))) + (clobber (match_operand 3 "register_operand" "=r")) + (use (match_operand 4 "" ""))] + "GET_MODE (operands[3]) == Pmode" +{ + if (get_attr_op_type (insn) == OP_TYPE_RR) + return "basr\t%3,%1%J4"; + else + return "bas\t%3,%a1%J4"; +} + [(set (attr "op_type") + (if_then_else (match_operand 1 "register_operand" "") + (const_string "RR") (const_string "RX"))) + (set_attr "type" "jsr") + (set_attr "atype" "agen")]) ;; ;;- Miscellaneous instructions. @@ -6736,13 +7273,12 @@ (plus (reg 15) (match_operand 1 "general_operand" ""))) (set (match_operand 0 "general_operand" "") (reg 15))] - "" - " + "TARGET_BACKCHAIN" { rtx stack = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM); rtx chain = gen_rtx (MEM, Pmode, stack); rtx temp = gen_reg_rtx (Pmode); - + emit_move_insn (temp, chain); if (TARGET_64BIT) @@ -6752,66 +7288,23 @@ emit_move_insn (chain, temp); - emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); DONE; -}") +}) ; -; setjmp/longjmp instruction pattern(s). +; setjmp instruction pattern. ; -(define_expand "builtin_setjmp_setup" - [(unspec [(match_operand 0 "register_operand" "a")] 1)] - "" - " -{ - rtx base = gen_rtx_MEM (Pmode, plus_constant (operands[0], 4 * GET_MODE_SIZE (Pmode))); - rtx basereg = gen_rtx_REG (Pmode, BASE_REGISTER); - - emit_move_insn (base, basereg); - DONE; -}") - (define_expand "builtin_setjmp_receiver" - [(unspec_volatile [(label_ref (match_operand 0 "" ""))] 2)] + [(match_operand 0 "" "")] "flag_pic" - " -{ - rtx gotreg = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); - rtx got = gen_rtx_SYMBOL_REF (Pmode, \"_GLOBAL_OFFSET_TABLE_\"); - SYMBOL_REF_FLAG (got) = 1; - - emit_move_insn (gotreg, got); - emit_insn (gen_rtx_USE (VOIDmode, gotreg)); - DONE; -}") - -(define_expand "builtin_longjmp" - [(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)] - "" - " { - /* The elements of the buffer are, in order: */ - rtx fp = gen_rtx_MEM (Pmode, operands[0]); - rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], GET_MODE_SIZE (Pmode))); - rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2 * GET_MODE_SIZE (Pmode))); - rtx base = gen_rtx_MEM (Pmode, plus_constant (operands[0], 4 * GET_MODE_SIZE (Pmode))); - rtx basereg = gen_rtx_REG (Pmode, BASE_REGISTER); - rtx jmp = gen_rtx_REG (Pmode, 14); - - emit_move_insn (jmp, lab); - emit_move_insn (basereg, base); - emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); - emit_move_insn (hard_frame_pointer_rtx, fp); - - emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, basereg)); - emit_indirect_jump (jmp); + s390_load_got (false); + emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); DONE; -}") - +}) ;; These patterns say how to save and restore the stack pointer. We need not ;; save the stack pointer at function level since we are careful to @@ -6840,49 +7333,57 @@ (set (match_dup 0) (match_operand 1 "register_operand" "")) (set (match_dup 3) (match_dup 2))] "" - " { operands[2] = gen_reg_rtx (Pmode); operands[3] = gen_rtx_MEM (Pmode, operands[0]); -}") +}) (define_expand "save_stack_nonlocal" [(match_operand 0 "memory_operand" "") (match_operand 1 "register_operand" "")] "" - " { rtx temp = gen_reg_rtx (Pmode); - /* Copy the backchain to the first word, sp to the second. */ + /* Copy the backchain to the first word, sp to the second and the literal pool + base to the third. */ + emit_move_insn (operand_subword (operands[0], 2, 0, + TARGET_64BIT ? OImode : TImode), + gen_rtx_REG (Pmode, BASE_REGISTER)); emit_move_insn (temp, gen_rtx_MEM (Pmode, operands[1])); emit_move_insn (operand_subword (operands[0], 0, 0, - TARGET_64BIT ? TImode : DImode), + TARGET_64BIT ? OImode : TImode), temp); emit_move_insn (operand_subword (operands[0], 1, 0, - TARGET_64BIT ? TImode : DImode), + TARGET_64BIT ? OImode : TImode), operands[1]); DONE; -}") +}) (define_expand "restore_stack_nonlocal" [(match_operand 0 "register_operand" "") (match_operand 1 "memory_operand" "")] "" - " { rtx temp = gen_reg_rtx (Pmode); + rtx base = gen_rtx_REG (Pmode, BASE_REGISTER); - /* Restore the backchain from the first word, sp from the second. */ + /* Restore the backchain from the first word, sp from the second and the + literal pool base from the third. */ emit_move_insn (temp, operand_subword (operands[1], 0, 0, - TARGET_64BIT ? TImode : DImode)); + TARGET_64BIT ? OImode : TImode)); emit_move_insn (operands[0], operand_subword (operands[1], 1, 0, - TARGET_64BIT ? TImode : DImode)); + TARGET_64BIT ? OImode : TImode)); emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), temp); + emit_move_insn (base, + operand_subword (operands[1], 2, 0, + TARGET_64BIT ? OImode : TImode)); + emit_insn (gen_rtx_USE (VOIDmode, base)); + DONE; -}") +}) ; @@ -6892,7 +7393,7 @@ (define_insn "nop" [(const_int 0)] "" - "lr\\t0,0" + "lr\t0,0" [(set_attr "op_type" "RR")]) @@ -6900,143 +7401,97 @@ ; Special literal pool access instruction pattern(s). ; -(define_insn "consttable_qi" - [(unspec_volatile [(match_operand:QI 0 "consttable_operand" "X")] 200)] - "" - "* -{ - assemble_integer (operands[0], 1, BITS_PER_UNIT, 1); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "1")]) - -(define_insn "consttable_hi" - [(unspec_volatile [(match_operand:HI 0 "consttable_operand" "X")] 201)] - "" - "* -{ - assemble_integer (operands[0], 2, 2*BITS_PER_UNIT, 1); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "2")]) - -(define_insn "consttable_si" - [(unspec_volatile [(match_operand:SI 0 "consttable_operand" "X")] 202)] +(define_insn "*pool_entry" + [(unspec_volatile [(match_operand 0 "consttable_operand" "X")] + UNSPECV_POOL_ENTRY)] "" - "* { - if (!TARGET_64BIT && flag_pic && SYMBOLIC_CONST (operands[0])) - return \".long\\t%0\"; - - assemble_integer (operands[0], 4, 4*BITS_PER_UNIT, 1); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "4")]) - -(define_insn "consttable_di" - [(unspec_volatile [(match_operand:DI 0 "consttable_operand" "X")] 203)] - "" - "* -{ - assemble_integer (operands[0], 8, 8*BITS_PER_UNIT, 1); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "8")]) - -(define_insn "consttable_sf" - [(unspec_volatile [(match_operand:SF 0 "consttable_operand" "X")] 204)] - "" - "* -{ - REAL_VALUE_TYPE r; - - if (GET_CODE (operands[0]) != CONST_DOUBLE) - abort (); - - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); - assemble_real (r, SFmode, 4*BITS_PER_UNIT); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "4")]) - -(define_insn "consttable_df" - [(unspec_volatile [(match_operand:DF 0 "consttable_operand" "X")] 205)] - "" - "* -{ - REAL_VALUE_TYPE r; - - if (GET_CODE (operands[0]) != CONST_DOUBLE) - abort (); - - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]); - assemble_real (r, DFmode, 8*BITS_PER_UNIT); - return \"\"; -}" - [(set_attr "op_type" "NN") - (set_attr "length" "8")]) + enum machine_mode mode = GET_MODE (PATTERN (insn)); + unsigned int align = GET_MODE_BITSIZE (mode); + s390_output_pool_entry (asm_out_file, operands[0], mode, align); + return ""; +} + [(set_attr "op_type" "NN") + (set (attr "length") + (symbol_ref "GET_MODE_SIZE (GET_MODE (PATTERN (insn)))"))]) (define_insn "pool_start_31" - [(unspec_volatile [(const_int 0)] 206)] - "!TARGET_64BIT" - ".align\\t4" + [(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)] + "!TARGET_CPU_ZARCH" + ".align\t4" [(set_attr "op_type" "NN") (set_attr "length" "2")]) (define_insn "pool_end_31" - [(unspec_volatile [(const_int 0)] 207)] - "!TARGET_64BIT" - ".align\\t2" + [(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)] + "!TARGET_CPU_ZARCH" + ".align\t2" [(set_attr "op_type" "NN") (set_attr "length" "2")]) (define_insn "pool_start_64" - [(unspec_volatile [(const_int 0)] 206)] - "TARGET_64BIT" - ".section\\t.rodata\;.align\\t8" + [(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)] + "TARGET_CPU_ZARCH" + ".section\t.rodata\;.align\t8" [(set_attr "op_type" "NN") (set_attr "length" "0")]) (define_insn "pool_end_64" - [(unspec_volatile [(const_int 0)] 207)] - "TARGET_64BIT" + [(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)] + "TARGET_CPU_ZARCH" ".previous" [(set_attr "op_type" "NN") (set_attr "length" "0")]) +(define_insn "main_base_31_small" + [(set (match_operand 0 "register_operand" "=a") + (unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))] + "!TARGET_CPU_ZARCH && GET_MODE (operands[0]) == Pmode" + "basr\t%0,0" + [(set_attr "op_type" "RR") + (set_attr "type" "la")]) + +(define_insn "main_base_31_large" + [(set (match_operand 0 "register_operand" "=a") + (unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE)) + (set (pc) (label_ref (match_operand 2 "" "")))] + "!TARGET_CPU_ZARCH && GET_MODE (operands[0]) == Pmode" + "bras\t%0,%2" + [(set_attr "op_type" "RI")]) + +(define_insn "main_base_64" + [(set (match_operand 0 "register_operand" "=a") + (unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_MAIN_BASE))] + "TARGET_CPU_ZARCH && GET_MODE (operands[0]) == Pmode" + "larl\t%0,%1" + [(set_attr "op_type" "RIL") + (set_attr "type" "larl")]) + +(define_insn "main_pool" + [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)] + "" + "* abort ();" + [(set_attr "op_type" "NN")]) + (define_insn "reload_base_31" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(label_ref (match_operand 1 "" ""))] 210))] - "!TARGET_64BIT" - "basr\\t%0,0\;la\\t%0,%1-.(%0)" + [(set (match_operand 0 "register_operand" "=a") + (unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))] + "!TARGET_CPU_ZARCH && GET_MODE (operands[0]) == Pmode" + "basr\t%0,0\;la\t%0,%1-.(%0)" [(set_attr "op_type" "NN") (set_attr "type" "la") (set_attr "length" "6")]) (define_insn "reload_base_64" - [(set (match_operand:DI 0 "register_operand" "=a") - (unspec:DI [(label_ref (match_operand 1 "" ""))] 210))] - "TARGET_64BIT" - "larl\\t%0,%1" + [(set (match_operand 0 "register_operand" "=a") + (unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_RELOAD_BASE))] + "TARGET_CPU_ZARCH && GET_MODE (operands[0]) == Pmode" + "larl\t%0,%1" [(set_attr "op_type" "RIL") - (set_attr "type" "la")]) - -(define_insn "reload_anchor" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SI 1 "register_operand" "a")] 211))] - "!TARGET_64BIT" - "l\\t%0,0(%1)\;la\\t%0,0(%0,%1)" - [(set_attr "op_type" "NN") - (set_attr "type" "la") - (set_attr "length" "8")]) + (set_attr "type" "larl")]) (define_insn "pool" - [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] 220)] + [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] UNSPECV_POOL)] "" "* abort ();" [(set_attr "op_type" "NN") @@ -7050,78 +7505,33 @@ (define_expand "prologue" [(use (const_int 0))] "" - " -{ - s390_emit_prologue (); - DONE; -}") + "s390_emit_prologue (); DONE;") (define_expand "epilogue" [(use (const_int 1))] "" - " -{ - s390_emit_epilogue (); - DONE; -}") - + "s390_emit_epilogue (); DONE;") -(define_insn "*return_si" +(define_insn "*return" [(return) - (use (match_operand:SI 0 "register_operand" "a"))] - "!TARGET_64BIT" - "br\\t%0" + (use (match_operand 0 "register_operand" "a"))] + "GET_MODE (operands[0]) == Pmode" + "br\t%0" [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) + (set_attr "type" "jsr") + (set_attr "atype" "agen")]) -(define_insn "*return_di" - [(return) - (use (match_operand:DI 0 "register_operand" "a"))] - "TARGET_64BIT" - "br\\t%0" - [(set_attr "op_type" "RR") - (set_attr "type" "jsr") - (set_attr "atype" "mem")]) -(define_insn "literal_pool_31" - [(unspec_volatile [(const_int 0)] 300) - (set (match_operand:SI 0 "register_operand" "=a") - (label_ref (match_operand 1 "" ""))) - (use (label_ref (match_operand 2 "" "")))] - "" -{ - if (s390_nr_constants) - { - output_asm_insn ("bras\\t%0,%2", operands); - s390_output_constant_pool (operands[1], operands[2]); - } - else if (flag_pic) - { - /* We need the anchor label in any case. */ - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", - CODE_LABEL_NUMBER (operands[1])); - } - - return ""; -} - [(set_attr "op_type" "NN") - (set_attr "type" "la")]) +;; Instruction definition to extend a 31-bit pointer into a 64-bit +;; pointer. This is used for compatibility. -(define_insn "literal_pool_64" - [(unspec_volatile [(const_int 0)] 300) - (set (match_operand:DI 0 "register_operand" "=a") - (label_ref (match_operand 1 "" ""))) - (use (label_ref (match_operand 2 "" "")))] - "" +(define_expand "ptr_extend" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r"))] + "TARGET_64BIT" { - if (s390_nr_constants) - { - output_asm_insn ("larl\\t%0,%1", operands); - s390_output_constant_pool (operands[1], operands[2]); - } - - return ""; -} - [(set_attr "op_type" "NN") - (set_attr "type" "la")]) + emit_insn (gen_anddi3 (operands[0], + gen_lowpart (DImode, operands[1]), + GEN_INT (0x7fffffff))); + DONE; +}) diff --git a/contrib/gcc/config/s390/s390x.h b/contrib/gcc/config/s390/s390x.h index c79acf5..f9177c1 100644 --- a/contrib/gcc/config/s390/s390x.h +++ b/contrib/gcc/config/s390/s390x.h @@ -2,22 +2,23 @@ Copyright (C) 2002 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). -This file is part of GNU CC. -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +This file is part of GCC. -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ #ifndef _S390X_H #define _S390X_H diff --git a/contrib/gcc/config/s390/t-tpf b/contrib/gcc/config/s390/t-tpf new file mode 100644 index 0000000..c04d562 --- /dev/null +++ b/contrib/gcc/config/s390/t-tpf @@ -0,0 +1,13 @@ +# Compile crtbeginS.o and crtendS.o with pic. +CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC +# Compile libgcc2.a with pic. +TARGET_LIBGCC2_CFLAGS = -fPIC + +# Override t-slibgcc-elf-ver to export some libgcc symbols with +# the symbol versions that glibc used. +SHLIB_MAPFILES += $(srcdir)/config/s390/libgcc-glibc.ver + +# Use unwind-dw2-fde-glibc +LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c +LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c gthr-gnat.c diff --git a/contrib/gcc/config/s390/tpf.h b/contrib/gcc/config/s390/tpf.h new file mode 100644 index 0000000..ce984e6 --- /dev/null +++ b/contrib/gcc/config/s390/tpf.h @@ -0,0 +1,112 @@ +/* Definitions for target OS TPF for GNU compiler, for IBM S/390 hardware + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by P.J. Darcy (darcypj@us.ibm.com), + Hartmut Penner (hpenner@de.ibm.com), and + Ulrich Weigand (uweigand@de.ibm.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _TPF_H +#define _TPF_H + +/* TPF wants the following macros defined/undefined as follows. */ +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" +#define NO_IMPLICIT_EXTERN_C +#define TARGET_HAS_F_SETLKW +#undef MD_EXEC_PREFIX +#undef MD_STARTFILE_PREFIX + +#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 + + +/* Basic record keeping for the TPF OS name. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (TPF: zSeries)"); + +/* TPF OS specific stack-pointer offset. */ +#undef STACK_POINTER_OFFSET +#define STACK_POINTER_OFFSET 280 + +/* When building for TPF, set a generic default target that is 64 bits. */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0x33 + +/* TPF OS specific compiler settings. */ +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + builtin_define_std ("tpf"); \ + builtin_assert ("system=tpf"); \ + builtin_define ("__ELF__"); \ + if (flag_pic) \ + { \ + builtin_define ("__PIC__"); \ + builtin_define ("__pic__"); \ + } \ + } \ + while (0) + + +/* Make TPF specific spec file settings here. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shared: \ + %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \ + %{!p:%{profile:gcrt1.o%s} \ + %{!profile:crt1.o%s}}}} \ + crti.o%s %{static:crtbeginT.o%s} \ + %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" + +/* The GNU C++ standard library requires that these macros be defined. */ +#undef CPLUSPLUS_CPP_SPEC +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)" + +#undef LIB_SPEC +#define LIB_SPEC "%{pthread:-lpthread} -lc" + +#undef TARGET_C99_FUNCTIONS +#define TARGET_C99_FUNCTIONS 1 + +#undef LINK_SPEC +#define LINK_SPEC \ + "-m elf64_s390 \ + %{shared:-shared} \ + %{!shared: \ + %{static:-static} \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld64.so}}}" + +#endif /* ! _TPF_H */ + |