diff options
Diffstat (limited to 'gcc-4.7/gcc/config/s390')
-rw-r--r-- | gcc-4.7/gcc/config/s390/2064.md | 135 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/2084.md | 310 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/2097.md | 764 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/2817.md | 315 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/constraints.md | 492 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/linux.h | 91 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/predicates.md | 406 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390-modes.def | 174 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390-opts.h | 41 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390-protos.h | 113 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390.c | 10793 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390.h | 909 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390.md | 9416 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390.opt | 148 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/s390x.h | 27 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/t-linux64 | 10 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/tpf.h | 124 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/tpf.md | 33 | ||||
-rw-r--r-- | gcc-4.7/gcc/config/s390/tpf.opt | 27 |
19 files changed, 0 insertions, 24328 deletions
diff --git a/gcc-4.7/gcc/config/s390/2064.md b/gcc-4.7/gcc/config/s390/2064.md deleted file mode 100644 index 143978334..000000000 --- a/gcc-4.7/gcc/config/s390/2064.md +++ /dev/null @@ -1,135 +0,0 @@ -;; Scheduling description for z900 (cpu 2064). -;; Copyright (C) 2003, 2004, 2005, 2007 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 3, or (at your option) any later -;; version. - -;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; -;; 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 - -;; This scheduler description is also used for the g5 and g6. - -(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,g5,g6") - (eq_attr "type" "la")) - "z_e1,z_wr") - -(define_insn_reservation "z_larl" 1 - (and (eq_attr "cpu" "z900,g5,g6") - (eq_attr "type" "larl")) - "z_e1,z_wr") - -(define_insn_reservation "z_load" 1 - (and (eq_attr "cpu" "z900,g5,g6") - (eq_attr "type" "load")) - "z_e1,z_wr") - -(define_insn_reservation "z_store" 1 - (and (eq_attr "cpu" "z900,g5,g6") - (eq_attr "type" "store")) - "z_e1,z_wr") - -(define_insn_reservation "z_sem" 2 - (and (eq_attr "cpu" "z900,g5,g6") - (eq_attr "type" "sem")) - "z_e1*2,z_wr") - -(define_insn_reservation "z_call" 5 - (and (eq_attr "cpu" "z900,g5,g6") - (eq_attr "type" "jsr")) - "z_e1*5,z_wr") - -(define_insn_reservation "z_mul" 5 - (and (eq_attr "cpu" "g5,g6,z900") - (eq_attr "type" "imulsi,imulhi")) - "z_e1*5,z_wr") - -(define_insn_reservation "z_inf" 10 - (and (eq_attr "cpu" "g5,g6,z900") - (eq_attr "type" "idiv,imuldi")) - "z_e1*10,z_wr") - -;; For everything else we check the atype flag. - -(define_insn_reservation "z_int" 1 - (and (eq_attr "cpu" "z900,g5,g6") - (and (not (eq_attr "type" "la,larl,load,store,jsr")) - (eq_attr "atype" "reg"))) - "z_e1,z_wr") - -(define_insn_reservation "z_agen" 1 - (and (eq_attr "cpu" "z900,g5,g6") - (and (not (eq_attr "type" "la,larl,load,store,jsr")) - (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/gcc-4.7/gcc/config/s390/2084.md b/gcc-4.7/gcc/config/s390/2084.md deleted file mode 100644 index 2379f965e..000000000 --- a/gcc-4.7/gcc/config/s390/2084.md +++ /dev/null @@ -1,310 +0,0 @@ -;; Scheduling description for z990 (cpu 2084). -;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 -;; 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 3, or (at your option) any later -;; version. - -;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -(define_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_int" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (and (eq_attr "type" "integer") - (eq_attr "atype" "reg"))) - "x-e1-st,x-wr-st") - -(define_insn_reservation "x_agen" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (and (eq_attr "type" "integer") - (eq_attr "atype" "agen"))) - "x-e1-st,x-wr-st") - -(define_insn_reservation "x_lr" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "lr")) - "x-e1-st,x-wr-st") - -(define_insn_reservation "x_la" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "la")) - "x-e1-st,x-wr-st") - -(define_insn_reservation "x_larl" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "larl")) - "x-e1-st,x-wr-st") - -(define_insn_reservation "x_load" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "load")) - "x-e1-st+x-mem,x-wr-st") - -(define_insn_reservation "x_store" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "store")) - "x-e1-st+x_store_tok,x-wr-st") - -(define_insn_reservation "x_branch" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "branch")) - "x_e1_r,x_wr_r") - -(define_insn_reservation "x_call" 5 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "jsr")) - "x-e1-np*5,x-wr-np") - -(define_insn_reservation "x_mul_hi" 2 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "imulhi")) - "x-e1-np*2,x-wr-np") - -(define_insn_reservation "x_mul_sidi" 4 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "imulsi,imuldi")) - "x-e1-np*4,x-wr-np") - -(define_insn_reservation "x_div" 10 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "idiv")) - "x-e1-np*10,x-wr-np") - -(define_insn_reservation "x_sem" 17 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "sem")) - "x-e1-np+x-mem,x-e1-np*16,x-wr-st") - -;; -;; Multicycle insns -;; - -(define_insn_reservation "x_cs" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "cs")) - "x-e1-np,x-wr-np") - -(define_insn_reservation "x_vs" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "vs")) - "x-e1-np*10,x-wr-np") - -(define_insn_reservation "x_stm" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (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,z9_109,z9_ec") - (eq_attr "type" "lm")) - "x-e1-np*10,x-wr-np") - -(define_insn_reservation "x_other" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "other")) - "x-e1-np,x-wr-np") - -;; -;; Floating point insns -;; - -(define_insn_reservation "x_fsimptf" 7 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fsimptf,fhex")) - "x_e1_t*2,x-wr-fp") - -(define_insn_reservation "x_fsimpdf" 6 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fsimpdf,fmuldf,fmadddf,fhex")) - "x_e1_t,x-wr-fp") - -(define_insn_reservation "x_fsimpsf" 6 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fsimpsf,fmulsf,fmaddsf,fhex")) - "x_e1_t,x-wr-fp") - - -(define_insn_reservation "x_fmultf" 33 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fmultf")) - "x_e1_t*27,x-wr-fp") - - -(define_insn_reservation "x_fdivtf" 82 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fdivtf,fsqrttf")) - "x_e1_t*76,x-wr-fp") - -(define_insn_reservation "x_fdivdf" 36 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fdivdf,fsqrtdf")) - "x_e1_t*30,x-wr-fp") - -(define_insn_reservation "x_fdivsf" 36 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fdivsf,fsqrtsf")) - "x_e1_t*30,x-wr-fp") - - -(define_insn_reservation "x_floadtf" 6 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "floadtf")) - "x_e1_t,x-wr-fp") - -(define_insn_reservation "x_floaddf" 6 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "floaddf")) - "x_e1_t,x-wr-fp") - -(define_insn_reservation "x_floadsf" 6 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "floadsf")) - "x_e1_t,x-wr-fp") - - -(define_insn_reservation "x_fstoredf" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fstoredf")) - "x_e1_t,x-wr-fp") - -(define_insn_reservation "x_fstoresf" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "fstoresf")) - "x_e1_t,x-wr-fp") - - -(define_insn_reservation "x_ftrunctf" 16 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "ftrunctf")) - "x_e1_t*10,x-wr-fp") - -(define_insn_reservation "x_ftruncdf" 11 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "ftruncdf")) - "x_e1_t*5,x-wr-fp") - - -(define_insn_reservation "x_ftoi" 1 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "ftoi")) - "x_e1_t*3,x-wr-fp") - -(define_insn_reservation "x_itof" 7 - (and (eq_attr "cpu" "z990,z9_109,z9_ec") - (eq_attr "type" "itoftf,itofdf,itofsf")) - "x_e1_t*3,x-wr-fp") - -(define_bypass 1 "x_fsimpdf" "x_fstoredf") - -(define_bypass 1 "x_fsimpsf" "x_fstoresf") - -(define_bypass 1 "x_floaddf" "x_fsimpdf,x_fstoredf,x_floaddf") - -(define_bypass 1 "x_floadsf" "x_fsimpsf,x_fstoresf,x_floadsf") - -;; -;; 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_branch,x_call,x_load,x_store,x_cs,x_stm,x_lm,x_other" - "s390_agen_dep_p") - -(define_bypass 9 "x_int,x_agen,x_lr" - "x_floadtf, x_floaddf, x_floadsf, x_fstoredf, x_fstoresf,\ - x_fsimpdf, x_fsimpsf, x_fdivdf, x_fdivsf" - "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_branch,x_call,x_load,x_store,x_cs,x_stm,x_lm,x_other" - "s390_agen_dep_p") - -(define_bypass 5 "x_load" - "x_floadtf, x_floaddf, x_floadsf, x_fstoredf, x_fstoresf,\ - x_fsimpdf, x_fsimpsf, x_fdivdf, x_fdivsf" - "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_branch,x_call,x_load,x_store,x_cs,x_stm,x_lm,x_other" - "s390_agen_dep_p") - -(define_bypass 5 "x_larl, x_la" - "x_floadtf, x_floaddf, x_floadsf, x_fstoredf, x_fstoresf,\ - x_fsimpdf, x_fsimpsf, x_fdivdf, x_fdivsf" - "s390_agen_dep_p") - -;; -;; Operand forwarding -;; - -(define_bypass 0 "x_lr,x_la,x_load" "x_int,x_lr") - - diff --git a/gcc-4.7/gcc/config/s390/2097.md b/gcc-4.7/gcc/config/s390/2097.md deleted file mode 100644 index 77c206ecd..000000000 --- a/gcc-4.7/gcc/config/s390/2097.md +++ /dev/null @@ -1,764 +0,0 @@ -;; Scheduling description for z10 (cpu 2097). -;; Copyright (C) 2008, 2010 Free Software Foundation, Inc. -;; Contributed by Wolfgang Gellerich (gellerich@de.ibm.com). - - -; General naming conventions used in this file: -; - The two pipelines are called S and T, respectively. -; - A name ending "_S" or "_T" indicates that something happens in -; (or belongs to) this pipeline. -; - A name ending "_ANY" indicates that something happens in (or belongs -; to) either of the two pipelines. -; - A name ending "_BOTH" indicates that something happens in (or belongs -; to) both pipelines. - - -;; Automaton and components. - -(define_automaton "z10_cpu") - -(define_cpu_unit "z10_e1_S, z10_e1_T" "z10_cpu") -(define_reservation "z10_e1_ANY" "(z10_e1_S | z10_e1_T)") -(define_reservation "z10_e1_BOTH" "(z10_e1_S + z10_e1_T)") - - -; Both pipelines can execute a branch instruction, and branch -; instructions can be grouped with all other groupable instructions -; but not with a second branch instruction. - -(define_cpu_unit "z10_branch_ANY" "z10_cpu") - -(define_insn_reservation "z10_branch" 4 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "branch")) - "z10_branch_ANY + z10_e1_ANY, z10_Gate_ANY") - - -; Z10 operand and result forwarding. - -; Instructions marked with the attributes as z10_fwd or z10_fr can -; forward a value they load from one of their operants into a register -; if the instruction in the second pipeline reads the same register. -; The second operation must be superscalar. Instructions marked as -; z10_rec or z10_fr can receive a value they read from a register is -; this register gets updated by an instruction in the first pipeline. -; The first instruction must be superscalar. - - -; Forwarding from z10_fwd and z10_fr to z10_super. - -(define_bypass 0 "z10_la_fwd, z10_la_fwd_A1, z10_larl_fwd, z10_larl_fwd_A3, \ - z10_load_fwd, z10_load_fwd_A3, \ - z10_other_fwd, z10_other_fwd_A1, z10_other_fwd_A3, \ - z10_other_fr, z10_other_fr_A3, z10_other_fr_E1, \ - z10_other_fwd_E1, z10_lr_fr, z10_lr_fr_E1, \ - z10_int_fwd, z10_int_fwd_A1, z10_int_fwd_A3, \ - z10_int_fwd_E1, z10_int_fr, z10_int_fr_E1, \ - z10_int_fr_A3" - "z10_other_super, z10_other_super_c_E1, z10_other_super_E1, \ - z10_int_super, z10_int_super_E1, \ - z10_lr, z10_store_super" - " ! s390_agen_dep_p") - - -; Forwarding from z10_super to frz10_ and z10_rec. - -(define_bypass 0 "z10_other_super, z10_other_super_E1, z10_other_super_c_E1, \ - z10_int_super, z10_int_super_E1, \ - z10_larl_super_E1, z10_larl_super, \ - z10_store_super" - "z10_int_fr, z10_int_fr_E1, z10_int_fr_A3, \ - z10_other_fr, z10_other_fr_A3, z10_lr_fr, z10_lr_fr_E1, \ - z10_other_fr_E1, z10_store_rec" - " ! s390_agen_dep_p") - - -; Forwarding from z10_fwd and z10_fr to z10_rec and z10_fr. - -(define_bypass 0 "z10_la_fwd, z10_la_fwd_A1, z10_larl_fwd, z10_larl_fwd_A3, \ - z10_load_fwd, z10_load_fwd_A3, \ - z10_other_fwd, z10_other_fwd_A1, z10_other_fwd_A3, \ - z10_other_fr, z10_other_fr_A3, z10_other_fr_E1, \ - z10_other_fwd_E1, \ - z10_lr_fr, z10_lr_fr_E1, \ - z10_int_fwd, z10_int_fwd_A1, z10_int_fwd_A3, \ - z10_int_fwd_E1, z10_int_fr, z10_int_fr_E1, \ - z10_int_fr_A3" - "z10_int_fr, z10_int_fr_E1, z10_int_fr_A3, \ - z10_other_fr, z10_other_fr_A3, z10_lr_fr, z10_lr_fr_E1, \ - z10_other_fr_E1, z10_store_rec" - " ! s390_agen_dep_p") - - -; -; Simple insns -; - -; Here is the cycle diagram for FXU-executed instructions: -; ... A1 A2 A3 E1 P1 P2 P3 R0 ... -; ^ ^ ^ -; | | updated GPR is available -; | write to GPR -; instruction reads GPR during this cycle - - -; Variants of z10_int follow. - -(define_insn_reservation "z10_int" 6 - (and (and (eq_attr "cpu" "z10") - (eq_attr "type" "integer")) - (and (eq_attr "atype" "reg") - (and (and (eq_attr "z10prop" "!z10_super") - (eq_attr "z10prop" "!z10_super_c")) - (and (and (and (and (eq_attr "z10prop" "!z10_super_E1") - (eq_attr "z10prop" "!z10_super_c_E1")) - (eq_attr "z10prop" "!z10_fwd")) - (and (eq_attr "z10prop" "!z10_fwd_A1") - (eq_attr "z10prop" "!z10_fwd_A3"))) - (and (and (eq_attr "z10prop" "!z10_fwd_E1") - (eq_attr "z10prop" "!z10_fr")) - (and (eq_attr "z10prop" "!z10_fr_E1") - (eq_attr "z10prop" "!z10_fr_A3"))))))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_super" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (ior (eq_attr "z10prop" "z10_super") - (eq_attr "z10prop" "z10_super_c"))))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_super_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (ior (eq_attr "z10prop" "z10_super_E1") - (eq_attr "z10prop" "z10_super_c_E1"))))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fwd" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fwd")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fwd_A1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fwd_A1")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fwd_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fwd_A3")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fwd_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fwd_E1")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fr" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fr")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fr_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fr_E1")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_int_fr_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (and (eq_attr "atype" "reg") - (eq_attr "z10prop" "z10_fr_A3")))) - "z10_e1_ANY, z10_Gate_ANY") - -; END of z10_int variants - - -(define_insn_reservation "z10_agen" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "integer") - (eq_attr "atype" "agen"))) - "z10_e1_ANY, z10_Gate_ANY") - - -(define_insn_reservation "z10_lr" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "lr") - (and (eq_attr "z10prop" "!z10_fr") - (eq_attr "z10prop" "!z10_fr_E1")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_lr_fr" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "lr") - (eq_attr "z10prop" "z10_fr"))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_lr_fr_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "lr") - (eq_attr "z10prop" "z10_fr_E1"))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_la" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "la") - (and (eq_attr "z10prop" "!z10_fwd") - (eq_attr "z10prop" "!z10_fwd_A1")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_la_fwd" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "la") - (eq_attr "z10prop" "z10_fwd"))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_la_fwd_A1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "la") - (eq_attr "z10prop" "z10_fwd_A1"))) - "z10_e1_ANY, z10_Gate_ANY") - - -; larl-type instructions - -(define_insn_reservation "z10_larl" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (and (eq_attr "z10prop" "!z10_super_A1") - (and (eq_attr "z10prop" "!z10_fwd") - (and (eq_attr "z10prop" "!z10_fwd_A3") - (and (eq_attr "z10prop" "!z10_super") - (eq_attr "z10prop" "!z10_super_c")) - (and (eq_attr "z10prop" "!z10_super_E1") - (eq_attr "z10prop" "!z10_super_c_E1"))))))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_larl_super" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (and (eq_attr "z10prop" "z10_super") - (eq_attr "z10prop" "z10_super_c")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_larl_fwd" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (eq_attr "z10prop" "z10_fwd"))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_larl_fwd_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (eq_attr "z10prop" "z10_fwd_A3"))) - "z10_e1_ANY, z10_Gate_ANY") - - -(define_insn_reservation "z10_larl_A1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (eq_attr "z10prop" "z10_super_A1"))) - "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") - -(define_insn_reservation "z10_larl_super_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "larl") - (ior (eq_attr "z10prop" "z10_super_E1") - (eq_attr "z10prop" "z10_super_c_E1")))) - "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") - - -(define_insn_reservation "z10_load" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "load") - (and (eq_attr "z10prop" "!z10_fwd") - (eq_attr "z10prop" "!z10_fwd_A3")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_load_fwd" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "load") - (eq_attr "z10prop" "z10_fwd"))) - "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") - -(define_insn_reservation "z10_load_fwd_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "load") - (eq_attr "z10prop" "z10_fwd_A3"))) - "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") - -(define_insn_reservation "z10_store" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "store") - (and (eq_attr "z10prop" "!z10_rec") - (and (eq_attr "z10prop" "!z10_super") - (eq_attr "z10prop" "!z10_super_c"))))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_store_super" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "store") - (ior (eq_attr "z10prop" "z10_super") - (eq_attr "z10prop" "z10_super_c")))) - "z10_e1_ANY, z10_Gate_ANY") - -(define_insn_reservation "z10_store_rec" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "store") - (eq_attr "z10prop" "z10_rec"))) - "z10_e1_ANY, z10_Gate_ANY") - -; The default_latency is chosen to drain off the pipeline. -(define_insn_reservation "z10_call" 14 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "jsr")) - "z10_e1_BOTH*4, z10_Gate_BOTH") - -; The default latency is for worst case. CS and CSG take one -; cycle only (i.e. latency would be 6). -(define_insn_reservation "z10_sem" 9 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "sem")) - "z10_e1_BOTH*5, z10_Gate_ANY") - -(define_insn_reservation "z10_cs" 6 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "cs")) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_vs" 6 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "vs")) - "z10_e1_BOTH*4, z10_Gate_BOTH") - -; Load and store multiple. Actual number of cycles -; in unknown at compile.time. -(define_insn_reservation "z10_stm" 10 - (and (eq_attr "cpu" "z10") - (ior (eq_attr "type" "stm") - (eq_attr "type" "lm"))) - "z10_e1_BOTH*4, z10_Gate_BOTH") - - -; Subsets of z10_other follow. - -(define_insn_reservation "z10_other" 6 - (and (and (eq_attr "cpu" "z10") - (eq_attr "type" "other")) - (and (and (eq_attr "z10prop" "!z10_fwd") - (eq_attr "z10prop" "!z10_fwd_A1")) - (and (and (and (eq_attr "z10prop" "!z10_fr_A3") - (eq_attr "z10prop" "!z10_fwd_A3")) - (and (eq_attr "z10prop" "!z10_fr") - (eq_attr "z10prop" "!z10_fr_E1"))) - (and (and (and (eq_attr "z10prop" "!z10_super") - (eq_attr "z10prop" "!z10_super_c")) - (eq_attr "z10prop" "!z10_super_c_E1")) - (and (eq_attr "z10prop" "!z10_super_E1") - (eq_attr "z10prop" "!z10_fwd_E1")))))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fr_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fr_E1"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_super_c_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_super_c_E1"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_super_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_super_E1"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fwd_E1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fwd_E1"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fwd" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fwd"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fwd_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fwd_A3"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fwd_A1" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fwd_A1"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fr" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fr"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_fr_A3" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (eq_attr "z10prop" "z10_fr_A3"))) - "z10_e1_BOTH, z10_Gate_BOTH") - -(define_insn_reservation "z10_other_super" 6 - (and (eq_attr "cpu" "z10") - (and (eq_attr "type" "other") - (ior (eq_attr "z10prop" "z10_super") - (eq_attr "z10prop" "z10_super_c")))) - "z10_e1_BOTH, z10_Gate_BOTH") - -; END of z10_other subsets. - - -; -; Floating point insns -; - -; Z10 executes the following integer operations in the BFU pipeline. - -(define_insn_reservation "z10_mul_sidi" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "imulsi,imuldi,imulhi")) - "z10_e1_BOTH, z10_Gate_FP") - -; Some variants take fewer cycles, but that is not relevant here. -(define_insn_reservation "z10_div" 162 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "idiv")) - "z10_e1_BOTH*4, z10_Gate_FP") - - -; BFP multiplication and general instructions - -(define_insn_reservation "z10_fsimpdf" 6 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimpdf,fmuldf,fmadddf")) - "z10_e1_BOTH, z10_Gate_FP") - -(define_insn_reservation "z10_fsimpsf" 6 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimpsf,fmulsf,fmaddsf")) - "z10_e1_BOTH, z10_Gate_FP") - -(define_insn_reservation "z10_fmultf" 52 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fmultf")) - "z10_e1_BOTH*4, z10_Gate_FP") - -(define_insn_reservation "z10_fsimptf" 14 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimptf")) - "z10_e1_BOTH*2, z10_Gate_FP") - - -; BFP division - -(define_insn_reservation "z10_fdivtf" 113 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fdivtf")) - "z10_e1_T*4, z10_Gate_FP") - -(define_insn_reservation "z10_fdivdf" 41 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fdivdf")) - "z10_e1_T*4, z10_Gate_FP") - -(define_insn_reservation "z10_fdivsf" 34 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fdivsf")) - "z10_e1_T*4, z10_Gate_FP") - - -; BFP sqrt - -(define_insn_reservation "z10_fsqrtsf" 41 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsqrtsf")) - "z10_e1_T*4, z10_Gate_FP") - -(define_insn_reservation "z10_fsqrtdf" 54 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsqrtdf")) - "z10_e1_T*4, z10_Gate_FP") - -(define_insn_reservation "z10_fsqrtf" 122 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsqrttf")) - "z10_e1_T*4, z10_Gate_FP") - - -; BFP load and store - -(define_insn_reservation "z10_floadtf" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "floadtf")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_floaddf" 1 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "floaddf")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_floadsf" 1 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "floadsf")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_fstoredf" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fstoredf,fstoredd")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_fstoresf" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fstoresf,fstoresd")) - "z10_e1_T, z10_Gate_FP") - - -; BFP truncate -(define_insn_reservation "z10_ftrunctf" 16 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftrunctf")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_ftruncdf" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftruncdf")) - "z10_e1_T, z10_Gate_FP") - - -; Conversion between BFP and int. -(define_insn_reservation "z10_ftoi" 13 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftoi")) - "z10_e1_T, z10_Gate_FP") - -(define_insn_reservation "z10_itoftf" 14 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "itoftf")) - "z10_e1_T*2, z10_Gate_FP") - -(define_insn_reservation "z10_itofsfdf" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "itofdf,itofsf")) - "z10_e1_T, z10_Gate_FP") - - - -; BFP-related bypasses. There is no bypass for extended mode. -(define_bypass 1 "z10_fsimpdf" "z10_fstoredf") -(define_bypass 1 "z10_fsimpsf" "z10_fstoresf") -(define_bypass 1 "z10_floaddf" "z10_fsimpdf, z10_fstoredf") -(define_bypass 1 "z10_floadsf" "z10_fsimpsf, z10_fstoresf") - - -; -; insn_reservations for DFP instructions. -; - -; Exact number of cycles is not known at compile-time. -(define_insn_reservation "z10_fdivddtd" 40 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fdivdd,fdivtd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_ftruncsd" 38 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftruncsd")) - "z10_e1_BOTH*4,z10_Gate_DFU") - -(define_insn_reservation "z10_ftruncdd" 340 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftruncsd")) - "z10_e1_BOTH*4,z10_Gate_DFU") - -(define_insn_reservation "z10_floaddd" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "floaddd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_floadsd" 12 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "floadsd")) - "z10_e1_BOTH,z10_Gate_DFU") - -; Exact number of cycles is not known at compile-time. -(define_insn_reservation "z10_fmulddtd" 35 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fmuldd,fmultd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_fsimpdd" 17 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimpdd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_fsimpsd" 17 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimpsd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_fsimptd" 18 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "fsimptd")) - "z10_e1_BOTH,z10_Gate_DFU") - -(define_insn_reservation "z10_itofdd" 36 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "itofdd")) - "z10_e1_BOTH*3,z10_Gate_DFU") - -(define_insn_reservation "z10_itoftd" 49 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "itoftd")) - "z10_e1_BOTH*3,z10_Gate_DFU") - -; Exact number of cycles is not known at compile-time. -(define_insn_reservation "z10_ftoidfp" 30 - (and (eq_attr "cpu" "z10") - (eq_attr "type" "ftoidfp")) - "z10_e1_BOTH*3,z10_Gate_DFU") - - -; -; Address-related bypasses -; - -; Here is the cycle diagram for address-related bypasses: -; ... G1 G2 G3 A0 A1 A2 A3 E1 P1 P2 P3 R0 ... -; ^ ^ ^ ^ ^ ^ -; | | | | | without bypass, its available AFTER this cycle -; | | | | E1-type bypasses provide the new value AFTER this cycle -; | | | A3-type bypasses provide the new value AFTER this cycle -; | | A1-type bypasses provide the new value AFTER this cycle -; | AGI resolution, actual USE of new value is DURING this cycle -; AGI detection - -(define_bypass 3 "z10_larl_A1, z10_la_fwd_A1, z10_other_fwd_A1, \ - z10_int_fwd_A1" - "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ - z10_store, \ - z10_cs, z10_stm, z10_other" - "s390_agen_dep_p") - -(define_bypass 5 "z10_larl_fwd_A3, z10_load_fwd_A3, z10_other_fwd_A3, \ - z10_other_fr_A3, z10_int_fwd_A3, z10_int_fr_A3" - "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ - z10_store, \ - z10_cs, z10_stm, z10_other" - "s390_agen_dep_p") - -(define_bypass 6 "z10_other_fr_E1, z10_other_super_c_E1, z10_other_super_E1, \ - z10_other_fwd_E1, \ - z10_lr_fr_E1, z10_larl_super_E1, \ - z10_int_super_E1, z10_int_fwd_E1, z10_int_fr_E1" - "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ - z10_store, \ - z10_cs, z10_stm, z10_other" - "s390_agen_dep_p") - -(define_bypass 9 "z10_int_super, z10_int_fwd, z10_int_fr" - "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ - z10_store, \ - z10_cs, z10_stm, z10_other" - "s390_agen_dep_p") - - - -; -; Try to avoid transitions between DFU-, BFU- and FXU-executed instructions as there is a -; dispatch delay required. -; - - -; Declaration for some pseudo-pipeline stages that reflect the -; dispatch gap when issueing an INT/FXU/BFU-executed instruction after -; an instruction executed by a different unit has been executed. The -; approach is that we pretend a pipelined execution of BFU operations -; with as many stages as the gap is long and request that none of -; these stages is busy when issueing a FXU- or DFU-executed -; instruction. Similar for FXU- and DFU-executed instructions. - -; Declaration for FPU stages. -(define_cpu_unit "z10_f0, z10_f1, z10_f2, z10_f3, z10_f4, z10_f5, z10_f6, \ - z10_f7, z10_f8, z10_f9, z10_f10, z10_f11, z10_f12" "z10_cpu") -(define_reservation "z10_FP_PP" "z10_f0, z10_f1, z10_f2, z10_f3, z10_f4, \ - z10_f5, z10_f6, z10_f7, z10_f8, z10_f9, z10_f10, z10_f11, \ - z10_f12") - -; Declaration for FXU stages. -(define_cpu_unit "z10_S1, z10_S2, z10_S3, z10_S4, z10_S5, z10_S6" "z10_cpu") -(define_cpu_unit "z10_T1, z10_T2, z10_T3, z10_T4, z10_T5, z10_T6" "z10_cpu") -(define_reservation "z10_INT_PP" "z10_S1 | z10_T1, z10_S2 | z10_T2, z10_S3 \ - | z10_T3, z10_S4 | z10_T4, z10_S5 | \ - z10_T5, z10_S6 | z10_T6") - -; Declaration for DFU stages. -(define_cpu_unit "z10_d0, z10_d1, z10_d2, z10_d3, z10_d4, z10_d5, z10_d6" - "z10_cpu") -(define_reservation "z10_DFU_PP" "z10_d0, z10_d1, z10_d2, z10_d3, z10_d4, \ - z10_d5, z10_d6") - - -; Pseudo-units representing whether the respective unit is available -; in the sense that using it does not cause a dispatch delay. - -(define_cpu_unit "z10_S_avail, z10_T_avail, z10_FP_avail, z10_DFU_avail" - "z10_cpu") - -(absence_set "z10_FP_avail" - "z10_S1, z10_S2, z10_S3, z10_S4, z10_S5, z10_S6, z10_T1, z10_T2, z10_T3, z10_T4, \ - z10_T5, z10_T6, \ - z10_d0, z10_d1, z10_d2, z10_d3, z10_d4, z10_d5, z10_d6") - -(absence_set "z10_S_avail,z10_T_avail" - "z10_f0, z10_f1, z10_f2, z10_f3, z10_f4, z10_f5, z10_f6, z10_f7, \ - z10_f8, z10_f9, z10_f10, z10_f11, z10_f12, \ - z10_d0, z10_d1, z10_d2, z10_d3, z10_d4, z10_d5, z10_d6") - -(absence_set "z10_DFU_avail" - "z10_S1, z10_S2, z10_S3, z10_S4, z10_S5, z10_S6, z10_T1, z10_T2, z10_T3, z10_T4, \ - z10_T5, z10_T6, \ - z10_f0, z10_f1, z10_f2, z10_f3, z10_f4, z10_f5, z10_f6, z10_f7, \ - z10_f8, z10_f9, z10_f10, z10_f11, z10_f12") - - -; Pseudo-units to be used in insn_reservations. - -(define_reservation "z10_Gate_ANY" "((z10_S_avail | z10_T_avail), z10_INT_PP)") -(define_reservation "z10_Gate_BOTH" "((z10_S_avail + z10_T_avail), z10_INT_PP)") - -(define_reservation "z10_Gate_FP" "z10_FP_avail, z10_FP_PP") - -(define_reservation "z10_Gate_DFU" "z10_DFU_avail, z10_DFU_PP") diff --git a/gcc-4.7/gcc/config/s390/2817.md b/gcc-4.7/gcc/config/s390/2817.md deleted file mode 100644 index ea181b01f..000000000 --- a/gcc-4.7/gcc/config/s390/2817.md +++ /dev/null @@ -1,315 +0,0 @@ -;; Scheduling description for z196 (cpu 2817). -;; Copyright (C) 2010 -;; Free Software Foundation, Inc. -;; Contributed by Christian Borntraeger (Christian.Borntraeger@de.ibm.com) -;; Andreas Krebbel (Andreas.Krebbel@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 3, or (at your option) any later -;; version. - -;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -(define_automaton "z196_ipu") - -;; Fetch + Decoder -(define_cpu_unit "z196_g1" "z196_ipu") -(define_cpu_unit "z196_g2" "z196_ipu") -(define_cpu_unit "z196_g3" "z196_ipu") -(define_cpu_unit "z196_cr1" "z196_ipu") -(define_cpu_unit "z196_cr2" "z196_ipu") -(define_cpu_unit "z196_cr3" "z196_ipu") - -(final_presence_set "z196_g2" "z196_g1") -(final_presence_set "z196_g3" "z196_g2") -(final_presence_set "z196_cr2" "z196_cr1") -(final_presence_set "z196_cr3" "z196_cr2") -(exclusion_set "z196_g1" "z196_cr1") - -;; Instructions can be groupable, end a group, or be alone in a group. -(define_reservation "z196_simple" "( z196_g1 | z196_g2 | z196_g3 )") -(define_reservation "z196_ends" "( z196_g3 | ( z196_g2 + z196_g3 ) | ( z196_g1 + z196_g2 + z196_g3 ) )") - -;; Try to keep cracked and alone insns together in a clump. This will also -;; improve the clumping of "normal" insns. We also allow crackes insns -;; to go as a last instruction together with normal ones. -(define_reservation "z196_crack" "( z196_cr1 | z196_cr2 | z196_cr3 | z196_g3)") -(define_reservation "z196_alone" "( z196_cr1 | z196_cr2 | z196_cr3 )") - -;; Most simple instruction a fast enough to be handled by OOO even with -;; latency == 0. This reduces life ranges and spilling. We want to increase -;; life range for longer running ops, though, thats why we do not use -;; -fno-schedule-insns. -(define_insn_reservation "z196_simple_LSU" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "load,store,lr") - (eq_attr "z196prop" "none"))) - "z196_simple") - -(define_insn_reservation "z196_simple_FXU" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "integer,la,larl,other") - (and (eq_attr "z196prop" "none") - (eq_attr "op_type" "RR")))) - "z196_simple") - -(define_insn_reservation "z196_simple_DUAL" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "integer,la,larl,other") - (and (eq_attr "z196prop" "none") - (eq_attr "op_type" "!RR")))) - "z196_simple") - -(define_insn_reservation "z196_cracked" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "integer,la,larl,load,lr,store,other") - (eq_attr "z196prop" "z196_cracked"))) - "z196_crack") - -(define_insn_reservation "z196_alone" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "integer,la,larl,load,lr,store,other") - (eq_attr "z196prop" "z196_alone"))) - "z196_alone") - -(define_insn_reservation "z196_ends" 0 - (and (eq_attr "cpu" "z196") - (and (eq_attr "type" "integer,la,larl,load,lr,store,other") - (eq_attr "z196prop" "z196_ends"))) - "z196_ends") - -(define_insn_reservation "z196_branch" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "branch")) - "z196_ends") - -(define_insn_reservation "z196_call" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "jsr")) - "z196_ends") - -(define_insn_reservation "z196_mul_hi" 10 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "imulhi")) - "z196_simple") - -(define_insn_reservation "z196_mul_si" 12 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "imulsi")) - "z196_simple") - -(define_insn_reservation "z196_mul_di" 14 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "imuldi")) - "z196_simple") - -(define_insn_reservation "z196_div" 73 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "idiv")) - "z196_alone") - -(define_insn_reservation "z196_sem" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "sem")) - "z196_crack") - -(define_insn_reservation "z196_cs" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "cs")) - "z196_crack") - -(define_insn_reservation "z196_vs" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "vs")) - "z196_alone") - -(define_insn_reservation "z196_lm_stm" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "stm,lm")) - "z196_crack") - - -;; -;; Binary Floating Point -;; - -(define_insn_reservation "z196_fsimptf" 18 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimptf,fhex")) - "z196_alone") - -(define_insn_reservation "z196_fmultf" 47 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fmultf")) - "z196_alone") - -(define_insn_reservation "z196_fsimpdf" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimpdf,fmuldf,fhex")) - "z196_simple") - -(define_insn_reservation "z196_fmadddf" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fmadddf")) - "z196_alone") - -(define_insn_reservation "z196_fsimpsf" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimpsf,fmulsf,fhex")) - "z196_simple") - -(define_insn_reservation "z196_fmaddsf" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fmaddsf")) - "z196_alone") - -(define_insn_reservation "z196_fdivtf" 108 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fdivtf,fsqrttf")) - "z196_alone") - -(define_insn_reservation "z196_fdivdf" 36 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fdivdf,fsqrtdf")) - "z196_simple") - -(define_insn_reservation "z196_fdivsf" 29 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fdivsf,fsqrtsf")) - "z196_simple") - - -;; Loads and stores are cheap as well. -(define_insn_reservation "z196_floaddf" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "floaddf")) - "z196_simple") - -(define_insn_reservation "z196_floadsf" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "floadsf")) - "z196_simple") - -(define_insn_reservation "z196_fstoredf" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fstoredf")) - "z196_simple") - -(define_insn_reservation "z196_fstoresf" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fstoresf")) - "z196_simple") - - -(define_insn_reservation "z196_ftrunctf" 9 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftrunctf")) - "z196_simple") - -(define_insn_reservation "z196_ftruncdf" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftruncdf")) - "z196_simple") - - -(define_insn_reservation "z196_ftoi" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftoi")) - "z196_crack") - -(define_insn_reservation "z196_itof" 7 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "itoftf,itofdf,itofsf")) - "z196_crack") - -;; -;; Decimal Floating Point -;; - -;; DDTR -(define_insn_reservation "z196_fdivdd" 33 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fdivdd")) - "z196_simple") - -;; DXTR -(define_insn_reservation "z196_fdivtd" 35 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fdivtd")) - "z196_alone") - -;; LEDTR -(define_insn_reservation "z196_ftruncsd" 34 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftruncsd")) - "z196_simple") - -;; LDXTR -(define_insn_reservation "z196_ftruncdd" 36 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftruncdd")) - "z196_simple") - -;; These are normal fp loads/stores - which are cheap. -(define_insn_reservation "z196_floadsddd" 0 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "floadsd,floaddd,fstoredd,fstoresd")) - "z196_simple") - -;; MDTR -(define_insn_reservation "z196_fmuldd" 23 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fmuldd")) - "z196_simple") - -;; MXTR -(define_insn_reservation "z196_fmultd" 25 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fmultd")) - "z196_alone") - -;; multiple different isns like add, sub etc. -;; Just use the same defaults as z10. -(define_insn_reservation "z196_fsimpsd" 17 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimpsd")) - "z196_simple") -(define_insn_reservation "z196_fsimpdd" 17 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimpdd")) - "z196_simple") -(define_insn_reservation "z196_fsimptd" 18 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "fsimptd")) - "z196_alone") - -;; CDGTR -(define_insn_reservation "z196_itofdd" 45 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "itofdd")) - "z196_crack") - -;; CXGTR -(define_insn_reservation "z196_itoftd" 33 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "itoftd")) - "z196_crack") - -;; CGXTR, CGDTR -(define_insn_reservation "z196_ftoidfp" 33 - (and (eq_attr "cpu" "z196") - (eq_attr "type" "ftoidfp")) - "z196_crack") - - - diff --git a/gcc-4.7/gcc/config/s390/constraints.md b/gcc-4.7/gcc/config/s390/constraints.md deleted file mode 100644 index 8564b6619..000000000 --- a/gcc-4.7/gcc/config/s390/constraints.md +++ /dev/null @@ -1,492 +0,0 @@ -;; Constraints definitions belonging to the gcc backend for IBM S/390. -;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. -;; Written by Wolfgang Gellerich, using code and information found in -;; files s390.md, s390.h, and s390.c. -;; -;; This file is part of GCC. -;; -;; GCC is free software; you can redistribute it and/or modify it under -;; the terms of the GNU General Public License as published by the Free -;; Software Foundation; either version 3, or (at your option) any later -;; version. -;; -;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - - -;; -;; Special constraints for s/390 machine description: -;; -;; a -- Any address register from 1 to 15. -;; b -- Memory operand whose address is a symbol reference or a symbol -;; reference + constant which can be proven to be naturally aligned. -;; c -- Condition code register 33. -;; d -- Any register from 0 to 15. -;; f -- Floating point registers. -;; t -- Access registers 36 and 37. -;; C -- A signed 8-bit constant (-128..127) -;; D -- An unsigned 16-bit constant (0..65535) -;; G -- Const double zero operand -;; I -- An 8-bit constant (0..255). -;; J -- A 12-bit constant (0..4095). -;; K -- A 16-bit constant (-32768..32767). -;; 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,x: 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. If the letter x -;; is specified instead of a part number, the constraint matches -;; if there is any single part with non-default value. -;; O -- Multiple letter constraint followed by 1 parameter. -;; s: Signed extended immediate value (-2G .. 2G-1). -;; p: Positive extended immediate value (0 .. 4G-1). -;; n: Negative extended immediate value (-4G+1 .. -1). -;; These constraints do not accept any operand if the machine does -;; not provide the extended-immediate facility. -;; P -- Any integer constant that can be loaded without literal pool. -;; 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. -;; A -- Multiple letter constraint followed by Q, R, S, or T: -;; Offsettable memory reference of type specified by second letter. -;; B -- Multiple letter constraint followed by Q, R, S, or T: -;; Memory reference of the type specified by second letter that -;; does *not* refer to a literal pool entry. -;; U -- Pointer with short displacement. (deprecated - use ZQZR) -;; W -- Pointer with long displacement. (deprecated - use ZSZT) -;; Y -- Shift count operand. -;; ZQ -- Pointer without index register and with short displacement. -;; ZR -- Pointer with index register and short displacement. -;; ZS -- Pointer without index register but with long displacement. -;; ZT -- Pointer with index register and long displacement. -;; -;; - - -;; -;; Register constraints. -;; - -(define_register_constraint "a" - "ADDR_REGS" - "Any address register from 1 to 15.") - - -(define_register_constraint "c" - "CC_REGS" - "Condition code register 33") - - -(define_register_constraint "d" - "GENERAL_REGS" - "Any register from 0 to 15") - - -(define_register_constraint "f" - "FP_REGS" - "Floating point registers") - - -(define_register_constraint "t" - "ACCESS_REGS" - "@internal - Access registers 36 and 37") - - -;; -;; General constraints for constants. -;; - -(define_constraint "C" - "@internal - An 8-bit signed immediate constant (-128..127)" - (and (match_code "const_int") - (match_test "ival >= -128 && ival <= 127"))) - - -(define_constraint "D" - "An unsigned 16-bit constant (0..65535)" - (and (match_code "const_int") - (match_test "ival >= 0 && ival <= 65535"))) - - -(define_constraint "G" - "@internal - Const double zero operand" - (and (match_code "const_double") - (match_test "s390_float_const_zero_p (op)"))) - - -(define_constraint "I" - "An 8-bit constant (0..255)" - (and (match_code "const_int") - (match_test "(unsigned HOST_WIDE_INT) ival <= 255"))) - - -(define_constraint "J" - "A 12-bit constant (0..4095)" - (and (match_code "const_int") - (match_test "(unsigned HOST_WIDE_INT) ival <= 4095"))) - - -(define_constraint "K" - "A 16-bit constant (-32768..32767)" - (and (match_code "const_int") - (match_test "ival >= -32768 && ival <= 32767"))) - - -(define_constraint "L" - "Value appropriate as displacement. - (0..4095) for short displacement - (-524288..524287) for long displacement" - (and (match_code "const_int") - (match_test "TARGET_LONG_DISPLACEMENT ? - (ival >= -524288 && ival <= 524287) - : (ival >= 0 && ival <= 4095)"))) - - -(define_constraint "M" - "Constant integer with a value of 0x7fffffff" - (and (match_code "const_int") - (match_test "ival == 2147483647"))) - - -(define_constraint "P" - "@internal - Any integer constant that can be loaded without literal pool" - (and (match_code "const_int") - (match_test "legitimate_reload_constant_p (GEN_INT (ival))"))) - - -(define_address_constraint "Y" - "Shift count operand" - -;; Simply check for the basic form of a shift count. Reload will -;; take care of making sure we have a proper base register. - - (match_test "s390_decompose_shift_count (op, NULL, NULL)" )) - - -;; N -- Multiple letter constraint followed by 4 parameter letters. -;; 0..9,x: 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. If the letter x -;; is specified instead of a part number, the constraint matches -;; if there is any single part with non-default value. -;; -;; The following patterns define only those constraints that are actually -;; used in s390.md. If you need an additional one, simply add it in the -;; obvious way. Function s390_N_constraint_str is ready to handle all -;; combinations. -;; - - -(define_constraint "NxQS0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQS0\", ival)"))) - - -(define_constraint "NxQD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQD0\", ival)"))) - - -(define_constraint "N3HD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"3HD0\", ival)"))) - - -(define_constraint "N2HD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"2HD0\", ival)"))) - - -(define_constraint "N1SD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1SD0\", ival)"))) - - -(define_constraint "N1HS0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1HS0\", ival)"))) - - -(define_constraint "N1HD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1HD0\", ival)"))) - - -(define_constraint "N0SD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0SD0\", ival)"))) - - -(define_constraint "N0HS0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0HS0\", ival)"))) - - -(define_constraint "N0HD0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0HD0\", ival)"))) - - -(define_constraint "NxQDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQDF\", ival)"))) - - -(define_constraint "N1SDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1SDF\", ival)"))) - - -(define_constraint "N0SDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0SDF\", ival)"))) - - -(define_constraint "N3HDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"3HDF\", ival)"))) - - -(define_constraint "N2HDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"2HDF\", ival)"))) - - -(define_constraint "N1HDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1HDF\", ival)"))) - - -(define_constraint "N0HDF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0HDF\", ival)"))) - - -(define_constraint "N0HSF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"0HSF\", ival)"))) - - -(define_constraint "N1HSF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"1HSF\", ival)"))) - - -(define_constraint "NxQSF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQSF\", ival)"))) - - -(define_constraint "NxQHF" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQHF\", ival)"))) - - -(define_constraint "NxQH0" - "@internal" - (and (match_code "const_int") - (match_test "s390_N_constraint_str (\"xQH0\", ival)"))) - - - - -;; -;; Double-letter constraints starting with O follow. -;; - - -(define_constraint "Os" - "@internal - Signed extended immediate value (-2G .. 2G-1). - This constraint will only match if the machine provides - the extended-immediate facility." - (and (match_code "const_int") - (match_test "s390_O_constraint_str ('s', ival)"))) - - -(define_constraint "Op" - "@internal - Positive extended immediate value (0 .. 4G-1). - This constraint will only match if the machine provides - the extended-immediate facility." - (and (match_code "const_int") - (match_test "s390_O_constraint_str ('p', ival)"))) - - -(define_constraint "On" - "@internal - Negative extended immediate value (-4G+1 .. -1). - This constraint will only match if the machine provides - the extended-immediate facility." - (and (match_code "const_int") - (match_test "s390_O_constraint_str ('n', ival)"))) - - - - -;; -;; Memory constraints follow. -;; - -(define_memory_constraint "Q" - "Memory reference without index register and with short displacement" - (match_test "s390_mem_constraint (\"Q\", op)")) - - -(define_memory_constraint "R" - "Memory reference with index register and short displacement" - (match_test "s390_mem_constraint (\"R\", op)")) - - -(define_memory_constraint "S" - "Memory reference without index register but with long displacement" - (match_test "s390_mem_constraint (\"S\", op)")) - - -(define_memory_constraint "T" - "Memory reference with index register and long displacement" - (match_test "s390_mem_constraint (\"T\", op)")) - - -(define_memory_constraint "b" - "Memory reference whose address is a naturally aligned symbol reference." - (match_test "MEM_P (op) - && s390_check_symref_alignment (XEXP (op, 0), - GET_MODE_SIZE (GET_MODE (op)))")) - -(define_memory_constraint "e" - "Matches all memory references available on the current architecture -level. This constraint will never be used and using it in an inline -assembly is *always* a bug since there is no instruction accepting all -those addresses. It just serves as a placeholder for a generic memory -constraint." - (match_test "strict_memory_address_p (GET_MODE (op), op)")) - -; This defines 'm' as normal memory constraint. This is only possible -; since the standard memory constraint is re-defined in s390.h using -; the TARGET_MEM_CONSTRAINT macro. -(define_memory_constraint "m" - "Matches the most general memory address for pre-z10 machines." - (match_test "s390_mem_constraint (\"R\", op) - || s390_mem_constraint (\"T\", op)")) - -(define_memory_constraint "AQ" - "@internal - Offsettable memory reference without index register and with short displacement" - (match_test "s390_mem_constraint (\"AQ\", op)")) - - -(define_memory_constraint "AR" - "@internal - Offsettable memory reference with index register and short displacement" - (match_test "s390_mem_constraint (\"AR\", op)")) - - -(define_memory_constraint "AS" - "@internal - Offsettable memory reference without index register but with long displacement" - (match_test "s390_mem_constraint (\"AS\", op)")) - - -(define_memory_constraint "AT" - "@internal - Offsettable memory reference with index register and long displacement" - (match_test "s390_mem_constraint (\"AT\", op)")) - - - -(define_constraint "BQ" - "@internal - Memory reference without index register and with short - displacement that does *not* refer to a literal pool entry." - (match_test "s390_mem_constraint (\"BQ\", op)")) - - -(define_constraint "BR" - "@internal - Memory reference with index register and short displacement that - does *not* refer to a literal pool entry. " - (match_test "s390_mem_constraint (\"BR\", op)")) - - -(define_constraint "BS" - "@internal - Memory reference without index register but with long displacement - that does *not* refer to a literal pool entry. " - (match_test "s390_mem_constraint (\"BS\", op)")) - - -(define_constraint "BT" - "@internal - Memory reference with index register and long displacement that - does *not* refer to a literal pool entry. " - (match_test "s390_mem_constraint (\"BT\", op)")) - - -(define_address_constraint "U" - "Pointer with short displacement. (deprecated - use ZQZR)" - (match_test "s390_mem_constraint (\"U\", op)")) - -(define_address_constraint "W" - "Pointer with long displacement. (deprecated - use ZSZT)" - (match_test "s390_mem_constraint (\"W\", op)")) - - -(define_address_constraint "ZQ" - "Pointer without index register and with short displacement." - (match_test "s390_mem_constraint (\"ZQ\", op)")) - -(define_address_constraint "ZR" - "Pointer with index register and short displacement." - (match_test "s390_mem_constraint (\"ZR\", op)")) - -(define_address_constraint "ZS" - "Pointer without index register but with long displacement." - (match_test "s390_mem_constraint (\"ZS\", op)")) - -(define_address_constraint "ZT" - "Pointer with index register and long displacement." - (match_test "s390_mem_constraint (\"ZT\", op)")) diff --git a/gcc-4.7/gcc/config/s390/linux.h b/gcc-4.7/gcc/config/s390/linux.h deleted file mode 100644 index e5385eca3..000000000 --- a/gcc-4.7/gcc/config/s390/linux.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Definitions for Linux for S/390. - Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2010, 2011 - 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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef _LINUX_H -#define _LINUX_H - -/* Target specific type definitions. */ - -/* ??? Do we really want long as size_t on 31-bit? */ -#undef SIZE_TYPE -#define SIZE_TYPE (TARGET_64BIT ? "long unsigned int" : "long unsigned int") -#undef PTRDIFF_TYPE -#define PTRDIFF_TYPE (TARGET_64BIT ? "long int" : "int") - -#undef WCHAR_TYPE -#define WCHAR_TYPE "int" -#undef WCHAR_TYPE_SIZE -#define WCHAR_TYPE_SIZE 32 - - -/* Target specific preprocessor settings. */ - -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - GNU_USER_TARGET_OS_CPP_BUILTINS(); \ - } \ - while (0) - - -/* Target specific assembler settings. */ - -#undef ASM_SPEC -#define ASM_SPEC "%{m31&m64}%{mesa&mzarch}%{march=*}" - - -/* Target specific linker settings. */ - -#ifdef DEFAULT_TARGET_64BIT -#define MULTILIB_DEFAULTS { "m64" } -#else -#define MULTILIB_DEFAULTS { "m31" } -#endif - -#define GLIBC_DYNAMIC_LINKER32 "/lib/ld.so.1" -#define GLIBC_DYNAMIC_LINKER64 "/lib/ld64.so.1" - -#undef LINK_SPEC -#define LINK_SPEC \ - "%{m31:-m elf_s390}%{m64:-m elf64_s390} \ - %{shared:-shared} \ - %{!shared: \ - %{static:-static} \ - %{!static: \ - %{rdynamic:-export-dynamic} \ - %{m31:-dynamic-linker " GNU_USER_DYNAMIC_LINKER32 "} \ - %{m64:-dynamic-linker " GNU_USER_DYNAMIC_LINKER64 "}}}" - -#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" - -#define TARGET_ASM_FILE_END file_end_indicate_exec_stack - -#ifdef TARGET_LIBC_PROVIDES_SSP -/* s390 glibc provides __stack_chk_guard in 0x14(tp), - s390x glibc provides it at 0x28(tp). */ -#define TARGET_THREAD_SSP_OFFSET (TARGET_64BIT ? 0x28 : 0x14) -#endif - -/* Define if long doubles should be mangled as 'g'. */ -#define TARGET_ALTERNATE_LONG_DOUBLE_MANGLING - -#endif diff --git a/gcc-4.7/gcc/config/s390/predicates.md b/gcc-4.7/gcc/config/s390/predicates.md deleted file mode 100644 index 9d619fbc0..000000000 --- a/gcc-4.7/gcc/config/s390/predicates.md +++ /dev/null @@ -1,406 +0,0 @@ -;; Predicate definitions for S/390 and zSeries. -;; Copyright (C) 2005, 2007, 2008 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; OP is the current operation. -;; MODE is the current operation mode. - -;; operands -------------------------------------------------------------- - -;; Return true if OP a (const_int 0) operand. - -(define_predicate "const0_operand" - (and (match_code "const_int, const_double") - (match_test "op == CONST0_RTX (mode)"))) - -;; Return true if OP is constant. - -(define_special_predicate "consttable_operand" - (and (match_code "symbol_ref, label_ref, const, const_int, const_double") - (match_test "CONSTANT_P (op)"))) - -;; Return true if OP is a valid S-type operand. - -(define_predicate "s_operand" - (and (match_code "subreg, mem") - (match_operand 0 "general_operand")) -{ - /* Just like memory_operand, allow (subreg (mem ...)) - after reload. */ - if (reload_completed - && GET_CODE (op) == SUBREG - && GET_CODE (SUBREG_REG (op)) == MEM) - op = SUBREG_REG (op); - - if (GET_CODE (op) != MEM) - return false; - if (!s390_legitimate_address_without_index_p (op)) - return false; - - return true; -}) - -;; Return true if OP is a valid operand for the BRAS instruction. -;; Allow SYMBOL_REFs and @PLT stubs. - -(define_special_predicate "bras_sym_operand" - (ior (and (match_code "symbol_ref") - (match_test "!flag_pic || SYMBOL_REF_LOCAL_P (op)")) - (and (match_code "const") - (and (match_test "GET_CODE (XEXP (op, 0)) == UNSPEC") - (match_test "XINT (XEXP (op, 0), 1) == UNSPEC_PLT"))))) - -;; Return true if OP is a PLUS that is not a legitimate -;; operand for the LA instruction. - -(define_predicate "s390_plus_operand" - (and (match_code "plus") - (and (match_test "mode == Pmode") - (match_test "!legitimate_la_operand_p (op)")))) - -;; Return true if OP is a valid operand as shift count or setmem. - -(define_predicate "shift_count_or_setmem_operand" - (match_code "reg, subreg, plus, const_int") -{ - HOST_WIDE_INT offset; - rtx base; - - /* Extract base register and offset. */ - if (!s390_decompose_shift_count (op, &base, &offset)) - return false; - - /* Don't allow any non-base hard registers. Doing so without - confusing reload and/or regrename would be tricky, and doesn't - buy us much anyway. */ - if (base && REGNO (base) < FIRST_PSEUDO_REGISTER && !ADDR_REG_P (base)) - return false; - - /* Unfortunately we have to reject constants that are invalid - for an address, or else reload will get confused. */ - if (!DISP_IN_RANGE (offset)) - return false; - - return true; -}) - -;; Return true if OP a valid operand for the LARL instruction. - -(define_predicate "larl_operand" - (match_code "label_ref, symbol_ref, const, const_int, const_double") -{ - /* Allow labels and local symbols. */ - if (GET_CODE (op) == LABEL_REF) - return true; - if (GET_CODE (op) == SYMBOL_REF) - return (!SYMBOL_REF_ALIGN1_P (op) - && 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 false; - op = XEXP (op, 0); - - /* 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 false; - if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 31 - || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 31)) - return false; - op = XEXP (op, 0); - } - - /* Labels and local symbols allowed here as well. */ - if (GET_CODE (op) == LABEL_REF) - return true; - 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) == UNSPEC_GOTENT) - return true; - if (GET_CODE (op) == UNSPEC - && XINT (op, 1) == UNSPEC_PLT) - return true; - if (GET_CODE (op) == UNSPEC - && XINT (op, 1) == UNSPEC_INDNTPOFF) - return true; - - return false; -}) - -;; operators -------------------------------------------------------------- - -;; Return nonzero if OP is a valid comparison operator -;; for a branch condition. - -(define_predicate "s390_comparison" - (match_code "eq, ne, lt, gt, le, ge, ltu, gtu, leu, geu, - uneq, unlt, ungt, unle, unge, ltgt, - unordered, ordered") -{ - if (GET_CODE (XEXP (op, 0)) != REG - || REGNO (XEXP (op, 0)) != CC_REGNUM - || XEXP (op, 1) != const0_rtx) - return false; - - return (s390_branch_condition_mask (op) >= 0); -}) - -;; Return true if op is the cc register. -(define_predicate "cc_reg_operand" - (and (match_code "reg") - (match_test "REGNO (op) == CC_REGNUM"))) - -(define_predicate "s390_signed_integer_comparison" - (match_code "eq, ne, lt, gt, le, ge") -{ - return (s390_compare_and_branch_condition_mask (op) >= 0); -}) - -(define_predicate "s390_unsigned_integer_comparison" - (match_code "eq, ne, ltu, gtu, leu, geu") -{ - return (s390_compare_and_branch_condition_mask (op) >= 0); -}) - -;; Return nonzero if OP is a valid comparison operator for the -;; cstore expanders -- respectively cstorecc4 and integer cstore. -(define_predicate "s390_eqne_operator" - (match_code "eq, ne")) - -(define_predicate "s390_scond_operator" - (match_code "ltu, gtu, leu, geu")) - -(define_predicate "s390_brx_operator" - (match_code "le, gt")) - -;; Return nonzero if OP is a valid comparison operator -;; for an ALC condition. - -(define_predicate "s390_alc_comparison" - (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu") -{ - while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND) - op = XEXP (op, 0); - - if (!COMPARISON_P (op)) - return false; - - if (GET_CODE (XEXP (op, 0)) != REG - || REGNO (XEXP (op, 0)) != CC_REGNUM - || XEXP (op, 1) != const0_rtx) - return false; - - switch (GET_MODE (XEXP (op, 0))) - { - case CCL1mode: - return GET_CODE (op) == LTU; - - case CCL2mode: - return GET_CODE (op) == LEU; - - case CCL3mode: - return GET_CODE (op) == GEU; - - 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 false; - } -}) - -;; Return nonzero if OP is a valid comparison operator -;; for an SLB condition. - -(define_predicate "s390_slb_comparison" - (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu") -{ - while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND) - op = XEXP (op, 0); - - if (!COMPARISON_P (op)) - return false; - - if (GET_CODE (XEXP (op, 0)) != REG - || REGNO (XEXP (op, 0)) != CC_REGNUM - || XEXP (op, 1) != const0_rtx) - return false; - - switch (GET_MODE (XEXP (op, 0))) - { - case CCL1mode: - return GET_CODE (op) == GEU; - - case CCL2mode: - return GET_CODE (op) == GTU; - - case CCL3mode: - return GET_CODE (op) == LTU; - - 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 false; - } -}) - -;; Return true if OP is a load multiple operation. It is known to be a -;; PARALLEL and the first section will be tested. - -(define_special_predicate "load_multiple_operation" - (match_code "parallel") -{ - enum machine_mode elt_mode; - int count = XVECLEN (op, 0); - unsigned int dest_regno; - rtx src_addr; - int i, off; - - /* Perform a quick check so we don't blow up below. */ - if (count <= 1 - || GET_CODE (XVECEXP (op, 0, 0)) != SET - || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG - || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM) - return false; - - 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, 1)) == CONST_INT) - { - off = INTVAL (XEXP (src_addr, 1)); - src_addr = XEXP (src_addr, 0); - } - else - return false; - - for (i = 1; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i); - - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != REG - || 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)) != 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 * GET_MODE_SIZE (elt_mode)) - return false; - } - - return true; -}) - -;; Return true if OP is a store multiple operation. It is known to be a -;; PARALLEL and the first section will be tested. - -(define_special_predicate "store_multiple_operation" - (match_code "parallel") -{ - enum machine_mode elt_mode; - int count = XVECLEN (op, 0); - unsigned int src_regno; - rtx dest_addr; - int i, off; - - /* Perform a quick check so we don't blow up below. */ - if (count <= 1 - || GET_CODE (XVECEXP (op, 0, 0)) != SET - || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM - || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG) - return false; - - 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, 1)) == CONST_INT) - { - off = INTVAL (XEXP (dest_addr, 1)); - dest_addr = XEXP (dest_addr, 0); - } - else - return false; - - for (i = 1; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i); - - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != REG - || 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)) != 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 * GET_MODE_SIZE (elt_mode)) - return false; - } - return true; -}) diff --git a/gcc-4.7/gcc/config/s390/s390-modes.def b/gcc-4.7/gcc/config/s390/s390-modes.def deleted file mode 100644 index be2bf6ea7..000000000 --- a/gcc-4.7/gcc/config/s390/s390-modes.def +++ /dev/null @@ -1,174 +0,0 @@ -/* Definitions of target machine for GNU compiler, for IBM S/390 - Copyright (C) 2002, 2003, 2004, 2005, 2007 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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* 256-bit integer mode is needed for STACK_SAVEAREA_MODE. */ -INT_MODE (OI, 32); - -/* Define TFmode to work around reload problem PR 20927. */ -FLOAT_MODE (TF, 16, ieee_quad_format); - -/* Add any extra modes needed to represent the condition code. */ - -/* - -Condition Codes - -Check for zero - -CCZ: EQ NE NE NE -CCZ1: EQ NE (CS) - -Unsigned compares - -CCU: EQ LTU GTU NE (CLG/R, CL/R/Y, CLM/Y, CLI/Y) -CCUR: EQ GTU LTU NE (CLGF/R) - -Signed compares - -CCS: EQ LT GT UNORDERED (LTGFR, LTGR, LTR, ICM/Y, - LTDBR, LTDR, LTEBR, LTER, - CG/R, C/R/Y, CGHI, CHI, - CDB/R, CD/R, CEB/R, CE/R, - ADB/R, AEB/R, SDB/R, SEB/R, - SRAG, SRA, SRDA) -CCSR: EQ GT LT UNORDERED (CGF/R, CH/Y) - -Condition codes resulting from add with overflow - -CCA: EQ LT GT Overflow -CCAP: EQ LT GT LT (AGHI, AHI) -CCAN: EQ LT GT GT (AGHI, AHI) - -Condition codes of unsigned adds and subs - -CCL: EQ NE EQ NE (ALGF/R, ALG/R, AL/R/Y, - ALCG/R, ALC/R, - SLGF/R, SLG/R, SL/R/Y, - SLBG/R, SLB/R) -CCL1: GEU GEU LTU LTU (ALG/R, AL/R/Y) -CCL2: GTU GTU LEU LEU (SLG/R, SL/R/Y) -CCL3: EQ LTU EQ GTU (SLG/R, SL/R/Y) - -Test under mask checks - -CCT: EQ NE NE NE (ICM/Y, TML, CG/R, CGHI, - C/R/Y, CHI, NG/R, N/R/Y, - OG/R, O/R/Y, XG/R, X/R/Y) -CCT1: NE EQ NE NE (TMH, TML) -CCT2: NE NE EQ NE (TMH, TML) -CCT3: NE NE NE EQ (TMH, TML) - -CCA and CCT modes are request only modes. These modes are never returned by -s390_select_cc_mode. They are only intended to match other modes. - -Requested mode -> Destination CC register mode - -CCS, CCU, CCT, CCSR, CCUR -> CCZ -CCA -> CCAP, CCAN - - -*** Comments *** - -CCAP, CCAN - -The CC obtained from add instruction usually can't be used for comparisons -because its coupling with overflow flag. In case of an overflow the -less than/greater than data are lost. Nevertheless a comparison can be done -whenever immediate values are involved because they are known at compile time. -If you know whether the used constant is positive or negative you can predict -the sign of the result even in case of an overflow. - - -CCT, CCT1, CCT2, CCT3 - -If bits of an integer masked with an AND instruction are checked, the test under -mask instructions turn out to be very handy for a set of special cases. -The simple cases are checks whether all masked bits are zero or ones: - - int a; - if ((a & (16 + 128)) == 0) -> CCT/CCZ - if ((a & (16 + 128)) == 16 + 128) -> CCT3 - -Using two extra modes makes it possible to do complete checks on two bits of an -integer (This is possible on register operands only. TM does not provide the -information necessary for CCT1 and CCT2 modes.): - - int a; - if ((a & (16 + 128)) == 16) -> CCT1 - if ((a & (16 + 128)) == 128) -> CCT2 - - -CCSR, CCUR - -There are several instructions comparing 32 bit with 64-bit unsigned/signed -values. Such instructions can be considered to have a builtin zero/sign_extend. -The problem is that in the RTL (to be canonical) the zero/sign extended operand -has to be the first one but the machine instructions like it the other way -around. The following both modes can be considered as CCS and CCU modes with -exchanged operands. - - -CCL1, CCL2 - -These modes represent the result of overflow checks. - -if (a + b < a) -> CCL1 state of the carry bit (CC2 | CC3) -if (a - b > a) -> CCL2 state of the borrow bit (CC0 | CC1) - -They are used when multi word numbers are computed dealing one SImode part after -another or whenever manual overflow checks like the examples above are -compiled. - - -CCL3 - -A logical subtract instruction sets the borrow bit in case of an overflow. -The resulting condition code of those instructions is represented by the -CCL3 mode. Together with the CCU mode this mode is used for jumpless -implementations of several if-constructs - see s390_expand_addcc for more -details. - -CCZ1 - -The compare and swap instructions sets the condition code to 0/1 if the -operands were equal/unequal. The CCZ1 mode ensures the result can be -effectively placed into a register. - -*/ - - -CC_MODE (CCZ); -CC_MODE (CCZ1); -CC_MODE (CCA); -CC_MODE (CCAP); -CC_MODE (CCAN); -CC_MODE (CCL); -CC_MODE (CCL1); -CC_MODE (CCL2); -CC_MODE (CCL3); -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/gcc-4.7/gcc/config/s390/s390-opts.h b/gcc-4.7/gcc/config/s390/s390-opts.h deleted file mode 100644 index 668aaaa84..000000000 --- a/gcc-4.7/gcc/config/s390/s390-opts.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Definitions for option handling for IBM S/390. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef S390_OPTS_H -#define S390_OPTS_H - -/* 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_2094_Z9_109, - PROCESSOR_2094_Z9_EC, - PROCESSOR_2097_Z10, - PROCESSOR_2817_Z196, - PROCESSOR_max -}; - -#endif diff --git a/gcc-4.7/gcc/config/s390/s390-protos.h b/gcc-4.7/gcc/config/s390/s390-protos.h deleted file mode 100644 index 01a3584fe..000000000 --- a/gcc-4.7/gcc/config/s390/s390-protos.h +++ /dev/null @@ -1,113 +0,0 @@ -/* Definitions of target machine for GNU compiler, for IBM S/390. - Copyright (C) 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. - - Contributed by Hartmut Penner (hpenner@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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - - -/* Prototypes of functions used for constraint evaluation in - constraints.c. */ - -extern int s390_mem_constraint (const char *str, rtx op); -extern int s390_O_constraint_str (const char c, HOST_WIDE_INT value); -extern int s390_N_constraint_str (const char *str, HOST_WIDE_INT value); -extern int s390_float_const_zero_p (rtx value); -extern bool s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment); - - -/* Declare functions in s390.c. */ - -extern HOST_WIDE_INT s390_initial_elimination_offset (int, int); -extern void s390_emit_prologue (void); -extern void s390_emit_epilogue (bool); -extern void s390_function_profiler (FILE *, int); -extern void s390_set_has_landing_pad_p (bool); -extern bool s390_hard_regno_mode_ok (unsigned int, enum machine_mode); -extern bool s390_hard_regno_rename_ok (unsigned int, unsigned int); -extern int s390_class_max_nregs (enum reg_class, enum machine_mode); - -#ifdef RTX_CODE -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 s390_const_double_ok_for_constraint_p (rtx, int, const char *); -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_contiguous_bitmask_p (unsigned HOST_WIDE_INT, int, int *, int *); -extern bool s390_split_ok_p (rtx, rtx, enum machine_mode, int); -extern bool s390_overlap_p (rtx, rtx, HOST_WIDE_INT); -extern bool s390_offset_p (rtx, rtx, rtx); -extern int tls_symbolic_operand (rtx); - -extern bool s390_match_ccmode (rtx, enum machine_mode); -extern enum machine_mode s390_tm_ccmode (rtx, rtx, bool); -extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx); -extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *); -extern rtx s390_emit_compare (enum rtx_code, rtx, rtx); -extern void s390_emit_jump (rtx, rtx); -extern bool symbolic_reference_mentioned_p (rtx); -extern bool tls_symbolic_reference_mentioned_p (rtx); -extern bool legitimate_la_operand_p (rtx); -extern bool preferred_la_operand_p (rtx, rtx); -extern int legitimate_pic_operand_p (rtx); -extern bool legitimate_reload_constant_p (rtx); -extern rtx legitimize_pic_address (rtx, rtx); -extern rtx legitimize_reload_address (rtx, enum machine_mode, int, int); -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 void s390_reload_larl_operand (rtx , rtx , rtx); -extern void s390_reload_symref_address (rtx , rtx , rtx , bool); -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_movmem (rtx, rtx, rtx); -extern void s390_expand_setmem (rtx, rtx, rtx); -extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx); -extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx); -extern bool s390_expand_insv (rtx, rtx, rtx, rtx); -extern void s390_expand_cs_hqi (enum machine_mode, rtx, rtx, rtx, rtx); -extern void s390_expand_atomic (enum machine_mode, enum rtx_code, - rtx, rtx, rtx, bool); -extern rtx s390_return_addr_rtx (int, rtx); -extern rtx s390_back_chain_rtx (void); -extern rtx s390_emit_call (rtx, rtx, rtx, rtx); -extern void s390_expand_logical_operator (enum rtx_code, - enum machine_mode, rtx *); -extern bool s390_logical_operator_ok_p (rtx *); -extern void s390_narrow_logical_operator (enum rtx_code, rtx *, rtx *); -extern void s390_split_access_reg (rtx, rtx *, rtx *); - -extern void print_operand_address (FILE *, rtx); -extern void print_operand (FILE *, rtx, int); -extern void s390_output_pool_entry (rtx, enum machine_mode, unsigned int); -extern int s390_label_align (rtx); -extern int s390_agen_dep_p (rtx, rtx); -extern rtx s390_load_got (void); -extern rtx s390_get_thread_pointer (void); -extern void s390_emit_tpf_eh_return (rtx); -extern bool s390_legitimate_address_without_index_p (rtx); -extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *); -extern int s390_branch_condition_mask (rtx); -extern int s390_compare_and_branch_condition_mask (rtx); - -#endif /* RTX_CODE */ diff --git a/gcc-4.7/gcc/config/s390/s390.c b/gcc-4.7/gcc/config/s390/s390.c deleted file mode 100644 index d6e250fd5..000000000 --- a/gcc-4.7/gcc/config/s390/s390.c +++ /dev/null @@ -1,10793 +0,0 @@ -/* Subroutines used for code generation on IBM S/390 and zSeries - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. - Contributed by Hartmut Penner (hpenner@de.ibm.com) and - Ulrich Weigand (uweigand@de.ibm.com) and - Andreas Krebbel (Andreas.Krebbel@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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "tree.h" -#include "tm_p.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.h" -#include "output.h" -#include "insn-attr.h" -#include "flags.h" -#include "except.h" -#include "function.h" -#include "recog.h" -#include "expr.h" -#include "reload.h" -#include "diagnostic-core.h" -#include "basic-block.h" -#include "integrate.h" -#include "ggc.h" -#include "target.h" -#include "target-def.h" -#include "debug.h" -#include "langhooks.h" -#include "optabs.h" -#include "gimple.h" -#include "df.h" -#include "params.h" -#include "cfgloop.h" -#include "opts.h" - -/* Define the specific costs for a given cpu. */ - -struct processor_costs -{ - /* multiplication */ - const int m; /* cost of an M instruction. */ - const int mghi; /* cost of an MGHI instruction. */ - const int mh; /* cost of an MH instruction. */ - const int mhi; /* cost of an MHI instruction. */ - const int ml; /* cost of an ML instruction. */ - const int mr; /* cost of an MR instruction. */ - const int ms; /* cost of an MS instruction. */ - const int msg; /* cost of an MSG instruction. */ - const int msgf; /* cost of an MSGF instruction. */ - const int msgfr; /* cost of an MSGFR instruction. */ - const int msgr; /* cost of an MSGR instruction. */ - const int msr; /* cost of an MSR instruction. */ - const int mult_df; /* cost of multiplication in DFmode. */ - const int mxbr; - /* square root */ - const int sqxbr; /* cost of square root in TFmode. */ - const int sqdbr; /* cost of square root in DFmode. */ - const int sqebr; /* cost of square root in SFmode. */ - /* multiply and add */ - const int madbr; /* cost of multiply and add in DFmode. */ - const int maebr; /* cost of multiply and add in SFmode. */ - /* division */ - const int dxbr; - const int ddbr; - const int debr; - const int dlgr; - const int dlr; - const int dr; - const int dsgfr; - const int dsgr; -}; - -const struct processor_costs *s390_cost; - -static const -struct processor_costs z900_cost = -{ - COSTS_N_INSNS (5), /* M */ - COSTS_N_INSNS (10), /* MGHI */ - COSTS_N_INSNS (5), /* MH */ - COSTS_N_INSNS (4), /* MHI */ - COSTS_N_INSNS (5), /* ML */ - COSTS_N_INSNS (5), /* MR */ - COSTS_N_INSNS (4), /* MS */ - COSTS_N_INSNS (15), /* MSG */ - COSTS_N_INSNS (7), /* MSGF */ - COSTS_N_INSNS (7), /* MSGFR */ - COSTS_N_INSNS (10), /* MSGR */ - COSTS_N_INSNS (4), /* MSR */ - COSTS_N_INSNS (7), /* multiplication in DFmode */ - COSTS_N_INSNS (13), /* MXBR */ - COSTS_N_INSNS (136), /* SQXBR */ - COSTS_N_INSNS (44), /* SQDBR */ - COSTS_N_INSNS (35), /* SQEBR */ - COSTS_N_INSNS (18), /* MADBR */ - COSTS_N_INSNS (13), /* MAEBR */ - COSTS_N_INSNS (134), /* DXBR */ - COSTS_N_INSNS (30), /* DDBR */ - COSTS_N_INSNS (27), /* DEBR */ - COSTS_N_INSNS (220), /* DLGR */ - COSTS_N_INSNS (34), /* DLR */ - COSTS_N_INSNS (34), /* DR */ - COSTS_N_INSNS (32), /* DSGFR */ - COSTS_N_INSNS (32), /* DSGR */ -}; - -static const -struct processor_costs z990_cost = -{ - COSTS_N_INSNS (4), /* M */ - COSTS_N_INSNS (2), /* MGHI */ - COSTS_N_INSNS (2), /* MH */ - COSTS_N_INSNS (2), /* MHI */ - COSTS_N_INSNS (4), /* ML */ - COSTS_N_INSNS (4), /* MR */ - COSTS_N_INSNS (5), /* MS */ - COSTS_N_INSNS (6), /* MSG */ - COSTS_N_INSNS (4), /* MSGF */ - COSTS_N_INSNS (4), /* MSGFR */ - COSTS_N_INSNS (4), /* MSGR */ - COSTS_N_INSNS (4), /* MSR */ - COSTS_N_INSNS (1), /* multiplication in DFmode */ - COSTS_N_INSNS (28), /* MXBR */ - COSTS_N_INSNS (130), /* SQXBR */ - COSTS_N_INSNS (66), /* SQDBR */ - COSTS_N_INSNS (38), /* SQEBR */ - COSTS_N_INSNS (1), /* MADBR */ - COSTS_N_INSNS (1), /* MAEBR */ - COSTS_N_INSNS (60), /* DXBR */ - COSTS_N_INSNS (40), /* DDBR */ - COSTS_N_INSNS (26), /* DEBR */ - COSTS_N_INSNS (176), /* DLGR */ - COSTS_N_INSNS (31), /* DLR */ - COSTS_N_INSNS (31), /* DR */ - COSTS_N_INSNS (31), /* DSGFR */ - COSTS_N_INSNS (31), /* DSGR */ -}; - -static const -struct processor_costs z9_109_cost = -{ - COSTS_N_INSNS (4), /* M */ - COSTS_N_INSNS (2), /* MGHI */ - COSTS_N_INSNS (2), /* MH */ - COSTS_N_INSNS (2), /* MHI */ - COSTS_N_INSNS (4), /* ML */ - COSTS_N_INSNS (4), /* MR */ - COSTS_N_INSNS (5), /* MS */ - COSTS_N_INSNS (6), /* MSG */ - COSTS_N_INSNS (4), /* MSGF */ - COSTS_N_INSNS (4), /* MSGFR */ - COSTS_N_INSNS (4), /* MSGR */ - COSTS_N_INSNS (4), /* MSR */ - COSTS_N_INSNS (1), /* multiplication in DFmode */ - COSTS_N_INSNS (28), /* MXBR */ - COSTS_N_INSNS (130), /* SQXBR */ - COSTS_N_INSNS (66), /* SQDBR */ - COSTS_N_INSNS (38), /* SQEBR */ - COSTS_N_INSNS (1), /* MADBR */ - COSTS_N_INSNS (1), /* MAEBR */ - COSTS_N_INSNS (60), /* DXBR */ - COSTS_N_INSNS (40), /* DDBR */ - COSTS_N_INSNS (26), /* DEBR */ - COSTS_N_INSNS (30), /* DLGR */ - COSTS_N_INSNS (23), /* DLR */ - COSTS_N_INSNS (23), /* DR */ - COSTS_N_INSNS (24), /* DSGFR */ - COSTS_N_INSNS (24), /* DSGR */ -}; - -static const -struct processor_costs z10_cost = -{ - COSTS_N_INSNS (10), /* M */ - COSTS_N_INSNS (10), /* MGHI */ - COSTS_N_INSNS (10), /* MH */ - COSTS_N_INSNS (10), /* MHI */ - COSTS_N_INSNS (10), /* ML */ - COSTS_N_INSNS (10), /* MR */ - COSTS_N_INSNS (10), /* MS */ - COSTS_N_INSNS (10), /* MSG */ - COSTS_N_INSNS (10), /* MSGF */ - COSTS_N_INSNS (10), /* MSGFR */ - COSTS_N_INSNS (10), /* MSGR */ - COSTS_N_INSNS (10), /* MSR */ - COSTS_N_INSNS (1) , /* multiplication in DFmode */ - COSTS_N_INSNS (50), /* MXBR */ - COSTS_N_INSNS (120), /* SQXBR */ - COSTS_N_INSNS (52), /* SQDBR */ - COSTS_N_INSNS (38), /* SQEBR */ - COSTS_N_INSNS (1), /* MADBR */ - COSTS_N_INSNS (1), /* MAEBR */ - COSTS_N_INSNS (111), /* DXBR */ - COSTS_N_INSNS (39), /* DDBR */ - COSTS_N_INSNS (32), /* DEBR */ - COSTS_N_INSNS (160), /* DLGR */ - COSTS_N_INSNS (71), /* DLR */ - COSTS_N_INSNS (71), /* DR */ - COSTS_N_INSNS (71), /* DSGFR */ - COSTS_N_INSNS (71), /* DSGR */ -}; - -static const -struct processor_costs z196_cost = -{ - COSTS_N_INSNS (7), /* M */ - COSTS_N_INSNS (5), /* MGHI */ - COSTS_N_INSNS (5), /* MH */ - COSTS_N_INSNS (5), /* MHI */ - COSTS_N_INSNS (7), /* ML */ - COSTS_N_INSNS (7), /* MR */ - COSTS_N_INSNS (6), /* MS */ - COSTS_N_INSNS (8), /* MSG */ - COSTS_N_INSNS (6), /* MSGF */ - COSTS_N_INSNS (6), /* MSGFR */ - COSTS_N_INSNS (8), /* MSGR */ - COSTS_N_INSNS (6), /* MSR */ - COSTS_N_INSNS (1) , /* multiplication in DFmode */ - COSTS_N_INSNS (40), /* MXBR B+40 */ - COSTS_N_INSNS (100), /* SQXBR B+100 */ - COSTS_N_INSNS (42), /* SQDBR B+42 */ - COSTS_N_INSNS (28), /* SQEBR B+28 */ - COSTS_N_INSNS (1), /* MADBR B */ - COSTS_N_INSNS (1), /* MAEBR B */ - COSTS_N_INSNS (101), /* DXBR B+101 */ - COSTS_N_INSNS (29), /* DDBR */ - COSTS_N_INSNS (22), /* DEBR */ - COSTS_N_INSNS (160), /* DLGR cracked */ - COSTS_N_INSNS (160), /* DLR cracked */ - COSTS_N_INSNS (160), /* DR expanded */ - COSTS_N_INSNS (160), /* DSGFR cracked */ - COSTS_N_INSNS (160), /* DSGR cracked */ -}; - -extern int reload_completed; - -/* Kept up to date using the SCHED_VARIABLE_ISSUE hook. */ -static rtx last_scheduled_insn; - -/* Structure used to hold the components of a S/390 memory - address. A legitimate address on S/390 is of the general - form - base + index + displacement - where any of the components is optional. - - base and index are registers of the class ADDR_REGS, - displacement is an unsigned 12-bit immediate constant. */ - -struct s390_address -{ - rtx base; - rtx indx; - rtx disp; - bool pointer; - bool literal_pool; -}; - -/* The following structure is embedded in the machine - specific part of struct function. */ - -struct GTY (()) s390_frame_layout -{ - /* Offset within stack frame. */ - HOST_WIDE_INT gprs_offset; - HOST_WIDE_INT f0_offset; - HOST_WIDE_INT f4_offset; - HOST_WIDE_INT f8_offset; - HOST_WIDE_INT backchain_offset; - - /* Number of first and last gpr where slots in the register - save area are reserved for. */ - int first_save_gpr_slot; - int last_save_gpr_slot; - - /* Number of first and last gpr to be saved, restored. */ - int first_save_gpr; - int first_restore_gpr; - int last_save_gpr; - int last_restore_gpr; - - /* Bits standing for floating point registers. Set, if the - respective register has to be saved. Starting with reg 16 (f0) - at the rightmost bit. - Bit 15 - 8 7 6 5 4 3 2 1 0 - fpr 15 - 8 7 5 3 1 6 4 2 0 - reg 31 - 24 23 22 21 20 19 18 17 16 */ - unsigned int fpr_bitmap; - - /* Number of floating point registers f8-f15 which must be saved. */ - int high_fprs; - - /* Set if return address needs to be saved. - This flag is set by s390_return_addr_rtx if it could not use - the initial value of r14 and therefore depends on r14 saved - to the stack. */ - bool save_return_addr_p; - - /* Size of stack frame. */ - HOST_WIDE_INT frame_size; -}; - -/* Define the structure for the machine field in struct function. */ - -struct GTY(()) machine_function -{ - struct s390_frame_layout frame_layout; - - /* Literal pool base register. */ - rtx base_reg; - - /* True if we may need to perform branch splitting. */ - bool split_branches_pending_p; - - /* Some local-dynamic TLS symbol name. */ - const char *some_ld_name; - - bool has_landing_pad_p; -}; - -/* Few accessor macros for struct cfun->machine->s390_frame_layout. */ - -#define cfun_frame_layout (cfun->machine->frame_layout) -#define cfun_save_high_fprs_p (!!cfun_frame_layout.high_fprs) -#define cfun_gprs_save_area_size ((cfun_frame_layout.last_save_gpr_slot - \ - cfun_frame_layout.first_save_gpr_slot + 1) * UNITS_PER_LONG) -#define cfun_set_fpr_bit(BITNUM) (cfun->machine->frame_layout.fpr_bitmap |= \ - (1 << (BITNUM))) -#define cfun_fpr_bit_p(BITNUM) (!!(cfun->machine->frame_layout.fpr_bitmap & \ - (1 << (BITNUM)))) - -/* Number of GPRs and FPRs used for argument passing. */ -#define GP_ARG_NUM_REG 5 -#define FP_ARG_NUM_REG (TARGET_64BIT? 4 : 2) - -/* A couple of shortcuts. */ -#define CONST_OK_FOR_J(x) \ - CONST_OK_FOR_CONSTRAINT_P((x), 'J', "J") -#define CONST_OK_FOR_K(x) \ - CONST_OK_FOR_CONSTRAINT_P((x), 'K', "K") -#define CONST_OK_FOR_Os(x) \ - CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Os") -#define CONST_OK_FOR_Op(x) \ - CONST_OK_FOR_CONSTRAINT_P((x), 'O', "Op") -#define CONST_OK_FOR_On(x) \ - CONST_OK_FOR_CONSTRAINT_P((x), 'O', "On") - -#define REGNO_PAIR_OK(REGNO, MODE) \ - (HARD_REGNO_NREGS ((REGNO), (MODE)) == 1 || !((REGNO) & 1)) - -/* That's the read ahead of the dynamic branch prediction unit in - bytes on a z10 (or higher) CPU. */ -#define PREDICT_DISTANCE (TARGET_Z10 ? 384 : 2048) - -/* Return the alignment for LABEL. We default to the -falign-labels - value except for the literal pool base label. */ -int -s390_label_align (rtx label) -{ - rtx prev_insn = prev_active_insn (label); - - if (prev_insn == NULL_RTX) - goto old; - - prev_insn = single_set (prev_insn); - - if (prev_insn == NULL_RTX) - goto old; - - prev_insn = SET_SRC (prev_insn); - - /* Don't align literal pool base labels. */ - if (GET_CODE (prev_insn) == UNSPEC - && XINT (prev_insn, 1) == UNSPEC_MAIN_BASE) - return 0; - - old: - return align_labels_log; -} - -static enum machine_mode -s390_libgcc_cmp_return_mode (void) -{ - return TARGET_64BIT ? DImode : SImode; -} - -static enum machine_mode -s390_libgcc_shift_count_mode (void) -{ - return TARGET_64BIT ? DImode : SImode; -} - -static enum machine_mode -s390_unwind_word_mode (void) -{ - return TARGET_64BIT ? DImode : SImode; -} - -/* Return true if the back end supports mode MODE. */ -static bool -s390_scalar_mode_supported_p (enum machine_mode mode) -{ - /* In contrast to the default implementation reject TImode constants on 31bit - TARGET_ZARCH for ABI compliance. */ - if (!TARGET_64BIT && TARGET_ZARCH && mode == TImode) - return false; - - if (DECIMAL_FLOAT_MODE_P (mode)) - return default_decimal_float_supported_p (); - - return default_scalar_mode_supported_p (mode); -} - -/* Set the has_landing_pad_p flag in struct machine_function to VALUE. */ - -void -s390_set_has_landing_pad_p (bool value) -{ - cfun->machine->has_landing_pad_p = value; -} - -/* If two condition code modes are compatible, return a condition code - mode which is compatible with both. Otherwise, return - VOIDmode. */ - -static enum machine_mode -s390_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2) -{ - if (m1 == m2) - return m1; - - switch (m1) - { - case CCZmode: - if (m2 == CCUmode || m2 == CCTmode || m2 == CCZ1mode - || m2 == CCSmode || m2 == CCSRmode || m2 == CCURmode) - return m2; - return VOIDmode; - - case CCSmode: - case CCUmode: - case CCTmode: - case CCSRmode: - case CCURmode: - case CCZ1mode: - if (m2 == CCZmode) - return m1; - - return VOIDmode; - - default: - return VOIDmode; - } - return VOIDmode; -} - -/* Return true if SET either doesn't set the CC register, or else - the source and destination have matching CC modes and that - CC mode is at least as constrained as REQ_MODE. */ - -static bool -s390_match_ccmode_set (rtx set, enum machine_mode req_mode) -{ - enum machine_mode set_mode; - - gcc_assert (GET_CODE (set) == SET); - - if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set)))) - return 1; - - set_mode = GET_MODE (SET_DEST (set)); - switch (set_mode) - { - case CCSmode: - case CCSRmode: - case CCUmode: - case CCURmode: - case CCLmode: - case CCL1mode: - case CCL2mode: - case CCL3mode: - case CCT1mode: - case CCT2mode: - case CCT3mode: - if (req_mode != set_mode) - return 0; - break; - - case CCZmode: - if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode - && req_mode != CCSRmode && req_mode != CCURmode) - return 0; - break; - - case CCAPmode: - case CCANmode: - if (req_mode != CCAmode) - return 0; - break; - - default: - gcc_unreachable (); - } - - 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. - If REQ_MODE is VOIDmode, always return false. */ - -bool -s390_match_ccmode (rtx insn, enum machine_mode req_mode) -{ - int i; - - /* s390_tm_ccmode returns VOIDmode to indicate failure. */ - if (req_mode == VOIDmode) - return false; - - if (GET_CODE (PATTERN (insn)) == SET) - return s390_match_ccmode_set (PATTERN (insn), req_mode); - - if (GET_CODE (PATTERN (insn)) == PARALLEL) - for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) - { - rtx set = XVECEXP (PATTERN (insn), 0, i); - if (GET_CODE (set) == SET) - if (!s390_match_ccmode_set (set, req_mode)) - return false; - } - - return true; -} - -/* 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. - 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 (rtx op1, rtx op2, bool mixed) -{ - int bit0, bit1; - - /* ??? Fixme: should work on CONST_DOUBLE as well. */ - if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT) - return VOIDmode; - - /* Selected bits all zero: CC0. - e.g.: int a; if ((a & (16 + 128)) == 0) */ - if (INTVAL (op2) == 0) - return CCTmode; - - /* Selected bits all one: CC3. - e.g.: int a; if ((a & (16 + 128)) == 16 + 128) */ - if (INTVAL (op2) == INTVAL (op1)) - return CCT3mode; - - /* Exactly two bits selected, mixed zeroes and ones: CC1 or CC2. e.g.: - int a; - if ((a & (16 + 128)) == 16) -> CCT1 - if ((a & (16 + 128)) == 128) -> CCT2 */ - if (mixed) - { - bit1 = exact_log2 (INTVAL (op2)); - bit0 = exact_log2 (INTVAL (op1) ^ INTVAL (op2)); - if (bit0 != -1 && bit1 != -1) - return bit0 > bit1 ? CCT1mode : CCT2mode; - } - - 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 - comparison. */ - -enum machine_mode -s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1) -{ - switch (code) - { - case EQ: - case NE: - if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS) - && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) - return CCAPmode; - if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT - && CONST_OK_FOR_K (INTVAL (XEXP (op0, 1)))) - return CCAPmode; - 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) - { - /* Check whether we can potentially do it via TM. */ - enum machine_mode ccmode; - ccmode = s390_tm_ccmode (XEXP (op0, 1), op1, 1); - if (ccmode != VOIDmode) - { - /* Relax CCTmode to CCZmode to allow fall-back to AND - if that turns out to be beneficial. */ - return ccmode == CCTmode ? CCZmode : ccmode; - } - } - - if (register_operand (op0, HImode) - && GET_CODE (op1) == CONST_INT - && (INTVAL (op1) == -1 || INTVAL (op1) == 65535)) - return CCT3mode; - if (register_operand (op0, QImode) - && GET_CODE (op1) == CONST_INT - && (INTVAL (op1) == -1 || INTVAL (op1) == 255)) - return CCT3mode; - - return CCZmode; - - case LE: - case LT: - case GE: - case GT: - /* The only overflow condition of NEG and ABS happens when - -INT_MAX is used as parameter, which stays negative. So - we have an overflow from a positive value to a negative. - Using CCAP mode the resulting cc can be used for comparisons. */ - if ((GET_CODE (op0) == NEG || GET_CODE (op0) == ABS) - && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT) - return CCAPmode; - - /* If constants are involved in an add instruction it is possible to use - the resulting cc for comparisons with zero. Knowing the sign of the - constant the overflow behavior gets predictable. e.g.: - int a, b; if ((b = a + c) > 0) - with c as a constant value: c < 0 -> CCAN and c >= 0 -> CCAP */ - if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT - && CONST_OK_FOR_K (INTVAL (XEXP (op0, 1)))) - { - if (INTVAL (XEXP((op0), 1)) < 0) - return CCANmode; - else - return CCAPmode; - } - /* Fall through. */ - case UNORDERED: - case ORDERED: - case UNEQ: - case UNLE: - case UNLT: - case UNGE: - case UNGT: - case LTGT: - if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op0) == ZERO_EXTEND) - && GET_CODE (op1) != CONST_INT) - return CCSRmode; - return CCSmode; - - case LTU: - case GEU: - 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) - && GET_CODE (op1) != CONST_INT) - return CCURmode; - return CCUmode; - - case LEU: - case GTU: - 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) - && GET_CODE (op1) != CONST_INT) - return CCURmode; - return CCUmode; - - default: - gcc_unreachable (); - } -} - -/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one - that we can implement more efficiently. */ - -void -s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1) -{ - /* Convert ZERO_EXTRACT back to AND to enable TM patterns. */ - if ((*code == EQ || *code == NE) - && *op1 == const0_rtx - && GET_CODE (*op0) == ZERO_EXTRACT - && GET_CODE (XEXP (*op0, 1)) == CONST_INT - && GET_CODE (XEXP (*op0, 2)) == CONST_INT - && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0)))) - { - rtx inner = XEXP (*op0, 0); - HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner)); - HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1)); - HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2)); - - if (len > 0 && len < modesize - && pos >= 0 && pos + len <= modesize - && modesize <= HOST_BITS_PER_WIDE_INT) - { - unsigned HOST_WIDE_INT block; - block = ((unsigned HOST_WIDE_INT) 1 << len) - 1; - block <<= modesize - pos - len; - - *op0 = gen_rtx_AND (GET_MODE (inner), inner, - gen_int_mode (block, GET_MODE (inner))); - } - } - - /* Narrow AND of memory against immediate to enable TM. */ - if ((*code == EQ || *code == NE) - && *op1 == const0_rtx - && GET_CODE (*op0) == AND - && GET_CODE (XEXP (*op0, 1)) == CONST_INT - && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0)))) - { - rtx inner = XEXP (*op0, 0); - rtx mask = XEXP (*op0, 1); - - /* Ignore paradoxical SUBREGs if all extra bits are masked out. */ - if (GET_CODE (inner) == SUBREG - && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner))) - && (GET_MODE_SIZE (GET_MODE (inner)) - >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner)))) - && ((INTVAL (mask) - & GET_MODE_MASK (GET_MODE (inner)) - & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner)))) - == 0)) - inner = SUBREG_REG (inner); - - /* Do not change volatile MEMs. */ - if (MEM_P (inner) && !MEM_VOLATILE_P (inner)) - { - int part = s390_single_part (XEXP (*op0, 1), - GET_MODE (inner), QImode, 0); - if (part >= 0) - { - mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode); - inner = adjust_address_nv (inner, QImode, part); - *op0 = gen_rtx_AND (QImode, inner, mask); - } - } - } - - /* Narrow comparisons against 0xffff to HImode if possible. */ - if ((*code == EQ || *code == NE) - && GET_CODE (*op1) == CONST_INT - && INTVAL (*op1) == 0xffff - && SCALAR_INT_MODE_P (GET_MODE (*op0)) - && (nonzero_bits (*op0, GET_MODE (*op0)) - & ~(unsigned HOST_WIDE_INT) 0xffff) == 0) - { - *op0 = gen_lowpart (HImode, *op0); - *op1 = constm1_rtx; - } - - /* Remove redundant UNSPEC_CCU_TO_INT conversions if possible. */ - if (GET_CODE (*op0) == UNSPEC - && XINT (*op0, 1) == UNSPEC_CCU_TO_INT - && XVECLEN (*op0, 0) == 1 - && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode - && GET_CODE (XVECEXP (*op0, 0, 0)) == REG - && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM - && *op1 == const0_rtx) - { - enum rtx_code new_code = UNKNOWN; - switch (*code) - { - case EQ: new_code = EQ; break; - case NE: new_code = NE; break; - case LT: new_code = GTU; break; - case GT: new_code = LTU; break; - case LE: new_code = GEU; break; - case GE: new_code = LEU; break; - default: break; - } - - if (new_code != UNKNOWN) - { - *op0 = XVECEXP (*op0, 0, 0); - *code = new_code; - } - } - - /* Remove redundant UNSPEC_CCZ_TO_INT conversions if possible. */ - if (GET_CODE (*op0) == UNSPEC - && XINT (*op0, 1) == UNSPEC_CCZ_TO_INT - && XVECLEN (*op0, 0) == 1 - && GET_MODE (XVECEXP (*op0, 0, 0)) == CCZmode - && GET_CODE (XVECEXP (*op0, 0, 0)) == REG - && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM - && *op1 == const0_rtx) - { - enum rtx_code new_code = UNKNOWN; - switch (*code) - { - case EQ: new_code = EQ; break; - case NE: new_code = NE; break; - default: break; - } - - if (new_code != UNKNOWN) - { - *op0 = XVECEXP (*op0, 0, 0); - *code = new_code; - } - } - - /* Simplify cascaded EQ, NE with const0_rtx. */ - if ((*code == NE || *code == EQ) - && (GET_CODE (*op0) == EQ || GET_CODE (*op0) == NE) - && GET_MODE (*op0) == SImode - && GET_MODE (XEXP (*op0, 0)) == CCZ1mode - && REG_P (XEXP (*op0, 0)) - && XEXP (*op0, 1) == const0_rtx - && *op1 == const0_rtx) - { - if ((*code == EQ && GET_CODE (*op0) == NE) - || (*code == NE && GET_CODE (*op0) == EQ)) - *code = EQ; - else - *code = NE; - *op0 = XEXP (*op0, 0); - } - - /* Prefer register over memory as first operand. */ - if (MEM_P (*op0) && REG_P (*op1)) - { - rtx tem = *op0; *op0 = *op1; *op1 = tem; - *code = swap_condition (*code); - } -} - -/* Emit a compare instruction suitable to implement the comparison - OP0 CODE OP1. Return the correct condition RTL to be placed in - the IF_THEN_ELSE of the conditional branch testing the result. */ - -rtx -s390_emit_compare (enum rtx_code code, rtx op0, rtx op1) -{ - enum machine_mode mode = s390_select_ccmode (code, op0, op1); - rtx cc; - - /* Do not output a redundant compare instruction if a compare_and_swap - pattern already computed the result and the machine modes are compatible. */ - if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC) - { - gcc_assert (s390_cc_modes_compatible (GET_MODE (op0), mode) - == GET_MODE (op0)); - cc = op0; - } - else - { - cc = gen_rtx_REG (mode, CC_REGNUM); - emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1))); - } - - return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx); -} - -/* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD - matches CMP. - Return the correct condition RTL to be placed in the IF_THEN_ELSE of the - conditional branch testing the result. */ - -static rtx -s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new_rtx) -{ - emit_insn (gen_sync_compare_and_swapsi (old, mem, cmp, new_rtx)); - return s390_emit_compare (code, gen_rtx_REG (CCZ1mode, CC_REGNUM), const0_rtx); -} - -/* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an - unconditional jump, else a conditional jump under condition COND. */ - -void -s390_emit_jump (rtx target, rtx cond) -{ - rtx insn; - - target = gen_rtx_LABEL_REF (VOIDmode, target); - if (cond) - target = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, target, pc_rtx); - - insn = gen_rtx_SET (VOIDmode, pc_rtx, target); - emit_jump_insn (insn); -} - -/* Return branch condition mask to implement a branch - specified by CODE. Return -1 for invalid comparisons. */ - -int -s390_branch_condition_mask (rtx code) -{ - const int CC0 = 1 << 3; - const int CC1 = 1 << 2; - const int CC2 = 1 << 1; - const int CC3 = 1 << 0; - - gcc_assert (GET_CODE (XEXP (code, 0)) == REG); - gcc_assert (REGNO (XEXP (code, 0)) == CC_REGNUM); - gcc_assert (XEXP (code, 1) == const0_rtx); - - switch (GET_MODE (XEXP (code, 0))) - { - case CCZmode: - case CCZ1mode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC1 | CC2 | CC3; - default: return -1; - } - break; - - case CCT1mode: - switch (GET_CODE (code)) - { - case EQ: return CC1; - case NE: return CC0 | CC2 | CC3; - default: return -1; - } - break; - - case CCT2mode: - switch (GET_CODE (code)) - { - case EQ: return CC2; - case NE: return CC0 | CC1 | CC3; - default: return -1; - } - break; - - case CCT3mode: - switch (GET_CODE (code)) - { - case EQ: return CC3; - case NE: return CC0 | CC1 | CC2; - default: return -1; - } - break; - - case CCLmode: - switch (GET_CODE (code)) - { - case EQ: return CC0 | CC2; - case NE: return CC1 | CC3; - default: return -1; - } - break; - - case CCL1mode: - switch (GET_CODE (code)) - { - case LTU: return CC2 | CC3; /* carry */ - case GEU: return CC0 | CC1; /* no carry */ - default: return -1; - } - break; - - case CCL2mode: - switch (GET_CODE (code)) - { - case GTU: return CC0 | CC1; /* borrow */ - case LEU: return CC2 | CC3; /* no borrow */ - default: return -1; - } - break; - - case CCL3mode: - switch (GET_CODE (code)) - { - case EQ: return CC0 | CC2; - case NE: return CC1 | CC3; - case LTU: return CC1; - case GTU: return CC3; - case LEU: return CC1 | CC2; - case GEU: return CC2 | CC3; - default: return -1; - } - - case CCUmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC1 | CC2 | CC3; - case LTU: return CC1; - case GTU: return CC2; - case LEU: return CC0 | CC1; - case GEU: return CC0 | CC2; - default: return -1; - } - break; - - case CCURmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC2 | CC1 | CC3; - case LTU: return CC2; - case GTU: return CC1; - case LEU: return CC0 | CC2; - case GEU: return CC0 | CC1; - default: return -1; - } - break; - - case CCAPmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC1 | CC2 | CC3; - case LT: return CC1 | CC3; - case GT: return CC2; - case LE: return CC0 | CC1 | CC3; - case GE: return CC0 | CC2; - default: return -1; - } - break; - - case CCANmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC1 | CC2 | CC3; - case LT: return CC1; - case GT: return CC2 | CC3; - case LE: return CC0 | CC1; - case GE: return CC0 | CC2 | CC3; - default: return -1; - } - break; - - case CCSmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC1 | CC2 | CC3; - case LT: return CC1; - case GT: return CC2; - case LE: return CC0 | CC1; - case GE: return CC0 | CC2; - case UNORDERED: return CC3; - case ORDERED: return CC0 | CC1 | CC2; - case UNEQ: return CC0 | CC3; - case UNLT: return CC1 | CC3; - case UNGT: return CC2 | CC3; - case UNLE: return CC0 | CC1 | CC3; - case UNGE: return CC0 | CC2 | CC3; - case LTGT: return CC1 | CC2; - default: return -1; - } - break; - - case CCSRmode: - switch (GET_CODE (code)) - { - case EQ: return CC0; - case NE: return CC2 | CC1 | CC3; - case LT: return CC2; - case GT: return CC1; - case LE: return CC0 | CC2; - case GE: return CC0 | CC1; - case UNORDERED: return CC3; - case ORDERED: return CC0 | CC2 | CC1; - case UNEQ: return CC0 | CC3; - case UNLT: return CC2 | CC3; - case UNGT: return CC1 | CC3; - case UNLE: return CC0 | CC2 | CC3; - case UNGE: return CC0 | CC1 | CC3; - case LTGT: return CC2 | CC1; - default: return -1; - } - break; - - default: - return -1; - } -} - - -/* Return branch condition mask to implement a compare and branch - specified by CODE. Return -1 for invalid comparisons. */ - -int -s390_compare_and_branch_condition_mask (rtx code) -{ - const int CC0 = 1 << 3; - const int CC1 = 1 << 2; - const int CC2 = 1 << 1; - - switch (GET_CODE (code)) - { - case EQ: - return CC0; - case NE: - return CC1 | CC2; - case LT: - case LTU: - return CC1; - case GT: - case GTU: - return CC2; - case LE: - case LEU: - return CC0 | CC1; - case GE: - case GEU: - return CC0 | CC2; - default: - gcc_unreachable (); - } - return -1; -} - -/* 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 (rtx code, int inv) -{ - int mask; - - static const char *const mnemonic[16] = - { - NULL, "o", "h", "nle", - "l", "nhe", "lh", "ne", - "e", "nlh", "he", "nl", - "le", "nh", "no", NULL - }; - - if (GET_CODE (XEXP (code, 0)) == REG - && REGNO (XEXP (code, 0)) == CC_REGNUM - && XEXP (code, 1) == const0_rtx) - mask = s390_branch_condition_mask (code); - else - mask = s390_compare_and_branch_condition_mask (code); - - gcc_assert (mask >= 0); - - if (inv) - mask ^= 15; - - gcc_assert (mask >= 1 && mask <= 14); - - return mnemonic[mask]; -} - -/* 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. */ - -unsigned HOST_WIDE_INT -s390_extract_part (rtx op, enum machine_mode mode, int def) -{ - 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 - = ((unsigned HOST_WIDE_INT)1 << part_bits) - 1; - int i; - - for (i = 0; i < max_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) INTVAL (op); - else - value >>= part_bits; - - if ((value & part_mask) != (def & part_mask)) - return value & part_mask; - } - - gcc_unreachable (); -} - -/* If OP is an integer constant of mode MODE with exactly one - part of mode PART_MODE unequal to DEF, return the number of that - part. Otherwise, return -1. */ - -int -s390_single_part (rtx op, - enum machine_mode mode, - enum machine_mode part_mode, - int def) -{ - unsigned HOST_WIDE_INT value = 0; - int n_parts = GET_MODE_SIZE (mode) / GET_MODE_SIZE (part_mode); - unsigned HOST_WIDE_INT part_mask - = ((unsigned HOST_WIDE_INT)1 << GET_MODE_BITSIZE (part_mode)) - 1; - int i, part = -1; - - if (GET_CODE (op) != CONST_INT) - return -1; - - for (i = 0; i < n_parts; i++) - { - if (i == 0) - value = (unsigned HOST_WIDE_INT) INTVAL (op); - else - value >>= GET_MODE_BITSIZE (part_mode); - - if ((value & part_mask) != (def & part_mask)) - { - if (part != -1) - return -1; - else - part = i; - } - } - return part == -1 ? -1 : n_parts - 1 - part; -} - -/* Return true if IN contains a contiguous bitfield in the lower SIZE - bits and no other bits are set in IN. POS and LENGTH can be used - to obtain the start position and the length of the bitfield. - - POS gives the position of the first bit of the bitfield counting - from the lowest order bit starting with zero. In order to use this - value for S/390 instructions this has to be converted to "bits big - endian" style. */ - -bool -s390_contiguous_bitmask_p (unsigned HOST_WIDE_INT in, int size, - int *pos, int *length) -{ - int tmp_pos = 0; - int tmp_length = 0; - int i; - unsigned HOST_WIDE_INT mask = 1ULL; - bool contiguous = false; - - for (i = 0; i < size; mask <<= 1, i++) - { - if (contiguous) - { - if (mask & in) - tmp_length++; - else - break; - } - else - { - if (mask & in) - { - contiguous = true; - tmp_length++; - } - else - tmp_pos++; - } - } - - if (!tmp_length) - return false; - - /* Calculate a mask for all bits beyond the contiguous bits. */ - mask = (-1LL & ~(((1ULL << (tmp_length + tmp_pos - 1)) << 1) - 1)); - - if (mask & in) - return false; - - if (tmp_length + tmp_pos - 1 > size) - return false; - - if (length) - *length = tmp_length; - - if (pos) - *pos = tmp_pos; - - return true; -} - -/* 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 (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 accessible. */ - if (s_operand (src, mode) || s_operand (dst, mode)) - return false; - - /* Non-offsettable memory references cannot be split. */ - if ((GET_CODE (src) == MEM && !offsettable_memref_p (src)) - || (GET_CODE (dst) == MEM && !offsettable_memref_p (dst))) - return false; - - /* Moving the first subword must not clobber a register - needed to move the second subword. */ - if (register_operand (dst, mode)) - { - rtx subreg = operand_subword (dst, first_subword, 0, mode); - if (reg_overlap_mentioned_p (subreg, src)) - return false; - } - - return true; -} - -/* Return true if it can be proven that [MEM1, MEM1 + SIZE] - and [MEM2, MEM2 + SIZE] do overlap and false - otherwise. */ - -bool -s390_overlap_p (rtx mem1, rtx mem2, HOST_WIDE_INT size) -{ - rtx addr1, addr2, addr_delta; - HOST_WIDE_INT delta; - - if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM) - return true; - - if (size == 0) - return false; - - addr1 = XEXP (mem1, 0); - addr2 = XEXP (mem2, 0); - - addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1); - - /* This overlapping check is used by peepholes merging memory block operations. - Overlapping operations would otherwise be recognized by the S/390 hardware - and would fall back to a slower implementation. Allowing overlapping - operations would lead to slow code but not to wrong code. Therefore we are - somewhat optimistic if we cannot prove that the memory blocks are - overlapping. - That's why we return false here although this may accept operations on - overlapping memory areas. */ - if (!addr_delta || GET_CODE (addr_delta) != CONST_INT) - return false; - - delta = INTVAL (addr_delta); - - if (delta == 0 - || (delta > 0 && delta < size) - || (delta < 0 && -delta < size)) - return true; - - return false; -} - -/* Check whether the address of memory reference MEM2 equals exactly - the address of memory reference MEM1 plus DELTA. Return true if - we can prove this to be the case, false otherwise. */ - -bool -s390_offset_p (rtx mem1, rtx mem2, rtx delta) -{ - rtx addr1, addr2, addr_delta; - - if (GET_CODE (mem1) != MEM || GET_CODE (mem2) != MEM) - return false; - - addr1 = XEXP (mem1, 0); - addr2 = XEXP (mem2, 0); - - addr_delta = simplify_binary_operation (MINUS, Pmode, addr2, addr1); - if (!addr_delta || !rtx_equal_p (addr_delta, delta)) - return false; - - return true; -} - -/* Expand logical operator CODE in mode MODE with operands OPERANDS. */ - -void -s390_expand_logical_operator (enum rtx_code code, enum machine_mode mode, - rtx *operands) -{ - enum machine_mode wmode = mode; - rtx dst = operands[0]; - rtx src1 = operands[1]; - rtx src2 = operands[2]; - rtx op, clob, tem; - - /* If we cannot handle the operation directly, use a temp register. */ - if (!s390_logical_operator_ok_p (operands)) - dst = gen_reg_rtx (mode); - - /* QImode and HImode patterns make sense only if we have a destination - in memory. Otherwise perform the operation in SImode. */ - if ((mode == QImode || mode == HImode) && GET_CODE (dst) != MEM) - wmode = SImode; - - /* Widen operands if required. */ - if (mode != wmode) - { - if (GET_CODE (dst) == SUBREG - && (tem = simplify_subreg (wmode, dst, mode, 0)) != 0) - dst = tem; - else if (REG_P (dst)) - dst = gen_rtx_SUBREG (wmode, dst, 0); - else - dst = gen_reg_rtx (wmode); - - if (GET_CODE (src1) == SUBREG - && (tem = simplify_subreg (wmode, src1, mode, 0)) != 0) - src1 = tem; - else if (GET_MODE (src1) != VOIDmode) - src1 = gen_rtx_SUBREG (wmode, force_reg (mode, src1), 0); - - if (GET_CODE (src2) == SUBREG - && (tem = simplify_subreg (wmode, src2, mode, 0)) != 0) - src2 = tem; - else if (GET_MODE (src2) != VOIDmode) - src2 = gen_rtx_SUBREG (wmode, force_reg (mode, src2), 0); - } - - /* Emit the instruction. */ - op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, wmode, src1, src2)); - clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); - - /* Fix up the destination if needed. */ - if (dst != operands[0]) - emit_move_insn (operands[0], gen_lowpart (mode, dst)); -} - -/* Check whether OPERANDS are OK for a logical operation (AND, IOR, XOR). */ - -bool -s390_logical_operator_ok_p (rtx *operands) -{ - /* If the destination operand is in memory, it needs to coincide - with one of the source operands. After reload, it has to be - the first source operand. */ - if (GET_CODE (operands[0]) == MEM) - return rtx_equal_p (operands[0], operands[1]) - || (!reload_completed && rtx_equal_p (operands[0], operands[2])); - - return true; -} - -/* Narrow logical operation CODE of memory operand MEMOP with immediate - operand IMMOP to switch from SS to SI type instructions. */ - -void -s390_narrow_logical_operator (enum rtx_code code, rtx *memop, rtx *immop) -{ - int def = code == AND ? -1 : 0; - HOST_WIDE_INT mask; - int part; - - gcc_assert (GET_CODE (*memop) == MEM); - gcc_assert (!MEM_VOLATILE_P (*memop)); - - mask = s390_extract_part (*immop, QImode, def); - part = s390_single_part (*immop, GET_MODE (*memop), QImode, def); - gcc_assert (part >= 0); - - *memop = adjust_address (*memop, QImode, part); - *immop = gen_int_mode (mask, QImode); -} - - -/* How to allocate a 'struct machine_function'. */ - -static struct machine_function * -s390_init_machine_status (void) -{ - return ggc_alloc_cleared_machine_function (); -} - -static void -s390_option_override (void) -{ - /* 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; - } - - /* Set the march default in case it hasn't been specified on - cmdline. */ - if (s390_arch == PROCESSOR_max) - { - s390_arch_string = TARGET_ZARCH? "z900" : "g5"; - s390_arch = TARGET_ZARCH ? PROCESSOR_2064_Z900 : PROCESSOR_9672_G5; - s390_arch_flags = processor_flags_table[(int)s390_arch]; - } - - /* Determine processor to tune for. */ - if (s390_tune == PROCESSOR_max) - { - s390_tune = s390_arch; - s390_tune_flags = s390_arch_flags; - } - - /* Sanity checks. */ - if (TARGET_ZARCH && !TARGET_CPU_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"); - - /* Use hardware DFP if available and not explicitly disabled by - user. E.g. with -m31 -march=z10 -mzarch */ - if (!(target_flags_explicit & MASK_HARD_DFP) && TARGET_DFP) - target_flags |= MASK_HARD_DFP; - - if (TARGET_HARD_DFP && !TARGET_DFP) - { - if (target_flags_explicit & MASK_HARD_DFP) - { - if (!TARGET_CPU_DFP) - error ("hardware decimal floating point instructions" - " not available on %s", s390_arch_string); - if (!TARGET_ZARCH) - error ("hardware decimal floating point instructions" - " not available in ESA/390 mode"); - } - else - target_flags &= ~MASK_HARD_DFP; - } - - if ((target_flags_explicit & MASK_SOFT_FLOAT) && TARGET_SOFT_FLOAT) - { - if ((target_flags_explicit & MASK_HARD_DFP) && TARGET_HARD_DFP) - error ("-mhard-dfp can%'t be used in conjunction with -msoft-float"); - - target_flags &= ~MASK_HARD_DFP; - } - - /* Set processor cost function. */ - switch (s390_tune) - { - case PROCESSOR_2084_Z990: - s390_cost = &z990_cost; - break; - case PROCESSOR_2094_Z9_109: - s390_cost = &z9_109_cost; - break; - case PROCESSOR_2097_Z10: - s390_cost = &z10_cost; - case PROCESSOR_2817_Z196: - s390_cost = &z196_cost; - break; - default: - s390_cost = &z900_cost; - } - - if (TARGET_BACKCHAIN && TARGET_PACKED_STACK && TARGET_HARD_FLOAT) - error ("-mbackchain -mpacked-stack -mhard-float are not supported " - "in combination"); - - if (s390_stack_size) - { - if (s390_stack_guard >= s390_stack_size) - error ("stack size must be greater than the stack guard value"); - else if (s390_stack_size > 1 << 16) - error ("stack size must not be greater than 64k"); - } - else if (s390_stack_guard) - error ("-mstack-guard implies use of -mstack-size"); - -#ifdef TARGET_DEFAULT_LONG_DOUBLE_128 - if (!(target_flags_explicit & MASK_LONG_DOUBLE_128)) - target_flags |= MASK_LONG_DOUBLE_128; -#endif - - if (s390_tune == PROCESSOR_2097_Z10 - || s390_tune == PROCESSOR_2817_Z196) - { - maybe_set_param_value (PARAM_MAX_UNROLLED_INSNS, 100, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_MAX_UNROLL_TIMES, 32, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_MAX_COMPLETELY_PEELED_INSNS, 2000, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_MAX_COMPLETELY_PEEL_TIMES, 64, - global_options.x_param_values, - global_options_set.x_param_values); - } - - maybe_set_param_value (PARAM_MAX_PENDING_LIST_LENGTH, 256, - global_options.x_param_values, - global_options_set.x_param_values); - /* values for loop prefetching */ - maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE, 256, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_L1_CACHE_SIZE, 128, - global_options.x_param_values, - global_options_set.x_param_values); - /* s390 has more than 2 levels and the size is much larger. Since - we are always running virtualized assume that we only get a small - part of the caches above l1. */ - maybe_set_param_value (PARAM_L2_CACHE_SIZE, 1500, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_PREFETCH_MIN_INSN_TO_MEM_RATIO, 2, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES, 6, - global_options.x_param_values, - global_options_set.x_param_values); - - /* This cannot reside in s390_option_optimization_table since HAVE_prefetch - requires the arch flags to be evaluated already. Since prefetching - is beneficial on s390, we enable it if available. */ - if (flag_prefetch_loop_arrays < 0 && HAVE_prefetch && optimize >= 3) - flag_prefetch_loop_arrays = 1; -} - -/* Map for smallest class containing reg regno. */ - -const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = -{ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, - ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, - ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, - ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, - FP_REGS, FP_REGS, FP_REGS, FP_REGS, - 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, CC_REGS, ADDR_REGS, ADDR_REGS, - ACCESS_REGS, ACCESS_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 DISP is a valid short displacement. */ - -static bool -s390_short_displacement (rtx disp) -{ - /* No displacement is OK. */ - if (!disp) - return true; - - /* Without the long displacement facility we don't need to - distingiush between long and short displacement. */ - if (!TARGET_LONG_DISPLACEMENT) - return true; - - /* 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 - || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF)) - return false; - - /* All other symbolic constants are literal pool references, - which are OK as the literal pool must be small. */ - if (GET_CODE (disp) == CONST) - return true; - - return false; -} - -/* Decompose a RTL expression ADDR for a memory address into - its components, returned in OUT. - - Returns false if ADDR is not a valid memory address, true - otherwise. If OUT is NULL, don't return the components, - but check for validity only. - - Note: Only addresses in canonical form are recognized. - LEGITIMIZE_ADDRESS should convert non-canonical forms to the - canonical form so that they will be recognized. */ - -static int -s390_decompose_address (rtx addr, struct s390_address *out) -{ - HOST_WIDE_INT offset = 0; - rtx base = NULL_RTX; - rtx indx = NULL_RTX; - rtx disp = NULL_RTX; - rtx orig_disp; - bool pointer = false; - bool base_ptr = false; - bool indx_ptr = false; - bool literal_pool = false; - - /* We may need to substitute the literal pool base register into the address - below. However, at this point we do not know which register is going to - be used as base, so we substitute the arg pointer register. This is going - to be treated as holding a pointer below -- it shouldn't be used for any - other purpose. */ - rtx fake_pool_base = gen_rtx_REG (Pmode, ARG_POINTER_REGNUM); - - /* Decompose address into base + index + displacement. */ - - if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC) - base = addr; - - else if (GET_CODE (addr) == PLUS) - { - rtx op0 = XEXP (addr, 0); - rtx op1 = XEXP (addr, 1); - enum rtx_code code0 = GET_CODE (op0); - enum rtx_code code1 = GET_CODE (op1); - - if (code0 == REG || code0 == UNSPEC) - { - if (code1 == REG || code1 == UNSPEC) - { - indx = op0; /* index + base */ - base = op1; - } - - else - { - base = op0; /* base + displacement */ - disp = op1; - } - } - - else if (code0 == PLUS) - { - indx = XEXP (op0, 0); /* index + base + disp */ - base = XEXP (op0, 1); - disp = op1; - } - - else - { - return false; - } - } - - else - disp = addr; /* displacement */ - - /* Extract integer part of displacement. */ - orig_disp = disp; - if (disp) - { - if (GET_CODE (disp) == CONST_INT) - { - offset = INTVAL (disp); - disp = NULL_RTX; - } - else if (GET_CODE (disp) == CONST - && GET_CODE (XEXP (disp, 0)) == PLUS - && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) - { - offset = INTVAL (XEXP (XEXP (disp, 0), 1)); - disp = XEXP (XEXP (disp, 0), 0); - } - } - - /* Strip off CONST here to avoid special case tests later. */ - if (disp && GET_CODE (disp) == CONST) - disp = XEXP (disp, 0); - - /* We can convert literal pool addresses to - displacements by basing them off the base register. */ - if (disp && GET_CODE (disp) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (disp)) - { - /* Either base or index must be free to hold the base register. */ - if (!base) - base = fake_pool_base, literal_pool = true; - else if (!indx) - indx = fake_pool_base, literal_pool = true; - else - return false; - - /* Mark up the displacement. */ - disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), - UNSPEC_LTREL_OFFSET); - } - - /* Validate base register. */ - if (base) - { - if (GET_CODE (base) == UNSPEC) - switch (XINT (base, 1)) - { - case UNSPEC_LTREF: - if (!disp) - disp = gen_rtx_UNSPEC (Pmode, - gen_rtvec (1, XVECEXP (base, 0, 0)), - UNSPEC_LTREL_OFFSET); - else - return false; - - base = XVECEXP (base, 0, 1); - break; - - case UNSPEC_LTREL_BASE: - if (XVECLEN (base, 0) == 1) - base = fake_pool_base, literal_pool = true; - else - base = XVECEXP (base, 0, 1); - break; - - default: - return false; - } - - if (!REG_P (base) - || (GET_MODE (base) != SImode - && GET_MODE (base) != Pmode)) - return false; - - if (REGNO (base) == STACK_POINTER_REGNUM - || REGNO (base) == FRAME_POINTER_REGNUM - || ((reload_completed || reload_in_progress) - && frame_pointer_needed - && REGNO (base) == HARD_FRAME_POINTER_REGNUM) - || REGNO (base) == ARG_POINTER_REGNUM - || (flag_pic - && REGNO (base) == PIC_OFFSET_TABLE_REGNUM)) - pointer = base_ptr = true; - - if ((reload_completed || reload_in_progress) - && base == cfun->machine->base_reg) - pointer = base_ptr = literal_pool = true; - } - - /* Validate index register. */ - if (indx) - { - if (GET_CODE (indx) == UNSPEC) - switch (XINT (indx, 1)) - { - case UNSPEC_LTREF: - if (!disp) - disp = gen_rtx_UNSPEC (Pmode, - gen_rtvec (1, XVECEXP (indx, 0, 0)), - UNSPEC_LTREL_OFFSET); - else - return false; - - indx = XVECEXP (indx, 0, 1); - break; - - case UNSPEC_LTREL_BASE: - if (XVECLEN (indx, 0) == 1) - indx = fake_pool_base, literal_pool = true; - else - indx = XVECEXP (indx, 0, 1); - break; - - default: - return false; - } - - if (!REG_P (indx) - || (GET_MODE (indx) != SImode - && GET_MODE (indx) != Pmode)) - return false; - - if (REGNO (indx) == STACK_POINTER_REGNUM - || REGNO (indx) == FRAME_POINTER_REGNUM - || ((reload_completed || reload_in_progress) - && frame_pointer_needed - && REGNO (indx) == HARD_FRAME_POINTER_REGNUM) - || REGNO (indx) == ARG_POINTER_REGNUM - || (flag_pic - && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM)) - pointer = indx_ptr = true; - - if ((reload_completed || reload_in_progress) - && indx == cfun->machine->base_reg) - pointer = indx_ptr = literal_pool = 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. */ - if (!disp) - { - /* If virtual registers are involved, the displacement will change later - anyway as the virtual registers get eliminated. This could make a - valid displacement invalid, but it is more likely to make an invalid - displacement valid, because we sometimes access the register save area - via negative offsets to one of those registers. - Thus we don't check the displacement for validity here. If after - elimination the displacement turns out to be invalid after all, - this is fixed up by reload in any case. */ - if (base != arg_pointer_rtx - && indx != arg_pointer_rtx - && base != return_address_pointer_rtx - && indx != return_address_pointer_rtx - && base != frame_pointer_rtx - && indx != frame_pointer_rtx - && base != virtual_stack_vars_rtx - && indx != virtual_stack_vars_rtx) - if (!DISP_IN_RANGE (offset)) - return false; - } - else - { - /* All the special cases are pointers. */ - pointer = true; - - /* In the small-PIC case, the linker converts @GOT - and @GOTNTPOFF offsets to possible displacements. */ - if (GET_CODE (disp) == UNSPEC - && (XINT (disp, 1) == UNSPEC_GOT - || XINT (disp, 1) == UNSPEC_GOTNTPOFF) - && flag_pic == 1) - { - ; - } - - /* Accept pool label offsets. */ - else if (GET_CODE (disp) == UNSPEC - && XINT (disp, 1) == UNSPEC_POOL_OFFSET) - ; - - /* Accept literal pool references. */ - else if (GET_CODE (disp) == UNSPEC - && XINT (disp, 1) == UNSPEC_LTREL_OFFSET) - { - /* In case CSE pulled a non literal pool reference out of - the pool we have to reject the address. This is - especially important when loading the GOT pointer on non - zarch CPUs. In this case the literal pool contains an lt - relative offset to the _GLOBAL_OFFSET_TABLE_ label which - will most likely exceed the displacement. */ - if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF - || !CONSTANT_POOL_ADDRESS_P (XVECEXP (disp, 0, 0))) - return false; - - orig_disp = gen_rtx_CONST (Pmode, disp); - if (offset) - { - /* If we have an offset, make sure it does not - exceed the size of the constant pool entry. */ - rtx sym = XVECEXP (disp, 0, 0); - if (offset >= GET_MODE_SIZE (get_pool_mode (sym))) - return false; - - orig_disp = plus_constant (orig_disp, offset); - } - } - - else - return false; - } - - if (!base && !indx) - pointer = true; - - if (out) - { - out->base = base; - out->indx = indx; - out->disp = orig_disp; - out->pointer = pointer; - out->literal_pool = literal_pool; - } - - return true; -} - -/* Decompose a RTL expression OP for a shift count into its components, - and return the base register in BASE and the offset in OFFSET. - - Return true if OP is a valid shift count, false if not. */ - -bool -s390_decompose_shift_count (rtx op, rtx *base, HOST_WIDE_INT *offset) -{ - HOST_WIDE_INT off = 0; - - /* We can have an integer constant, an address register, - or a sum of the two. */ - if (GET_CODE (op) == CONST_INT) - { - off = INTVAL (op); - op = NULL_RTX; - } - if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) - { - off = 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 false; - - if (offset) - *offset = off; - if (base) - *base = op; - - return true; -} - - -/* Return true if CODE is a valid address without index. */ - -bool -s390_legitimate_address_without_index_p (rtx op) -{ - struct s390_address addr; - - if (!s390_decompose_address (XEXP (op, 0), &addr)) - return false; - if (addr.indx) - return false; - - return true; -} - - -/* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int - and return these parts in SYMREF and ADDEND. You can pass NULL in - SYMREF and/or ADDEND if you are not interested in these values. - Literal pool references are *not* considered symbol references. */ - -static bool -s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend) -{ - HOST_WIDE_INT tmpaddend = 0; - - if (GET_CODE (addr) == CONST) - addr = XEXP (addr, 0); - - if (GET_CODE (addr) == PLUS) - { - if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF - && !CONSTANT_POOL_ADDRESS_P (XEXP (addr, 0)) - && CONST_INT_P (XEXP (addr, 1))) - { - tmpaddend = INTVAL (XEXP (addr, 1)); - addr = XEXP (addr, 0); - } - else - return false; - } - else - if (GET_CODE (addr) != SYMBOL_REF || CONSTANT_POOL_ADDRESS_P (addr)) - return false; - - if (symref) - *symref = addr; - if (addend) - *addend = tmpaddend; - - return true; -} - - -/* Return true if the address in OP is valid for constraint letter C - if wrapped in a MEM rtx. Set LIT_POOL_OK to true if it literal - pool MEMs should be accepted. Only the Q, R, S, T constraint - letters are allowed for C. */ - -static int -s390_check_qrst_address (char c, rtx op, bool lit_pool_ok) -{ - struct s390_address addr; - bool decomposed = false; - - /* This check makes sure that no symbolic address (except literal - pool references) are accepted by the R or T constraints. */ - if (s390_symref_operand_p (op, NULL, NULL)) - return 0; - - /* Ensure literal pool references are only accepted if LIT_POOL_OK. */ - if (!lit_pool_ok) - { - if (!s390_decompose_address (op, &addr)) - return 0; - if (addr.literal_pool) - return 0; - decomposed = true; - } - - switch (c) - { - case 'Q': /* no index short displacement */ - if (!decomposed && !s390_decompose_address (op, &addr)) - return 0; - if (addr.indx) - return 0; - if (!s390_short_displacement (addr.disp)) - return 0; - break; - - case 'R': /* with index short displacement */ - if (TARGET_LONG_DISPLACEMENT) - { - if (!decomposed && !s390_decompose_address (op, &addr)) - return 0; - if (!s390_short_displacement (addr.disp)) - return 0; - } - /* Any invalid address here will be fixed up by reload, - so accept it for the most generic constraint. */ - break; - - case 'S': /* no index long displacement */ - if (!TARGET_LONG_DISPLACEMENT) - return 0; - if (!decomposed && !s390_decompose_address (op, &addr)) - return 0; - if (addr.indx) - return 0; - if (s390_short_displacement (addr.disp)) - return 0; - break; - - case 'T': /* with index long displacement */ - 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 ((decomposed || s390_decompose_address (op, &addr)) - && s390_short_displacement (addr.disp)) - return 0; - break; - default: - return 0; - } - return 1; -} - - -/* Evaluates constraint strings described by the regular expression - ([A|B|Z](Q|R|S|T))|U|W|Y and returns 1 if OP is a valid operand for - the constraint given in STR, or 0 else. */ - -int -s390_mem_constraint (const char *str, rtx op) -{ - char c = str[0]; - - switch (c) - { - case 'A': - /* Check for offsettable variants of memory constraints. */ - if (!MEM_P (op) || MEM_VOLATILE_P (op)) - return 0; - if ((reload_completed || reload_in_progress) - ? !offsettable_memref_p (op) : !offsettable_nonstrict_memref_p (op)) - return 0; - return s390_check_qrst_address (str[1], XEXP (op, 0), true); - case 'B': - /* Check for non-literal-pool variants of memory constraints. */ - if (!MEM_P (op)) - return 0; - return s390_check_qrst_address (str[1], XEXP (op, 0), false); - case 'Q': - case 'R': - case 'S': - case 'T': - if (GET_CODE (op) != MEM) - return 0; - return s390_check_qrst_address (c, XEXP (op, 0), true); - case 'U': - return (s390_check_qrst_address ('Q', op, true) - || s390_check_qrst_address ('R', op, true)); - case 'W': - return (s390_check_qrst_address ('S', op, true) - || s390_check_qrst_address ('T', op, true)); - case 'Y': - /* Simply check for the basic form of a shift count. Reload will - take care of making sure we have a proper base register. */ - if (!s390_decompose_shift_count (op, NULL, NULL)) - return 0; - break; - case 'Z': - return s390_check_qrst_address (str[1], op, true); - default: - return 0; - } - return 1; -} - - -/* Evaluates constraint strings starting with letter O. Input - parameter C is the second letter following the "O" in the constraint - string. Returns 1 if VALUE meets the respective constraint and 0 - otherwise. */ - -int -s390_O_constraint_str (const char c, HOST_WIDE_INT value) -{ - if (!TARGET_EXTIMM) - return 0; - - switch (c) - { - case 's': - return trunc_int_for_mode (value, SImode) == value; - - case 'p': - return value == 0 - || s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1; - - case 'n': - return s390_single_part (GEN_INT (value - 1), DImode, SImode, -1) == 1; - - default: - gcc_unreachable (); - } -} - - -/* Evaluates constraint strings starting with letter N. Parameter STR - contains the letters following letter "N" in the constraint string. - Returns true if VALUE matches the constraint. */ - -int -s390_N_constraint_str (const char *str, HOST_WIDE_INT value) -{ - enum machine_mode mode, part_mode; - int def; - int part, part_goal; - - - if (str[0] == 'x') - part_goal = -1; - else - part_goal = str[0] - '0'; - - switch (str[1]) - { - case 'Q': - part_mode = QImode; - break; - case 'H': - part_mode = HImode; - break; - case 'S': - part_mode = SImode; - break; - default: - return 0; - } - - switch (str[2]) - { - case 'H': - mode = HImode; - break; - case 'S': - mode = SImode; - break; - case 'D': - mode = DImode; - break; - default: - return 0; - } - - switch (str[3]) - { - 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; - - part = s390_single_part (GEN_INT (value), mode, part_mode, def); - if (part < 0) - return 0; - if (part_goal != -1 && part_goal != part) - return 0; - - return 1; -} - - -/* Returns true if the input parameter VALUE is a float zero. */ - -int -s390_float_const_zero_p (rtx value) -{ - return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT - && value == CONST0_RTX (GET_MODE (value))); -} - -/* Implement TARGET_REGISTER_MOVE_COST. */ - -static int -s390_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, - reg_class_t from, reg_class_t to) -{ -/* On s390, copy between fprs and gprs is expensive. */ - if ((reg_classes_intersect_p (from, GENERAL_REGS) - && reg_classes_intersect_p (to, FP_REGS)) - || (reg_classes_intersect_p (from, FP_REGS) - && reg_classes_intersect_p (to, GENERAL_REGS))) - return 10; - - return 1; -} - -/* Implement TARGET_MEMORY_MOVE_COST. */ - -static int -s390_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, - reg_class_t rclass ATTRIBUTE_UNUSED, - bool in ATTRIBUTE_UNUSED) -{ - 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. - CODE contains GET_CODE (x), OUTER_CODE contains the code - of the superexpression of x. */ - -static bool -s390_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, - int *total, bool speed ATTRIBUTE_UNUSED) -{ - switch (code) - { - case CONST: - case CONST_INT: - case LABEL_REF: - case SYMBOL_REF: - case CONST_DOUBLE: - case MEM: - *total = 0; - return true; - - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - case ROTATE: - case ROTATERT: - case AND: - case IOR: - case XOR: - case NEG: - case NOT: - *total = COSTS_N_INSNS (1); - return false; - - case PLUS: - case MINUS: - *total = COSTS_N_INSNS (1); - return false; - - case MULT: - switch (GET_MODE (x)) - { - case SImode: - { - rtx left = XEXP (x, 0); - rtx right = XEXP (x, 1); - if (GET_CODE (right) == CONST_INT - && CONST_OK_FOR_K (INTVAL (right))) - *total = s390_cost->mhi; - else if (GET_CODE (left) == SIGN_EXTEND) - *total = s390_cost->mh; - else - *total = s390_cost->ms; /* msr, ms, msy */ - break; - } - case DImode: - { - rtx left = XEXP (x, 0); - rtx right = XEXP (x, 1); - if (TARGET_ZARCH) - { - if (GET_CODE (right) == CONST_INT - && CONST_OK_FOR_K (INTVAL (right))) - *total = s390_cost->mghi; - else if (GET_CODE (left) == SIGN_EXTEND) - *total = s390_cost->msgf; - else - *total = s390_cost->msg; /* msgr, msg */ - } - else /* TARGET_31BIT */ - { - if (GET_CODE (left) == SIGN_EXTEND - && GET_CODE (right) == SIGN_EXTEND) - /* mulsidi case: mr, m */ - *total = s390_cost->m; - else if (GET_CODE (left) == ZERO_EXTEND - && GET_CODE (right) == ZERO_EXTEND - && TARGET_CPU_ZARCH) - /* umulsidi case: ml, mlr */ - *total = s390_cost->ml; - else - /* Complex calculation is required. */ - *total = COSTS_N_INSNS (40); - } - break; - } - case SFmode: - case DFmode: - *total = s390_cost->mult_df; - break; - case TFmode: - *total = s390_cost->mxbr; - break; - default: - return false; - } - return false; - - case FMA: - switch (GET_MODE (x)) - { - case DFmode: - *total = s390_cost->madbr; - break; - case SFmode: - *total = s390_cost->maebr; - break; - default: - return false; - } - /* Negate in the third argument is free: FMSUB. */ - if (GET_CODE (XEXP (x, 2)) == NEG) - { - *total += (rtx_cost (XEXP (x, 0), FMA, 0, speed) - + rtx_cost (XEXP (x, 1), FMA, 1, speed) - + rtx_cost (XEXP (XEXP (x, 2), 0), FMA, 2, speed)); - return true; - } - return false; - - case UDIV: - case UMOD: - if (GET_MODE (x) == TImode) /* 128 bit division */ - *total = s390_cost->dlgr; - else if (GET_MODE (x) == DImode) - { - rtx right = XEXP (x, 1); - if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ - *total = s390_cost->dlr; - else /* 64 by 64 bit division */ - *total = s390_cost->dlgr; - } - else if (GET_MODE (x) == SImode) /* 32 bit division */ - *total = s390_cost->dlr; - return false; - - case DIV: - case MOD: - if (GET_MODE (x) == DImode) - { - rtx right = XEXP (x, 1); - if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ - if (TARGET_ZARCH) - *total = s390_cost->dsgfr; - else - *total = s390_cost->dr; - else /* 64 by 64 bit division */ - *total = s390_cost->dsgr; - } - else if (GET_MODE (x) == SImode) /* 32 bit division */ - *total = s390_cost->dlr; - else if (GET_MODE (x) == SFmode) - { - *total = s390_cost->debr; - } - else if (GET_MODE (x) == DFmode) - { - *total = s390_cost->ddbr; - } - else if (GET_MODE (x) == TFmode) - { - *total = s390_cost->dxbr; - } - return false; - - case SQRT: - if (GET_MODE (x) == SFmode) - *total = s390_cost->sqebr; - else if (GET_MODE (x) == DFmode) - *total = s390_cost->sqdbr; - else /* TFmode */ - *total = s390_cost->sqxbr; - return false; - - case SIGN_EXTEND: - case ZERO_EXTEND: - if (outer_code == MULT || outer_code == DIV || outer_code == MOD - || outer_code == PLUS || outer_code == MINUS - || outer_code == COMPARE) - *total = 0; - return false; - - case COMPARE: - *total = COSTS_N_INSNS (1); - if (GET_CODE (XEXP (x, 0)) == AND - && GET_CODE (XEXP (x, 1)) == CONST_INT - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) - { - rtx op0 = XEXP (XEXP (x, 0), 0); - rtx op1 = XEXP (XEXP (x, 0), 1); - rtx op2 = XEXP (x, 1); - - if (memory_operand (op0, GET_MODE (op0)) - && s390_tm_ccmode (op1, op2, 0) != VOIDmode) - return true; - if (register_operand (op0, GET_MODE (op0)) - && s390_tm_ccmode (op1, op2, 1) != VOIDmode) - return true; - } - return false; - - default: - return false; - } -} - -/* Return the cost of an address rtx ADDR. */ - -static int -s390_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) -{ - struct s390_address ad; - if (!s390_decompose_address (addr, &ad)) - return 1000; - - return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1); -} - -/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode, - otherwise return 0. */ - -int -tls_symbolic_operand (rtx op) -{ - if (GET_CODE (op) != SYMBOL_REF) - return 0; - return SYMBOL_REF_TLS_MODEL (op); -} - -/* Split DImode access register reference REG (on 64-bit) into its constituent - low and high parts, and store them into LO and HI. Note that gen_lowpart/ - gen_highpart cannot be used as they assume all registers are word-sized, - while our access registers have only half that size. */ - -void -s390_split_access_reg (rtx reg, rtx *lo, rtx *hi) -{ - gcc_assert (TARGET_64BIT); - gcc_assert (ACCESS_REG_P (reg)); - gcc_assert (GET_MODE (reg) == DImode); - gcc_assert (!(REGNO (reg) & 1)); - - *lo = gen_rtx_REG (SImode, REGNO (reg) + 1); - *hi = gen_rtx_REG (SImode, REGNO (reg)); -} - -/* Return true if OP contains a symbol reference */ - -bool -symbolic_reference_mentioned_p (rtx op) -{ - const char *fmt; - int i; - - if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) - return 1; - - fmt = GET_RTX_FORMAT (GET_CODE (op)); - for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - int j; - - for (j = XVECLEN (op, i) - 1; j >= 0; j--) - if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) - return 1; - } - - else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) - return 1; - } - - return 0; -} - -/* Return true if OP contains a reference to a thread-local symbol. */ - -bool -tls_symbolic_reference_mentioned_p (rtx op) -{ - const char *fmt; - int i; - - if (GET_CODE (op) == SYMBOL_REF) - return tls_symbolic_operand (op); - - fmt = GET_RTX_FORMAT (GET_CODE (op)); - for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - int j; - - for (j = XVECLEN (op, i) - 1; j >= 0; j--) - if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j))) - return true; - } - - else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i))) - return true; - } - - return false; -} - - -/* 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 (rtx op) -{ - /* Accept all non-symbolic constants. */ - if (!SYMBOLIC_CONST (op)) - return 1; - - /* Reject everything else; must be handled - via emit_symbolic_move. */ - return 0; -} - -/* Returns true if the constant value OP is a legitimate general operand. - It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */ - -static bool -s390_legitimate_constant_p (enum machine_mode mode, rtx op) -{ - /* Accept all non-symbolic constants. */ - if (!SYMBOLIC_CONST (op)) - return 1; - - /* Accept immediate LARL operands. */ - if (TARGET_CPU_ZARCH && larl_operand (op, mode)) - return 1; - - /* Thread-local symbols are never legal constants. This is - so that emit_call knows that computing such addresses - might require a function call. */ - if (TLS_SYMBOLIC_CONST (op)) - return 0; - - /* In the PIC case, symbolic constants must *not* be - forced into the literal pool. We accept them here, - so that they will be handled by emit_symbolic_move. */ - if (flag_pic) - return 1; - - /* All remaining non-PIC symbolic constants are - forced into the literal pool. */ - return 0; -} - -/* Determine if it's legal to put X into the constant pool. This - is not possible if X contains the address of a symbol that is - not constant (TLS) or not known at final link time (PIC). */ - -static bool -s390_cannot_force_const_mem (enum machine_mode mode, rtx x) -{ - switch (GET_CODE (x)) - { - case CONST_INT: - case CONST_DOUBLE: - /* Accept all non-symbolic constants. */ - return false; - - case LABEL_REF: - /* Labels are OK iff we are non-PIC. */ - return flag_pic != 0; - - case SYMBOL_REF: - /* 'Naked' TLS symbol references are never OK, - non-TLS symbols are OK iff we are non-PIC. */ - if (tls_symbolic_operand (x)) - return true; - else - return flag_pic != 0; - - case CONST: - return s390_cannot_force_const_mem (mode, XEXP (x, 0)); - case PLUS: - case MINUS: - return s390_cannot_force_const_mem (mode, XEXP (x, 0)) - || s390_cannot_force_const_mem (mode, XEXP (x, 1)); - - case UNSPEC: - switch (XINT (x, 1)) - { - /* Only lt-relative or GOT-relative UNSPECs are OK. */ - case UNSPEC_LTREL_OFFSET: - case UNSPEC_GOT: - case UNSPEC_GOTOFF: - case UNSPEC_PLTOFF: - case UNSPEC_TLSGD: - case UNSPEC_TLSLDM: - case UNSPEC_NTPOFF: - case UNSPEC_DTPOFF: - case UNSPEC_GOTNTPOFF: - case UNSPEC_INDNTPOFF: - return false; - - /* If the literal pool shares the code section, be put - execute template placeholders into the pool as well. */ - case UNSPEC_INSN: - return TARGET_CPU_ZARCH; - - default: - return true; - } - break; - - default: - gcc_unreachable (); - } -} - -/* Returns true if the constant value OP is a legitimate general - 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. - This function accepts all constants which can be loaded directly - into a GPR. */ - -bool -legitimate_reload_constant_p (rtx op) -{ - /* Accept la(y) operands. */ - if (GET_CODE (op) == CONST_INT - && DISP_IN_RANGE (INTVAL (op))) - return true; - - /* Accept l(g)hi/l(g)fi operands. */ - if (GET_CODE (op) == CONST_INT - && (CONST_OK_FOR_K (INTVAL (op)) || CONST_OK_FOR_Os (INTVAL (op)))) - return true; - - /* Accept lliXX operands. */ - if (TARGET_ZARCH - && GET_CODE (op) == CONST_INT - && trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op) - && s390_single_part (op, word_mode, HImode, 0) >= 0) - return true; - - if (TARGET_EXTIMM - && GET_CODE (op) == CONST_INT - && trunc_int_for_mode (INTVAL (op), word_mode) == INTVAL (op) - && s390_single_part (op, word_mode, SImode, 0) >= 0) - return true; - - /* Accept larl operands. */ - if (TARGET_CPU_ZARCH - && larl_operand (op, VOIDmode)) - return true; - - /* Accept floating-point zero operands that fit into a single GPR. */ - if (GET_CODE (op) == CONST_DOUBLE - && s390_float_const_zero_p (op) - && GET_MODE_SIZE (GET_MODE (op)) <= UNITS_PER_WORD) - return true; - - /* Accept double-word operands that can be split. */ - if (GET_CODE (op) == CONST_INT - && trunc_int_for_mode (INTVAL (op), word_mode) != INTVAL (op)) - { - enum machine_mode dword_mode = word_mode == SImode ? DImode : TImode; - rtx hi = operand_subword (op, 0, 0, dword_mode); - rtx lo = operand_subword (op, 1, 0, dword_mode); - return legitimate_reload_constant_p (hi) - && legitimate_reload_constant_p (lo); - } - - /* Everything else cannot be handled without reload. */ - return false; -} - -/* Returns true if the constant value OP is a legitimate fp operand - during and after reload. - This function accepts all constants which can be loaded directly - into an FPR. */ - -static bool -legitimate_reload_fp_constant_p (rtx op) -{ - /* Accept floating-point zero operands if the load zero instruction - can be used. */ - if (TARGET_Z196 - && GET_CODE (op) == CONST_DOUBLE - && s390_float_const_zero_p (op)) - return true; - - return false; -} - -/* Given an rtx OP being reloaded into a reg required to be in class RCLASS, - return the class of reg to actually use. */ - -static reg_class_t -s390_preferred_reload_class (rtx op, reg_class_t rclass) -{ - switch (GET_CODE (op)) - { - /* Constants we cannot reload into general registers - must be forced into the literal pool. */ - case CONST_DOUBLE: - case CONST_INT: - if (reg_class_subset_p (GENERAL_REGS, rclass) - && legitimate_reload_constant_p (op)) - return GENERAL_REGS; - else if (reg_class_subset_p (ADDR_REGS, rclass) - && legitimate_reload_constant_p (op)) - return ADDR_REGS; - else if (reg_class_subset_p (FP_REGS, rclass) - && legitimate_reload_fp_constant_p (op)) - return FP_REGS; - return NO_REGS; - - /* If a symbolic constant or a PLUS is reloaded, - it is most likely being used as an address, so - prefer ADDR_REGS. If 'class' is not a superset - of ADDR_REGS, e.g. FP_REGS, reject this reload. */ - case LABEL_REF: - case SYMBOL_REF: - case CONST: - if (!legitimate_reload_constant_p (op)) - return NO_REGS; - /* fallthrough */ - case PLUS: - /* load address will be used. */ - if (reg_class_subset_p (ADDR_REGS, rclass)) - return ADDR_REGS; - else - return NO_REGS; - - default: - break; - } - - return rclass; -} - -/* Return true if ADDR is SYMBOL_REF + addend with addend being a - multiple of ALIGNMENT and the SYMBOL_REF being naturally - aligned. */ - -bool -s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment) -{ - HOST_WIDE_INT addend; - rtx symref; - - if (!s390_symref_operand_p (addr, &symref, &addend)) - return false; - - return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref) - && !(addend & (alignment - 1))); -} - -/* ADDR is moved into REG using larl. If ADDR isn't a valid larl - operand SCRATCH is used to reload the even part of the address and - adding one. */ - -void -s390_reload_larl_operand (rtx reg, rtx addr, rtx scratch) -{ - HOST_WIDE_INT addend; - rtx symref; - - if (!s390_symref_operand_p (addr, &symref, &addend)) - gcc_unreachable (); - - if (!(addend & 1)) - /* Easy case. The addend is even so larl will do fine. */ - emit_move_insn (reg, addr); - else - { - /* We can leave the scratch register untouched if the target - register is a valid base register. */ - if (REGNO (reg) < FIRST_PSEUDO_REGISTER - && REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS) - scratch = reg; - - gcc_assert (REGNO (scratch) < FIRST_PSEUDO_REGISTER); - gcc_assert (REGNO_REG_CLASS (REGNO (scratch)) == ADDR_REGS); - - if (addend != 1) - emit_move_insn (scratch, - gen_rtx_CONST (Pmode, - gen_rtx_PLUS (Pmode, symref, - GEN_INT (addend - 1)))); - else - emit_move_insn (scratch, symref); - - /* Increment the address using la in order to avoid clobbering cc. */ - emit_move_insn (reg, gen_rtx_PLUS (Pmode, scratch, const1_rtx)); - } -} - -/* Generate what is necessary to move between REG and MEM using - SCRATCH. The direction is given by TOMEM. */ - -void -s390_reload_symref_address (rtx reg, rtx mem, rtx scratch, bool tomem) -{ - /* Reload might have pulled a constant out of the literal pool. - Force it back in. */ - if (CONST_INT_P (mem) || GET_CODE (mem) == CONST_DOUBLE - || GET_CODE (mem) == CONST) - mem = force_const_mem (GET_MODE (reg), mem); - - gcc_assert (MEM_P (mem)); - - /* For a load from memory we can leave the scratch register - untouched if the target register is a valid base register. */ - if (!tomem - && REGNO (reg) < FIRST_PSEUDO_REGISTER - && REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS - && GET_MODE (reg) == GET_MODE (scratch)) - scratch = reg; - - /* Load address into scratch register. Since we can't have a - secondary reload for a secondary reload we have to cover the case - where larl would need a secondary reload here as well. */ - s390_reload_larl_operand (scratch, XEXP (mem, 0), scratch); - - /* Now we can use a standard load/store to do the move. */ - if (tomem) - emit_move_insn (replace_equiv_address (mem, scratch), reg); - else - emit_move_insn (reg, replace_equiv_address (mem, scratch)); -} - -/* Inform reload about cases where moving X with a mode MODE to a register in - RCLASS requires an extra scratch or immediate register. Return the class - needed for the immediate register. */ - -static reg_class_t -s390_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, - enum machine_mode mode, secondary_reload_info *sri) -{ - enum reg_class rclass = (enum reg_class) rclass_i; - - /* Intermediate register needed. */ - if (reg_classes_intersect_p (CC_REGS, rclass)) - return GENERAL_REGS; - - if (TARGET_Z10) - { - HOST_WIDE_INT offset; - rtx symref; - - /* On z10 several optimizer steps may generate larl operands with - an odd addend. */ - if (in_p - && s390_symref_operand_p (x, &symref, &offset) - && mode == Pmode - && !SYMBOL_REF_ALIGN1_P (symref) - && (offset & 1) == 1) - sri->icode = ((mode == DImode) ? CODE_FOR_reloaddi_larl_odd_addend_z10 - : CODE_FOR_reloadsi_larl_odd_addend_z10); - - /* On z10 we need a scratch register when moving QI, TI or floating - point mode values from or to a memory location with a SYMBOL_REF - or if the symref addend of a SI or DI move is not aligned to the - width of the access. */ - if (MEM_P (x) - && s390_symref_operand_p (XEXP (x, 0), NULL, NULL) - && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode) - || (!TARGET_ZARCH && mode == DImode) - || ((mode == HImode || mode == SImode || mode == DImode) - && (!s390_check_symref_alignment (XEXP (x, 0), - GET_MODE_SIZE (mode)))))) - { -#define __SECONDARY_RELOAD_CASE(M,m) \ - case M##mode: \ - if (TARGET_64BIT) \ - sri->icode = in_p ? CODE_FOR_reload##m##di_toreg_z10 : \ - CODE_FOR_reload##m##di_tomem_z10; \ - else \ - sri->icode = in_p ? CODE_FOR_reload##m##si_toreg_z10 : \ - CODE_FOR_reload##m##si_tomem_z10; \ - break; - - switch (GET_MODE (x)) - { - __SECONDARY_RELOAD_CASE (QI, qi); - __SECONDARY_RELOAD_CASE (HI, hi); - __SECONDARY_RELOAD_CASE (SI, si); - __SECONDARY_RELOAD_CASE (DI, di); - __SECONDARY_RELOAD_CASE (TI, ti); - __SECONDARY_RELOAD_CASE (SF, sf); - __SECONDARY_RELOAD_CASE (DF, df); - __SECONDARY_RELOAD_CASE (TF, tf); - __SECONDARY_RELOAD_CASE (SD, sd); - __SECONDARY_RELOAD_CASE (DD, dd); - __SECONDARY_RELOAD_CASE (TD, td); - - default: - gcc_unreachable (); - } -#undef __SECONDARY_RELOAD_CASE - } - } - - /* We need a scratch register when loading a PLUS expression which - is not a legitimate operand of the LOAD ADDRESS instruction. */ - if (in_p && s390_plus_operand (x, mode)) - sri->icode = (TARGET_64BIT ? - CODE_FOR_reloaddi_plus : CODE_FOR_reloadsi_plus); - - /* Performing a multiword move from or to memory we have to make sure the - second chunk in memory is addressable without causing a displacement - overflow. If that would be the case we calculate the address in - a scratch register. */ - if (MEM_P (x) - && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT - && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (x, 0), 1)) - + GET_MODE_SIZE (mode) - 1)) - { - /* For GENERAL_REGS a displacement overflow is no problem if occurring - in a s_operand address since we may fallback to lm/stm. So we only - have to care about overflows in the b+i+d case. */ - if ((reg_classes_intersect_p (GENERAL_REGS, rclass) - && s390_class_max_nregs (GENERAL_REGS, mode) > 1 - && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS) - /* For FP_REGS no lm/stm is available so this check is triggered - for displacement overflows in b+i+d and b+d like addresses. */ - || (reg_classes_intersect_p (FP_REGS, rclass) - && s390_class_max_nregs (FP_REGS, mode) > 1)) - { - if (in_p) - sri->icode = (TARGET_64BIT ? - CODE_FOR_reloaddi_nonoffmem_in : - CODE_FOR_reloadsi_nonoffmem_in); - else - sri->icode = (TARGET_64BIT ? - CODE_FOR_reloaddi_nonoffmem_out : - CODE_FOR_reloadsi_nonoffmem_out); - } - } - - /* A scratch address register is needed when a symbolic constant is - copied to r0 compiling with -fPIC. In other cases the target - register might be used as temporary (see legitimize_pic_address). */ - if (in_p && SYMBOLIC_CONST (x) && flag_pic == 2 && rclass != ADDR_REGS) - sri->icode = (TARGET_64BIT ? - CODE_FOR_reloaddi_PIC_addr : - CODE_FOR_reloadsi_PIC_addr); - - /* Either scratch or no register needed. */ - return NO_REGS; -} - -/* Generate code to load SRC, which is PLUS that is not a - legitimate operand for the LA instruction, into TARGET. - SCRATCH may be used as scratch register. */ - -void -s390_expand_plus_operand (rtx target, rtx src, - rtx scratch) -{ - rtx sum1, sum2; - struct s390_address ad; - - /* src must be a PLUS; get its two operands. */ - gcc_assert (GET_CODE (src) == PLUS); - gcc_assert (GET_MODE (src) == Pmode); - - /* Check if any of the two operands is already scheduled - for replacement by reload. This can happen e.g. when - float registers occur in an address. */ - sum1 = find_replacement (&XEXP (src, 0)); - sum2 = find_replacement (&XEXP (src, 1)); - src = gen_rtx_PLUS (Pmode, sum1, sum2); - - /* If the address is already strictly valid, there's nothing to do. */ - if (!s390_decompose_address (src, &ad) - || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - || (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))) - { - /* Otherwise, one of the operands cannot be an address register; - we reload its value into the scratch register. */ - if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15) - { - emit_move_insn (scratch, sum1); - sum1 = scratch; - } - if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15) - { - emit_move_insn (scratch, sum2); - sum2 = scratch; - } - - /* According to the way these invalid addresses are generated - in reload.c, it should never happen (at least on s390) that - *neither* of the PLUS components, after find_replacements - was applied, is an address register. */ - if (sum1 == scratch && sum2 == scratch) - { - debug_rtx (src); - gcc_unreachable (); - } - - src = gen_rtx_PLUS (Pmode, sum1, sum2); - } - - /* Emit the LOAD ADDRESS pattern. Note that reload of PLUS - is only ever performed on addresses, so we can mark the - sum as legitimate for LA in any case. */ - s390_load_address (target, src); -} - - -/* Return true if ADDR is a valid memory address. - STRICT specifies whether strict register checking applies. */ - -static bool -s390_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) -{ - struct s390_address ad; - - if (TARGET_Z10 - && larl_operand (addr, VOIDmode) - && (mode == VOIDmode - || s390_check_symref_alignment (addr, GET_MODE_SIZE (mode)))) - return true; - - if (!s390_decompose_address (addr, &ad)) - return false; - - if (strict) - { - if (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - return false; - - if (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx))) - return false; - } - else - { - if (ad.base - && !(REGNO (ad.base) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (ad.base)) == ADDR_REGS)) - return false; - - if (ad.indx - && !(REGNO (ad.indx) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (ad.indx)) == ADDR_REGS)) - return false; - } - return true; -} - -/* Return true if OP is a valid operand for the LA instruction. - In 31-bit, we need to prove that the result is used as an - address, as LA performs only a 31-bit addition. */ - -bool -legitimate_la_operand_p (rtx op) -{ - struct s390_address addr; - if (!s390_decompose_address (op, &addr)) - return false; - - return (TARGET_64BIT || addr.pointer); -} - -/* Return true if it is valid *and* preferable to use LA to - compute the sum of OP1 and OP2. */ - -bool -preferred_la_operand_p (rtx op1, rtx op2) -{ - struct s390_address addr; - - if (op2 != const0_rtx) - op1 = gen_rtx_PLUS (Pmode, op1, op2); - - if (!s390_decompose_address (op1, &addr)) - return false; - if (addr.base && !REGNO_OK_FOR_BASE_P (REGNO (addr.base))) - return false; - if (addr.indx && !REGNO_OK_FOR_INDEX_P (REGNO (addr.indx))) - return false; - - /* Avoid LA instructions with index register on z196; it is - preferable to use regular add instructions when possible. */ - if (addr.indx && s390_tune == PROCESSOR_2817_Z196) - return false; - - if (!TARGET_64BIT && !addr.pointer) - return false; - - if (addr.pointer) - return true; - - if ((addr.base && REG_P (addr.base) && REG_POINTER (addr.base)) - || (addr.indx && REG_P (addr.indx) && REG_POINTER (addr.indx))) - return true; - - return false; -} - -/* Emit a forced load-address operation to load SRC into DST. - This will use the LOAD ADDRESS instruction even in situations - where legitimate_la_operand_p (SRC) returns false. */ - -void -s390_load_address (rtx dst, rtx src) -{ - if (TARGET_64BIT) - emit_move_insn (dst, src); - else - emit_insn (gen_force_la_31 (dst, src)); -} - -/* Return a legitimate reference for ORIG (an address) using the - register REG. If REG is 0, a new pseudo is generated. - - There are two types of references that must be handled: - - 1. Global data references must load the address from the GOT, via - the PIC reg. An insn is emitted to do this load, and the reg is - returned. - - 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_FLAG_LOCAL set to - differentiate them from global data objects. The returned - address is the PIC reg + an unspec constant. - - TARGET_LEGITIMIZE_ADDRESS_P rejects symbolic references unless the PIC - reg also appears in the address. */ - -rtx -legitimize_pic_address (rtx orig, rtx reg) -{ - rtx addr = orig; - rtx new_rtx = orig; - rtx base; - - gcc_assert (!TLS_SYMBOLIC_CONST (addr)); - - if (GET_CODE (addr) == LABEL_REF - || (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (addr))) - { - /* This is a local symbol. */ - 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 - handled automatically ... */ - } - else - { - /* Access local symbols relative to the GOT. */ - - rtx temp = reg? reg : gen_reg_rtx (Pmode); - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - 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); - - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - } - } - else if (GET_CODE (addr) == SYMBOL_REF) - { - if (reg == 0) - reg = gen_reg_rtx (Pmode); - - if (flag_pic == 1) - { - /* Assume GOT offset < 4k. This is handled the same way - in both 31- and 64-bit code (@GOT). */ - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx); - new_rtx = gen_const_mem (Pmode, new_rtx); - emit_move_insn (reg, new_rtx); - new_rtx = reg; - } - 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 = reg ? reg : gen_reg_rtx (Pmode); - - gcc_assert (REGNO (temp) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (temp)) == ADDR_REGS); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTENT); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - emit_move_insn (temp, new_rtx); - - new_rtx = gen_const_mem (Pmode, temp); - emit_move_insn (reg, new_rtx); - new_rtx = reg; - } - else - { - /* If the GOT offset might be >= 4k, we have to load it - from the literal pool (@GOT). */ - - rtx temp = reg ? reg : gen_reg_rtx (Pmode); - - gcc_assert (REGNO (temp) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (temp)) == ADDR_REGS); - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - 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); - - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); - new_rtx = gen_const_mem (Pmode, new_rtx); - emit_move_insn (reg, new_rtx); - new_rtx = reg; - } - } - else - { - if (GET_CODE (addr) == CONST) - { - addr = XEXP (addr, 0); - if (GET_CODE (addr) == UNSPEC) - { - gcc_assert (XVECLEN (addr, 0) == 1); - switch (XINT (addr, 1)) - { - /* If someone moved a GOT-relative UNSPEC - out of the literal pool, force them back in. */ - case UNSPEC_GOTOFF: - case UNSPEC_PLTOFF: - new_rtx = force_const_mem (Pmode, orig); - break; - - /* @GOT is OK as is if small. */ - case UNSPEC_GOT: - if (flag_pic == 2) - new_rtx = force_const_mem (Pmode, orig); - break; - - /* @GOTENT is OK as is. */ - case UNSPEC_GOTENT: - break; - - /* @PLT is OK as is on 64-bit, must be converted to - 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) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - addr = XVECEXP (addr, 0, 0); - 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); - - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - } - break; - - /* Everything else cannot happen. */ - default: - gcc_unreachable (); - } - } - else - gcc_assert (GET_CODE (addr) == PLUS); - } - if (GET_CODE (addr) == PLUS) - { - rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); - - gcc_assert (!TLS_SYMBOLIC_CONST (op0)); - gcc_assert (!TLS_SYMBOLIC_CONST (op1)); - - /* 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_LOCAL_P (op0))) - && GET_CODE (op1) == CONST_INT) - { - if (TARGET_CPU_ZARCH - && larl_operand (op0, VOIDmode) - && INTVAL (op1) < (HOST_WIDE_INT)1 << 31 - && INTVAL (op1) >= -((HOST_WIDE_INT)1 << 31)) - { - if (INTVAL (op1) & 1) - { - /* LARL can't handle odd offsets, so emit a - pair of LARL and LA. */ - rtx temp = reg? reg : gen_reg_rtx (Pmode); - - if (!DISP_IN_RANGE (INTVAL (op1))) - { - HOST_WIDE_INT even = INTVAL (op1) - 1; - op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even)); - op0 = gen_rtx_CONST (Pmode, op0); - op1 = const1_rtx; - } - - emit_move_insn (temp, op0); - new_rtx = gen_rtx_PLUS (Pmode, temp, op1); - - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - } - else - { - /* If the offset is even, we can just use LARL. - This will happen automatically. */ - } - } - else - { - /* Access local symbols relative to the GOT. */ - - rtx temp = reg? reg : gen_reg_rtx (Pmode); - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - 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); - - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - } - } - - /* 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 - && XINT (op0, 1) == UNSPEC_GOTOFF) - { - gcc_assert (XVECLEN (op0, 0) == 1); - - new_rtx = force_const_mem (Pmode, orig); - } - - /* Otherwise, compute the sum. */ - else - { - base = legitimize_pic_address (XEXP (addr, 0), reg); - new_rtx = legitimize_pic_address (XEXP (addr, 1), - base == reg ? NULL_RTX : reg); - if (GET_CODE (new_rtx) == CONST_INT) - new_rtx = plus_constant (base, INTVAL (new_rtx)); - else - { - if (GET_CODE (new_rtx) == PLUS && CONSTANT_P (XEXP (new_rtx, 1))) - { - base = gen_rtx_PLUS (Pmode, base, XEXP (new_rtx, 0)); - new_rtx = XEXP (new_rtx, 1); - } - new_rtx = gen_rtx_PLUS (Pmode, base, new_rtx); - } - - if (GET_CODE (new_rtx) == CONST) - new_rtx = XEXP (new_rtx, 0); - new_rtx = force_operand (new_rtx, 0); - } - } - } - return new_rtx; -} - -/* Load the thread pointer into a register. */ - -rtx -s390_get_thread_pointer (void) -{ - rtx tp = gen_reg_rtx (Pmode); - - emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM)); - mark_reg_pointer (tp, BITS_PER_WORD); - - return tp; -} - -/* Emit a tls call insn. The call target is the SYMBOL_REF stored - in s390_tls_symbol which always refers to __tls_get_offset. - The returned offset is written to RESULT_REG and an USE rtx is - generated for TLS_CALL. */ - -static GTY(()) rtx s390_tls_symbol; - -static void -s390_emit_tls_call_insn (rtx result_reg, rtx tls_call) -{ - rtx insn; - - if (!flag_pic) - emit_insn (s390_load_got ()); - - if (!s390_tls_symbol) - s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset"); - - insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg, - gen_rtx_REG (Pmode, RETURN_REGNUM)); - - use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg); - RTL_CONST_CALL_P (insn) = 1; -} - -/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute - this (thread-local) address. REG may be used as temporary. */ - -static rtx -legitimize_tls_address (rtx addr, rtx reg) -{ - rtx new_rtx, tls_call, temp, base, r2, insn; - - if (GET_CODE (addr) == SYMBOL_REF) - switch (tls_symbolic_operand (addr)) - { - case TLS_MODEL_GLOBAL_DYNAMIC: - start_sequence (); - r2 = gen_rtx_REG (Pmode, 2); - tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLSGD); - new_rtx = gen_rtx_CONST (Pmode, tls_call); - new_rtx = force_const_mem (Pmode, new_rtx); - emit_move_insn (r2, new_rtx); - s390_emit_tls_call_insn (r2, tls_call); - insn = get_insns (); - end_sequence (); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF); - temp = gen_reg_rtx (Pmode); - emit_libcall_block (insn, temp, r2, new_rtx); - - new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - break; - - case TLS_MODEL_LOCAL_DYNAMIC: - start_sequence (); - r2 = gen_rtx_REG (Pmode, 2); - tls_call = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM); - new_rtx = gen_rtx_CONST (Pmode, tls_call); - new_rtx = force_const_mem (Pmode, new_rtx); - emit_move_insn (r2, new_rtx); - s390_emit_tls_call_insn (r2, tls_call); - insn = get_insns (); - end_sequence (); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TLSLDM_NTPOFF); - temp = gen_reg_rtx (Pmode); - emit_libcall_block (insn, temp, r2, new_rtx); - - new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); - base = gen_reg_rtx (Pmode); - s390_load_address (base, new_rtx); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_DTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = force_const_mem (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - - new_rtx = gen_rtx_PLUS (Pmode, base, temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - break; - - case TLS_MODEL_INITIAL_EXEC: - if (flag_pic == 1) - { - /* Assume GOT offset < 4k. This is handled the same way - in both 31- and 64-bit code. */ - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new_rtx); - new_rtx = gen_const_mem (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - } - 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. */ - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - - new_rtx = gen_const_mem (Pmode, temp); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - } - else if (flag_pic) - { - /* If the GOT offset might be >= 4k, we have to load it - from the literal pool. */ - - if (reload_in_progress || reload_completed) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = force_const_mem (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - - new_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); - new_rtx = gen_const_mem (Pmode, new_rtx); - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new_rtx, addr), UNSPEC_TLS_LOAD); - temp = gen_reg_rtx (Pmode); - emit_insn (gen_rtx_SET (Pmode, temp, new_rtx)); - } - else - { - /* In position-dependent code, load the absolute address of - the GOT entry from the literal pool. */ - - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_INDNTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = force_const_mem (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - - new_rtx = temp; - new_rtx = gen_const_mem (Pmode, new_rtx); - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new_rtx, addr), UNSPEC_TLS_LOAD); - temp = gen_reg_rtx (Pmode); - emit_insn (gen_rtx_SET (Pmode, temp, new_rtx)); - } - - new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - break; - - case TLS_MODEL_LOCAL_EXEC: - new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_NTPOFF); - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - new_rtx = force_const_mem (Pmode, new_rtx); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, new_rtx); - - new_rtx = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp); - if (reg != 0) - { - s390_load_address (reg, new_rtx); - new_rtx = reg; - } - break; - - default: - gcc_unreachable (); - } - - else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC) - { - switch (XINT (XEXP (addr, 0), 1)) - { - case UNSPEC_INDNTPOFF: - gcc_assert (TARGET_CPU_ZARCH); - new_rtx = addr; - break; - - default: - gcc_unreachable (); - } - } - - else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS - && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT) - { - new_rtx = XEXP (XEXP (addr, 0), 0); - if (GET_CODE (new_rtx) != SYMBOL_REF) - new_rtx = gen_rtx_CONST (Pmode, new_rtx); - - new_rtx = legitimize_tls_address (new_rtx, reg); - new_rtx = plus_constant (new_rtx, INTVAL (XEXP (XEXP (addr, 0), 1))); - new_rtx = force_operand (new_rtx, 0); - } - - else - gcc_unreachable (); /* for now ... */ - - return new_rtx; -} - -/* Emit insns making the address in operands[1] valid for a standard - move to operands[0]. operands[1] is replaced by an address which - should be used instead of the former RTX to emit the move - pattern. */ - -void -emit_symbolic_move (rtx *operands) -{ - rtx temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode); - - if (GET_CODE (operands[0]) == MEM) - operands[1] = force_reg (Pmode, operands[1]); - else if (TLS_SYMBOLIC_CONST (operands[1])) - operands[1] = legitimize_tls_address (operands[1], temp); - else if (flag_pic) - operands[1] = legitimize_pic_address (operands[1], temp); -} - -/* Try machine-dependent ways of modifying an illegitimate address X - to be legitimate. If we find one, return the new, valid address. - - OLDX is the address as it was before break_out_memory_refs was called. - In some cases it is useful to look at this to decide what needs to be done. - - MODE is the mode of the operand pointed to by X. - - When -fpic is used, special handling is needed for symbolic references. - See comments by legitimize_pic_address for details. */ - -static rtx -s390_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - rtx constant_term = const0_rtx; - - if (TLS_SYMBOLIC_CONST (x)) - { - x = legitimize_tls_address (x, 0); - - if (s390_legitimate_address_p (mode, x, FALSE)) - return x; - } - else if (GET_CODE (x) == PLUS - && (TLS_SYMBOLIC_CONST (XEXP (x, 0)) - || TLS_SYMBOLIC_CONST (XEXP (x, 1)))) - { - return x; - } - else if (flag_pic) - { - if (SYMBOLIC_CONST (x) - || (GET_CODE (x) == PLUS - && (SYMBOLIC_CONST (XEXP (x, 0)) - || SYMBOLIC_CONST (XEXP (x, 1))))) - x = legitimize_pic_address (x, 0); - - if (s390_legitimate_address_p (mode, x, FALSE)) - return x; - } - - x = eliminate_constant_term (x, &constant_term); - - /* 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. - - 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 - && !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; - HOST_WIDE_INT upper = INTVAL (constant_term) ^ lower; - - rtx temp = gen_reg_rtx (Pmode); - rtx val = force_operand (GEN_INT (upper), temp); - if (val != temp) - emit_move_insn (temp, val); - - x = gen_rtx_PLUS (Pmode, x, temp); - constant_term = GEN_INT (lower); - } - - if (GET_CODE (x) == PLUS) - { - if (GET_CODE (XEXP (x, 0)) == REG) - { - rtx temp = gen_reg_rtx (Pmode); - rtx val = force_operand (XEXP (x, 1), temp); - if (val != temp) - emit_move_insn (temp, val); - - x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp); - } - - else if (GET_CODE (XEXP (x, 1)) == REG) - { - rtx temp = gen_reg_rtx (Pmode); - rtx val = force_operand (XEXP (x, 0), temp); - if (val != temp) - emit_move_insn (temp, val); - - x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1)); - } - } - - if (constant_term != const0_rtx) - x = gen_rtx_PLUS (Pmode, x, constant_term); - - return x; -} - -/* Try a machine-dependent way of reloading an illegitimate address AD - operand. If we find one, push the reload and return the new address. - - MODE is the mode of the enclosing MEM. OPNUM is the operand number - and TYPE is the reload type of the current reload. */ - -rtx -legitimize_reload_address (rtx ad, enum machine_mode mode ATTRIBUTE_UNUSED, - int opnum, int type) -{ - if (!optimize || TARGET_LONG_DISPLACEMENT) - return NULL_RTX; - - if (GET_CODE (ad) == PLUS) - { - rtx tem = simplify_binary_operation (PLUS, Pmode, - XEXP (ad, 0), XEXP (ad, 1)); - if (tem) - ad = tem; - } - - if (GET_CODE (ad) == PLUS - && GET_CODE (XEXP (ad, 0)) == REG - && GET_CODE (XEXP (ad, 1)) == CONST_INT - && !DISP_IN_RANGE (INTVAL (XEXP (ad, 1)))) - { - HOST_WIDE_INT lower = INTVAL (XEXP (ad, 1)) & 0xfff; - HOST_WIDE_INT upper = INTVAL (XEXP (ad, 1)) ^ lower; - rtx cst, tem, new_rtx; - - cst = GEN_INT (upper); - if (!legitimate_reload_constant_p (cst)) - cst = force_const_mem (Pmode, cst); - - tem = gen_rtx_PLUS (Pmode, XEXP (ad, 0), cst); - new_rtx = gen_rtx_PLUS (Pmode, tem, GEN_INT (lower)); - - push_reload (XEXP (tem, 1), 0, &XEXP (tem, 1), 0, - BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, - opnum, (enum reload_type) type); - return new_rtx; - } - - return NULL_RTX; -} - -/* Emit code to move LEN bytes from DST to SRC. */ - -void -s390_expand_movmem (rtx dst, rtx src, rtx len) -{ - if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) - { - if (INTVAL (len) > 0) - emit_insn (gen_movmem_short (dst, src, GEN_INT (INTVAL (len) - 1))); - } - - else if (TARGET_MVCLE) - { - emit_insn (gen_movmem_long (dst, src, convert_to_mode (Pmode, len, 1))); - } - - else - { - rtx dst_addr, src_addr, count, blocks, temp; - rtx loop_start_label = gen_label_rtx (); - rtx loop_end_label = gen_label_rtx (); - rtx end_label = gen_label_rtx (); - enum machine_mode mode; - - mode = GET_MODE (len); - if (mode == VOIDmode) - mode = Pmode; - - dst_addr = gen_reg_rtx (Pmode); - src_addr = gen_reg_rtx (Pmode); - count = gen_reg_rtx (mode); - blocks = gen_reg_rtx (mode); - - convert_move (count, len, 1); - 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, - OPTAB_DIRECT); - if (temp != count) - emit_move_insn (count, temp); - - temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_label (loop_start_label); - - if (TARGET_Z10 - && (GET_CODE (len) != CONST_INT || INTVAL (len) > 768)) - { - rtx prefetch; - - /* Issue a read prefetch for the +3 cache line. */ - prefetch = gen_prefetch (gen_rtx_PLUS (Pmode, src_addr, GEN_INT (768)), - const0_rtx, const0_rtx); - PREFETCH_SCHEDULE_BARRIER_P (prefetch) = true; - emit_insn (prefetch); - - /* Issue a write prefetch for the +3 cache line. */ - prefetch = gen_prefetch (gen_rtx_PLUS (Pmode, dst_addr, GEN_INT (768)), - const1_rtx, const0_rtx); - PREFETCH_SCHEDULE_BARRIER_P (prefetch) = true; - emit_insn (prefetch); - } - - emit_insn (gen_movmem_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, - gen_rtx_PLUS (Pmode, src_addr, GEN_INT (256))); - - temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_jump (loop_start_label); - emit_label (loop_end_label); - - emit_insn (gen_movmem_short (dst, src, - convert_to_mode (Pmode, count, 1))); - emit_label (end_label); - } -} - -/* Emit code to set LEN bytes at DST to VAL. - Make use of clrmem if VAL is zero. */ - -void -s390_expand_setmem (rtx dst, rtx len, rtx val) -{ - if (GET_CODE (len) == CONST_INT && INTVAL (len) == 0) - return; - - gcc_assert (GET_CODE (val) == CONST_INT || GET_MODE (val) == QImode); - - if (GET_CODE (len) == CONST_INT && INTVAL (len) > 0 && INTVAL (len) <= 257) - { - if (val == const0_rtx && INTVAL (len) <= 256) - emit_insn (gen_clrmem_short (dst, GEN_INT (INTVAL (len) - 1))); - else - { - /* Initialize memory by storing the first byte. */ - emit_move_insn (adjust_address (dst, QImode, 0), val); - - if (INTVAL (len) > 1) - { - /* Initiate 1 byte overlap move. - The first byte of DST is propagated through DSTP1. - Prepare a movmem for: DST+1 = DST (length = LEN - 1). - DST is set to size 1 so the rest of the memory location - does not count as source operand. */ - rtx dstp1 = adjust_address (dst, VOIDmode, 1); - set_mem_size (dst, 1); - - emit_insn (gen_movmem_short (dstp1, dst, - GEN_INT (INTVAL (len) - 2))); - } - } - } - - else if (TARGET_MVCLE) - { - val = force_not_mem (convert_modes (Pmode, QImode, val, 1)); - emit_insn (gen_setmem_long (dst, convert_to_mode (Pmode, len, 1), val)); - } - - else - { - rtx dst_addr, count, blocks, temp, dstp1 = NULL_RTX; - rtx loop_start_label = gen_label_rtx (); - rtx loop_end_label = gen_label_rtx (); - rtx end_label = gen_label_rtx (); - enum machine_mode mode; - - mode = GET_MODE (len); - if (mode == VOIDmode) - mode = Pmode; - - dst_addr = gen_reg_rtx (Pmode); - count = gen_reg_rtx (mode); - blocks = gen_reg_rtx (mode); - - convert_move (count, len, 1); - 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); - - if (val == const0_rtx) - temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, - OPTAB_DIRECT); - else - { - dstp1 = adjust_address (dst, VOIDmode, 1); - set_mem_size (dst, 1); - - /* Initialize memory by storing the first byte. */ - emit_move_insn (adjust_address (dst, QImode, 0), val); - - /* If count is 1 we are done. */ - emit_cmp_and_jump_insns (count, const1_rtx, - EQ, NULL_RTX, mode, 1, end_label); - - temp = expand_binop (mode, add_optab, count, GEN_INT (-2), count, 1, - OPTAB_DIRECT); - } - if (temp != count) - emit_move_insn (count, temp); - - temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_label (loop_start_label); - - if (TARGET_Z10 - && (GET_CODE (len) != CONST_INT || INTVAL (len) > 1024)) - { - /* Issue a write prefetch for the +4 cache line. */ - rtx prefetch = gen_prefetch (gen_rtx_PLUS (Pmode, dst_addr, - GEN_INT (1024)), - const1_rtx, const0_rtx); - emit_insn (prefetch); - PREFETCH_SCHEDULE_BARRIER_P (prefetch) = true; - } - - if (val == const0_rtx) - emit_insn (gen_clrmem_short (dst, GEN_INT (255))); - else - emit_insn (gen_movmem_short (dstp1, 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, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_jump (loop_start_label); - emit_label (loop_end_label); - - if (val == const0_rtx) - emit_insn (gen_clrmem_short (dst, convert_to_mode (Pmode, count, 1))); - else - emit_insn (gen_movmem_short (dstp1, dst, convert_to_mode (Pmode, count, 1))); - emit_label (end_label); - } -} - -/* Emit code to compare LEN bytes at OP0 with those at OP1, - and return the result in TARGET. */ - -void -s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) -{ - rtx ccreg = gen_rtx_REG (CCUmode, CC_REGNUM); - rtx tmp; - - /* As the result of CMPINT is inverted compared to what we need, - we have to swap the operands. */ - tmp = op0; op0 = op1; op1 = tmp; - - if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256) - { - if (INTVAL (len) > 0) - { - emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (INTVAL (len) - 1))); - emit_insn (gen_cmpint (target, ccreg)); - } - else - emit_move_insn (target, const0_rtx); - } - else if (TARGET_MVCLE) - { - emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1))); - emit_insn (gen_cmpint (target, ccreg)); - } - else - { - rtx addr0, addr1, count, blocks, temp; - rtx loop_start_label = gen_label_rtx (); - rtx loop_end_label = gen_label_rtx (); - rtx end_label = gen_label_rtx (); - enum machine_mode mode; - - mode = GET_MODE (len); - if (mode == VOIDmode) - mode = Pmode; - - addr0 = gen_reg_rtx (Pmode); - addr1 = gen_reg_rtx (Pmode); - count = gen_reg_rtx (mode); - blocks = gen_reg_rtx (mode); - - convert_move (count, len, 1); - 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, - OPTAB_DIRECT); - if (temp != count) - emit_move_insn (count, temp); - - temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_label (loop_start_label); - - if (TARGET_Z10 - && (GET_CODE (len) != CONST_INT || INTVAL (len) > 512)) - { - rtx prefetch; - - /* Issue a read prefetch for the +2 cache line of operand 1. */ - prefetch = gen_prefetch (gen_rtx_PLUS (Pmode, addr0, GEN_INT (512)), - const0_rtx, const0_rtx); - emit_insn (prefetch); - PREFETCH_SCHEDULE_BARRIER_P (prefetch) = true; - - /* Issue a read prefetch for the +2 cache line of operand 2. */ - prefetch = gen_prefetch (gen_rtx_PLUS (Pmode, addr1, GEN_INT (512)), - const0_rtx, const0_rtx); - emit_insn (prefetch); - PREFETCH_SCHEDULE_BARRIER_P (prefetch) = true; - } - - emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255))); - temp = gen_rtx_NE (VOIDmode, ccreg, const0_rtx); - 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, - gen_rtx_PLUS (Pmode, addr0, GEN_INT (256))); - s390_load_address (addr1, - gen_rtx_PLUS (Pmode, addr1, GEN_INT (256))); - - temp = expand_binop (mode, add_optab, blocks, constm1_rtx, blocks, 1, - OPTAB_DIRECT); - if (temp != blocks) - emit_move_insn (blocks, temp); - - emit_cmp_and_jump_insns (blocks, const0_rtx, - EQ, NULL_RTX, mode, 1, loop_end_label); - - emit_jump (loop_start_label); - emit_label (loop_end_label); - - emit_insn (gen_cmpmem_short (op0, op1, - convert_to_mode (Pmode, count, 1))); - emit_label (end_label); - - emit_insn (gen_cmpint (target, ccreg)); - } -} - - -/* Expand conditional increment or decrement using alc/slb instructions. - Should generate code setting DST to either SRC or SRC + INCREMENT, - depending on the result of the comparison CMP_OP0 CMP_CODE CMP_OP1. - Returns true if successful, false otherwise. - - That makes it possible to implement some if-constructs without jumps e.g.: - (borrow = CC0 | CC1 and carry = CC2 | CC3) - unsigned int a, b, c; - if (a < b) c++; -> CCU b > a -> CC2; c += carry; - if (a < b) c--; -> CCL3 a - b -> borrow; c -= borrow; - if (a <= b) c++; -> CCL3 b - a -> borrow; c += carry; - if (a <= b) c--; -> CCU a <= b -> borrow; c -= borrow; - - Checks for EQ and NE with a nonzero value need an additional xor e.g.: - if (a == b) c++; -> CCL3 a ^= b; 0 - a -> borrow; c += carry; - if (a == b) c--; -> CCU a ^= b; a <= 0 -> CC0 | CC1; c -= borrow; - if (a != b) c++; -> CCU a ^= b; a > 0 -> CC2; c += carry; - if (a != b) c--; -> CCL3 a ^= b; 0 - a -> borrow; c -= borrow; */ - -bool -s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1, - rtx dst, rtx src, rtx increment) -{ - enum machine_mode cmp_mode; - enum machine_mode cc_mode; - rtx op_res; - rtx insn; - rtvec p; - int ret; - - if ((GET_MODE (cmp_op0) == SImode || GET_MODE (cmp_op0) == VOIDmode) - && (GET_MODE (cmp_op1) == SImode || GET_MODE (cmp_op1) == VOIDmode)) - cmp_mode = SImode; - else if ((GET_MODE (cmp_op0) == DImode || GET_MODE (cmp_op0) == VOIDmode) - && (GET_MODE (cmp_op1) == DImode || GET_MODE (cmp_op1) == VOIDmode)) - cmp_mode = DImode; - else - return false; - - /* Try ADD LOGICAL WITH CARRY. */ - if (increment == const1_rtx) - { - /* Determine CC mode to use. */ - if (cmp_code == EQ || cmp_code == NE) - { - if (cmp_op1 != const0_rtx) - { - cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1, - NULL_RTX, 0, OPTAB_WIDEN); - cmp_op1 = const0_rtx; - } - - cmp_code = cmp_code == EQ ? LEU : GTU; - } - - if (cmp_code == LTU || cmp_code == LEU) - { - rtx tem = cmp_op0; - cmp_op0 = cmp_op1; - cmp_op1 = tem; - cmp_code = swap_condition (cmp_code); - } - - switch (cmp_code) - { - case GTU: - cc_mode = CCUmode; - break; - - case GEU: - cc_mode = CCL3mode; - break; - - default: - return false; - } - - /* Emit comparison instruction pattern. */ - if (!register_operand (cmp_op0, cmp_mode)) - cmp_op0 = force_reg (cmp_mode, cmp_op0); - - insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), - gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); - /* We use insn_invalid_p here to add clobbers if required. */ - ret = insn_invalid_p (emit_insn (insn)); - gcc_assert (!ret); - - /* Emit ALC instruction pattern. */ - op_res = gen_rtx_fmt_ee (cmp_code, GET_MODE (dst), - gen_rtx_REG (cc_mode, CC_REGNUM), - const0_rtx); - - if (src != const0_rtx) - { - if (!register_operand (src, GET_MODE (dst))) - src = force_reg (GET_MODE (dst), src); - - op_res = gen_rtx_PLUS (GET_MODE (dst), op_res, src); - op_res = gen_rtx_PLUS (GET_MODE (dst), op_res, const0_rtx); - } - - p = rtvec_alloc (2); - RTVEC_ELT (p, 0) = - gen_rtx_SET (VOIDmode, dst, op_res); - RTVEC_ELT (p, 1) = - gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); - - return true; - } - - /* Try SUBTRACT LOGICAL WITH BORROW. */ - if (increment == constm1_rtx) - { - /* Determine CC mode to use. */ - if (cmp_code == EQ || cmp_code == NE) - { - if (cmp_op1 != const0_rtx) - { - cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1, - NULL_RTX, 0, OPTAB_WIDEN); - cmp_op1 = const0_rtx; - } - - cmp_code = cmp_code == EQ ? LEU : GTU; - } - - if (cmp_code == GTU || cmp_code == GEU) - { - rtx tem = cmp_op0; - cmp_op0 = cmp_op1; - cmp_op1 = tem; - cmp_code = swap_condition (cmp_code); - } - - switch (cmp_code) - { - case LEU: - cc_mode = CCUmode; - break; - - case LTU: - cc_mode = CCL3mode; - break; - - default: - return false; - } - - /* Emit comparison instruction pattern. */ - if (!register_operand (cmp_op0, cmp_mode)) - cmp_op0 = force_reg (cmp_mode, cmp_op0); - - insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM), - gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1)); - /* We use insn_invalid_p here to add clobbers if required. */ - ret = insn_invalid_p (emit_insn (insn)); - gcc_assert (!ret); - - /* Emit SLB instruction pattern. */ - if (!register_operand (src, GET_MODE (dst))) - src = force_reg (GET_MODE (dst), src); - - op_res = gen_rtx_MINUS (GET_MODE (dst), - gen_rtx_MINUS (GET_MODE (dst), src, const0_rtx), - gen_rtx_fmt_ee (cmp_code, GET_MODE (dst), - gen_rtx_REG (cc_mode, CC_REGNUM), - const0_rtx)); - p = rtvec_alloc (2); - RTVEC_ELT (p, 0) = - gen_rtx_SET (VOIDmode, dst, op_res); - RTVEC_ELT (p, 1) = - gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); - - return true; - } - - return false; -} - -/* Expand code for the insv template. Return true if successful. */ - -bool -s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) -{ - int bitsize = INTVAL (op1); - int bitpos = INTVAL (op2); - - /* On z10 we can use the risbg instruction to implement insv. */ - if (TARGET_Z10 - && ((GET_MODE (dest) == DImode && GET_MODE (src) == DImode) - || (GET_MODE (dest) == SImode && GET_MODE (src) == SImode))) - { - rtx op; - rtx clobber; - - op = gen_rtx_SET (GET_MODE(src), - gen_rtx_ZERO_EXTRACT (GET_MODE (dest), dest, op1, op2), - src); - clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber))); - - return true; - } - - /* We need byte alignment. */ - if (bitsize % BITS_PER_UNIT) - return false; - - if (bitpos == 0 - && memory_operand (dest, VOIDmode) - && (register_operand (src, word_mode) - || const_int_operand (src, VOIDmode))) - { - /* Emit standard pattern if possible. */ - enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT); - if (GET_MODE_BITSIZE (mode) == bitsize) - emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src)); - - /* (set (ze (mem)) (const_int)). */ - else if (const_int_operand (src, VOIDmode)) - { - int size = bitsize / BITS_PER_UNIT; - rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode, - GET_MODE_SIZE (word_mode) - size); - - dest = adjust_address (dest, BLKmode, 0); - set_mem_size (dest, size); - s390_expand_movmem (dest, src_mem, GEN_INT (size)); - } - - /* (set (ze (mem)) (reg)). */ - else if (register_operand (src, word_mode)) - { - if (bitsize <= GET_MODE_BITSIZE (SImode)) - emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1, - const0_rtx), src); - else - { - /* Emit st,stcmh sequence. */ - int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode); - int size = stcmh_width / BITS_PER_UNIT; - - emit_move_insn (adjust_address (dest, SImode, size), - gen_lowpart (SImode, src)); - set_mem_size (dest, size); - emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT - (stcmh_width), const0_rtx), - gen_rtx_LSHIFTRT (word_mode, src, GEN_INT - (GET_MODE_BITSIZE (SImode)))); - } - } - else - return false; - - return true; - } - - /* (set (ze (reg)) (const_int)). */ - if (TARGET_ZARCH - && register_operand (dest, word_mode) - && (bitpos % 16) == 0 - && (bitsize % 16) == 0 - && const_int_operand (src, VOIDmode)) - { - HOST_WIDE_INT val = INTVAL (src); - int regpos = bitpos + bitsize; - - while (regpos > bitpos) - { - enum machine_mode putmode; - int putsize; - - if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32)) - putmode = SImode; - else - putmode = HImode; - - putsize = GET_MODE_BITSIZE (putmode); - regpos -= putsize; - emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, - GEN_INT (putsize), - GEN_INT (regpos)), - gen_int_mode (val, putmode)); - val >>= putsize; - } - gcc_assert (regpos == bitpos); - return true; - } - - return false; -} - -/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic which returns a - register that holds VAL of mode MODE shifted by COUNT bits. */ - -static inline rtx -s390_expand_mask_and_shift (rtx val, enum machine_mode mode, rtx count) -{ - val = expand_simple_binop (SImode, AND, val, GEN_INT (GET_MODE_MASK (mode)), - NULL_RTX, 1, OPTAB_DIRECT); - return expand_simple_binop (SImode, ASHIFT, val, count, - NULL_RTX, 1, OPTAB_DIRECT); -} - -/* Structure to hold the initial parameters for a compare_and_swap operation - in HImode and QImode. */ - -struct alignment_context -{ - rtx memsi; /* SI aligned memory location. */ - rtx shift; /* Bit offset with regard to lsb. */ - rtx modemask; /* Mask of the HQImode shifted by SHIFT bits. */ - rtx modemaski; /* ~modemask */ - bool aligned; /* True if memory is aligned, false else. */ -}; - -/* A subroutine of s390_expand_cs_hqi and s390_expand_atomic to initialize - structure AC for transparent simplifying, if the memory alignment is known - to be at least 32bit. MEM is the memory location for the actual operation - and MODE its mode. */ - -static void -init_alignment_context (struct alignment_context *ac, rtx mem, - enum machine_mode mode) -{ - ac->shift = GEN_INT (GET_MODE_SIZE (SImode) - GET_MODE_SIZE (mode)); - ac->aligned = (MEM_ALIGN (mem) >= GET_MODE_BITSIZE (SImode)); - - if (ac->aligned) - ac->memsi = adjust_address (mem, SImode, 0); /* Memory is aligned. */ - else - { - /* Alignment is unknown. */ - rtx byteoffset, addr, align; - - /* Force the address into a register. */ - addr = force_reg (Pmode, XEXP (mem, 0)); - - /* Align it to SImode. */ - align = expand_simple_binop (Pmode, AND, addr, - GEN_INT (-GET_MODE_SIZE (SImode)), - NULL_RTX, 1, OPTAB_DIRECT); - /* Generate MEM. */ - ac->memsi = gen_rtx_MEM (SImode, align); - MEM_VOLATILE_P (ac->memsi) = MEM_VOLATILE_P (mem); - set_mem_alias_set (ac->memsi, ALIAS_SET_MEMORY_BARRIER); - set_mem_align (ac->memsi, GET_MODE_BITSIZE (SImode)); - - /* Calculate shiftcount. */ - byteoffset = expand_simple_binop (Pmode, AND, addr, - GEN_INT (GET_MODE_SIZE (SImode) - 1), - NULL_RTX, 1, OPTAB_DIRECT); - /* As we already have some offset, evaluate the remaining distance. */ - ac->shift = expand_simple_binop (SImode, MINUS, ac->shift, byteoffset, - NULL_RTX, 1, OPTAB_DIRECT); - - } - /* Shift is the byte count, but we need the bitcount. */ - ac->shift = expand_simple_binop (SImode, MULT, ac->shift, GEN_INT (BITS_PER_UNIT), - NULL_RTX, 1, OPTAB_DIRECT); - /* Calculate masks. */ - ac->modemask = expand_simple_binop (SImode, ASHIFT, - GEN_INT (GET_MODE_MASK (mode)), ac->shift, - NULL_RTX, 1, OPTAB_DIRECT); - ac->modemaski = expand_simple_unop (SImode, NOT, ac->modemask, NULL_RTX, 1); -} - -/* Expand an atomic compare and swap operation for HImode and QImode. MEM is - the memory location, CMP the old value to compare MEM with and NEW_RTX the value - to set if CMP == MEM. - CMP is never in memory for compare_and_swap_cc because - expand_bool_compare_and_swap puts it into a register for later compare. */ - -void -s390_expand_cs_hqi (enum machine_mode mode, rtx target, rtx mem, rtx cmp, rtx new_rtx) -{ - struct alignment_context ac; - rtx cmpv, newv, val, resv, cc; - rtx res = gen_reg_rtx (SImode); - rtx csloop = gen_label_rtx (); - rtx csend = gen_label_rtx (); - - gcc_assert (register_operand (target, VOIDmode)); - gcc_assert (MEM_P (mem)); - - init_alignment_context (&ac, mem, mode); - - /* Shift the values to the correct bit positions. */ - if (!(ac.aligned && MEM_P (cmp))) - cmp = s390_expand_mask_and_shift (cmp, mode, ac.shift); - if (!(ac.aligned && MEM_P (new_rtx))) - new_rtx = s390_expand_mask_and_shift (new_rtx, mode, ac.shift); - - /* Load full word. Subsequent loads are performed by CS. */ - val = expand_simple_binop (SImode, AND, ac.memsi, ac.modemaski, - NULL_RTX, 1, OPTAB_DIRECT); - - /* Start CS loop. */ - emit_label (csloop); - /* val = "<mem>00..0<mem>" - * cmp = "00..0<cmp>00..0" - * new = "00..0<new>00..0" - */ - - /* Patch cmp and new with val at correct position. */ - if (ac.aligned && MEM_P (cmp)) - { - cmpv = force_reg (SImode, val); - store_bit_field (cmpv, GET_MODE_BITSIZE (mode), 0, - 0, 0, SImode, cmp); - } - else - cmpv = force_reg (SImode, expand_simple_binop (SImode, IOR, cmp, val, - NULL_RTX, 1, OPTAB_DIRECT)); - if (ac.aligned && MEM_P (new_rtx)) - { - newv = force_reg (SImode, val); - store_bit_field (newv, GET_MODE_BITSIZE (mode), 0, - 0, 0, SImode, new_rtx); - } - else - newv = force_reg (SImode, expand_simple_binop (SImode, IOR, new_rtx, val, - NULL_RTX, 1, OPTAB_DIRECT)); - - /* Jump to end if we're done (likely?). */ - s390_emit_jump (csend, s390_emit_compare_and_swap (EQ, res, ac.memsi, - cmpv, newv)); - - /* Check for changes outside mode. */ - resv = expand_simple_binop (SImode, AND, res, ac.modemaski, - NULL_RTX, 1, OPTAB_DIRECT); - cc = s390_emit_compare (NE, resv, val); - emit_move_insn (val, resv); - /* Loop internal if so. */ - s390_emit_jump (csloop, cc); - - emit_label (csend); - - /* Return the correct part of the bitfield. */ - convert_move (target, expand_simple_binop (SImode, LSHIFTRT, res, ac.shift, - NULL_RTX, 1, OPTAB_DIRECT), 1); -} - -/* Expand an atomic operation CODE of mode MODE. MEM is the memory location - and VAL the value to play with. If AFTER is true then store the value - MEM holds after the operation, if AFTER is false then store the value MEM - holds before the operation. If TARGET is zero then discard that value, else - store it to TARGET. */ - -void -s390_expand_atomic (enum machine_mode mode, enum rtx_code code, - rtx target, rtx mem, rtx val, bool after) -{ - struct alignment_context ac; - rtx cmp; - rtx new_rtx = gen_reg_rtx (SImode); - rtx orig = gen_reg_rtx (SImode); - rtx csloop = gen_label_rtx (); - - gcc_assert (!target || register_operand (target, VOIDmode)); - gcc_assert (MEM_P (mem)); - - init_alignment_context (&ac, mem, mode); - - /* Shift val to the correct bit positions. - Preserve "icm", but prevent "ex icm". */ - if (!(ac.aligned && code == SET && MEM_P (val))) - val = s390_expand_mask_and_shift (val, mode, ac.shift); - - /* Further preparation insns. */ - if (code == PLUS || code == MINUS) - emit_move_insn (orig, val); - else if (code == MULT || code == AND) /* val = "11..1<val>11..1" */ - val = expand_simple_binop (SImode, XOR, val, ac.modemaski, - NULL_RTX, 1, OPTAB_DIRECT); - - /* Load full word. Subsequent loads are performed by CS. */ - cmp = force_reg (SImode, ac.memsi); - - /* Start CS loop. */ - emit_label (csloop); - emit_move_insn (new_rtx, cmp); - - /* Patch new with val at correct position. */ - switch (code) - { - case PLUS: - case MINUS: - val = expand_simple_binop (SImode, code, new_rtx, orig, - NULL_RTX, 1, OPTAB_DIRECT); - val = expand_simple_binop (SImode, AND, val, ac.modemask, - NULL_RTX, 1, OPTAB_DIRECT); - /* FALLTHRU */ - case SET: - if (ac.aligned && MEM_P (val)) - store_bit_field (new_rtx, GET_MODE_BITSIZE (mode), 0, - 0, 0, SImode, val); - else - { - new_rtx = expand_simple_binop (SImode, AND, new_rtx, ac.modemaski, - NULL_RTX, 1, OPTAB_DIRECT); - new_rtx = expand_simple_binop (SImode, IOR, new_rtx, val, - NULL_RTX, 1, OPTAB_DIRECT); - } - break; - case AND: - case IOR: - case XOR: - new_rtx = expand_simple_binop (SImode, code, new_rtx, val, - NULL_RTX, 1, OPTAB_DIRECT); - break; - case MULT: /* NAND */ - new_rtx = expand_simple_binop (SImode, AND, new_rtx, val, - NULL_RTX, 1, OPTAB_DIRECT); - new_rtx = expand_simple_binop (SImode, XOR, new_rtx, ac.modemask, - NULL_RTX, 1, OPTAB_DIRECT); - break; - default: - gcc_unreachable (); - } - - s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, cmp, - ac.memsi, cmp, new_rtx)); - - /* Return the correct part of the bitfield. */ - if (target) - convert_move (target, expand_simple_binop (SImode, LSHIFTRT, - after ? new_rtx : cmp, ac.shift, - NULL_RTX, 1, OPTAB_DIRECT), 1); -} - -/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. - We need to emit DTP-relative relocations. */ - -static void s390_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; - -static 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: - gcc_unreachable (); - } - output_addr_const (file, x); - fputs ("@DTPOFF", file); -} - -#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING -/* Implement TARGET_MANGLE_TYPE. */ - -static const char * -s390_mangle_type (const_tree type) -{ - if (TYPE_MAIN_VARIANT (type) == long_double_type_node - && TARGET_LONG_DOUBLE_128) - return "g"; - - /* For all other types, use normal C++ mangling. */ - return NULL; -} -#endif - -/* In the name of slightly smaller debug output, and to cater to - general assembler lossage, recognize various UNSPEC sequences - and turn them back into a direct symbol reference. */ - -static rtx -s390_delegitimize_address (rtx orig_x) -{ - rtx x, y; - - orig_x = delegitimize_mem_from_attrs (orig_x); - x = orig_x; - - /* Extract the symbol ref from: - (plus:SI (reg:SI 12 %r12) - (const:SI (unspec:SI [(symbol_ref/f:SI ("*.LC0"))] - UNSPEC_GOTOFF/PLTOFF))) - and - (plus:SI (reg:SI 12 %r12) - (const:SI (plus:SI (unspec:SI [(symbol_ref:SI ("L"))] - UNSPEC_GOTOFF/PLTOFF) - (const_int 4 [0x4])))) */ - if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM - && GET_CODE (XEXP (x, 1)) == CONST) - { - HOST_WIDE_INT offset = 0; - - /* The const operand. */ - y = XEXP (XEXP (x, 1), 0); - - if (GET_CODE (y) == PLUS - && GET_CODE (XEXP (y, 1)) == CONST_INT) - { - offset = INTVAL (XEXP (y, 1)); - y = XEXP (y, 0); - } - - if (GET_CODE (y) == UNSPEC - && (XINT (y, 1) == UNSPEC_GOTOFF - || XINT (y, 1) == UNSPEC_PLTOFF)) - return plus_constant (XVECEXP (y, 0, 0), offset); - } - - if (GET_CODE (x) != MEM) - return orig_x; - - x = XEXP (x, 0); - if (GET_CODE (x) == PLUS - && GET_CODE (XEXP (x, 1)) == CONST - && GET_CODE (XEXP (x, 0)) == REG - && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM) - { - y = XEXP (XEXP (x, 1), 0); - if (GET_CODE (y) == UNSPEC - && XINT (y, 1) == UNSPEC_GOT) - y = XVECEXP (y, 0, 0); - else - return orig_x; - } - else if (GET_CODE (x) == CONST) - { - /* Extract the symbol ref from: - (mem:QI (const:DI (unspec:DI [(symbol_ref:DI ("foo"))] - UNSPEC_PLT/GOTENT))) */ - - y = XEXP (x, 0); - if (GET_CODE (y) == UNSPEC - && (XINT (y, 1) == UNSPEC_GOTENT - || XINT (y, 1) == UNSPEC_PLT)) - y = XVECEXP (y, 0, 0); - else - return orig_x; - } - else - return orig_x; - - if (GET_MODE (orig_x) != Pmode) - { - if (GET_MODE (orig_x) == BLKmode) - return orig_x; - y = lowpart_subreg (GET_MODE (orig_x), y, Pmode); - if (y == NULL_RTX) - return orig_x; - } - return y; -} - -/* Output operand OP to stdio stream FILE. - OP is an address (register + offset) which is not used to address data; - instead the rightmost bits are interpreted as the value. */ - -static void -print_shift_count_operand (FILE *file, rtx op) -{ - HOST_WIDE_INT offset; - rtx base; - - /* Extract base register and offset. */ - if (!s390_decompose_shift_count (op, &base, &offset)) - gcc_unreachable (); - - /* Sanity check. */ - if (base) - { - gcc_assert (GET_CODE (base) == REG); - gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); - gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS); - } - - /* Offsets are constricted to twelve bits. */ - fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & ((1 << 12) - 1)); - if (base) - fprintf (file, "(%s)", reg_names[REGNO (base)]); -} - -/* See 'get_some_local_dynamic_name'. */ - -static int -get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) -{ - rtx x = *px; - - if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x)) - { - x = get_pool_constant (x); - return for_each_rtx (&x, get_some_local_dynamic_name_1, 0); - } - - if (GET_CODE (x) == SYMBOL_REF - && tls_symbolic_operand (x) == TLS_MODEL_LOCAL_DYNAMIC) - { - cfun->machine->some_ld_name = XSTR (x, 0); - return 1; - } - - return 0; -} - -/* 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 (void) -{ - rtx insn; - - if (cfun->machine->some_ld_name) - return cfun->machine->some_ld_name; - - for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) - if (INSN_P (insn) - && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) - return cfun->machine->some_ld_name; - - gcc_unreachable (); -} - -/* Output machine-dependent UNSPECs occurring in address constant X - in assembler syntax to stdio stream FILE. Returns true if the - constant X could be recognized, false otherwise. */ - -static bool -s390_output_addr_const_extra (FILE *file, rtx x) -{ - if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1) - switch (XINT (x, 1)) - { - case UNSPEC_GOTENT: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@GOTENT"); - return true; - case UNSPEC_GOT: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@GOT"); - return true; - case UNSPEC_GOTOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@GOTOFF"); - return true; - case UNSPEC_PLT: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@PLT"); - return true; - case UNSPEC_PLTOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@PLTOFF"); - return true; - case UNSPEC_TLSGD: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@TLSGD"); - return true; - case UNSPEC_TLSLDM: - assemble_name (file, get_some_local_dynamic_name ()); - fprintf (file, "@TLSLDM"); - return true; - case UNSPEC_DTPOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@DTPOFF"); - return true; - case UNSPEC_NTPOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@NTPOFF"); - return true; - case UNSPEC_GOTNTPOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@GOTNTPOFF"); - return true; - case UNSPEC_INDNTPOFF: - output_addr_const (file, XVECEXP (x, 0, 0)); - fprintf (file, "@INDNTPOFF"); - return true; - } - - if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 2) - switch (XINT (x, 1)) - { - case UNSPEC_POOL_OFFSET: - x = gen_rtx_MINUS (GET_MODE (x), XVECEXP (x, 0, 0), XVECEXP (x, 0, 1)); - output_addr_const (file, x); - return true; - } - return false; -} - -/* Output address operand ADDR in assembler syntax to - stdio stream FILE. */ - -void -print_operand_address (FILE *file, rtx addr) -{ - struct s390_address ad; - - if (s390_symref_operand_p (addr, NULL, NULL)) - { - if (!TARGET_Z10) - { - output_operand_lossage ("symbolic memory references are " - "only supported on z10 or later"); - return; - } - output_addr_const (file, addr); - return; - } - - if (!s390_decompose_address (addr, &ad) - || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - || (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))) - output_operand_lossage ("cannot decompose address"); - - if (ad.disp) - output_addr_const (file, ad.disp); - else - fprintf (file, "0"); - - if (ad.base && ad.indx) - fprintf (file, "(%s,%s)", reg_names[REGNO (ad.indx)], - reg_names[REGNO (ad.base)]); - else if (ad.base) - 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 - are recognized: - - 'C': print opcode suffix for branch condition. - 'D': print opcode suffix for inverse branch condition. - 'E': print opcode suffix for branch on index instruction. - 'J': print tls_load/tls_gdcall/tls_ldcall suffix - 'G': print the size of the operand in bytes. - 'O': print only the displacement of a memory reference. - 'R': print only the base register of a memory reference. - 'S': print S-type memory reference (base+displacement). - '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. - 'c': print integer X as if it's an signed byte. - 'x': print integer X as if it's an unsigned halfword. - 'h': print integer X as if it's a signed halfword. - 'i': print the first nonzero HImode part of X. - 'j': print the first HImode part unequal to -1 of X. - 'k': print the first nonzero SImode part of X. - 'm': print the first SImode part unequal to -1 of X. - 'o': print integer X as if it's an unsigned 32bit word. */ - -void -print_operand (FILE *file, rtx x, int code) -{ - switch (code) - { - case 'C': - fprintf (file, s390_branch_condition_mnemonic (x, FALSE)); - return; - - case 'D': - fprintf (file, s390_branch_condition_mnemonic (x, TRUE)); - return; - - case 'E': - if (GET_CODE (x) == LE) - fprintf (file, "l"); - else if (GET_CODE (x) == GT) - fprintf (file, "h"); - else - output_operand_lossage ("invalid comparison operator " - "for 'E' output modifier"); - return; - - case 'J': - if (GET_CODE (x) == SYMBOL_REF) - { - fprintf (file, "%s", ":tls_load:"); - output_addr_const (file, x); - } - else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD) - { - fprintf (file, "%s", ":tls_gdcall:"); - output_addr_const (file, XVECEXP (x, 0, 0)); - } - else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM) - { - fprintf (file, "%s", ":tls_ldcall:"); - assemble_name (file, get_some_local_dynamic_name ()); - } - else - output_operand_lossage ("invalid reference for 'J' output modifier"); - return; - - case 'G': - fprintf (file, "%u", GET_MODE_SIZE (GET_MODE (x))); - return; - - case 'O': - { - struct s390_address ad; - int ret; - - if (!MEM_P (x)) - { - output_operand_lossage ("memory reference expected for " - "'O' output modifier"); - return; - } - - ret = s390_decompose_address (XEXP (x, 0), &ad); - - if (!ret - || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - || ad.indx) - { - output_operand_lossage ("invalid address for 'O' output modifier"); - return; - } - - if (ad.disp) - output_addr_const (file, ad.disp); - else - fprintf (file, "0"); - } - return; - - case 'R': - { - struct s390_address ad; - int ret; - - if (!MEM_P (x)) - { - output_operand_lossage ("memory reference expected for " - "'R' output modifier"); - return; - } - - ret = s390_decompose_address (XEXP (x, 0), &ad); - - if (!ret - || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - || ad.indx) - { - output_operand_lossage ("invalid address for 'R' output modifier"); - return; - } - - if (ad.base) - fprintf (file, "%s", reg_names[REGNO (ad.base)]); - else - fprintf (file, "0"); - } - return; - - case 'S': - { - struct s390_address ad; - int ret; - - if (!MEM_P (x)) - { - output_operand_lossage ("memory reference expected for " - "'S' output modifier"); - return; - } - ret = s390_decompose_address (XEXP (x, 0), &ad); - - if (!ret - || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) - || ad.indx) - { - output_operand_lossage ("invalid address for 'S' output modifier"); - return; - } - - if (ad.disp) - output_addr_const (file, ad.disp); - else - fprintf (file, "0"); - - if (ad.base) - fprintf (file, "(%s)", reg_names[REGNO (ad.base)]); - } - return; - - case 'N': - if (GET_CODE (x) == REG) - x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); - else if (GET_CODE (x) == MEM) - x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 4)); - else - output_operand_lossage ("register or memory expression expected " - "for 'N' output modifier"); - break; - - case 'M': - if (GET_CODE (x) == REG) - x = gen_rtx_REG (GET_MODE (x), REGNO (x) + 1); - else if (GET_CODE (x) == MEM) - x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8)); - else - output_operand_lossage ("register or memory expression expected " - "for 'M' output modifier"); - break; - - case 'Y': - print_shift_count_operand (file, x); - return; - } - - switch (GET_CODE (x)) - { - case REG: - fprintf (file, "%s", reg_names[REGNO (x)]); - break; - - case MEM: - output_address (XEXP (x, 0)); - break; - - case CONST: - case CODE_LABEL: - case LABEL_REF: - case SYMBOL_REF: - output_addr_const (file, x); - break; - - case CONST_INT: - if (code == 'b') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff); - else if (code == 'c') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xff) ^ 0x80) - 0x80); - else if (code == 'x') - 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 if (code == 'k') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, - s390_extract_part (x, SImode, 0)); - else if (code == 'm') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, - s390_extract_part (x, SImode, -1)); - else if (code == 'o') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffffffff); - else - fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); - break; - - case CONST_DOUBLE: - gcc_assert (GET_MODE (x) == VOIDmode); - if (code == 'b') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xff); - else if (code == 'x') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x) & 0xffff); - else if (code == 'h') - fprintf (file, HOST_WIDE_INT_PRINT_DEC, - ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000); - else - { - if (code == 0) - output_operand_lossage ("invalid constant - try using " - "an output modifier"); - else - output_operand_lossage ("invalid constant for output modifier '%c'", - code); - } - break; - - default: - if (code == 0) - output_operand_lossage ("invalid expression - try using " - "an output modifier"); - else - output_operand_lossage ("invalid expression for output " - "modifier '%c'", code); - break; - } -} - -/* Target hook for assembling integer objects. We need to define it - here to work a round a bug in some versions of GAS, which couldn't - handle values smaller than INT_MIN when printed in decimal. */ - -static bool -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) - { - 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); -} - -/* Returns true if register REGNO is used for forming - a memory address in expression X. */ - -static bool -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 true; - } - else if (code == SET - && GET_CODE (SET_DEST (x)) == PC) - { - if (refers_to_regno_p (regno, regno+1, - SET_SRC (x), 0)) - return true; - } - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e' - && reg_used_in_mem_p (regno, XEXP (x, i))) - return true; - - else if (fmt[i] == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - if (reg_used_in_mem_p (regno, XVECEXP (x, i, j))) - return true; - } - return false; -} - -/* Returns true if expression DEP_RTX sets an address register - used by instruction INSN to address memory. */ - -static bool -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); - if (GET_CODE (target) == STRICT_LOW_PART) - target = XEXP (target, 0); - while (GET_CODE (target) == SUBREG) - target = SUBREG_REG (target); - - if (GET_CODE (target) == REG) - { - int regno = REGNO (target); - - if (s390_safe_attr_type (insn) == TYPE_LA) - { - pat = PATTERN (insn); - if (GET_CODE (pat) == PARALLEL) - { - gcc_assert (XVECLEN (pat, 0) == 2); - pat = XVECEXP (pat, 0, 0); - } - gcc_assert (GET_CODE (pat) == SET); - return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0); - } - else if (get_attr_atype (insn) == ATYPE_AGEN) - return reg_used_in_mem_p (regno, PATTERN (insn)); - } - } - return false; -} - -/* 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; -} - - -/* A C statement (sans semicolon) to update the integer scheduling priority - 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 STD instruction should be scheduled earlier, - in order to use the bypass. */ -static int -s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority) -{ - if (! INSN_P (insn)) - return priority; - - if (s390_tune != PROCESSOR_2084_Z990 - && s390_tune != PROCESSOR_2094_Z9_109 - && s390_tune != PROCESSOR_2097_Z10 - && s390_tune != PROCESSOR_2817_Z196) - return priority; - - switch (s390_safe_attr_type (insn)) - { - case TYPE_FSTOREDF: - case TYPE_FSTORESF: - priority = priority << 3; - break; - case TYPE_STORE: - case TYPE_STM: - priority = priority << 1; - break; - default: - break; - } - return priority; -} - - -/* The number of instructions that can be issued per cycle. */ - -static int -s390_issue_rate (void) -{ - switch (s390_tune) - { - case PROCESSOR_2084_Z990: - case PROCESSOR_2094_Z9_109: - case PROCESSOR_2817_Z196: - return 3; - case PROCESSOR_2097_Z10: - return 2; - default: - return 1; - } -} - -static int -s390_first_cycle_multipass_dfa_lookahead (void) -{ - return 4; -} - -/* Annotate every literal pool reference in X by an UNSPEC_LTREF expression. - Fix up MEMs as required. */ - -static void -annotate_constant_pool_refs (rtx *x) -{ - int i, j; - const char *fmt; - - gcc_assert (GET_CODE (*x) != SYMBOL_REF - || !CONSTANT_POOL_ADDRESS_P (*x)); - - /* Literal pool references can only occur inside a MEM ... */ - if (GET_CODE (*x) == MEM) - { - rtx memref = XEXP (*x, 0); - - if (GET_CODE (memref) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (memref)) - { - rtx base = cfun->machine->base_reg; - rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, memref, base), - UNSPEC_LTREF); - - *x = replace_equiv_address (*x, addr); - return; - } - - if (GET_CODE (memref) == CONST - && GET_CODE (XEXP (memref, 0)) == PLUS - && GET_CODE (XEXP (XEXP (memref, 0), 1)) == CONST_INT - && GET_CODE (XEXP (XEXP (memref, 0), 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (memref, 0), 0))) - { - HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1)); - rtx sym = XEXP (XEXP (memref, 0), 0); - rtx base = cfun->machine->base_reg; - rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base), - UNSPEC_LTREF); - - *x = replace_equiv_address (*x, plus_constant (addr, off)); - return; - } - } - - /* ... or a load-address type pattern. */ - if (GET_CODE (*x) == SET) - { - rtx addrref = SET_SRC (*x); - - if (GET_CODE (addrref) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (addrref)) - { - rtx base = cfun->machine->base_reg; - rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addrref, base), - UNSPEC_LTREF); - - SET_SRC (*x) = addr; - return; - } - - if (GET_CODE (addrref) == CONST - && GET_CODE (XEXP (addrref, 0)) == PLUS - && GET_CODE (XEXP (XEXP (addrref, 0), 1)) == CONST_INT - && GET_CODE (XEXP (XEXP (addrref, 0), 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (addrref, 0), 0))) - { - HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1)); - rtx sym = XEXP (XEXP (addrref, 0), 0); - rtx base = cfun->machine->base_reg; - rtx addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, sym, base), - UNSPEC_LTREF); - - SET_SRC (*x) = plus_constant (addr, off); - return; - } - } - - /* Annotate LTREL_BASE as well. */ - if (GET_CODE (*x) == UNSPEC - && XINT (*x, 1) == UNSPEC_LTREL_BASE) - { - rtx base = cfun->machine->base_reg; - *x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XVECEXP (*x, 0, 0), base), - UNSPEC_LTREL_BASE); - return; - } - - fmt = GET_RTX_FORMAT (GET_CODE (*x)); - for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - annotate_constant_pool_refs (&XEXP (*x, i)); - } - else if (fmt[i] == 'E') - { - for (j = 0; j < XVECLEN (*x, i); j++) - annotate_constant_pool_refs (&XVECEXP (*x, i, j)); - } - } -} - -/* Split all branches that exceed the maximum distance. - Returns true if this created a new literal pool entry. */ - -static int -s390_split_branches (void) -{ - rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); - int new_literal = 0, ret; - rtx insn, pat, tmp, target; - rtx *label; - - /* We need correct insn addresses. */ - - shorten_branches (get_insns ()); - - /* Find all branches that exceed 64KB, and split them. */ - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) != JUMP_INSN) - continue; - - pat = PATTERN (insn); - if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2) - pat = XVECEXP (pat, 0, 0); - if (GET_CODE (pat) != SET || SET_DEST (pat) != pc_rtx) - continue; - - if (GET_CODE (SET_SRC (pat)) == LABEL_REF) - { - label = &SET_SRC (pat); - } - else if (GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE) - { - 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) - label = &XEXP (SET_SRC (pat), 2); - else - continue; - } - else - continue; - - if (get_attr_length (insn) <= 4) - continue; - - /* We are going to use the return register as scratch register, - make sure it will be saved/restored by the prologue/epilogue. */ - cfun_frame_layout.save_return_addr_p = 1; - - if (!flag_pic) - { - new_literal = 1; - tmp = force_const_mem (Pmode, *label); - tmp = emit_insn_before (gen_rtx_SET (Pmode, temp_reg, tmp), insn); - INSN_ADDRESSES_NEW (tmp, -1); - annotate_constant_pool_refs (&PATTERN (tmp)); - - target = temp_reg; - } - else - { - new_literal = 1; - 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); - annotate_constant_pool_refs (&PATTERN (tmp)); - - target = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, XEXP (target, 0), - cfun->machine->base_reg), - UNSPEC_LTREL_BASE); - target = gen_rtx_PLUS (Pmode, temp_reg, target); - } - - ret = validate_change (insn, label, target, 0); - gcc_assert (ret); - } - - return new_literal; -} - - -/* Find an annotated 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. - - 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 (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; - - gcc_assert (GET_CODE (x) != SYMBOL_REF - || !CONSTANT_POOL_ADDRESS_P (x)); - - if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_LTREF) - { - rtx sym = XVECEXP (x, 0, 0); - gcc_assert (GET_CODE (sym) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (sym)); - - if (*ref == NULL_RTX) - *ref = sym; - else - gcc_assert (*ref == sym); - - return; - } - - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - find_constant_pool_ref (XEXP (x, i), ref); - } - else if (fmt[i] == 'E') - { - for (j = 0; j < XVECLEN (x, i); j++) - find_constant_pool_ref (XVECEXP (x, i, j), ref); - } - } -} - -/* Replace every reference to the annotated literal pool - symbol REF in X by its base plus OFFSET. */ - -static void -replace_constant_pool_ref (rtx *x, rtx ref, rtx offset) -{ - int i, j; - const char *fmt; - - gcc_assert (*x != ref); - - if (GET_CODE (*x) == UNSPEC - && XINT (*x, 1) == UNSPEC_LTREF - && XVECEXP (*x, 0, 0) == ref) - { - *x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset); - return; - } - - if (GET_CODE (*x) == PLUS - && GET_CODE (XEXP (*x, 1)) == CONST_INT - && GET_CODE (XEXP (*x, 0)) == UNSPEC - && XINT (XEXP (*x, 0), 1) == UNSPEC_LTREF - && XVECEXP (XEXP (*x, 0), 0, 0) == ref) - { - rtx addr = gen_rtx_PLUS (Pmode, XVECEXP (XEXP (*x, 0), 0, 1), offset); - *x = plus_constant (addr, INTVAL (XEXP (*x, 1))); - return; - } - - fmt = GET_RTX_FORMAT (GET_CODE (*x)); - for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - replace_constant_pool_ref (&XEXP (*x, i), ref, offset); - } - else if (fmt[i] == 'E') - { - for (j = 0; j < XVECLEN (*x, i); j++) - replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset); - } - } -} - -/* Check whether X contains an UNSPEC_LTREL_BASE. - Return its constant pool symbol if found, NULL_RTX otherwise. */ - -static rtx -find_ltrel_base (rtx x) -{ - int i, j; - const char *fmt; - - 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') - { - 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++) - { - rtx fnd = find_ltrel_base (XVECEXP (x, i, j)); - if (fnd) - return fnd; - } - } - } - - return NULL_RTX; -} - -/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base. */ - -static void -replace_ltrel_base (rtx *x) -{ - int i, j; - const char *fmt; - - if (GET_CODE (*x) == UNSPEC - && XINT (*x, 1) == UNSPEC_LTREL_BASE) - { - *x = XVECEXP (*x, 0, 1); - return; - } - - fmt = GET_RTX_FORMAT (GET_CODE (*x)); - for (i = GET_RTX_LENGTH (GET_CODE (*x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - replace_ltrel_base (&XEXP (*x, i)); - } - else if (fmt[i] == 'E') - { - for (j = 0; j < XVECLEN (*x, i); j++) - replace_ltrel_base (&XVECEXP (*x, i, j)); - } - } -} - - -/* 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 11 -enum machine_mode constant_modes[NR_C_MODES] = -{ - TFmode, TImode, TDmode, - DFmode, DImode, DDmode, - SFmode, SImode, SDmode, - HImode, - QImode -}; - -struct constant -{ - struct constant *next; - rtx value; - rtx label; -}; - -struct constant_pool -{ - struct constant_pool *next; - rtx first_insn; - rtx pool_insn; - bitmap insns; - rtx emit_pool_after; - - struct constant *constants[NR_C_MODES]; - struct constant *execute; - rtx label; - int size; -}; - -/* 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->execute = NULL; - pool->label = gen_label_rtx (); - pool->first_insn = NULL_RTX; - pool->pool_insn = NULL_RTX; - pool->insns = BITMAP_ALLOC (NULL); - pool->size = 0; - pool->emit_pool_after = NULL_RTX; - - return 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 (struct constant_pool **pool_list, rtx insn) -{ - struct constant_pool *pool, **prev; - - pool = s390_alloc_pool (); - pool->first_insn = insn; - - for (prev = pool_list; *prev; prev = &(*prev)->next) - ; - *prev = pool; - - return pool; -} - -/* End range of instructions covered by POOL at INSN and emit - placeholder insn representing the pool. */ - -static void -s390_end_pool (struct constant_pool *pool, rtx insn) -{ - rtx pool_size = GEN_INT (pool->size + 8 /* alignment slop */); - - if (!insn) - insn = get_last_insn (); - - pool->pool_insn = emit_insn_after (gen_pool (pool_size), insn); - INSN_ADDRESSES_NEW (pool->pool_insn, -1); -} - -/* Add INSN to the list of insns covered by POOL. */ - -static void -s390_add_pool_insn (struct constant_pool *pool, rtx insn) -{ - bitmap_set_bit (pool->insns, INSN_UID (insn)); -} - -/* Return pool out of POOL_LIST that covers INSN. */ - -static struct constant_pool * -s390_find_pool (struct constant_pool *pool_list, rtx insn) -{ - struct constant_pool *pool; - - for (pool = pool_list; pool; pool = pool->next) - if (bitmap_bit_p (pool->insns, INSN_UID (insn))) - break; - - return pool; -} - -/* Add constant VAL of mode MODE to the constant pool POOL. */ - -static void -s390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode) -{ - struct constant *c; - int i; - - for (i = 0; i < NR_C_MODES; i++) - if (constant_modes[i] == mode) - break; - gcc_assert (i != NR_C_MODES); - - for (c = pool->constants[i]; c != NULL; c = c->next) - if (rtx_equal_p (val, c->value)) - break; - - if (c == NULL) - { - c = (struct constant *) xmalloc (sizeof *c); - c->value = val; - c->label = gen_label_rtx (); - c->next = pool->constants[i]; - pool->constants[i] = c; - pool->size += GET_MODE_SIZE (mode); - } -} - -/* Return an rtx that represents the offset of X from the start of - pool POOL. */ - -static rtx -s390_pool_offset (struct constant_pool *pool, rtx x) -{ - rtx label; - - label = gen_rtx_LABEL_REF (GET_MODE (x), pool->label); - x = gen_rtx_UNSPEC (GET_MODE (x), gen_rtvec (2, x, label), - UNSPEC_POOL_OFFSET); - return gen_rtx_CONST (GET_MODE (x), x); -} - -/* 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 (struct constant_pool *pool, rtx val, - enum machine_mode mode) -{ - struct constant *c; - int i; - - for (i = 0; i < NR_C_MODES; i++) - if (constant_modes[i] == mode) - break; - gcc_assert (i != NR_C_MODES); - - for (c = pool->constants[i]; c != NULL; c = c->next) - if (rtx_equal_p (val, c->value)) - break; - - gcc_assert (c); - - return s390_pool_offset (pool, gen_rtx_LABEL_REF (Pmode, c->label)); -} - -/* Check whether INSN is an execute. Return the label_ref to its - execute target template if so, NULL_RTX otherwise. */ - -static rtx -s390_execute_label (rtx insn) -{ - if (GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == PARALLEL - && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC - && XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_EXECUTE) - return XVECEXP (XVECEXP (PATTERN (insn), 0, 0), 0, 2); - - return NULL_RTX; -} - -/* Add execute target for INSN to the constant pool POOL. */ - -static void -s390_add_execute (struct constant_pool *pool, rtx insn) -{ - struct constant *c; - - for (c = pool->execute; c != NULL; c = c->next) - if (INSN_UID (insn) == INSN_UID (c->value)) - break; - - if (c == NULL) - { - c = (struct constant *) xmalloc (sizeof *c); - c->value = insn; - c->label = gen_label_rtx (); - c->next = pool->execute; - pool->execute = c; - pool->size += 6; - } -} - -/* Find execute target for INSN in the constant pool POOL. - Return an RTX describing the distance from the start of - the pool to the location of the execute target. */ - -static rtx -s390_find_execute (struct constant_pool *pool, rtx insn) -{ - struct constant *c; - - for (c = pool->execute; c != NULL; c = c->next) - if (INSN_UID (insn) == INSN_UID (c->value)) - break; - - gcc_assert (c); - - return s390_pool_offset (pool, gen_rtx_LABEL_REF (Pmode, c->label)); -} - -/* For an execute INSN, extract the execute target template. */ - -static rtx -s390_execute_target (rtx insn) -{ - rtx pattern = PATTERN (insn); - gcc_assert (s390_execute_label (insn)); - - if (XVECLEN (pattern, 0) == 2) - { - pattern = copy_rtx (XVECEXP (pattern, 0, 1)); - } - else - { - rtvec vec = rtvec_alloc (XVECLEN (pattern, 0) - 1); - int i; - - for (i = 0; i < XVECLEN (pattern, 0) - 1; i++) - RTVEC_ELT (vec, i) = copy_rtx (XVECEXP (pattern, 0, i + 1)); - - pattern = gen_rtx_PARALLEL (VOIDmode, vec); - } - - return pattern; -} - -/* Indicate that INSN cannot be duplicated. This is the case for - execute insns that carry a unique label. */ - -static bool -s390_cannot_copy_insn_p (rtx insn) -{ - rtx label = s390_execute_label (insn); - return label && label != const0_rtx; -} - -/* Dump out the constants in POOL. If REMOTE_LABEL is true, - do not emit the pool base label. */ - -static void -s390_dump_pool (struct constant_pool *pool, bool remote_label) -{ - struct constant *c; - rtx insn = pool->pool_insn; - int i; - - /* Switch to rodata section. */ - if (TARGET_CPU_ZARCH) - { - insn = emit_insn_after (gen_pool_section_start (), insn); - INSN_ADDRESSES_NEW (insn, -1); - } - - /* Ensure minimum pool alignment. */ - if (TARGET_CPU_ZARCH) - insn = emit_insn_after (gen_pool_align (GEN_INT (8)), insn); - else - insn = emit_insn_after (gen_pool_align (GEN_INT (4)), insn); - INSN_ADDRESSES_NEW (insn, -1); - - /* Emit pool base label. */ - if (!remote_label) - { - insn = emit_label_after (pool->label, insn); - INSN_ADDRESSES_NEW (insn, -1); - } - - /* Dump constants in descending alignment requirement order, - ensuring proper alignment for every constant. */ - for (i = 0; i < NR_C_MODES; i++) - for (c = pool->constants[i]; c; c = c->next) - { - /* Convert UNSPEC_LTREL_OFFSET unspecs to pool-relative references. */ - rtx value = copy_rtx (c->value); - if (GET_CODE (value) == CONST - && GET_CODE (XEXP (value, 0)) == UNSPEC - && XINT (XEXP (value, 0), 1) == UNSPEC_LTREL_OFFSET - && XVECLEN (XEXP (value, 0), 0) == 1) - value = s390_pool_offset (pool, XVECEXP (XEXP (value, 0), 0, 0)); - - insn = emit_label_after (c->label, insn); - INSN_ADDRESSES_NEW (insn, -1); - - 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); - } - - /* Ensure minimum alignment for instructions. */ - insn = emit_insn_after (gen_pool_align (GEN_INT (2)), insn); - INSN_ADDRESSES_NEW (insn, -1); - - /* Output in-pool execute template insns. */ - for (c = pool->execute; c; c = c->next) - { - insn = emit_label_after (c->label, insn); - INSN_ADDRESSES_NEW (insn, -1); - - insn = emit_insn_after (s390_execute_target (c->value), insn); - INSN_ADDRESSES_NEW (insn, -1); - } - - /* Switch back to previous section. */ - if (TARGET_CPU_ZARCH) - { - insn = emit_insn_after (gen_pool_section_end (), insn); - INSN_ADDRESSES_NEW (insn, -1); - } - - insn = emit_barrier_after (insn); - INSN_ADDRESSES_NEW (insn, -1); - - /* Remove placeholder insn. */ - remove_insn (pool->pool_insn); -} - -/* Free all memory used by POOL. */ - -static void -s390_free_pool (struct constant_pool *pool) -{ - struct constant *c, *next; - int i; - - for (i = 0; i < NR_C_MODES; i++) - for (c = pool->constants[i]; c; c = next) - { - next = c->next; - free (c); - } - - for (c = pool->execute; c; c = next) - { - next = c->next; - free (c); - } - - BITMAP_FREE (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)) == SET - && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE - && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL) - { - gcc_assert (!pool->pool_insn); - pool->pool_insn = insn; - } - - if (!TARGET_CPU_ZARCH && s390_execute_label (insn)) - { - s390_add_execute (pool, insn); - } - else 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 hot/cold partitioning is enabled we have to make sure that - the literal pool is emitted in the same section where the - initialization of the literal pool base pointer takes place. - emit_pool_after is only used in the non-overflow case on non - Z cpus where we can emit the literal pool at the end of the - function body within the text section. */ - if (NOTE_P (insn) - && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS - && !pool->emit_pool_after) - pool->emit_pool_after = PREV_INSN (insn); - } - - gcc_assert (pool->pool_insn || pool->size == 0); - - 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; - } - - /* If the functions ends with the section where the literal pool - should be emitted set the marker to its end. */ - if (pool && !pool->emit_pool_after) - pool->emit_pool_after = get_last_insn (); - - 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. */ - -static void -s390_mainpool_finish (struct constant_pool *pool) -{ - rtx base_reg = cfun->machine->base_reg; - rtx insn; - - /* If the pool is empty, we're done. */ - if (pool->size == 0) - { - /* We don't actually need a base register after all. */ - cfun->machine->base_reg = NULL_RTX; - - if (pool->pool_insn) - 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 (pool->emit_pool_after)) - + 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); - - /* emit_pool_after will be set by s390_mainpool_start to the - last insn of the section where the literal pool should be - emitted. */ - insn = pool->emit_pool_after; - - 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_jump_insn_after (insn, pool->pool_insn); - JUMP_LABEL (insn) = pool_end; - 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)); - - 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) - { - if (s390_execute_label (insn)) - addr = s390_find_execute (pool, insn); - else - addr = s390_find_constant (pool, get_pool_constant (pool_ref), - get_pool_mode (pool_ref)); - - replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); - INSN_CODE (insn) = -1; - } - } - } - - - /* 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); -} - - -/* Chunkify the literal pool. */ - -#define S390_POOL_CHUNK_MIN 0xc00 -#define S390_POOL_CHUNK_MAX 0xe00 - -static struct constant_pool * -s390_chunkify_start (void) -{ - 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) (rtx, rtx) = - TARGET_CPU_ZARCH? gen_reload_base_64 : gen_reload_base_31; - - - /* We need correct insn addresses. */ - - shorten_branches (get_insns ()); - - /* Scan all insns and move literals to pool chunks. */ - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - bool section_switch_p = false; - - /* Check for pending LTREL_BASE. */ - if (INSN_P (insn)) - { - rtx ltrel_base = find_ltrel_base (PATTERN (insn)); - if (ltrel_base) - { - gcc_assert (ltrel_base == pending_ltrel); - pending_ltrel = NULL_RTX; - } - } - - if (!TARGET_CPU_ZARCH && s390_execute_label (insn)) - { - if (!curr_pool) - curr_pool = s390_start_pool (&pool_list, insn); - - s390_add_execute (curr_pool, insn); - s390_add_pool_insn (curr_pool, insn); - } - else if (GET_CODE (insn) == INSN || CALL_P (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, constant, mode); - 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) - { - gcc_assert (!pending_ltrel); - 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); - /* An LTREL_BASE must follow within the same basic block. */ - gcc_assert (!pending_ltrel); - } - - if (NOTE_P (insn)) - switch (NOTE_KIND (insn)) - { - case NOTE_INSN_SWITCH_TEXT_SECTIONS: - section_switch_p = true; - break; - case NOTE_INSN_VAR_LOCATION: - case NOTE_INSN_CALL_ARG_LOCATION: - continue; - default: - break; - } - - if (!curr_pool - || INSN_ADDRESSES_SIZE () <= (size_t) INSN_UID (insn) - || INSN_ADDRESSES (INSN_UID (insn)) == -1) - continue; - - if (TARGET_CPU_ZARCH) - { - if (curr_pool->size < S390_POOL_CHUNK_MAX) - continue; - - s390_end_pool (curr_pool, NULL_RTX); - curr_pool = NULL; - } - else - { - int chunk_size = INSN_ADDRESSES (INSN_UID (insn)) - - INSN_ADDRESSES (INSN_UID (curr_pool->first_insn)) - + extra_size; - - /* We will later have to insert base register reload insns. - Those will have an effect on code size, which we need to - consider here. This calculation makes rather pessimistic - worst-case assumptions. */ - if (GET_CODE (insn) == CODE_LABEL) - extra_size += 6; - - if (chunk_size < S390_POOL_CHUNK_MIN - && curr_pool->size < S390_POOL_CHUNK_MIN - && !section_switch_p) - continue; - - /* Pool chunks can only be inserted after BARRIERs ... */ - if (GET_CODE (insn) == BARRIER) - { - s390_end_pool (curr_pool, insn); - curr_pool = NULL; - extra_size = 0; - } - - /* ... so if we don't find one in time, create one. */ - else if (chunk_size > S390_POOL_CHUNK_MAX - || curr_pool->size > S390_POOL_CHUNK_MAX - || section_switch_p) - { - rtx label, jump, barrier, next, prev; - - if (!section_switch_p) - { - /* We can insert the barrier only after a 'real' insn. */ - if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN) - continue; - if (get_attr_length (insn) == 0) - continue; - /* Don't separate LTREL_BASE from the corresponding - LTREL_OFFSET load. */ - if (pending_ltrel) - continue; - next = insn; - do - { - insn = next; - next = NEXT_INSN (insn); - } - while (next - && NOTE_P (next) - && (NOTE_KIND (next) == NOTE_INSN_VAR_LOCATION - || NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)); - } - else - { - gcc_assert (!pending_ltrel); - - /* The old pool has to end before the section switch - note in order to make it part of the current - section. */ - insn = PREV_INSN (insn); - } - - label = gen_label_rtx (); - prev = insn; - if (prev && NOTE_P (prev)) - prev = prev_nonnote_insn (prev); - if (prev) - jump = emit_jump_insn_after_setloc (gen_jump (label), insn, - INSN_LOCATOR (prev)); - else - jump = emit_jump_insn_after_noloc (gen_jump (label), insn); - barrier = emit_barrier_after (jump); - insn = emit_label_after (label, barrier); - JUMP_LABEL (jump) = label; - LABEL_NUSES (label) = 1; - - INSN_ADDRESSES_NEW (jump, -1); - INSN_ADDRESSES_NEW (barrier, -1); - INSN_ADDRESSES_NEW (insn, -1); - - s390_end_pool (curr_pool, barrier); - curr_pool = NULL; - extra_size = 0; - } - } - } - - if (curr_pool) - s390_end_pool (curr_pool, NULL_RTX); - gcc_assert (!pending_ltrel); - - /* Find all labels that are branched into - from an insn belonging to a different chunk. */ - - far_labels = BITMAP_ALLOC (NULL); - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - /* Labels marked with LABEL_PRESERVE_P can be target - of non-local jumps, so we have to mark them. - The same holds for named labels. - - Don't do that, however, if it is the label before - a jump table. */ - - 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 ? - PATTERN (vec_insn) : NULL_RTX; - if (!vec_pat - || !(GET_CODE (vec_pat) == ADDR_VEC - || GET_CODE (vec_pat) == ADDR_DIFF_VEC)) - bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (insn)); - } - - /* If we have a direct jump (conditional or unconditional) - or a casesi jump, check all potential targets. */ - 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) - { - rtx label = JUMP_LABEL (insn); - if (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 - && GET_CODE (XVECEXP (pat, 0, 1)) == USE - && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == LABEL_REF) - { - /* 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 ? - PATTERN (vec_insn) : NULL_RTX; - if (vec_pat - && (GET_CODE (vec_pat) == ADDR_VEC - || GET_CODE (vec_pat) == ADDR_DIFF_VEC)) - { - int i, diff_p = GET_CODE (vec_pat) == ADDR_DIFF_VEC; - - for (i = 0; i < XVECLEN (vec_pat, diff_p); i++) - { - rtx label = XEXP (XVECEXP (vec_pat, diff_p, i), 0); - - if (s390_find_pool (pool_list, label) - != s390_find_pool (pool_list, insn)) - bitmap_set_bit (far_labels, CODE_LABEL_NUMBER (label)); - } - } - } - } - } - - /* Insert base register reload insns before every pool. */ - - for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) - { - rtx new_insn = gen_reload_base (cfun->machine->base_reg, - curr_pool->label); - rtx insn = curr_pool->first_insn; - INSN_ADDRESSES_NEW (emit_insn_before (new_insn, insn), -1); - } - - /* Insert base register reload insns at every far label. */ - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - 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); - if (pool) - { - rtx new_insn = gen_reload_base (cfun->machine->base_reg, - pool->label); - INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1); - } - } - - - BITMAP_FREE (far_labels); - - - /* Recompute insn addresses. */ - - init_insn_lengths (); - shorten_branches (get_insns ()); - - return pool_list; -} - -/* 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. */ - -static void -s390_chunkify_finish (struct constant_pool *pool_list) -{ - struct constant_pool *curr_pool = NULL; - rtx insn; - - - /* Replace all literal pool references. */ - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - replace_ltrel_base (&PATTERN (insn)); - - curr_pool = s390_find_pool (pool_list, insn); - if (!curr_pool) - continue; - - 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) - { - if (s390_execute_label (insn)) - addr = s390_find_execute (curr_pool, insn); - else - addr = s390_find_constant (curr_pool, - get_pool_constant (pool_ref), - get_pool_mode (pool_ref)); - - replace_constant_pool_ref (&PATTERN (insn), pool_ref, addr); - INSN_CODE (insn) = -1; - } - } - } - - /* Dump out all literal pools. */ - - for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) - s390_dump_pool (curr_pool, 0); - - /* Free pool list. */ - - while (pool_list) - { - struct constant_pool *next = pool_list->next; - s390_free_pool (pool_list); - pool_list = next; - } -} - -/* 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 (struct constant_pool *pool_list) -{ - struct constant_pool *curr_pool = NULL; - rtx insn; - - /* Remove all pool placeholder insns. */ - - for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next) - { - /* Did we insert an extra barrier? Remove it. */ - rtx barrier = PREV_INSN (curr_pool->pool_insn); - rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX; - rtx label = NEXT_INSN (curr_pool->pool_insn); - - if (jump && GET_CODE (jump) == JUMP_INSN - && barrier && GET_CODE (barrier) == BARRIER - && label && GET_CODE (label) == CODE_LABEL - && GET_CODE (PATTERN (jump)) == SET - && SET_DEST (PATTERN (jump)) == pc_rtx - && GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF - && XEXP (SET_SRC (PATTERN (jump)), 0) == label) - { - remove_insn (jump); - remove_insn (barrier); - remove_insn (label); - } - - remove_insn (curr_pool->pool_insn); - } - - /* Remove all base register reload insns. */ - - for (insn = get_insns (); insn; ) - { - rtx next_insn = NEXT_INSN (insn); - - if (GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET - && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC - && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE) - remove_insn (insn); - - insn = next_insn; - } - - /* Free pool list. */ - - while (pool_list) - { - struct constant_pool *next = pool_list->next; - s390_free_pool (pool_list); - pool_list = next; - } -} - -/* Output the constant pool entry EXP in mode MODE with alignment ALIGN. */ - -void -s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align) -{ - REAL_VALUE_TYPE r; - - switch (GET_MODE_CLASS (mode)) - { - case MODE_FLOAT: - case MODE_DECIMAL_FLOAT: - gcc_assert (GET_CODE (exp) == CONST_DOUBLE); - - REAL_VALUE_FROM_CONST_DOUBLE (r, exp); - assemble_real (r, mode, align); - break; - - case MODE_INT: - assemble_integer (exp, GET_MODE_SIZE (mode), align, 1); - mark_symbol_refs_as_used (exp); - break; - - default: - gcc_unreachable (); - } -} - - -/* Return an RTL expression representing the value of the return address - for the frame COUNT steps up from the current frame. FRAME is the - frame pointer of that frame. */ - -rtx -s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) -{ - int offset; - rtx addr; - - /* 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) - { - /* On non-z architectures branch splitting could overwrite r14. */ - if (TARGET_CPU_ZARCH) - return get_hard_reg_initial_val (Pmode, RETURN_REGNUM); - else - { - cfun_frame_layout.save_return_addr_p = true; - return gen_rtx_MEM (Pmode, return_address_pointer_rtx); - } - } - - if (TARGET_PACKED_STACK) - offset = -2 * UNITS_PER_LONG; - else - offset = RETURN_REGNUM * UNITS_PER_LONG; - - addr = plus_constant (frame, offset); - addr = memory_address (Pmode, addr); - return gen_rtx_MEM (Pmode, addr); -} - -/* Return an RTL expression representing the back chain stored in - the current stack frame. */ - -rtx -s390_back_chain_rtx (void) -{ - rtx chain; - - gcc_assert (TARGET_BACKCHAIN); - - if (TARGET_PACKED_STACK) - chain = plus_constant (stack_pointer_rtx, - STACK_POINTER_OFFSET - UNITS_PER_LONG); - else - chain = stack_pointer_rtx; - - chain = gen_rtx_MEM (Pmode, chain); - return chain; -} - -/* Find first call clobbered register unused 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 (void) -{ - int i; - for (i = 0; i < 6; i++) - if (!df_regs_ever_live_p (i)) - return i; - return 0; -} - - -/* Helper function for s390_regs_ever_clobbered. Sets the fields in DATA for all - clobbered hard regs in SETREG. */ - -static void -s390_reg_clobbered_rtx (rtx setreg, const_rtx set_insn ATTRIBUTE_UNUSED, void *data) -{ - int *regs_ever_clobbered = (int *)data; - unsigned int i, regno; - enum machine_mode mode = GET_MODE (setreg); - - if (GET_CODE (setreg) == SUBREG) - { - rtx inner = SUBREG_REG (setreg); - if (!GENERAL_REG_P (inner)) - return; - regno = subreg_regno (setreg); - } - else if (GENERAL_REG_P (setreg)) - regno = REGNO (setreg); - else - return; - - for (i = regno; - i < regno + HARD_REGNO_NREGS (regno, mode); - i++) - regs_ever_clobbered[i] = 1; -} - -/* Walks through all basic blocks of the current function looking - for clobbered hard regs using s390_reg_clobbered_rtx. The fields - of the passed integer array REGS_EVER_CLOBBERED are set to one for - each of those regs. */ - -static void -s390_regs_ever_clobbered (int *regs_ever_clobbered) -{ - basic_block cur_bb; - rtx cur_insn; - unsigned int i; - - memset (regs_ever_clobbered, 0, 16 * sizeof (int)); - - /* For non-leaf functions we have to consider all call clobbered regs to be - clobbered. */ - if (!current_function_is_leaf) - { - for (i = 0; i < 16; i++) - regs_ever_clobbered[i] = call_really_used_regs[i]; - } - - /* Make the "magic" eh_return registers live if necessary. For regs_ever_live - this work is done by liveness analysis (mark_regs_live_at_end). - Special care is needed for functions containing landing pads. Landing pads - may use the eh registers, but the code which sets these registers is not - contained in that function. Hence s390_regs_ever_clobbered is not able to - deal with this automatically. */ - if (crtl->calls_eh_return || cfun->machine->has_landing_pad_p) - for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++) - if (crtl->calls_eh_return - || (cfun->machine->has_landing_pad_p - && df_regs_ever_live_p (EH_RETURN_DATA_REGNO (i)))) - regs_ever_clobbered[EH_RETURN_DATA_REGNO (i)] = 1; - - /* For nonlocal gotos all call-saved registers have to be saved. - This flag is also set for the unwinding code in libgcc. - See expand_builtin_unwind_init. For regs_ever_live this is done by - reload. */ - if (cfun->has_nonlocal_label) - for (i = 0; i < 16; i++) - if (!call_really_used_regs[i]) - regs_ever_clobbered[i] = 1; - - FOR_EACH_BB (cur_bb) - { - FOR_BB_INSNS (cur_bb, cur_insn) - { - if (INSN_P (cur_insn)) - note_stores (PATTERN (cur_insn), - s390_reg_clobbered_rtx, - regs_ever_clobbered); - } - } -} - -/* Determine the frame area which actually has to be accessed - in the function epilogue. The values are stored at the - given pointers AREA_BOTTOM (address of the lowest used stack - address) and AREA_TOP (address of the first item which does - not belong to the stack frame). */ - -static void -s390_frame_area (int *area_bottom, int *area_top) -{ - int b, t; - int i; - - b = INT_MAX; - t = INT_MIN; - - if (cfun_frame_layout.first_restore_gpr != -1) - { - b = (cfun_frame_layout.gprs_offset - + cfun_frame_layout.first_restore_gpr * UNITS_PER_LONG); - t = b + (cfun_frame_layout.last_restore_gpr - - cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_LONG; - } - - if (TARGET_64BIT && cfun_save_high_fprs_p) - { - b = MIN (b, cfun_frame_layout.f8_offset); - t = MAX (t, (cfun_frame_layout.f8_offset - + cfun_frame_layout.high_fprs * 8)); - } - - if (!TARGET_64BIT) - for (i = 2; i < 4; i++) - if (cfun_fpr_bit_p (i)) - { - b = MIN (b, cfun_frame_layout.f4_offset + (i - 2) * 8); - t = MAX (t, cfun_frame_layout.f4_offset + (i - 1) * 8); - } - - *area_bottom = b; - *area_top = t; -} - -/* Fill cfun->machine with info about register usage of current function. - Return in CLOBBERED_REGS which GPRs are currently considered set. */ - -static void -s390_register_info (int clobbered_regs[]) -{ - int i, j; - - /* fprs 8 - 15 are call saved for 64 Bit ABI. */ - cfun_frame_layout.fpr_bitmap = 0; - cfun_frame_layout.high_fprs = 0; - if (TARGET_64BIT) - for (i = 24; i < 32; i++) - if (df_regs_ever_live_p (i) && !global_regs[i]) - { - cfun_set_fpr_bit (i - 16); - cfun_frame_layout.high_fprs++; - } - - /* Find first and last gpr to be saved. We trust regs_ever_live - data, except that we don't save and restore global registers. - - Also, all registers with special meaning to the compiler need - to be handled extra. */ - - s390_regs_ever_clobbered (clobbered_regs); - - for (i = 0; i < 16; i++) - clobbered_regs[i] = clobbered_regs[i] && !global_regs[i] && !fixed_regs[i]; - - if (frame_pointer_needed) - clobbered_regs[HARD_FRAME_POINTER_REGNUM] = 1; - - if (flag_pic) - clobbered_regs[PIC_OFFSET_TABLE_REGNUM] - |= df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM); - - clobbered_regs[BASE_REGNUM] - |= (cfun->machine->base_reg - && REGNO (cfun->machine->base_reg) == BASE_REGNUM); - - clobbered_regs[RETURN_REGNUM] - |= (!current_function_is_leaf - || TARGET_TPF_PROFILING - || cfun->machine->split_branches_pending_p - || cfun_frame_layout.save_return_addr_p - || crtl->calls_eh_return - || cfun->stdarg); - - clobbered_regs[STACK_POINTER_REGNUM] - |= (!current_function_is_leaf - || TARGET_TPF_PROFILING - || cfun_save_high_fprs_p - || get_frame_size () > 0 - || cfun->calls_alloca - || cfun->stdarg); - - for (i = 6; i < 16; i++) - if (df_regs_ever_live_p (i) || clobbered_regs[i]) - break; - for (j = 15; j > i; j--) - if (df_regs_ever_live_p (j) || clobbered_regs[j]) - break; - - if (i == 16) - { - /* Nothing to save/restore. */ - cfun_frame_layout.first_save_gpr_slot = -1; - cfun_frame_layout.last_save_gpr_slot = -1; - cfun_frame_layout.first_save_gpr = -1; - cfun_frame_layout.first_restore_gpr = -1; - cfun_frame_layout.last_save_gpr = -1; - cfun_frame_layout.last_restore_gpr = -1; - } - else - { - /* Save slots for gprs from i to j. */ - cfun_frame_layout.first_save_gpr_slot = i; - cfun_frame_layout.last_save_gpr_slot = j; - - for (i = cfun_frame_layout.first_save_gpr_slot; - i < cfun_frame_layout.last_save_gpr_slot + 1; - i++) - if (clobbered_regs[i]) - break; - - for (j = cfun_frame_layout.last_save_gpr_slot; j > i; j--) - if (clobbered_regs[j]) - break; - - if (i == cfun_frame_layout.last_save_gpr_slot + 1) - { - /* Nothing to save/restore. */ - cfun_frame_layout.first_save_gpr = -1; - cfun_frame_layout.first_restore_gpr = -1; - cfun_frame_layout.last_save_gpr = -1; - cfun_frame_layout.last_restore_gpr = -1; - } - else - { - /* Save / Restore from gpr i to j. */ - cfun_frame_layout.first_save_gpr = i; - cfun_frame_layout.first_restore_gpr = i; - cfun_frame_layout.last_save_gpr = j; - cfun_frame_layout.last_restore_gpr = j; - } - } - - if (cfun->stdarg) - { - /* Varargs functions need to save gprs 2 to 6. */ - if (cfun->va_list_gpr_size - && crtl->args.info.gprs < GP_ARG_NUM_REG) - { - int min_gpr = crtl->args.info.gprs; - int max_gpr = min_gpr + cfun->va_list_gpr_size; - if (max_gpr > GP_ARG_NUM_REG) - max_gpr = GP_ARG_NUM_REG; - - if (cfun_frame_layout.first_save_gpr == -1 - || cfun_frame_layout.first_save_gpr > 2 + min_gpr) - { - cfun_frame_layout.first_save_gpr = 2 + min_gpr; - cfun_frame_layout.first_save_gpr_slot = 2 + min_gpr; - } - - if (cfun_frame_layout.last_save_gpr == -1 - || cfun_frame_layout.last_save_gpr < 2 + max_gpr - 1) - { - cfun_frame_layout.last_save_gpr = 2 + max_gpr - 1; - cfun_frame_layout.last_save_gpr_slot = 2 + max_gpr - 1; - } - } - - /* Mark f0, f2 for 31 bit and f0-f4 for 64 bit to be saved. */ - if (TARGET_HARD_FLOAT && cfun->va_list_fpr_size - && crtl->args.info.fprs < FP_ARG_NUM_REG) - { - int min_fpr = crtl->args.info.fprs; - int max_fpr = min_fpr + cfun->va_list_fpr_size; - if (max_fpr > FP_ARG_NUM_REG) - max_fpr = FP_ARG_NUM_REG; - - /* ??? This is currently required to ensure proper location - of the fpr save slots within the va_list save area. */ - if (TARGET_PACKED_STACK) - min_fpr = 0; - - for (i = min_fpr; i < max_fpr; i++) - cfun_set_fpr_bit (i); - } - } - - if (!TARGET_64BIT) - for (i = 2; i < 4; i++) - if (df_regs_ever_live_p (i + 16) && !global_regs[i + 16]) - cfun_set_fpr_bit (i); -} - -/* Fill cfun->machine with info about frame of current function. */ - -static void -s390_frame_info (void) -{ - int i; - - cfun_frame_layout.frame_size = get_frame_size (); - if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000) - fatal_error ("total size of local variables exceeds architecture limit"); - - if (!TARGET_PACKED_STACK) - { - cfun_frame_layout.backchain_offset = 0; - cfun_frame_layout.f0_offset = 16 * UNITS_PER_LONG; - cfun_frame_layout.f4_offset = cfun_frame_layout.f0_offset + 2 * 8; - cfun_frame_layout.f8_offset = -cfun_frame_layout.high_fprs * 8; - cfun_frame_layout.gprs_offset = (cfun_frame_layout.first_save_gpr_slot - * UNITS_PER_LONG); - } - else if (TARGET_BACKCHAIN) /* kernel stack layout */ - { - cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET - - UNITS_PER_LONG); - cfun_frame_layout.gprs_offset - = (cfun_frame_layout.backchain_offset - - (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr_slot + 1) - * UNITS_PER_LONG); - - if (TARGET_64BIT) - { - cfun_frame_layout.f4_offset - = (cfun_frame_layout.gprs_offset - - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); - - cfun_frame_layout.f0_offset - = (cfun_frame_layout.f4_offset - - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); - } - else - { - /* On 31 bit we have to care about alignment of the - floating point regs to provide fastest access. */ - cfun_frame_layout.f0_offset - = ((cfun_frame_layout.gprs_offset - & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)) - - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); - - cfun_frame_layout.f4_offset - = (cfun_frame_layout.f0_offset - - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); - } - } - else /* no backchain */ - { - cfun_frame_layout.f4_offset - = (STACK_POINTER_OFFSET - - 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3))); - - cfun_frame_layout.f0_offset - = (cfun_frame_layout.f4_offset - - 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1))); - - cfun_frame_layout.gprs_offset - = cfun_frame_layout.f0_offset - cfun_gprs_save_area_size; - } - - if (current_function_is_leaf - && !TARGET_TPF_PROFILING - && cfun_frame_layout.frame_size == 0 - && !cfun_save_high_fprs_p - && !cfun->calls_alloca - && !cfun->stdarg) - return; - - if (!TARGET_PACKED_STACK) - cfun_frame_layout.frame_size += (STACK_POINTER_OFFSET - + crtl->outgoing_args_size - + cfun_frame_layout.high_fprs * 8); - else - { - if (TARGET_BACKCHAIN) - cfun_frame_layout.frame_size += UNITS_PER_LONG; - - /* No alignment trouble here because f8-f15 are only saved under - 64 bit. */ - cfun_frame_layout.f8_offset = (MIN (MIN (cfun_frame_layout.f0_offset, - cfun_frame_layout.f4_offset), - cfun_frame_layout.gprs_offset) - - cfun_frame_layout.high_fprs * 8); - - cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8; - - for (i = 0; i < 8; i++) - if (cfun_fpr_bit_p (i)) - cfun_frame_layout.frame_size += 8; - - cfun_frame_layout.frame_size += cfun_gprs_save_area_size; - - /* If under 31 bit an odd number of gprs has to be saved we have to adjust - the frame size to sustain 8 byte alignment of stack frames. */ - cfun_frame_layout.frame_size = ((cfun_frame_layout.frame_size + - STACK_BOUNDARY / BITS_PER_UNIT - 1) - & ~(STACK_BOUNDARY / BITS_PER_UNIT - 1)); - - cfun_frame_layout.frame_size += crtl->outgoing_args_size; - } -} - -/* Generate frame layout. Fills in register and frame data for the current - function in cfun->machine. This routine can be called multiple times; - it will re-do the complete frame layout every time. */ - -static void -s390_init_frame_layout (void) -{ - HOST_WIDE_INT frame_size; - int base_used; - int clobbered_regs[16]; - - /* On S/390 machines, we may need to perform branch splitting, which - will require both base and return address register. We have no - choice but to assume we're going to need them until right at the - end of the machine dependent reorg phase. */ - if (!TARGET_CPU_ZARCH) - cfun->machine->split_branches_pending_p = true; - - do - { - frame_size = cfun_frame_layout.frame_size; - - /* Try to predict whether we'll need the base register. */ - base_used = cfun->machine->split_branches_pending_p - || crtl->uses_const_pool - || (!DISP_IN_RANGE (frame_size) - && !CONST_OK_FOR_K (frame_size)); - - /* Decide which register to use as literal pool base. In small - leaf functions, try to use an unused call-clobbered register - as base register to avoid save/restore overhead. */ - if (!base_used) - cfun->machine->base_reg = NULL_RTX; - else if (current_function_is_leaf && !df_regs_ever_live_p (5)) - cfun->machine->base_reg = gen_rtx_REG (Pmode, 5); - else - cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM); - - s390_register_info (clobbered_regs); - s390_frame_info (); - } - while (frame_size != cfun_frame_layout.frame_size); -} - -/* Update frame layout. Recompute actual register save data based on - current info and update regs_ever_live for the special registers. - May be called multiple times, but may never cause *more* registers - to be saved than s390_init_frame_layout allocated room for. */ - -static void -s390_update_frame_layout (void) -{ - int clobbered_regs[16]; - - s390_register_info (clobbered_regs); - - df_set_regs_ever_live (BASE_REGNUM, - clobbered_regs[BASE_REGNUM] ? true : false); - df_set_regs_ever_live (RETURN_REGNUM, - clobbered_regs[RETURN_REGNUM] ? true : false); - df_set_regs_ever_live (STACK_POINTER_REGNUM, - clobbered_regs[STACK_POINTER_REGNUM] ? true : false); - - if (cfun->machine->base_reg) - df_set_regs_ever_live (REGNO (cfun->machine->base_reg), true); -} - -/* Return true if it is legal to put a value with MODE into REGNO. */ - -bool -s390_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) -{ - switch (REGNO_REG_CLASS (regno)) - { - case FP_REGS: - if (REGNO_PAIR_OK (regno, mode)) - { - if (mode == SImode || mode == DImode) - return true; - - if (FLOAT_MODE_P (mode) && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) - return true; - } - break; - case ADDR_REGS: - if (FRAME_REGNO_P (regno) && mode == Pmode) - return true; - - /* fallthrough */ - case GENERAL_REGS: - if (REGNO_PAIR_OK (regno, mode)) - { - if (TARGET_ZARCH - || (mode != TFmode && mode != TCmode && mode != TDmode)) - return true; - } - break; - case CC_REGS: - if (GET_MODE_CLASS (mode) == MODE_CC) - return true; - break; - case ACCESS_REGS: - if (REGNO_PAIR_OK (regno, mode)) - { - if (mode == SImode || mode == Pmode) - return true; - } - break; - default: - return false; - } - - return false; -} - -/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */ - -bool -s390_hard_regno_rename_ok (unsigned int old_reg, unsigned int new_reg) -{ - /* Once we've decided upon a register to use as base register, it must - no longer be used for any other purpose. */ - if (cfun->machine->base_reg) - if (REGNO (cfun->machine->base_reg) == old_reg - || REGNO (cfun->machine->base_reg) == new_reg) - return false; - - return true; -} - -/* Maximum number of registers to represent a value of mode MODE - in a register of class RCLASS. */ - -int -s390_class_max_nregs (enum reg_class rclass, enum machine_mode mode) -{ - switch (rclass) - { - case FP_REGS: - if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) - return 2 * ((GET_MODE_SIZE (mode) / 2 + 8 - 1) / 8); - else - return (GET_MODE_SIZE (mode) + 8 - 1) / 8; - case ACCESS_REGS: - return (GET_MODE_SIZE (mode) + 4 - 1) / 4; - default: - break; - } - return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -} - -/* Return true if register FROM can be eliminated via register TO. */ - -static bool -s390_can_eliminate (const int from, const int to) -{ - /* On zSeries machines, we have not marked the base register as fixed. - Instead, we have an elimination rule BASE_REGNUM -> BASE_REGNUM. - If a function requires the base register, we say here that this - elimination cannot be performed. This will cause reload to free - up the base register (as if it were fixed). On the other hand, - if the current function does *not* require the base register, we - say here the elimination succeeds, which in turn allows reload - to allocate the base register for any other purpose. */ - if (from == BASE_REGNUM && to == BASE_REGNUM) - { - if (TARGET_CPU_ZARCH) - { - s390_init_frame_layout (); - return cfun->machine->base_reg == NULL_RTX; - } - - return false; - } - - /* Everything else must point into the stack frame. */ - gcc_assert (to == STACK_POINTER_REGNUM - || to == HARD_FRAME_POINTER_REGNUM); - - gcc_assert (from == FRAME_POINTER_REGNUM - || from == ARG_POINTER_REGNUM - || from == RETURN_ADDRESS_POINTER_REGNUM); - - /* Make sure we actually saved the return address. */ - if (from == RETURN_ADDRESS_POINTER_REGNUM) - if (!crtl->calls_eh_return - && !cfun->stdarg - && !cfun_frame_layout.save_return_addr_p) - return false; - - return true; -} - -/* Return offset between register FROM and TO initially after prolog. */ - -HOST_WIDE_INT -s390_initial_elimination_offset (int from, int to) -{ - HOST_WIDE_INT offset; - int index; - - /* ??? Why are we called for non-eliminable pairs? */ - if (!s390_can_eliminate (from, to)) - return 0; - - switch (from) - { - case FRAME_POINTER_REGNUM: - offset = (get_frame_size() - + STACK_POINTER_OFFSET - + crtl->outgoing_args_size); - break; - - case ARG_POINTER_REGNUM: - s390_init_frame_layout (); - offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET; - break; - - case RETURN_ADDRESS_POINTER_REGNUM: - s390_init_frame_layout (); - index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr_slot; - gcc_assert (index >= 0); - offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset; - offset += index * UNITS_PER_LONG; - break; - - case BASE_REGNUM: - offset = 0; - break; - - default: - gcc_unreachable (); - } - - return offset; -} - -/* Emit insn to save fpr REGNUM at offset OFFSET relative - to register BASE. Return generated insn. */ - -static rtx -save_fpr (rtx base, int offset, int regnum) -{ - rtx addr; - addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); - - if (regnum >= 16 && regnum <= (16 + FP_ARG_NUM_REG)) - set_mem_alias_set (addr, get_varargs_alias_set ()); - else - set_mem_alias_set (addr, get_frame_alias_set ()); - - return emit_move_insn (addr, gen_rtx_REG (DFmode, regnum)); -} - -/* Emit insn to restore fpr REGNUM from offset OFFSET relative - to register BASE. Return generated insn. */ - -static rtx -restore_fpr (rtx base, int offset, int regnum) -{ - rtx addr; - addr = gen_rtx_MEM (DFmode, plus_constant (base, offset)); - set_mem_alias_set (addr, get_frame_alias_set ()); - - return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr); -} - -/* Return true if REGNO is a global register, but not one - of the special ones that need to be saved/restored in anyway. */ - -static inline bool -global_not_special_regno_p (int regno) -{ - return (global_regs[regno] - /* These registers are special and need to be - restored in any case. */ - && !(regno == STACK_POINTER_REGNUM - || regno == RETURN_REGNUM - || regno == BASE_REGNUM - || (flag_pic && regno == (int)PIC_OFFSET_TABLE_REGNUM))); -} - -/* Generate insn to save registers FIRST to LAST into - the register save area located at offset OFFSET - relative to register BASE. */ - -static rtx -save_gprs (rtx base, int offset, int first, int last) -{ - rtx addr, insn, note; - int i; - - addr = plus_constant (base, offset); - addr = gen_rtx_MEM (Pmode, addr); - - set_mem_alias_set (addr, get_frame_alias_set ()); - - /* Special-case single register. */ - if (first == last) - { - if (TARGET_64BIT) - insn = gen_movdi (addr, gen_rtx_REG (Pmode, first)); - else - insn = gen_movsi (addr, gen_rtx_REG (Pmode, first)); - - if (!global_not_special_regno_p (first)) - RTX_FRAME_RELATED_P (insn) = 1; - return insn; - } - - - insn = gen_store_multiple (addr, - gen_rtx_REG (Pmode, first), - GEN_INT (last - first + 1)); - - if (first <= 6 && cfun->stdarg) - for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) - { - rtx mem = XEXP (XVECEXP (PATTERN (insn), 0, i), 0); - - if (first + i <= 6) - set_mem_alias_set (mem, get_varargs_alias_set ()); - } - - /* We need to set the FRAME_RELATED flag on all SETs - 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 ... - - ??? Unfortunately, it is not enough to simply not the - FRAME_RELATED flags for those SETs, because the first SET - of the PARALLEL is always treated as if it had the flag - set, even if it does not. Therefore we emit a new pattern - without those registers as REG_FRAME_RELATED_EXPR note. */ - - if (first >= 6 && !global_not_special_regno_p (first)) - { - rtx pat = PATTERN (insn); - - for (i = 0; i < XVECLEN (pat, 0); i++) - if (GET_CODE (XVECEXP (pat, 0, i)) == SET - && !global_not_special_regno_p (REGNO (SET_SRC (XVECEXP (pat, - 0, i))))) - RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1; - - RTX_FRAME_RELATED_P (insn) = 1; - } - else if (last >= 6) - { - int start; - - for (start = first >= 6 ? first : 6; start <= last; start++) - if (!global_not_special_regno_p (start)) - break; - - if (start > last) - return insn; - - addr = plus_constant (base, offset + (start - first) * UNITS_PER_LONG); - note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), - gen_rtx_REG (Pmode, start), - GEN_INT (last - start + 1)); - note = PATTERN (note); - - add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); - - for (i = 0; i < XVECLEN (note, 0); i++) - if (GET_CODE (XVECEXP (note, 0, i)) == SET - && !global_not_special_regno_p (REGNO (SET_SRC (XVECEXP (note, - 0, i))))) - RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1; - - RTX_FRAME_RELATED_P (insn) = 1; - } - - return insn; -} - -/* Generate insn to restore registers FIRST to LAST from - the register save area located at offset OFFSET - relative to register BASE. */ - -static rtx -restore_gprs (rtx base, int offset, int first, int last) -{ - rtx addr, insn; - - addr = plus_constant (base, offset); - addr = gen_rtx_MEM (Pmode, addr); - set_mem_alias_set (addr, get_frame_alias_set ()); - - /* Special-case single register. */ - if (first == last) - { - if (TARGET_64BIT) - insn = gen_movdi (gen_rtx_REG (Pmode, first), addr); - else - insn = gen_movsi (gen_rtx_REG (Pmode, first), addr); - - return insn; - } - - insn = gen_load_multiple (gen_rtx_REG (Pmode, first), - addr, - GEN_INT (last - first + 1)); - return insn; -} - -/* Return insn sequence to load the GOT register. */ - -static GTY(()) rtx got_symbol; -rtx -s390_load_got (void) -{ - rtx insns; - - /* We cannot use pic_offset_table_rtx here since we use this - function also for non-pic if __tls_get_offset is called and in - that case PIC_OFFSET_TABLE_REGNUM as well as pic_offset_table_rtx - aren't usable. */ - rtx got_rtx = gen_rtx_REG (Pmode, 12); - - if (!got_symbol) - { - got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - SYMBOL_REF_FLAGS (got_symbol) = SYMBOL_FLAG_LOCAL; - } - - start_sequence (); - - if (TARGET_CPU_ZARCH) - { - emit_move_insn (got_rtx, got_symbol); - } - else - { - rtx offset; - - 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); - - emit_move_insn (got_rtx, offset); - - offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)), - UNSPEC_LTREL_BASE); - offset = gen_rtx_PLUS (Pmode, got_rtx, offset); - - emit_move_insn (got_rtx, offset); - } - - insns = get_insns (); - end_sequence (); - return insns; -} - -/* This ties together stack memory (MEM with an alias set of frame_alias_set) - and the change to the stack pointer. */ - -static void -s390_emit_stack_tie (void) -{ - rtx mem = gen_frame_mem (BLKmode, - gen_rtx_REG (Pmode, STACK_POINTER_REGNUM)); - - emit_insn (gen_stack_tie (mem)); -} - -/* Expand the prologue into a bunch of separate insns. */ - -void -s390_emit_prologue (void) -{ - rtx insn, addr; - rtx temp_reg; - int i; - int offset; - int next_fpr = 0; - - /* Complete frame layout. */ - - s390_update_frame_layout (); - - /* Annotate all constant pool references to let the scheduler know - they implicitly use the base register. */ - - push_topmost_sequence (); - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - annotate_constant_pool_refs (&PATTERN (insn)); - df_insn_rescan (insn); - } - - pop_topmost_sequence (); - - /* Choose best register to use for temp use within prologue. - See below for why TPF must use the register 1. */ - - if (!has_hard_reg_initial_val (Pmode, RETURN_REGNUM) - && !current_function_is_leaf - && !TARGET_TPF_PROFILING) - temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); - else - temp_reg = gen_rtx_REG (Pmode, 1); - - /* Save call saved gprs. */ - if (cfun_frame_layout.first_save_gpr != -1) - { - insn = save_gprs (stack_pointer_rtx, - cfun_frame_layout.gprs_offset + - UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr - - cfun_frame_layout.first_save_gpr_slot), - cfun_frame_layout.first_save_gpr, - cfun_frame_layout.last_save_gpr); - emit_insn (insn); - } - - /* Dummy insn to mark literal pool slot. */ - - if (cfun->machine->base_reg) - emit_insn (gen_main_pool (cfun->machine->base_reg)); - - offset = cfun_frame_layout.f0_offset; - - /* Save f0 and f2. */ - for (i = 0; i < 2; i++) - { - if (cfun_fpr_bit_p (i)) - { - save_fpr (stack_pointer_rtx, offset, i + 16); - offset += 8; - } - else if (!TARGET_PACKED_STACK) - offset += 8; - } - - /* Save f4 and f6. */ - offset = cfun_frame_layout.f4_offset; - for (i = 2; i < 4; i++) - { - if (cfun_fpr_bit_p (i)) - { - insn = save_fpr (stack_pointer_rtx, offset, i + 16); - offset += 8; - - /* If f4 and f6 are call clobbered they are saved due to stdargs and - therefore are not frame related. */ - if (!call_really_used_regs[i + 16]) - RTX_FRAME_RELATED_P (insn) = 1; - } - else if (!TARGET_PACKED_STACK) - offset += 8; - } - - if (TARGET_PACKED_STACK - && cfun_save_high_fprs_p - && cfun_frame_layout.f8_offset + cfun_frame_layout.high_fprs * 8 > 0) - { - offset = (cfun_frame_layout.f8_offset - + (cfun_frame_layout.high_fprs - 1) * 8); - - for (i = 15; i > 7 && offset >= 0; i--) - if (cfun_fpr_bit_p (i)) - { - insn = save_fpr (stack_pointer_rtx, offset, i + 16); - - RTX_FRAME_RELATED_P (insn) = 1; - offset -= 8; - } - if (offset >= cfun_frame_layout.f8_offset) - next_fpr = i + 16; - } - - if (!TARGET_PACKED_STACK) - next_fpr = cfun_save_high_fprs_p ? 31 : 0; - - if (flag_stack_usage_info) - current_function_static_stack_size = cfun_frame_layout.frame_size; - - /* Decrement stack pointer. */ - - if (cfun_frame_layout.frame_size > 0) - { - rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size); - rtx real_frame_off; - - if (s390_stack_size) - { - HOST_WIDE_INT stack_guard; - - if (s390_stack_guard) - stack_guard = s390_stack_guard; - else - { - /* If no value for stack guard is provided the smallest power of 2 - larger than the current frame size is chosen. */ - stack_guard = 1; - while (stack_guard < cfun_frame_layout.frame_size) - stack_guard <<= 1; - } - - if (cfun_frame_layout.frame_size >= s390_stack_size) - { - warning (0, "frame size of function %qs is %wd" - " bytes exceeding user provided stack limit of " - "%d bytes. " - "An unconditional trap is added.", - current_function_name(), cfun_frame_layout.frame_size, - s390_stack_size); - emit_insn (gen_trap ()); - } - else - { - /* stack_guard has to be smaller than s390_stack_size. - Otherwise we would emit an AND with zero which would - not match the test under mask pattern. */ - if (stack_guard >= s390_stack_size) - { - warning (0, "frame size of function %qs is %wd" - " bytes which is more than half the stack size. " - "The dynamic check would not be reliable. " - "No check emitted for this function.", - current_function_name(), - cfun_frame_layout.frame_size); - } - else - { - HOST_WIDE_INT stack_check_mask = ((s390_stack_size - 1) - & ~(stack_guard - 1)); - - rtx t = gen_rtx_AND (Pmode, stack_pointer_rtx, - GEN_INT (stack_check_mask)); - if (TARGET_64BIT) - emit_insn (gen_ctrapdi4 (gen_rtx_EQ (VOIDmode, - t, const0_rtx), - t, const0_rtx, const0_rtx)); - else - emit_insn (gen_ctrapsi4 (gen_rtx_EQ (VOIDmode, - t, const0_rtx), - t, const0_rtx, const0_rtx)); - } - } - } - - if (s390_warn_framesize > 0 - && cfun_frame_layout.frame_size >= s390_warn_framesize) - warning (0, "frame size of %qs is %wd bytes", - current_function_name (), cfun_frame_layout.frame_size); - - if (s390_warn_dynamicstack_p && cfun->calls_alloca) - warning (0, "%qs uses dynamic stack allocation", current_function_name ()); - - /* Save incoming stack pointer into temp reg. */ - if (TARGET_BACKCHAIN || next_fpr) - insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx)); - - /* 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_K (INTVAL (frame_off))) - frame_off = force_const_mem (Pmode, frame_off); - - insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off)); - annotate_constant_pool_refs (&PATTERN (insn)); - } - - RTX_FRAME_RELATED_P (insn) = 1; - real_frame_off = GEN_INT (-cfun_frame_layout.frame_size); - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, stack_pointer_rtx, - gen_rtx_PLUS (Pmode, stack_pointer_rtx, - real_frame_off))); - - /* Set backchain. */ - - if (TARGET_BACKCHAIN) - { - if (cfun_frame_layout.backchain_offset) - addr = gen_rtx_MEM (Pmode, - plus_constant (stack_pointer_rtx, - cfun_frame_layout.backchain_offset)); - else - addr = gen_rtx_MEM (Pmode, stack_pointer_rtx); - set_mem_alias_set (addr, get_frame_alias_set ()); - insn = emit_insn (gen_move_insn (addr, temp_reg)); - } - - /* If we support non-call exceptions (e.g. for Java), - we need to make sure the backchain pointer is set up - before any possibly trapping memory access. */ - if (TARGET_BACKCHAIN && cfun->can_throw_non_call_exceptions) - { - addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)); - emit_clobber (addr); - } - } - - /* Save fprs 8 - 15 (64 bit ABI). */ - - if (cfun_save_high_fprs_p && next_fpr) - { - /* If the stack might be accessed through a different register - we have to make sure that the stack pointer decrement is not - moved below the use of the stack slots. */ - s390_emit_stack_tie (); - - insn = emit_insn (gen_add2_insn (temp_reg, - GEN_INT (cfun_frame_layout.f8_offset))); - - offset = 0; - - for (i = 24; i <= next_fpr; i++) - if (cfun_fpr_bit_p (i - 16)) - { - rtx addr = plus_constant (stack_pointer_rtx, - cfun_frame_layout.frame_size - + cfun_frame_layout.f8_offset - + offset); - - insn = save_fpr (temp_reg, offset, i); - offset += 8; - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, - gen_rtx_MEM (DFmode, addr), - gen_rtx_REG (DFmode, i))); - } - } - - /* Set frame pointer, if needed. */ - - if (frame_pointer_needed) - { - insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - } - - /* Set up got pointer, if needed. */ - - if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) - { - rtx insns = s390_load_got (); - - for (insn = insns; insn; insn = NEXT_INSN (insn)) - annotate_constant_pool_refs (&PATTERN (insn)); - - emit_insn (insns); - } - - if (TARGET_TPF_PROFILING) - { - /* Generate a BAS instruction to serve as a function - entry intercept to facilitate the use of tracing - algorithms located at the branch target. */ - emit_insn (gen_prologue_tpf ()); - - /* 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 (bool sibcall) -{ - rtx frame_pointer, return_reg, cfa_restores = NULL_RTX; - int area_bottom, area_top, offset = 0; - int next_offset; - rtvec p; - int i; - - if (TARGET_TPF_PROFILING) - { - - /* Generate a BAS instruction to serve as a function - entry intercept to facilitate the use of tracing - algorithms located at the branch target. */ - - /* Emit a blockage here so that all code - lies between the profiling mechanisms. */ - emit_insn (gen_blockage ()); - - emit_insn (gen_epilogue_tpf ()); - } - - /* Check whether to use frame or stack pointer for restore. */ - - frame_pointer = (frame_pointer_needed - ? hard_frame_pointer_rtx : stack_pointer_rtx); - - s390_frame_area (&area_bottom, &area_top); - - /* 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 (DISP_IN_RANGE (cfun_frame_layout.frame_size + area_bottom) - && DISP_IN_RANGE (cfun_frame_layout.frame_size + area_top - 1)) - { - /* Area is in range. */ - offset = cfun_frame_layout.frame_size; - } - else - { - rtx insn, frame_off, cfa; - - offset = area_bottom < 0 ? -area_bottom : 0; - frame_off = GEN_INT (cfun_frame_layout.frame_size - offset); - - cfa = gen_rtx_SET (VOIDmode, frame_pointer, - gen_rtx_PLUS (Pmode, frame_pointer, 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_K (INTVAL (frame_off))) - frame_off = force_const_mem (Pmode, frame_off); - - insn = emit_insn (gen_add2_insn (frame_pointer, frame_off)); - annotate_constant_pool_refs (&PATTERN (insn)); - } - add_reg_note (insn, REG_CFA_ADJUST_CFA, cfa); - RTX_FRAME_RELATED_P (insn) = 1; - } - - /* Restore call saved fprs. */ - - if (TARGET_64BIT) - { - if (cfun_save_high_fprs_p) - { - next_offset = cfun_frame_layout.f8_offset; - for (i = 24; i < 32; i++) - { - if (cfun_fpr_bit_p (i - 16)) - { - restore_fpr (frame_pointer, - offset + next_offset, i); - cfa_restores - = alloc_reg_note (REG_CFA_RESTORE, - gen_rtx_REG (DFmode, i), cfa_restores); - next_offset += 8; - } - } - } - - } - else - { - next_offset = cfun_frame_layout.f4_offset; - for (i = 18; i < 20; i++) - { - if (cfun_fpr_bit_p (i - 16)) - { - restore_fpr (frame_pointer, - offset + next_offset, i); - cfa_restores - = alloc_reg_note (REG_CFA_RESTORE, - gen_rtx_REG (DFmode, i), cfa_restores); - next_offset += 8; - } - else if (!TARGET_PACKED_STACK) - next_offset += 8; - } - - } - - /* Return register. */ - - return_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); - - /* Restore call saved gprs. */ - - if (cfun_frame_layout.first_restore_gpr != -1) - { - rtx insn, addr; - int i; - - /* Check for global register and save them - to stack location from where they get restored. */ - - for (i = cfun_frame_layout.first_restore_gpr; - i <= cfun_frame_layout.last_restore_gpr; - i++) - { - if (global_not_special_regno_p (i)) - { - addr = plus_constant (frame_pointer, - offset + cfun_frame_layout.gprs_offset - + (i - cfun_frame_layout.first_save_gpr_slot) - * UNITS_PER_LONG); - addr = gen_rtx_MEM (Pmode, addr); - set_mem_alias_set (addr, get_frame_alias_set ()); - emit_move_insn (addr, gen_rtx_REG (Pmode, i)); - } - else - cfa_restores - = alloc_reg_note (REG_CFA_RESTORE, - gen_rtx_REG (Pmode, i), cfa_restores); - } - - if (! sibcall) - { - /* Fetch return address from stack before load multiple, - this will do good for scheduling. */ - - if (cfun_frame_layout.save_return_addr_p - || (cfun_frame_layout.first_restore_gpr < BASE_REGNUM - && cfun_frame_layout.last_restore_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 + cfun_frame_layout.gprs_offset - + (RETURN_REGNUM - - cfun_frame_layout.first_save_gpr_slot) - * UNITS_PER_LONG); - addr = gen_rtx_MEM (Pmode, addr); - set_mem_alias_set (addr, get_frame_alias_set ()); - emit_move_insn (return_reg, addr); - } - } - - insn = restore_gprs (frame_pointer, - offset + cfun_frame_layout.gprs_offset - + (cfun_frame_layout.first_restore_gpr - - cfun_frame_layout.first_save_gpr_slot) - * UNITS_PER_LONG, - cfun_frame_layout.first_restore_gpr, - cfun_frame_layout.last_restore_gpr); - insn = emit_insn (insn); - REG_NOTES (insn) = cfa_restores; - add_reg_note (insn, REG_CFA_DEF_CFA, - plus_constant (stack_pointer_rtx, STACK_POINTER_OFFSET)); - RTX_FRAME_RELATED_P (insn) = 1; - } - - if (! sibcall) - { - - /* Return to caller. */ - - p = rtvec_alloc (2); - - RTVEC_ELT (p, 0) = ret_rtx; - 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 - type TYPE and/or mode MODE. At least one of TYPE or - MODE must be specified. */ - -static int -s390_function_arg_size (enum machine_mode mode, const_tree type) -{ - if (type) - return int_size_in_bytes (type); - - /* No type info available for some library calls ... */ - if (mode != BLKmode) - return GET_MODE_SIZE (mode); - - /* If we have neither type nor mode, abort */ - gcc_unreachable (); -} - -/* 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, const_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 || mode == SDmode || mode == DDmode; - - /* 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 = DECL_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, const_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 && SCALAR_FLOAT_MODE_P (mode)); - - /* We accept small integral (and similar) types. */ - if (INTEGRAL_TYPE_P (type) - || POINTER_TYPE_P (type) - || TREE_CODE (type) == NULLPTR_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, - all other structures (and complex numbers) are passed by - reference. */ - -static bool -s390_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, - enum machine_mode mode, const_tree type, - bool named ATTRIBUTE_UNUSED) -{ - int size = s390_function_arg_size (mode, type); - if (size > 8) - return true; - - if (type) - { - if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0) - return 1; - - if (TREE_CODE (type) == COMPLEX_TYPE - || TREE_CODE (type) == VECTOR_TYPE) - return 1; - } - - return 0; -} - -/* Update the data in CUM to advance over an argument of mode MODE and - data type TYPE. (TYPE is null for libcalls where that information - may not be available.). The boolean NAMED specifies whether the - argument is a named argument (as opposed to an unnamed argument - matching an ellipsis). */ - -static void -s390_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - - if (s390_function_arg_float (mode, type)) - { - cum->fprs += 1; - } - else if (s390_function_arg_integer (mode, type)) - { - int size = s390_function_arg_size (mode, type); - cum->gprs += ((size + UNITS_PER_LONG - 1) / UNITS_PER_LONG); - } - else - gcc_unreachable (); -} - -/* Define where to put the arguments to a function. - Value is zero to push the argument on the stack, - or a hard register in which to store the argument. - - MODE is the argument's machine mode. - TYPE is the data type of the argument (as a tree). - This is null for libcalls where that information may - not be available. - CUM is a variable of type CUMULATIVE_ARGS which gives info about - the preceding args and about the function being called. - NAMED is nonzero if this argument is a named parameter - (otherwise it is an extra parameter matching an ellipsis). - - On S/390, we use general purpose registers 2 through 6 to - pass integer, pointer, and certain structure arguments, and - floating point registers 0 and 2 (0, 2, 4, and 6 on 64-bit) - to pass floating point arguments. All remaining arguments - are pushed to the stack. */ - -static rtx -s390_function_arg (cumulative_args_t cum_v, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - - if (s390_function_arg_float (mode, type)) - { - if (cum->fprs + 1 > FP_ARG_NUM_REG) - return 0; - else - return gen_rtx_REG (mode, cum->fprs + 16); - } - else if (s390_function_arg_integer (mode, type)) - { - int size = s390_function_arg_size (mode, type); - int n_gprs = (size + UNITS_PER_LONG - 1) / UNITS_PER_LONG; - - if (cum->gprs + n_gprs > GP_ARG_NUM_REG) - return 0; - else if (n_gprs == 1 || UNITS_PER_WORD == UNITS_PER_LONG) - return gen_rtx_REG (mode, cum->gprs + 2); - else if (n_gprs == 2) - { - rtvec p = rtvec_alloc (2); - - RTVEC_ELT (p, 0) - = gen_rtx_EXPR_LIST (SImode, gen_rtx_REG (SImode, cum->gprs + 2), - const0_rtx); - RTVEC_ELT (p, 1) - = gen_rtx_EXPR_LIST (SImode, gen_rtx_REG (SImode, cum->gprs + 3), - GEN_INT (4)); - - return gen_rtx_PARALLEL (mode, p); - } - } - - /* 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; - - gcc_unreachable (); -} - -/* 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 (const_tree type, const_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; -} - -/* Function arguments and return values are promoted to word size. */ - -static enum machine_mode -s390_promote_function_mode (const_tree type, enum machine_mode mode, - int *punsignedp, - const_tree fntype ATTRIBUTE_UNUSED, - int for_return ATTRIBUTE_UNUSED) -{ - if (INTEGRAL_MODE_P (mode) - && GET_MODE_SIZE (mode) < UNITS_PER_LONG) - { - if (type != NULL_TREE && POINTER_TYPE_P (type)) - *punsignedp = POINTERS_EXTEND_UNSIGNED; - return Pmode; - } - - return mode; -} - -/* Define where to return a (scalar) value of type RET_TYPE. - If RET_TYPE is null, define where to return a (scalar) - value of mode MODE from a libcall. */ - -static rtx -s390_function_and_libcall_value (enum machine_mode mode, - const_tree ret_type, - const_tree fntype_or_decl, - bool outgoing ATTRIBUTE_UNUSED) -{ - /* For normal functions perform the promotion as - promote_function_mode would do. */ - if (ret_type) - { - int unsignedp = TYPE_UNSIGNED (ret_type); - mode = promote_function_mode (ret_type, mode, &unsignedp, - fntype_or_decl, 1); - } - - gcc_assert (GET_MODE_CLASS (mode) == MODE_INT || SCALAR_FLOAT_MODE_P (mode)); - gcc_assert (GET_MODE_SIZE (mode) <= 8); - - if (TARGET_HARD_FLOAT && SCALAR_FLOAT_MODE_P (mode)) - return gen_rtx_REG (mode, 16); - else if (GET_MODE_SIZE (mode) <= UNITS_PER_LONG - || UNITS_PER_LONG == UNITS_PER_WORD) - return gen_rtx_REG (mode, 2); - else if (GET_MODE_SIZE (mode) == 2 * UNITS_PER_LONG) - { - /* This case is triggered when returning a 64 bit value with - -m31 -mzarch. Although the value would fit into a single - register it has to be forced into a 32 bit register pair in - order to match the ABI. */ - rtvec p = rtvec_alloc (2); - - RTVEC_ELT (p, 0) - = gen_rtx_EXPR_LIST (SImode, gen_rtx_REG (SImode, 2), const0_rtx); - RTVEC_ELT (p, 1) - = gen_rtx_EXPR_LIST (SImode, gen_rtx_REG (SImode, 3), GEN_INT (4)); - - return gen_rtx_PARALLEL (mode, p); - } - - gcc_unreachable (); -} - -/* Define where to return a scalar return value of type RET_TYPE. */ - -static rtx -s390_function_value (const_tree ret_type, const_tree fn_decl_or_type, - bool outgoing) -{ - return s390_function_and_libcall_value (TYPE_MODE (ret_type), ret_type, - fn_decl_or_type, outgoing); -} - -/* Define where to return a scalar libcall return value of mode - MODE. */ - -static rtx -s390_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) -{ - return s390_function_and_libcall_value (mode, NULL_TREE, - NULL_TREE, true); -} - - -/* Create and return the va_list datatype. - - On S/390, va_list is an array type equivalent to - - typedef struct __va_list_tag - { - long __gpr; - 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 - 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. */ - -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); - - type_decl = - build_decl (BUILTINS_LOCATION, - TYPE_DECL, get_identifier ("__va_list_tag"), record); - - f_gpr = build_decl (BUILTINS_LOCATION, - FIELD_DECL, get_identifier ("__gpr"), - long_integer_type_node); - f_fpr = build_decl (BUILTINS_LOCATION, - FIELD_DECL, get_identifier ("__fpr"), - long_integer_type_node); - f_ovf = build_decl (BUILTINS_LOCATION, - FIELD_DECL, get_identifier ("__overflow_arg_area"), - ptr_type_node); - f_sav = build_decl (BUILTINS_LOCATION, - FIELD_DECL, get_identifier ("__reg_save_area"), - ptr_type_node); - - va_list_gpr_counter_field = f_gpr; - va_list_fpr_counter_field = f_fpr; - - DECL_FIELD_CONTEXT (f_gpr) = record; - DECL_FIELD_CONTEXT (f_fpr) = record; - DECL_FIELD_CONTEXT (f_ovf) = record; - DECL_FIELD_CONTEXT (f_sav) = record; - - TYPE_STUB_DECL (record) = type_decl; - TYPE_NAME (record) = type_decl; - TYPE_FIELDS (record) = f_gpr; - DECL_CHAIN (f_gpr) = f_fpr; - DECL_CHAIN (f_fpr) = f_ovf; - DECL_CHAIN (f_ovf) = f_sav; - - layout_type (record); - - /* The correct type is an array type of one element. */ - return build_array_type (record, build_index_type (size_zero_node)); -} - -/* Implement va_start by filling the va_list structure VALIST. - STDARG_P is always true, and ignored. - NEXTARG points to the first anonymous stack argument. - - The following global variables are used to initialize - the va_list structure: - - crtl->args.info: - holds number of gprs and fprs used for named arguments. - crtl->args.arg_offset_rtx: - holds the offset of the first anonymous stack argument - (relative to the virtual arg pointer). */ - -static void -s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) -{ - HOST_WIDE_INT n_gpr, n_fpr; - int off; - tree f_gpr, f_fpr, f_ovf, f_sav; - tree gpr, fpr, ovf, sav, t; - - f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); - f_fpr = DECL_CHAIN (f_gpr); - f_ovf = DECL_CHAIN (f_fpr); - f_sav = DECL_CHAIN (f_ovf); - - valist = build_simple_mem_ref (valist); - gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); - - /* Count number of gp and fp argument registers used. */ - - n_gpr = crtl->args.info.gprs; - n_fpr = crtl->args.info.fprs; - - if (cfun->va_list_gpr_size) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, - build_int_cst (NULL_TREE, n_gpr)); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - - if (cfun->va_list_fpr_size) - { - t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, - build_int_cst (NULL_TREE, n_fpr)); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - - /* Find the overflow area. */ - if (n_gpr + cfun->va_list_gpr_size > GP_ARG_NUM_REG - || n_fpr + cfun->va_list_fpr_size > FP_ARG_NUM_REG) - { - t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); - - off = INTVAL (crtl->args.arg_offset_rtx); - off = off < 0 ? 0 : off; - if (TARGET_DEBUG_ARG) - fprintf (stderr, "va_start: n_gpr = %d, n_fpr = %d off %d\n", - (int)n_gpr, (int)n_fpr, off); - - t = fold_build_pointer_plus_hwi (t, off); - - t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - - /* Find the register save area. */ - if ((cfun->va_list_gpr_size && n_gpr < GP_ARG_NUM_REG) - || (cfun->va_list_fpr_size && n_fpr < FP_ARG_NUM_REG)) - { - t = make_tree (TREE_TYPE (sav), return_address_pointer_rtx); - t = fold_build_pointer_plus_hwi (t, -RETURN_REGNUM * UNITS_PER_LONG); - - t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } -} - -/* Implement va_arg by updating the va_list structure - VALIST as required to retrieve an argument of type - TYPE, and returning that argument. - - Generates code equivalent to: - - if (integral value) { - if (size <= 4 && args.gpr < 5 || - size > 4 && args.gpr < 4 ) - ret = args.reg_save_area[args.gpr+8] - else - ret = *args.overflow_arg_area++; - } else if (float value) { - if (args.fgpr < 2) - ret = args.reg_save_area[args.fpr+64] - else - ret = *args.overflow_arg_area++; - } else if (aggregate value) { - if (args.gpr < 5) - ret = *args.reg_save_area[args.gpr] - else - ret = **args.overflow_arg_area++; - } */ - -static tree -s390_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, - gimple_seq *post_p ATTRIBUTE_UNUSED) -{ - tree f_gpr, f_fpr, f_ovf, f_sav; - tree gpr, fpr, ovf, sav, reg, t, u; - int indirect_p, size, n_reg, sav_ofs, sav_scale, max_reg; - tree lab_false, lab_over, addr; - - f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); - f_fpr = DECL_CHAIN (f_gpr); - f_ovf = DECL_CHAIN (f_fpr); - f_sav = DECL_CHAIN (f_ovf); - - valist = build_va_arg_indirect_ref (valist); - gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); - fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); - sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); - - /* The tree for args* cannot be shared between gpr/fpr and ovf since - both appear on a lhs. */ - valist = unshare_expr (valist); - ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); - - size = int_size_in_bytes (type); - - if (pass_by_reference (NULL, TYPE_MODE (type), type, false)) - { - if (TARGET_DEBUG_ARG) - { - fprintf (stderr, "va_arg: aggregate type"); - debug_tree (type); - } - - /* Aggregates are passed by reference. */ - indirect_p = 1; - reg = gpr; - n_reg = 1; - - /* kernel stack layout on 31 bit: It is assumed here that no padding - will be added by s390_frame_info because for va_args always an even - number of gprs has to be saved r15-r2 = 14 regs. */ - sav_ofs = 2 * UNITS_PER_LONG; - sav_scale = UNITS_PER_LONG; - size = UNITS_PER_LONG; - max_reg = GP_ARG_NUM_REG - n_reg; - } - else if (s390_function_arg_float (TYPE_MODE (type), type)) - { - if (TARGET_DEBUG_ARG) - { - fprintf (stderr, "va_arg: float type"); - debug_tree (type); - } - - /* FP args go in FP registers, if present. */ - indirect_p = 0; - reg = fpr; - n_reg = 1; - sav_ofs = 16 * UNITS_PER_LONG; - sav_scale = 8; - max_reg = FP_ARG_NUM_REG - n_reg; - } - else - { - if (TARGET_DEBUG_ARG) - { - fprintf (stderr, "va_arg: other type"); - debug_tree (type); - } - - /* Otherwise into GP registers. */ - indirect_p = 0; - reg = gpr; - n_reg = (size + UNITS_PER_LONG - 1) / UNITS_PER_LONG; - - /* kernel stack layout on 31 bit: It is assumed here that no padding - will be added by s390_frame_info because for va_args always an even - number of gprs has to be saved r15-r2 = 14 regs. */ - sav_ofs = 2 * UNITS_PER_LONG; - - if (size < UNITS_PER_LONG) - sav_ofs += UNITS_PER_LONG - size; - - sav_scale = UNITS_PER_LONG; - max_reg = GP_ARG_NUM_REG - n_reg; - } - - /* Pull the value out of the saved registers ... */ - - lab_false = create_artificial_label (UNKNOWN_LOCATION); - lab_over = create_artificial_label (UNKNOWN_LOCATION); - addr = create_tmp_var (ptr_type_node, "addr"); - - t = fold_convert (TREE_TYPE (reg), size_int (max_reg)); - t = build2 (GT_EXPR, boolean_type_node, reg, t); - u = build1 (GOTO_EXPR, void_type_node, lab_false); - t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE); - gimplify_and_add (t, pre_p); - - t = fold_build_pointer_plus_hwi (sav, sav_ofs); - u = build2 (MULT_EXPR, TREE_TYPE (reg), reg, - fold_convert (TREE_TYPE (reg), size_int (sav_scale))); - t = fold_build_pointer_plus (t, u); - - gimplify_assign (addr, t, pre_p); - - gimple_seq_add_stmt (pre_p, gimple_build_goto (lab_over)); - - gimple_seq_add_stmt (pre_p, gimple_build_label (lab_false)); - - - /* ... Otherwise out of the overflow area. */ - - t = ovf; - if (size < UNITS_PER_LONG) - t = fold_build_pointer_plus_hwi (t, UNITS_PER_LONG - size); - - gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue); - - gimplify_assign (addr, t, pre_p); - - t = fold_build_pointer_plus_hwi (t, size); - gimplify_assign (ovf, t, pre_p); - - gimple_seq_add_stmt (pre_p, gimple_build_label (lab_over)); - - - /* Increment register save count. */ - - u = build2 (PREINCREMENT_EXPR, TREE_TYPE (reg), reg, - fold_convert (TREE_TYPE (reg), size_int (n_reg))); - gimplify_and_add (u, pre_p); - - if (indirect_p) - { - t = build_pointer_type_for_mode (build_pointer_type (type), - ptr_mode, true); - addr = fold_convert (t, addr); - addr = build_va_arg_indirect_ref (addr); - } - else - { - t = build_pointer_type_for_mode (type, ptr_mode, true); - addr = fold_convert (t, addr); - } - - return build_va_arg_indirect_ref (addr); -} - - -/* Builtins. */ - -enum s390_builtin -{ - S390_BUILTIN_THREAD_POINTER, - S390_BUILTIN_SET_THREAD_POINTER, - - S390_BUILTIN_max -}; - -static enum insn_code const code_for_builtin_64[S390_BUILTIN_max] = { - CODE_FOR_get_tp_64, - CODE_FOR_set_tp_64 -}; - -static enum insn_code const code_for_builtin_31[S390_BUILTIN_max] = { - CODE_FOR_get_tp_31, - CODE_FOR_set_tp_31 -}; - -static void -s390_init_builtins (void) -{ - tree ftype; - - ftype = build_function_type_list (ptr_type_node, NULL_TREE); - add_builtin_function ("__builtin_thread_pointer", ftype, - S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD, - NULL, NULL_TREE); - - ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); - add_builtin_function ("__builtin_set_thread_pointer", ftype, - S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD, - NULL, NULL_TREE); -} - -/* Expand an expression EXP that calls a built-in function, - with result going to TARGET if that's convenient - (and in mode MODE if that's convenient). - SUBTARGET may be used as the target for computing one of EXP's operands. - IGNORE is nonzero if the value is to be ignored. */ - -static rtx -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 - - enum insn_code const *code_for_builtin = - TARGET_64BIT ? code_for_builtin_64 : code_for_builtin_31; - - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - unsigned int fcode = DECL_FUNCTION_CODE (fndecl); - enum insn_code icode; - rtx op[MAX_ARGS], pat; - int arity; - bool nonvoid; - tree arg; - call_expr_arg_iterator iter; - - if (fcode >= S390_BUILTIN_max) - internal_error ("bad builtin fcode"); - icode = code_for_builtin[fcode]; - if (icode == 0) - internal_error ("bad builtin fcode"); - - nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; - - arity = 0; - FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) - { - const struct insn_operand_data *insn_op; - - if (arg == error_mark_node) - return NULL_RTX; - if (arity > MAX_ARGS) - return NULL_RTX; - - insn_op = &insn_data[icode].operand[arity + nonvoid]; - - op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); - - if (!(*insn_op->predicate) (op[arity], insn_op->mode)) - op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]); - arity++; - } - - if (nonvoid) - { - enum machine_mode tmode = insn_data[icode].operand[0].mode; - if (!target - || GET_MODE (target) != tmode - || !(*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - } - - switch (arity) - { - case 0: - pat = GEN_FCN (icode) (target); - break; - case 1: - if (nonvoid) - pat = GEN_FCN (icode) (target, op[0]); - else - pat = GEN_FCN (icode) (op[0]); - break; - case 2: - pat = GEN_FCN (icode) (target, op[0], op[1]); - break; - default: - gcc_unreachable (); - } - if (!pat) - return NULL_RTX; - emit_insn (pat); - - if (nonvoid) - return target; - else - return const0_rtx; -} - - -/* Output assembly code for the trampoline template to - stdio stream FILE. - - On S/390, we use gpr 1 internally in the trampoline code; - gpr 0 is used to hold the static chain. */ - -static void -s390_asm_trampoline_template (FILE *file) -{ - rtx op[2]; - op[0] = gen_rtx_REG (Pmode, 0); - op[1] = gen_rtx_REG (Pmode, 1); - - if (TARGET_64BIT) - { - output_asm_insn ("basr\t%1,0", op); /* 2 byte */ - output_asm_insn ("lmg\t%0,%1,14(%1)", op); /* 6 byte */ - output_asm_insn ("br\t%1", op); /* 2 byte */ - ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 10)); - } - else - { - output_asm_insn ("basr\t%1,0", op); /* 2 byte */ - output_asm_insn ("lm\t%0,%1,6(%1)", op); /* 4 byte */ - output_asm_insn ("br\t%1", op); /* 2 byte */ - ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 8)); - } -} - -/* Emit RTL insns to initialize the variable parts of a trampoline. - FNADDR is an RTX for the address of the function's pure code. - CXT is an RTX for the static chain value for the function. */ - -static void -s390_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt) -{ - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx mem; - - emit_block_move (m_tramp, assemble_trampoline_template (), - GEN_INT (2 * UNITS_PER_LONG), BLOCK_OP_NORMAL); - - mem = adjust_address (m_tramp, Pmode, 2 * UNITS_PER_LONG); - emit_move_insn (mem, cxt); - mem = adjust_address (m_tramp, Pmode, 3 * UNITS_PER_LONG); - emit_move_insn (mem, fnaddr); -} - -/* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. */ - -void -s390_function_profiler (FILE *file, int labelno) -{ - rtx op[7]; - - char label[128]; - ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno); - - fprintf (file, "# function profiler \n"); - - op[0] = gen_rtx_REG (Pmode, RETURN_REGNUM); - op[1] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - op[1] = gen_rtx_MEM (Pmode, plus_constant (op[1], UNITS_PER_LONG)); - - op[2] = gen_rtx_REG (Pmode, 1); - op[3] = gen_rtx_SYMBOL_REF (Pmode, label); - 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]), UNSPEC_PLT); - op[4] = gen_rtx_CONST (Pmode, op[4]); - } - - if (TARGET_64BIT) - { - output_asm_insn ("stg\t%0,%1", op); - output_asm_insn ("larl\t%2,%3", op); - output_asm_insn ("brasl\t%0,%4", op); - output_asm_insn ("lg\t%0,%1", op); - } - else if (!flag_pic) - { - op[6] = gen_label_rtx (); - - output_asm_insn ("st\t%0,%1", op); - output_asm_insn ("bras\t%2,%l6", op); - output_asm_insn (".long\t%4", op); - output_asm_insn (".long\t%3", op); - 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); - output_asm_insn ("l\t%0,%1", op); - } - else - { - op[5] = gen_label_rtx (); - op[6] = gen_label_rtx (); - - output_asm_insn ("st\t%0,%1", op); - output_asm_insn ("bras\t%2,%l6", op); - 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); - 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); - output_asm_insn ("basr\t%0,%0", op); - output_asm_insn ("l\t%0,%1", op); - } -} - -/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF - into its SYMBOL_REF_FLAGS. */ - -static void -s390_encode_section_info (tree decl, rtx rtl, int first) -{ - default_encode_section_info (decl, rtl, first); - - if (TREE_CODE (decl) == VAR_DECL) - { - /* 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 (DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16) - SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1; - if (!DECL_SIZE (decl) - || !DECL_ALIGN (decl) - || !host_integerp (DECL_SIZE (decl), 0) - || (DECL_ALIGN (decl) <= 64 - && DECL_ALIGN (decl) != tree_low_cst (DECL_SIZE (decl), 0))) - SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED; - } - - /* Literal pool references don't have a decl so they are handled - differently here. We rely on the information in the MEM_ALIGN - entry to decide upon natural alignment. */ - if (MEM_P (rtl) - && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF - && TREE_CONSTANT_POOL_ADDRESS_P (XEXP (rtl, 0)) - && (MEM_ALIGN (rtl) == 0 - || GET_MODE_BITSIZE (GET_MODE (rtl)) == 0 - || MEM_ALIGN (rtl) < GET_MODE_BITSIZE (GET_MODE (rtl)))) - SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED; -} - -/* Output thunk to FILE that implements a C++ virtual function call (with - 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 *file, tree thunk ATTRIBUTE_UNUSED, - HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, - tree function) -{ - rtx op[10]; - int nonlocal = 0; - - /* Make sure unwind info is emitted for the thunk if needed. */ - final_start_function (emit_barrier (), file, 1); - - /* Operand 0 is the target function. */ - op[0] = XEXP (DECL_RTL (function), 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 ? 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)), function)) - op[1] = gen_rtx_REG (Pmode, 3); - else - op[1] = gen_rtx_REG (Pmode, 2); - - /* Operand 2 is the delta. */ - op[2] = GEN_INT (delta); - - /* Operand 3 is the vcall_offset. */ - op[3] = GEN_INT (vcall_offset); - - /* Operand 4 is the temporary register. */ - op[4] = gen_rtx_REG (Pmode, 1); - - /* Operands 5 to 8 can be used as labels. */ - op[5] = NULL_RTX; - op[6] = NULL_RTX; - op[7] = NULL_RTX; - op[8] = NULL_RTX; - - /* Operand 9 can be used for temporary register. */ - op[9] = NULL_RTX; - - /* Generate code. */ - if (TARGET_64BIT) - { - /* Setup literal pool pointer if required. */ - if ((!DISP_IN_RANGE (delta) - && !CONST_OK_FOR_K (delta) - && !CONST_OK_FOR_Os (delta)) - || (!DISP_IN_RANGE (vcall_offset) - && !CONST_OK_FOR_K (vcall_offset) - && !CONST_OK_FOR_Os (vcall_offset))) - { - op[5] = gen_label_rtx (); - output_asm_insn ("larl\t%4,%5", op); - } - - /* Add DELTA to this pointer. */ - if (delta) - { - if (CONST_OK_FOR_J (delta)) - output_asm_insn ("la\t%1,%2(%1)", op); - else if (DISP_IN_RANGE (delta)) - output_asm_insn ("lay\t%1,%2(%1)", op); - else if (CONST_OK_FOR_K (delta)) - output_asm_insn ("aghi\t%1,%2", op); - else if (CONST_OK_FOR_Os (delta)) - output_asm_insn ("agfi\t%1,%2", op); - else - { - op[6] = gen_label_rtx (); - output_asm_insn ("agf\t%1,%6-%5(%4)", op); - } - } - - /* Perform vcall adjustment. */ - if (vcall_offset) - { - 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_K (vcall_offset)) - { - output_asm_insn ("lghi\t%4,%3", op); - output_asm_insn ("ag\t%4,0(%1)", op); - output_asm_insn ("ag\t%1,0(%4)", op); - } - else if (CONST_OK_FOR_Os (vcall_offset)) - { - output_asm_insn ("lgfi\t%4,%3", op); - output_asm_insn ("ag\t%4,0(%1)", op); - output_asm_insn ("ag\t%1,0(%4)", op); - } - else - { - op[7] = gen_label_rtx (); - output_asm_insn ("llgf\t%4,%7-%5(%4)", op); - output_asm_insn ("ag\t%4,0(%1)", op); - output_asm_insn ("ag\t%1,0(%4)", op); - } - } - - /* Jump to target. */ - output_asm_insn ("jg\t%0", op); - - /* Output literal pool if required. */ - if (op[5]) - { - output_asm_insn (".align\t4", op); - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[5])); - } - if (op[6]) - { - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[6])); - output_asm_insn (".long\t%2", op); - } - if (op[7]) - { - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[7])); - output_asm_insn (".long\t%3", op); - } - } - else - { - /* Setup base pointer if required. */ - if (!vcall_offset - || (!DISP_IN_RANGE (delta) - && !CONST_OK_FOR_K (delta) - && !CONST_OK_FOR_Os (delta)) - || (!DISP_IN_RANGE (delta) - && !CONST_OK_FOR_K (vcall_offset) - && !CONST_OK_FOR_Os (vcall_offset))) - { - op[5] = gen_label_rtx (); - output_asm_insn ("basr\t%4,0", op); - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[5])); - } - - /* Add DELTA to this pointer. */ - if (delta) - { - if (CONST_OK_FOR_J (delta)) - output_asm_insn ("la\t%1,%2(%1)", op); - else if (DISP_IN_RANGE (delta)) - output_asm_insn ("lay\t%1,%2(%1)", op); - else if (CONST_OK_FOR_K (delta)) - output_asm_insn ("ahi\t%1,%2", op); - else if (CONST_OK_FOR_Os (delta)) - output_asm_insn ("afi\t%1,%2", op); - else - { - op[6] = gen_label_rtx (); - output_asm_insn ("a\t%1,%6-%5(%4)", op); - } - } - - /* Perform vcall adjustment. */ - if (vcall_offset) - { - if (CONST_OK_FOR_J (vcall_offset)) - { - output_asm_insn ("l\t%4,0(%1)", op); - output_asm_insn ("a\t%1,%3(%4)", op); - } - else if (DISP_IN_RANGE (vcall_offset)) - { - output_asm_insn ("l\t%4,0(%1)", op); - output_asm_insn ("ay\t%1,%3(%4)", op); - } - else if (CONST_OK_FOR_K (vcall_offset)) - { - output_asm_insn ("lhi\t%4,%3", op); - output_asm_insn ("a\t%4,0(%1)", op); - output_asm_insn ("a\t%1,0(%4)", op); - } - else if (CONST_OK_FOR_Os (vcall_offset)) - { - output_asm_insn ("iilf\t%4,%3", op); - output_asm_insn ("a\t%4,0(%1)", op); - output_asm_insn ("a\t%1,0(%4)", op); - } - else - { - op[7] = gen_label_rtx (); - output_asm_insn ("l\t%4,%7-%5(%4)", op); - output_asm_insn ("a\t%4,0(%1)", op); - output_asm_insn ("a\t%1,0(%4)", op); - } - - /* We had to clobber the base pointer register. - Re-setup the base pointer (with a different base). */ - op[5] = gen_label_rtx (); - output_asm_insn ("basr\t%4,0", op); - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[5])); - } - - /* Jump to target. */ - op[8] = gen_label_rtx (); - - if (!flag_pic) - output_asm_insn ("l\t%4,%8-%5(%4)", op); - else if (!nonlocal) - output_asm_insn ("a\t%4,%8-%5(%4)", op); - /* We cannot call through .plt, since .plt requires %r12 loaded. */ - else if (flag_pic == 1) - { - output_asm_insn ("a\t%4,%8-%5(%4)", op); - output_asm_insn ("l\t%4,%0(%4)", op); - } - else if (flag_pic == 2) - { - op[9] = gen_rtx_REG (Pmode, 0); - output_asm_insn ("l\t%9,%8-4-%5(%4)", op); - output_asm_insn ("a\t%4,%8-%5(%4)", op); - output_asm_insn ("ar\t%4,%9", op); - output_asm_insn ("l\t%4,0(%4)", op); - } - - output_asm_insn ("br\t%4", op); - - /* Output literal pool. */ - output_asm_insn (".align\t4", op); - - if (nonlocal && flag_pic == 2) - output_asm_insn (".long\t%0", op); - if (nonlocal) - { - op[0] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - SYMBOL_REF_FLAGS (op[0]) = SYMBOL_FLAG_LOCAL; - } - - targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (op[8])); - if (!flag_pic) - output_asm_insn (".long\t%0", op); - else - output_asm_insn (".long\t%0-%5", op); - - if (op[6]) - { - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[6])); - output_asm_insn (".long\t%2", op); - } - if (op[7]) - { - targetm.asm_out.internal_label (file, "L", - CODE_LABEL_NUMBER (op[7])); - output_asm_insn (".long\t%3", op); - } - } - final_end_function (); -} - -static bool -s390_valid_pointer_mode (enum machine_mode mode) -{ - return (mode == SImode || (TARGET_64BIT && mode == DImode)); -} - -/* Checks whether the given CALL_EXPR would use a caller - saved register. This is used to decide whether sibling call - optimization could be performed on the respective function - call. */ - -static bool -s390_call_saved_register_used (tree call_expr) -{ - CUMULATIVE_ARGS cum_v; - cumulative_args_t cum; - tree parameter; - enum machine_mode mode; - tree type; - rtx parm_rtx; - int reg, i; - - INIT_CUMULATIVE_ARGS (cum_v, NULL, NULL, 0, 0); - cum = pack_cumulative_args (&cum_v); - - for (i = 0; i < call_expr_nargs (call_expr); i++) - { - parameter = CALL_EXPR_ARG (call_expr, i); - gcc_assert (parameter); - - /* For an undeclared variable passed as parameter we will get - an ERROR_MARK node here. */ - if (TREE_CODE (parameter) == ERROR_MARK) - return true; - - type = TREE_TYPE (parameter); - gcc_assert (type); - - mode = TYPE_MODE (type); - gcc_assert (mode); - - if (pass_by_reference (&cum_v, mode, type, true)) - { - mode = Pmode; - type = build_pointer_type (type); - } - - parm_rtx = s390_function_arg (cum, mode, type, 0); - - s390_function_arg_advance (cum, mode, type, 0); - - if (!parm_rtx) - continue; - - if (REG_P (parm_rtx)) - { - for (reg = 0; - reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx)); - reg++) - if (!call_used_regs[reg + REGNO (parm_rtx)]) - return true; - } - - if (GET_CODE (parm_rtx) == PARALLEL) - { - int i; - - for (i = 0; i < XVECLEN (parm_rtx, 0); i++) - { - rtx r = XEXP (XVECEXP (parm_rtx, 0, i), 0); - - gcc_assert (REG_P (r)); - - for (reg = 0; - reg < HARD_REGNO_NREGS (REGNO (r), GET_MODE (r)); - reg++) - if (!call_used_regs[reg + REGNO (r)]) - return true; - } - } - - } - return false; -} - -/* Return true if the given call expression can be - turned into a sibling call. - DECL holds the declaration of the function to be called whereas - EXP is the call expression itself. */ - -static bool -s390_function_ok_for_sibcall (tree decl, tree exp) -{ - /* The TPF epilogue uses register 1. */ - if (TARGET_TPF_PROFILING) - return false; - - /* The 31 bit PLT code uses register 12 (GOT pointer - caller saved) - which would have to be restored before the sibcall. */ - if (!TARGET_64BIT && flag_pic && decl && !targetm.binds_local_p (decl)) - return false; - - /* Register 6 on s390 is available as an argument register but unfortunately - "caller saved". This makes functions needing this register for arguments - not suitable for sibcalls. */ - return !s390_call_saved_register_used (exp); -} - -/* Return the fixed registers used for condition codes. */ - -static bool -s390_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2) -{ - *p1 = CC_REGNUM; - *p2 = INVALID_REGNUM; - - return true; -} - -/* This function is used by the call expanders of the machine description. - It emits the call insn itself together with the necessary operations - to adjust the target address and returns the emitted insn. - ADDR_LOCATION is the target address rtx - TLS_CALL the location of the thread-local symbol - RESULT_REG the register where the result of the call should be stored - RETADDR_REG the register where the return address should be stored - If this parameter is NULL_RTX the call is considered - to be a sibling call. */ - -rtx -s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg, - rtx retaddr_reg) -{ - bool plt_call = false; - rtx insn; - rtx call; - rtx clobber; - rtvec vec; - - /* Direct function calls need special treatment. */ - if (GET_CODE (addr_location) == SYMBOL_REF) - { - /* When calling a global routine in PIC mode, we must - replace the symbol itself with the PLT stub. */ - if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location)) - { - if (retaddr_reg != NULL_RTX) - { - addr_location = gen_rtx_UNSPEC (Pmode, - gen_rtvec (1, addr_location), - UNSPEC_PLT); - addr_location = gen_rtx_CONST (Pmode, addr_location); - plt_call = true; - } - else - /* For -fpic code the PLT entries might use r12 which is - call-saved. Therefore we cannot do a sibcall when - calling directly using a symbol ref. When reaching - this point we decided (in s390_function_ok_for_sibcall) - to do a sibcall for a function pointer but one of the - optimizers was able to get rid of the function pointer - by propagating the symbol ref into the call. This - optimization is illegal for S/390 so we turn the direct - call into a indirect call again. */ - addr_location = force_reg (Pmode, addr_location); - } - - /* Unless we can use the bras(l) insn, force the - routine address into a register. */ - if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH) - { - if (flag_pic) - addr_location = legitimize_pic_address (addr_location, 0); - else - addr_location = force_reg (Pmode, addr_location); - } - } - - /* If it is already an indirect call or the code above moved the - SYMBOL_REF to somewhere else make sure the address can be found in - register 1. */ - if (retaddr_reg == NULL_RTX - && GET_CODE (addr_location) != SYMBOL_REF - && !plt_call) - { - emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location); - addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM); - } - - addr_location = gen_rtx_MEM (QImode, addr_location); - call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx); - - if (result_reg != NULL_RTX) - call = gen_rtx_SET (VOIDmode, result_reg, call); - - if (retaddr_reg != NULL_RTX) - { - clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg); - - if (tls_call != NULL_RTX) - vec = gen_rtvec (3, call, clobber, - gen_rtx_USE (VOIDmode, tls_call)); - else - vec = gen_rtvec (2, call, clobber); - - call = gen_rtx_PARALLEL (VOIDmode, vec); - } - - insn = emit_call_insn (call); - - /* 31-bit PLT stubs and tls calls use the GOT register implicitly. */ - if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX) - { - /* s390_function_ok_for_sibcall should - have denied sibcalls in this case. */ - gcc_assert (retaddr_reg != NULL_RTX); - use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, 12)); - } - return insn; -} - -/* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */ - -static void -s390_conditional_register_usage (void) -{ - int i; - - if (flag_pic) - { - fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; - call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; - } - if (TARGET_CPU_ZARCH) - { - fixed_regs[BASE_REGNUM] = 0; - call_used_regs[BASE_REGNUM] = 0; - fixed_regs[RETURN_REGNUM] = 0; - call_used_regs[RETURN_REGNUM] = 0; - } - if (TARGET_64BIT) - { - for (i = 24; i < 32; i++) - call_used_regs[i] = call_really_used_regs[i] = 0; - } - else - { - for (i = 18; i < 20; i++) - call_used_regs[i] = call_really_used_regs[i] = 0; - } - - if (TARGET_SOFT_FLOAT) - { - for (i = 16; i < 32; i++) - call_used_regs[i] = fixed_regs[i] = 1; - } -} - -/* Corresponding function to eh_return expander. */ - -static GTY(()) rtx s390_tpf_eh_return_symbol; -void -s390_emit_tpf_eh_return (rtx target) -{ - rtx insn, reg; - - if (!s390_tpf_eh_return_symbol) - s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return"); - - reg = gen_rtx_REG (Pmode, 2); - - emit_move_insn (reg, target); - insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg, - gen_rtx_REG (Pmode, RETURN_REGNUM)); - use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg); - - emit_move_insn (EH_RETURN_HANDLER_RTX, reg); -} - -/* Rework the prologue/epilogue to avoid saving/restoring - registers unnecessarily. */ - -static void -s390_optimize_prologue (void) -{ - rtx insn, new_insn, next_insn; - - /* Do a final recompute of the frame-related data. */ - - s390_update_frame_layout (); - - /* If all special registers are in fact used, there's nothing we - can do, so no point in walking the insn list. */ - - if (cfun_frame_layout.first_save_gpr <= BASE_REGNUM - && cfun_frame_layout.last_save_gpr >= BASE_REGNUM - && (TARGET_CPU_ZARCH - || (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM - && cfun_frame_layout.last_save_gpr >= RETURN_REGNUM))) - return; - - /* Search for prologue/epilogue insns and replace them. */ - - for (insn = get_insns (); insn; insn = next_insn) - { - int first, last, off; - rtx set, base, offset; - - next_insn = NEXT_INSN (insn); - - if (GET_CODE (insn) != INSN) - continue; - - if (GET_CODE (PATTERN (insn)) == PARALLEL - && store_multiple_operation (PATTERN (insn), VOIDmode)) - { - set = XVECEXP (PATTERN (insn), 0, 0); - first = REGNO (SET_SRC (set)); - last = first + XVECLEN (PATTERN (insn), 0) - 1; - offset = const0_rtx; - base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); - off = INTVAL (offset); - - if (GET_CODE (base) != REG || off < 0) - continue; - if (cfun_frame_layout.first_save_gpr != -1 - && (cfun_frame_layout.first_save_gpr < first - || cfun_frame_layout.last_save_gpr > last)) - continue; - if (REGNO (base) != STACK_POINTER_REGNUM - && REGNO (base) != HARD_FRAME_POINTER_REGNUM) - continue; - if (first > BASE_REGNUM || last < BASE_REGNUM) - continue; - - if (cfun_frame_layout.first_save_gpr != -1) - { - new_insn = save_gprs (base, - off + (cfun_frame_layout.first_save_gpr - - first) * UNITS_PER_LONG, - cfun_frame_layout.first_save_gpr, - cfun_frame_layout.last_save_gpr); - new_insn = emit_insn_before (new_insn, insn); - INSN_ADDRESSES_NEW (new_insn, -1); - } - - remove_insn (insn); - continue; - } - - if (cfun_frame_layout.first_save_gpr == -1 - && GET_CODE (PATTERN (insn)) == SET - && GET_CODE (SET_SRC (PATTERN (insn))) == REG - && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM - || (!TARGET_CPU_ZARCH - && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM)) - && GET_CODE (SET_DEST (PATTERN (insn))) == MEM) - { - set = PATTERN (insn); - first = REGNO (SET_SRC (set)); - offset = const0_rtx; - base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); - off = INTVAL (offset); - - if (GET_CODE (base) != REG || off < 0) - continue; - if (REGNO (base) != STACK_POINTER_REGNUM - && REGNO (base) != HARD_FRAME_POINTER_REGNUM) - continue; - - remove_insn (insn); - continue; - } - - if (GET_CODE (PATTERN (insn)) == PARALLEL - && load_multiple_operation (PATTERN (insn), VOIDmode)) - { - set = XVECEXP (PATTERN (insn), 0, 0); - first = REGNO (SET_DEST (set)); - last = first + XVECLEN (PATTERN (insn), 0) - 1; - offset = const0_rtx; - base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); - off = INTVAL (offset); - - if (GET_CODE (base) != REG || off < 0) - continue; - if (cfun_frame_layout.first_restore_gpr != -1 - && (cfun_frame_layout.first_restore_gpr < first - || cfun_frame_layout.last_restore_gpr > last)) - continue; - if (REGNO (base) != STACK_POINTER_REGNUM - && REGNO (base) != HARD_FRAME_POINTER_REGNUM) - continue; - if (first > BASE_REGNUM || last < BASE_REGNUM) - continue; - - if (cfun_frame_layout.first_restore_gpr != -1) - { - new_insn = restore_gprs (base, - off + (cfun_frame_layout.first_restore_gpr - - first) * UNITS_PER_LONG, - cfun_frame_layout.first_restore_gpr, - cfun_frame_layout.last_restore_gpr); - new_insn = emit_insn_before (new_insn, insn); - INSN_ADDRESSES_NEW (new_insn, -1); - } - - remove_insn (insn); - continue; - } - - if (cfun_frame_layout.first_restore_gpr == -1 - && GET_CODE (PATTERN (insn)) == SET - && GET_CODE (SET_DEST (PATTERN (insn))) == REG - && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM - || (!TARGET_CPU_ZARCH - && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM)) - && GET_CODE (SET_SRC (PATTERN (insn))) == MEM) - { - set = PATTERN (insn); - first = REGNO (SET_DEST (set)); - offset = const0_rtx; - base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); - off = INTVAL (offset); - - if (GET_CODE (base) != REG || off < 0) - continue; - if (REGNO (base) != STACK_POINTER_REGNUM - && REGNO (base) != HARD_FRAME_POINTER_REGNUM) - continue; - - remove_insn (insn); - continue; - } - } -} - -/* On z10 and later the dynamic branch prediction must see the - backward jump within a certain windows. If not it falls back to - the static prediction. This function rearranges the loop backward - branch in a way which makes the static prediction always correct. - The function returns true if it added an instruction. */ -static bool -s390_fix_long_loop_prediction (rtx insn) -{ - rtx set = single_set (insn); - rtx code_label, label_ref, new_label; - rtx uncond_jump; - rtx cur_insn; - rtx tmp; - int distance; - - /* This will exclude branch on count and branch on index patterns - since these are correctly statically predicted. */ - if (!set - || SET_DEST (set) != pc_rtx - || GET_CODE (SET_SRC(set)) != IF_THEN_ELSE) - return false; - - label_ref = (GET_CODE (XEXP (SET_SRC (set), 1)) == LABEL_REF ? - XEXP (SET_SRC (set), 1) : XEXP (SET_SRC (set), 2)); - - gcc_assert (GET_CODE (label_ref) == LABEL_REF); - - code_label = XEXP (label_ref, 0); - - if (INSN_ADDRESSES (INSN_UID (code_label)) == -1 - || INSN_ADDRESSES (INSN_UID (insn)) == -1 - || (INSN_ADDRESSES (INSN_UID (insn)) - - INSN_ADDRESSES (INSN_UID (code_label)) < PREDICT_DISTANCE)) - return false; - - for (distance = 0, cur_insn = PREV_INSN (insn); - distance < PREDICT_DISTANCE - 6; - distance += get_attr_length (cur_insn), cur_insn = PREV_INSN (cur_insn)) - if (!cur_insn || JUMP_P (cur_insn) || LABEL_P (cur_insn)) - return false; - - new_label = gen_label_rtx (); - uncond_jump = emit_jump_insn_after ( - gen_rtx_SET (VOIDmode, pc_rtx, - gen_rtx_LABEL_REF (VOIDmode, code_label)), - insn); - emit_label_after (new_label, uncond_jump); - - tmp = XEXP (SET_SRC (set), 1); - XEXP (SET_SRC (set), 1) = XEXP (SET_SRC (set), 2); - XEXP (SET_SRC (set), 2) = tmp; - INSN_CODE (insn) = -1; - - XEXP (label_ref, 0) = new_label; - JUMP_LABEL (insn) = new_label; - JUMP_LABEL (uncond_jump) = code_label; - - return true; -} - -/* Returns 1 if INSN reads the value of REG for purposes not related - to addressing of memory, and 0 otherwise. */ -static int -s390_non_addr_reg_read_p (rtx reg, rtx insn) -{ - return reg_referenced_p (reg, PATTERN (insn)) - && !reg_used_in_mem_p (REGNO (reg), PATTERN (insn)); -} - -/* Starting from INSN find_cond_jump looks downwards in the insn - stream for a single jump insn which is the last user of the - condition code set in INSN. */ -static rtx -find_cond_jump (rtx insn) -{ - for (; insn; insn = NEXT_INSN (insn)) - { - rtx ite, cc; - - if (LABEL_P (insn)) - break; - - if (!JUMP_P (insn)) - { - if (reg_mentioned_p (gen_rtx_REG (CCmode, CC_REGNUM), insn)) - break; - continue; - } - - /* This will be triggered by a return. */ - if (GET_CODE (PATTERN (insn)) != SET) - break; - - gcc_assert (SET_DEST (PATTERN (insn)) == pc_rtx); - ite = SET_SRC (PATTERN (insn)); - - if (GET_CODE (ite) != IF_THEN_ELSE) - break; - - cc = XEXP (XEXP (ite, 0), 0); - if (!REG_P (cc) || !CC_REGNO_P (REGNO (cc))) - break; - - if (find_reg_note (insn, REG_DEAD, cc)) - return insn; - break; - } - - return NULL_RTX; -} - -/* Swap the condition in COND and the operands in OP0 and OP1 so that - the semantics does not change. If NULL_RTX is passed as COND the - function tries to find the conditional jump starting with INSN. */ -static void -s390_swap_cmp (rtx cond, rtx *op0, rtx *op1, rtx insn) -{ - rtx tmp = *op0; - - if (cond == NULL_RTX) - { - rtx jump = find_cond_jump (NEXT_INSN (insn)); - jump = jump ? single_set (jump) : NULL_RTX; - - if (jump == NULL_RTX) - return; - - cond = XEXP (XEXP (jump, 1), 0); - } - - *op0 = *op1; - *op1 = tmp; - PUT_CODE (cond, swap_condition (GET_CODE (cond))); -} - -/* On z10, instructions of the compare-and-branch family have the - property to access the register occurring as second operand with - its bits complemented. If such a compare is grouped with a second - instruction that accesses the same register non-complemented, and - if that register's value is delivered via a bypass, then the - pipeline recycles, thereby causing significant performance decline. - This function locates such situations and exchanges the two - operands of the compare. The function return true whenever it - added an insn. */ -static bool -s390_z10_optimize_cmp (rtx insn) -{ - rtx prev_insn, next_insn; - bool insn_added_p = false; - rtx cond, *op0, *op1; - - if (GET_CODE (PATTERN (insn)) == PARALLEL) - { - /* Handle compare and branch and branch on count - instructions. */ - rtx pattern = single_set (insn); - - if (!pattern - || SET_DEST (pattern) != pc_rtx - || GET_CODE (SET_SRC (pattern)) != IF_THEN_ELSE) - return false; - - cond = XEXP (SET_SRC (pattern), 0); - op0 = &XEXP (cond, 0); - op1 = &XEXP (cond, 1); - } - else if (GET_CODE (PATTERN (insn)) == SET) - { - rtx src, dest; - - /* Handle normal compare instructions. */ - src = SET_SRC (PATTERN (insn)); - dest = SET_DEST (PATTERN (insn)); - - if (!REG_P (dest) - || !CC_REGNO_P (REGNO (dest)) - || GET_CODE (src) != COMPARE) - return false; - - /* s390_swap_cmp will try to find the conditional - jump when passing NULL_RTX as condition. */ - cond = NULL_RTX; - op0 = &XEXP (src, 0); - op1 = &XEXP (src, 1); - } - else - return false; - - if (!REG_P (*op0) || !REG_P (*op1)) - return false; - - if (GET_MODE_CLASS (GET_MODE (*op0)) != MODE_INT) - return false; - - /* Swap the COMPARE arguments and its mask if there is a - conflicting access in the previous insn. */ - prev_insn = prev_active_insn (insn); - if (prev_insn != NULL_RTX && INSN_P (prev_insn) - && reg_referenced_p (*op1, PATTERN (prev_insn))) - s390_swap_cmp (cond, op0, op1, insn); - - /* Check if there is a conflict with the next insn. If there - was no conflict with the previous insn, then swap the - COMPARE arguments and its mask. If we already swapped - the operands, or if swapping them would cause a conflict - with the previous insn, issue a NOP after the COMPARE in - order to separate the two instuctions. */ - next_insn = next_active_insn (insn); - if (next_insn != NULL_RTX && INSN_P (next_insn) - && s390_non_addr_reg_read_p (*op1, next_insn)) - { - if (prev_insn != NULL_RTX && INSN_P (prev_insn) - && s390_non_addr_reg_read_p (*op0, prev_insn)) - { - if (REGNO (*op1) == 0) - emit_insn_after (gen_nop1 (), insn); - else - emit_insn_after (gen_nop (), insn); - insn_added_p = true; - } - else - s390_swap_cmp (cond, op0, op1, insn); - } - return insn_added_p; -} - -/* Perform machine-dependent processing. */ - -static void -s390_reorg (void) -{ - 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 (); - - /* 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 - strictly decreases the total number of PC-relative branches - 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 = 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 (); - - /* Split out-of-range branches. If this has created new - literal pool entries, cancel current chunk list and - 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_overflow) - s390_chunkify_cancel (pool); - else - s390_mainpool_cancel (pool); - - continue; - } - - /* If we made it up to here, both conditions are satisfied. - Finish up literal pool related changes. */ - if (pool_overflow) - s390_chunkify_finish (pool); - else - s390_mainpool_finish (pool); - - /* We're done splitting branches. */ - cfun->machine->split_branches_pending_p = false; - break; - } - - /* Generate out-of-pool execute target insns. */ - if (TARGET_CPU_ZARCH) - { - rtx insn, label, target; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - label = s390_execute_label (insn); - if (!label) - continue; - - gcc_assert (label != const0_rtx); - - target = emit_label (XEXP (label, 0)); - INSN_ADDRESSES_NEW (target, -1); - - target = emit_insn (s390_execute_target (insn)); - INSN_ADDRESSES_NEW (target, -1); - } - } - - /* Try to optimize prologue and epilogue further. */ - s390_optimize_prologue (); - - /* Walk over the insns and do some >=z10 specific changes. */ - if (s390_tune == PROCESSOR_2097_Z10 - || s390_tune == PROCESSOR_2817_Z196) - { - rtx insn; - bool insn_added_p = false; - - /* The insn lengths and addresses have to be up to date for the - following manipulations. */ - shorten_branches (get_insns ()); - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (!INSN_P (insn) || INSN_CODE (insn) <= 0) - continue; - - if (JUMP_P (insn)) - insn_added_p |= s390_fix_long_loop_prediction (insn); - - if ((GET_CODE (PATTERN (insn)) == PARALLEL - || GET_CODE (PATTERN (insn)) == SET) - && s390_tune == PROCESSOR_2097_Z10) - insn_added_p |= s390_z10_optimize_cmp (insn); - } - - /* Adjust branches if we added new instructions. */ - if (insn_added_p) - shorten_branches (get_insns ()); - } -} - -/* Return true if INSN is a fp load insn writing register REGNO. */ -static inline bool -s390_fpload_toreg (rtx insn, unsigned int regno) -{ - rtx set; - enum attr_type flag = s390_safe_attr_type (insn); - - if (flag != TYPE_FLOADSF && flag != TYPE_FLOADDF) - return false; - - set = single_set (insn); - - if (set == NULL_RTX) - return false; - - if (!REG_P (SET_DEST (set)) || !MEM_P (SET_SRC (set))) - return false; - - if (REGNO (SET_DEST (set)) != regno) - return false; - - return true; -} - -/* This value describes the distance to be avoided between an - aritmetic fp instruction and an fp load writing the same register. - Z10_EARLYLOAD_DISTANCE - 1 as well as Z10_EARLYLOAD_DISTANCE + 1 is - fine but the exact value has to be avoided. Otherwise the FP - pipeline will throw an exception causing a major penalty. */ -#define Z10_EARLYLOAD_DISTANCE 7 - -/* Rearrange the ready list in order to avoid the situation described - for Z10_EARLYLOAD_DISTANCE. A problematic load instruction is - moved to the very end of the ready list. */ -static void -s390_z10_prevent_earlyload_conflicts (rtx *ready, int *nready_p) -{ - unsigned int regno; - int nready = *nready_p; - rtx tmp; - int i; - rtx insn; - rtx set; - enum attr_type flag; - int distance; - - /* Skip DISTANCE - 1 active insns. */ - for (insn = last_scheduled_insn, distance = Z10_EARLYLOAD_DISTANCE - 1; - distance > 0 && insn != NULL_RTX; - distance--, insn = prev_active_insn (insn)) - if (CALL_P (insn) || JUMP_P (insn)) - return; - - if (insn == NULL_RTX) - return; - - set = single_set (insn); - - if (set == NULL_RTX || !REG_P (SET_DEST (set)) - || GET_MODE_CLASS (GET_MODE (SET_DEST (set))) != MODE_FLOAT) - return; - - flag = s390_safe_attr_type (insn); - - if (flag == TYPE_FLOADSF || flag == TYPE_FLOADDF) - return; - - regno = REGNO (SET_DEST (set)); - i = nready - 1; - - while (!s390_fpload_toreg (ready[i], regno) && i > 0) - i--; - - if (!i) - return; - - tmp = ready[i]; - memmove (&ready[1], &ready[0], sizeof (rtx) * i); - ready[0] = tmp; -} - -/* This function is called via hook TARGET_SCHED_REORDER before - issueing one insn from list READY which contains *NREADYP entries. - For target z10 it reorders load instructions to avoid early load - conflicts in the floating point pipeline */ -static int -s390_sched_reorder (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED, - rtx *ready, int *nreadyp, int clock ATTRIBUTE_UNUSED) -{ - if (s390_tune == PROCESSOR_2097_Z10) - if (reload_completed && *nreadyp > 1) - s390_z10_prevent_earlyload_conflicts (ready, nreadyp); - - return s390_issue_rate (); -} - -/* This function is called via hook TARGET_SCHED_VARIABLE_ISSUE after - the scheduler has issued INSN. It stores the last issued insn into - last_scheduled_insn in order to make it available for - s390_sched_reorder. */ -static int -s390_sched_variable_issue (FILE *file ATTRIBUTE_UNUSED, - int verbose ATTRIBUTE_UNUSED, - rtx insn, int more) -{ - last_scheduled_insn = insn; - - if (GET_CODE (PATTERN (insn)) != USE - && GET_CODE (PATTERN (insn)) != CLOBBER) - return more - 1; - else - return more; -} - -static void -s390_sched_init (FILE *file ATTRIBUTE_UNUSED, - int verbose ATTRIBUTE_UNUSED, - int max_ready ATTRIBUTE_UNUSED) -{ - last_scheduled_insn = NULL_RTX; -} - -/* This function checks the whole of insn X for memory references. The - function always returns zero because the framework it is called - from would stop recursively analyzing the insn upon a return value - other than zero. The real result of this function is updating - counter variable MEM_COUNT. */ -static int -check_dpu (rtx *x, unsigned *mem_count) -{ - if (*x != NULL_RTX && MEM_P (*x)) - (*mem_count)++; - return 0; -} - -/* This target hook implementation for TARGET_LOOP_UNROLL_ADJUST calculates - a new number struct loop *loop should be unrolled if tuned for cpus with - a built-in stride prefetcher. - The loop is analyzed for memory accesses by calling check_dpu for - each rtx of the loop. Depending on the loop_depth and the amount of - memory accesses a new number <=nunroll is returned to improve the - behaviour of the hardware prefetch unit. */ -static unsigned -s390_loop_unroll_adjust (unsigned nunroll, struct loop *loop) -{ - basic_block *bbs; - rtx insn; - unsigned i; - unsigned mem_count = 0; - - if (s390_tune != PROCESSOR_2097_Z10 && s390_tune != PROCESSOR_2817_Z196) - return nunroll; - - /* Count the number of memory references within the loop body. */ - bbs = get_loop_body (loop); - for (i = 0; i < loop->num_nodes; i++) - { - for (insn = BB_HEAD (bbs[i]); insn != BB_END (bbs[i]); insn = NEXT_INSN (insn)) - if (INSN_P (insn) && INSN_CODE (insn) != -1) - for_each_rtx (&insn, (rtx_function) check_dpu, &mem_count); - } - free (bbs); - - /* Prevent division by zero, and we do not need to adjust nunroll in this case. */ - if (mem_count == 0) - return nunroll; - - switch (loop_depth(loop)) - { - case 1: - return MIN (nunroll, 28 / mem_count); - case 2: - return MIN (nunroll, 22 / mem_count); - default: - return MIN (nunroll, 16 / mem_count); - } -} - -/* Initialize GCC target structure. */ - -#undef TARGET_ASM_ALIGNED_HI_OP -#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" -#undef TARGET_ASM_ALIGNED_DI_OP -#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" -#undef TARGET_ASM_INTEGER -#define TARGET_ASM_INTEGER s390_assemble_integer - -#undef TARGET_ASM_OPEN_PAREN -#define TARGET_ASM_OPEN_PAREN "" - -#undef TARGET_ASM_CLOSE_PAREN -#define TARGET_ASM_CLOSE_PAREN "" - -#undef TARGET_OPTION_OVERRIDE -#define TARGET_OPTION_OVERRIDE s390_option_override - -#undef TARGET_ENCODE_SECTION_INFO -#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info - -#undef TARGET_SCALAR_MODE_SUPPORTED_P -#define TARGET_SCALAR_MODE_SUPPORTED_P s390_scalar_mode_supported_p - -#ifdef HAVE_AS_TLS -#undef TARGET_HAVE_TLS -#define TARGET_HAVE_TLS true -#endif -#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_LEGITIMIZE_ADDRESS -#define TARGET_LEGITIMIZE_ADDRESS s390_legitimize_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 -#define TARGET_EXPAND_BUILTIN s390_expand_builtin - -#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA -#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA s390_output_addr_const_extra - -#undef TARGET_ASM_OUTPUT_MI_THUNK -#define TARGET_ASM_OUTPUT_MI_THUNK s390_output_mi_thunk -#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK -#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true - -#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_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD -#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead - -#undef TARGET_SCHED_VARIABLE_ISSUE -#define TARGET_SCHED_VARIABLE_ISSUE s390_sched_variable_issue -#undef TARGET_SCHED_REORDER -#define TARGET_SCHED_REORDER s390_sched_reorder -#undef TARGET_SCHED_INIT -#define TARGET_SCHED_INIT s390_sched_init - -#undef TARGET_CANNOT_COPY_INSN_P -#define TARGET_CANNOT_COPY_INSN_P s390_cannot_copy_insn_p -#undef TARGET_RTX_COSTS -#define TARGET_RTX_COSTS s390_rtx_costs -#undef TARGET_ADDRESS_COST -#define TARGET_ADDRESS_COST s390_address_cost -#undef TARGET_REGISTER_MOVE_COST -#define TARGET_REGISTER_MOVE_COST s390_register_move_cost -#undef TARGET_MEMORY_MOVE_COST -#define TARGET_MEMORY_MOVE_COST s390_memory_move_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 -#undef TARGET_EXPAND_BUILTIN_VA_START -#define TARGET_EXPAND_BUILTIN_VA_START s390_va_start -#undef TARGET_GIMPLIFY_VA_ARG_EXPR -#define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg - -#undef TARGET_PROMOTE_FUNCTION_MODE -#define TARGET_PROMOTE_FUNCTION_MODE s390_promote_function_mode -#undef TARGET_PASS_BY_REFERENCE -#define TARGET_PASS_BY_REFERENCE s390_pass_by_reference - -#undef TARGET_FUNCTION_OK_FOR_SIBCALL -#define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall -#undef TARGET_FUNCTION_ARG -#define TARGET_FUNCTION_ARG s390_function_arg -#undef TARGET_FUNCTION_ARG_ADVANCE -#define TARGET_FUNCTION_ARG_ADVANCE s390_function_arg_advance -#undef TARGET_FUNCTION_VALUE -#define TARGET_FUNCTION_VALUE s390_function_value -#undef TARGET_LIBCALL_VALUE -#define TARGET_LIBCALL_VALUE s390_libcall_value - -#undef TARGET_FIXED_CONDITION_CODE_REGS -#define TARGET_FIXED_CONDITION_CODE_REGS s390_fixed_condition_code_regs - -#undef TARGET_CC_MODES_COMPATIBLE -#define TARGET_CC_MODES_COMPATIBLE s390_cc_modes_compatible - -#undef TARGET_INVALID_WITHIN_DOLOOP -#define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null - -#ifdef HAVE_AS_TLS -#undef TARGET_ASM_OUTPUT_DWARF_DTPREL -#define TARGET_ASM_OUTPUT_DWARF_DTPREL s390_output_dwarf_dtprel -#endif - -#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING -#undef TARGET_MANGLE_TYPE -#define TARGET_MANGLE_TYPE s390_mangle_type -#endif - -#undef TARGET_SCALAR_MODE_SUPPORTED_P -#define TARGET_SCALAR_MODE_SUPPORTED_P s390_scalar_mode_supported_p - -#undef TARGET_PREFERRED_RELOAD_CLASS -#define TARGET_PREFERRED_RELOAD_CLASS s390_preferred_reload_class - -#undef TARGET_SECONDARY_RELOAD -#define TARGET_SECONDARY_RELOAD s390_secondary_reload - -#undef TARGET_LIBGCC_CMP_RETURN_MODE -#define TARGET_LIBGCC_CMP_RETURN_MODE s390_libgcc_cmp_return_mode - -#undef TARGET_LIBGCC_SHIFT_COUNT_MODE -#define TARGET_LIBGCC_SHIFT_COUNT_MODE s390_libgcc_shift_count_mode - -#undef TARGET_LEGITIMATE_ADDRESS_P -#define TARGET_LEGITIMATE_ADDRESS_P s390_legitimate_address_p - -#undef TARGET_LEGITIMATE_CONSTANT_P -#define TARGET_LEGITIMATE_CONSTANT_P s390_legitimate_constant_p - -#undef TARGET_CAN_ELIMINATE -#define TARGET_CAN_ELIMINATE s390_can_eliminate - -#undef TARGET_CONDITIONAL_REGISTER_USAGE -#define TARGET_CONDITIONAL_REGISTER_USAGE s390_conditional_register_usage - -#undef TARGET_LOOP_UNROLL_ADJUST -#define TARGET_LOOP_UNROLL_ADJUST s390_loop_unroll_adjust - -#undef TARGET_ASM_TRAMPOLINE_TEMPLATE -#define TARGET_ASM_TRAMPOLINE_TEMPLATE s390_asm_trampoline_template -#undef TARGET_TRAMPOLINE_INIT -#define TARGET_TRAMPOLINE_INIT s390_trampoline_init - -#undef TARGET_UNWIND_WORD_MODE -#define TARGET_UNWIND_WORD_MODE s390_unwind_word_mode - -struct gcc_target targetm = TARGET_INITIALIZER; - -#include "gt-s390.h" diff --git a/gcc-4.7/gcc/config/s390/s390.h b/gcc-4.7/gcc/config/s390/s390.h deleted file mode 100644 index edc639978..000000000 --- a/gcc-4.7/gcc/config/s390/s390.h +++ /dev/null @@ -1,909 +0,0 @@ -/* Definitions of target machine for GNU compiler, for IBM S/390 - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. - Contributed by Hartmut Penner (hpenner@de.ibm.com) and - Ulrich Weigand (uweigand@de.ibm.com). - Andreas Krebbel (Andreas.Krebbel@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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef _S390_H -#define _S390_H - -/* Optional architectural facilities supported by the processor. */ - -enum processor_flags -{ - PF_IEEE_FLOAT = 1, - PF_ZARCH = 2, - PF_LONG_DISPLACEMENT = 4, - PF_EXTIMM = 8, - PF_DFP = 16, - PF_Z10 = 32, - PF_Z196 = 64 -}; - -/* This is necessary to avoid a warning about comparing different enum - types. */ -#define s390_tune_attr ((enum attr_cpu)s390_tune) - -/* These flags indicate that the generated code should run on a cpu - providing the respective hardware facility regardless of the - current cpu mode (ESA or z/Architecture). */ - -#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_CPU_EXTIMM \ - (s390_arch_flags & PF_EXTIMM) -#define TARGET_CPU_DFP \ - (s390_arch_flags & PF_DFP) -#define TARGET_CPU_Z10 \ - (s390_arch_flags & PF_Z10) -#define TARGET_CPU_Z196 \ - (s390_arch_flags & PF_Z196) - -/* These flags indicate that the generated code should run on a cpu - providing the respective hardware facility when run in - z/Architecture mode. */ - -#define TARGET_LONG_DISPLACEMENT \ - (TARGET_ZARCH && TARGET_CPU_LONG_DISPLACEMENT) -#define TARGET_EXTIMM \ - (TARGET_ZARCH && TARGET_CPU_EXTIMM) -#define TARGET_DFP \ - (TARGET_ZARCH && TARGET_CPU_DFP && TARGET_HARD_FLOAT) -#define TARGET_Z10 \ - (TARGET_ZARCH && TARGET_CPU_Z10) -#define TARGET_Z196 \ - (TARGET_ZARCH && TARGET_CPU_Z196) - - -#define TARGET_AVOID_CMP_AND_BRANCH (s390_tune == PROCESSOR_2817_Z196) - -/* Run-time target specification. */ - -/* Defaults for option flags defined only on some subtargets. */ -#ifndef TARGET_TPF_PROFILING -#define TARGET_TPF_PROFILING 0 -#endif - -/* This will be overridden by OS headers. */ -#define TARGET_TPF 0 - -/* Target CPU builtins. */ -#define TARGET_CPU_CPP_BUILTINS() \ - do \ - { \ - builtin_assert ("cpu=s390"); \ - builtin_assert ("machine=s390"); \ - builtin_define ("__s390__"); \ - if (TARGET_ZARCH) \ - builtin_define ("__zarch__"); \ - if (TARGET_64BIT) \ - builtin_define ("__s390x__"); \ - if (TARGET_LONG_DOUBLE_128) \ - builtin_define ("__LONG_DOUBLE_128__"); \ - } \ - while (0) - -#ifdef DEFAULT_TARGET_64BIT -#define TARGET_DEFAULT (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP) -#else -#define TARGET_DEFAULT 0 -#endif - -/* 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 - -/* Constants needed to control the TEST DATA CLASS (TDC) instruction. */ -#define S390_TDC_POSITIVE_ZERO (1 << 11) -#define S390_TDC_NEGATIVE_ZERO (1 << 10) -#define S390_TDC_POSITIVE_NORMALIZED_BFP_NUMBER (1 << 9) -#define S390_TDC_NEGATIVE_NORMALIZED_BFP_NUMBER (1 << 8) -#define S390_TDC_POSITIVE_DENORMALIZED_BFP_NUMBER (1 << 7) -#define S390_TDC_NEGATIVE_DENORMALIZED_BFP_NUMBER (1 << 6) -#define S390_TDC_POSITIVE_INFINITY (1 << 5) -#define S390_TDC_NEGATIVE_INFINITY (1 << 4) -#define S390_TDC_POSITIVE_QUIET_NAN (1 << 3) -#define S390_TDC_NEGATIVE_QUIET_NAN (1 << 2) -#define S390_TDC_POSITIVE_SIGNALING_NAN (1 << 1) -#define S390_TDC_NEGATIVE_SIGNALING_NAN (1 << 0) - -/* The following values are different for DFP. */ -#define S390_TDC_POSITIVE_DENORMALIZED_DFP_NUMBER (1 << 9) -#define S390_TDC_NEGATIVE_DENORMALIZED_DFP_NUMBER (1 << 8) -#define S390_TDC_POSITIVE_NORMALIZED_DFP_NUMBER (1 << 7) -#define S390_TDC_NEGATIVE_NORMALIZED_DFP_NUMBER (1 << 6) - -/* For signbit, the BFP-DFP-difference makes no difference. */ -#define S390_TDC_SIGNBIT_SET (S390_TDC_NEGATIVE_ZERO \ - | S390_TDC_NEGATIVE_NORMALIZED_BFP_NUMBER \ - | S390_TDC_NEGATIVE_DENORMALIZED_BFP_NUMBER\ - | S390_TDC_NEGATIVE_INFINITY \ - | S390_TDC_NEGATIVE_QUIET_NAN \ - | S390_TDC_NEGATIVE_SIGNALING_NAN ) - -#define S390_TDC_INFINITY (S390_TDC_POSITIVE_INFINITY \ - | S390_TDC_NEGATIVE_INFINITY ) - -/* Target machine storage layout. */ - -/* Everything is big-endian. */ -#define BITS_BIG_ENDIAN 1 -#define BYTES_BIG_ENDIAN 1 -#define WORDS_BIG_ENDIAN 1 - -#define STACK_SIZE_MODE (Pmode) - -#ifndef IN_LIBGCC2 - -/* Width of a word, in units (bytes). */ - #define UNITS_PER_WORD (TARGET_ZARCH ? 8 : 4) - -/* Width of a pointer. To be used instead of UNITS_PER_WORD in - ABI-relevant contexts. This always matches - GET_MODE_SIZE (Pmode). */ - #define UNITS_PER_LONG (TARGET_64BIT ? 8 : 4) - #define MIN_UNITS_PER_WORD 4 - #define MAX_BITS_PER_WORD 64 -#else - - /* In libgcc, UNITS_PER_WORD has ABI-relevant effects, e.g. whether - the library should export TImode functions or not. Thus, we have - to redefine UNITS_PER_WORD depending on __s390x__ for libgcc. */ - #ifdef __s390x__ - #define UNITS_PER_WORD 8 - #else - #define UNITS_PER_WORD 4 - #endif -#endif - -/* Width of a pointer, in bits. */ -#define POINTER_SIZE (TARGET_64BIT ? 64 : 32) - -/* Allocation boundary (in *bits*) for storing arguments in argument list. */ -#define PARM_BOUNDARY (TARGET_64BIT ? 64 : 32) - -/* Boundary (in *bits*) on which stack pointer should be aligned. */ -#define STACK_BOUNDARY 64 - -/* Allocation boundary (in *bits*) for the code of a function. */ -#define FUNCTION_BOUNDARY 32 - -/* There is no point aligning anything to a rounder boundary than this. */ -#define BIGGEST_ALIGNMENT 64 - -/* Alignment of field after `int : 0' in a structure. */ -#define EMPTY_FIELD_BOUNDARY 32 - -/* Alignment on even addresses for LARL instruction. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN) -#define DATA_ALIGNMENT(TYPE, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN) - -/* Alignment is not required by the hardware. */ -#define STRICT_ALIGNMENT 0 - -/* Mode of stack savearea. - FUNCTION is VOIDmode because calling convention maintains SP. - BLOCK needs Pmode for SP. - NONLOCAL needs twice Pmode to maintain both backchain and SP. */ -#define STACK_SAVEAREA_MODE(LEVEL) \ - (LEVEL == SAVE_FUNCTION ? VOIDmode \ - : LEVEL == SAVE_NONLOCAL ? (TARGET_64BIT ? OImode : TImode) : Pmode) - - -/* Type layout. */ - -/* Sizes in bits of the source language data types. */ -#define SHORT_TYPE_SIZE 16 -#define INT_TYPE_SIZE 32 -#define LONG_TYPE_SIZE (TARGET_64BIT ? 64 : 32) -#define LONG_LONG_TYPE_SIZE 64 -#define FLOAT_TYPE_SIZE 32 -#define DOUBLE_TYPE_SIZE 64 -#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64) - -/* Define this to set long double type size to use in libgcc2.c, which can - not depend on target_flags. */ -#ifdef __LONG_DOUBLE_128__ -#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128 -#else -#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 -#endif - -/* Work around target_flags dependency in ada/targtyps.c. */ -#define WIDEST_HARDWARE_FP_SIZE 64 - -/* We use "unsigned char" as default. */ -#define DEFAULT_SIGNED_CHAR 0 - - -/* Register usage. */ - -/* 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) - GPR 12: Global offset table pointer (if needed) - GPR 13: Literal pool base register - GPR 14: Return address register - GPR 15: Stack pointer - - Registers 32-35 are 'fake' hard registers that do not - correspond to actual hardware: - Reg 32: Argument pointer - Reg 33: Condition code - Reg 34: Frame pointer - Reg 35: Return address pointer - - Registers 36 and 37 are mapped to access registers - 0 and 1, used to implement thread-local storage. */ - -#define FIRST_PSEUDO_REGISTER 38 - -/* Standard register usage. */ -#define GENERAL_REGNO_P(N) ((int)(N) >= 0 && (N) < 16) -#define ADDR_REGNO_P(N) ((N) >= 1 && (N) < 16) -#define FP_REGNO_P(N) ((N) >= 16 && (N) < 32) -#define CC_REGNO_P(N) ((N) == 33) -#define FRAME_REGNO_P(N) ((N) == 32 || (N) == 34 || (N) == 35) -#define ACCESS_REGNO_P(N) ((N) == 36 || (N) == 37) - -#define GENERAL_REG_P(X) (REG_P (X) && GENERAL_REGNO_P (REGNO (X))) -#define ADDR_REG_P(X) (REG_P (X) && ADDR_REGNO_P (REGNO (X))) -#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X))) -#define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) -#define FRAME_REG_P(X) (REG_P (X) && FRAME_REGNO_P (REGNO (X))) -#define ACCESS_REG_P(X) (REG_P (X) && ACCESS_REGNO_P (REGNO (X))) - -/* Set up fixed registers and calling convention: - - GPRs 0-5 are always call-clobbered, - 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 on S/390 machines (as return address). - GPR 15 is always fixed (as stack pointer). - The 'fake' hard registers are call-clobbered and fixed. - The access registers are call-saved and fixed. - - On 31-bit, FPRs 18-19 are call-clobbered; - on 64-bit, FPRs 24-31 are call-clobbered. - The remaining FPRs are call-saved. */ - -#define FIXED_REGISTERS \ -{ 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 1, 1, 1, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 1, 1, 1, 1, \ - 1, 1 } - -#define CALL_USED_REGISTERS \ -{ 1, 1, 1, 1, \ - 1, 1, 0, 0, \ - 0, 0, 0, 0, \ - 0, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1 } - -#define CALL_REALLY_USED_REGISTERS \ -{ 1, 1, 1, 1, \ - 1, 1, 0, 0, \ - 0, 0, 0, 0, \ - 0, 0, 0, 0, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 1, 1, 1, 1, \ - 0, 0 } - -/* Preferred register allocation order. */ -#define REG_ALLOC_ORDER \ -{ 1, 2, 3, 4, 5, 0, 12, 11, 10, 9, 8, 7, 6, 14, 13, \ - 16, 17, 18, 19, 20, 21, 22, 23, \ - 24, 25, 26, 27, 28, 29, 30, 31, \ - 15, 32, 33, 34, 35, 36, 37 } - - -/* 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. - TFmode fits only into an even-odd FPR pair. - - Complex floating point modes fit either into two FPRs, or into - successive GPRs (again starting with an even number). - TCmode fits only into two successive even-odd FPR pairs. - - Condition code modes fit only into the CC register. */ - -/* Because all registers in a class have the same size HARD_REGNO_NREGS - is equivalent to CLASS_MAX_NREGS. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ - s390_class_max_nregs (REGNO_REG_CLASS (REGNO), (MODE)) - -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ - s390_hard_regno_mode_ok ((REGNO), (MODE)) - -#define HARD_REGNO_RENAME_OK(FROM, TO) \ - s390_hard_regno_rename_ok (FROM, TO) - -#define MODES_TIEABLE_P(MODE1, MODE2) \ - (((MODE1) == SFmode || (MODE1) == DFmode) \ - == ((MODE2) == SFmode || (MODE2) == DFmode)) - -/* When generating code that runs in z/Architecture mode, - but conforms to the 31-bit ABI, GPRs can hold 8 bytes; - the ABI guarantees only that the lower 4 bytes are - saved across calls, however. */ -#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ - (!TARGET_64BIT && TARGET_ZARCH \ - && GET_MODE_SIZE (MODE) > 4 \ - && (((REGNO) >= 6 && (REGNO) <= 15) || (REGNO) == 32)) - -/* Maximum number of registers to represent a value of mode MODE - in a register of class CLASS. */ -#define CLASS_MAX_NREGS(CLASS, MODE) \ - s390_class_max_nregs ((CLASS), (MODE)) - -/* If a 4-byte value is loaded into a FPR, it is placed into the - *upper* half of the register, not the lower. Therefore, we - cannot use SUBREGs to switch between modes in FP registers. - Likewise for access registers, since they have only half the - word size on 64-bit. */ -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ - ? ((reg_classes_intersect_p (FP_REGS, CLASS) \ - && (GET_MODE_SIZE (FROM) < 8 || GET_MODE_SIZE (TO) < 8)) \ - || reg_classes_intersect_p (ACCESS_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 - CC_REGS The condition code register - ACCESS_REGS The access registers - - GENERAL_FP_REGS Union of GENERAL_REGS and FP_REGS - ADDR_FP_REGS Union of ADDR_REGS and FP_REGS - GENERAL_CC_REGS Union of GENERAL_REGS and CC_REGS - ADDR_CC_REGS Union of ADDR_REGS and CC_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. */ - -enum reg_class -{ - NO_REGS, CC_REGS, ADDR_REGS, GENERAL_REGS, ACCESS_REGS, - ADDR_CC_REGS, GENERAL_CC_REGS, - FP_REGS, ADDR_FP_REGS, GENERAL_FP_REGS, - ALL_REGS, LIM_REG_CLASSES -}; -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ "NO_REGS", "CC_REGS", "ADDR_REGS", "GENERAL_REGS", "ACCESS_REGS", \ - "ADDR_CC_REGS", "GENERAL_CC_REGS", \ - "FP_REGS", "ADDR_FP_REGS", "GENERAL_FP_REGS", "ALL_REGS" } - -/* Class -> register mapping. */ -#define REG_CLASS_CONTENTS \ -{ \ - { 0x00000000, 0x00000000 }, /* NO_REGS */ \ - { 0x00000000, 0x00000002 }, /* CC_REGS */ \ - { 0x0000fffe, 0x0000000d }, /* ADDR_REGS */ \ - { 0x0000ffff, 0x0000000d }, /* GENERAL_REGS */ \ - { 0x00000000, 0x00000030 }, /* ACCESS_REGS */ \ - { 0x0000fffe, 0x0000000f }, /* ADDR_CC_REGS */ \ - { 0x0000ffff, 0x0000000f }, /* GENERAL_CC_REGS */ \ - { 0xffff0000, 0x00000000 }, /* FP_REGS */ \ - { 0xfffffffe, 0x0000000d }, /* ADDR_FP_REGS */ \ - { 0xffffffff, 0x0000000d }, /* GENERAL_FP_REGS */ \ - { 0xffffffff, 0x0000003f }, /* ALL_REGS */ \ -} - -/* In some case register allocation order is not enough for IRA to - generate a good code. The following macro (if defined) increases - cost of REGNO for a pseudo approximately by pseudo usage frequency - multiplied by the macro value. - - We avoid usage of BASE_REGNUM by nonzero macro value because the - reload can decide not to use the hard register because some - constant was forced to be in memory. */ -#define IRA_HARD_REGNO_ADD_COST_MULTIPLIER(regno) \ - (regno == BASE_REGNUM ? 0.0 : 0.5) - -/* Register -> class mapping. */ -extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; -#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO]) - -/* ADDR_REGS can be used as base or index register. */ -#define INDEX_REG_CLASS ADDR_REGS -#define BASE_REG_CLASS ADDR_REGS - -/* Check whether REGNO is a hard register of the suitable class - or a pseudo register currently allocated to one such. */ -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - (((REGNO) < FIRST_PSEUDO_REGISTER \ - && REGNO_REG_CLASS ((REGNO)) == ADDR_REGS) \ - || ADDR_REGNO_P (reg_renumber[REGNO])) -#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_INDEX_P (REGNO) - - -/* We need secondary memory to move data between GPRs and FPRs. With - DFP the ldgr lgdr instructions are available. But these - instructions do not handle GPR pairs so it is not possible for 31 - bit. */ -#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \ - ((CLASS1) != (CLASS2) \ - && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS) \ - && (!TARGET_DFP || !TARGET_64BIT || GET_MODE_SIZE (MODE) != 8)) - -/* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on 64bit - because the movsi and movsf patterns don't handle r/f moves. */ -#define SECONDARY_MEMORY_NEEDED_MODE(MODE) \ - (GET_MODE_BITSIZE (MODE) < 32 \ - ? mode_for_size (32, GET_MODE_CLASS (MODE), 0) \ - : MODE) - - -/* 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. */ -#define STACK_GROWS_DOWNWARD -#define FRAME_GROWS_DOWNWARD 1 -/* #undef ARGS_GROW_DOWNWARD */ - -/* The basic stack layout looks like this: the stack pointer points - to the register save area for called functions. Above that area - is the location to place outgoing arguments. Above those follow - dynamic allocations (alloca), and finally the local variables. */ - -/* Offset from stack-pointer to first location of outgoing args. */ -#define STACK_POINTER_OFFSET (TARGET_64BIT ? 160 : 96) - -/* Offset within stack frame to start allocating local variables at. */ -#define STARTING_FRAME_OFFSET 0 - -/* Offset from the stack pointer register to an item dynamically - allocated on the stack, e.g., by `alloca'. */ -#define STACK_DYNAMIC_OFFSET(FUNDECL) \ - (STACK_POINTER_OFFSET + crtl->outgoing_args_size) - -/* Offset of first parameter from the argument pointer register value. - We have a fake argument pointer register that points directly to - the argument area. */ -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Defining this macro makes __builtin_frame_address(0) and - __builtin_return_address(0) work with -fomit-frame-pointer. */ -#define INITIAL_FRAME_ADDRESS_RTX \ - (plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET)) - -/* 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. */ -#define DYNAMIC_CHAIN_ADDRESS(FRAME) \ - (TARGET_PACKED_STACK ? \ - plus_constant ((FRAME), STACK_POINTER_OFFSET - UNITS_PER_LONG) : (FRAME)) - -/* For -mpacked-stack this adds 160 - 8 (96 - 4) to the output of - builtin_frame_address. Otherwise arg pointer - - STACK_POINTER_OFFSET would be returned for - __builtin_frame_address(0) what might result in an address pointing - somewhere into the middle of the local variables since the packed - stack layout generally does not need all the bytes in the register - save area. */ -#define FRAME_ADDR_RTX(FRAME) \ - DYNAMIC_CHAIN_ADDRESS ((FRAME)) - -#define RETURN_ADDR_RTX(COUNT, FRAME) \ - s390_return_addr_rtx ((COUNT), DYNAMIC_CHAIN_ADDRESS ((FRAME))) - -/* In 31-bit mode, we need to mask off the high bit of return addresses. */ -#define MASK_RETURN_ADDR (TARGET_64BIT ? constm1_rtx : GEN_INT (0x7fffffff)) - - -/* 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 -#define DWARF_FRAME_RETURN_COLUMN 14 - -/* Describe how we implement __builtin_eh_return. */ -#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 6 : INVALID_REGNUM) -#define EH_RETURN_HANDLER_RTX gen_rtx_MEM (Pmode, return_address_pointer_rtx) - -/* Select a format to encode pointers in exception handling data. */ -#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ - (flag_pic \ - ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4 \ - : DW_EH_PE_absptr) - -/* Register save slot alignment. */ -#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_LONG) - - -/* Frame registers. */ - -#define STACK_POINTER_REGNUM 15 -#define FRAME_POINTER_REGNUM 34 -#define HARD_FRAME_POINTER_REGNUM 11 -#define ARG_POINTER_REGNUM 32 -#define RETURN_ADDRESS_POINTER_REGNUM 35 - -/* 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 - -/* Number of hardware registers that go into the DWARF-2 unwind info. - To avoid ABI incompatibility, this number must not change even as - 'fake' hard registers are added or removed. */ -#define DWARF_FRAME_REGISTERS 34 - - -/* Frame pointer and argument pointer elimination. */ - -#define ELIMINABLE_REGS \ -{{ 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 }, \ - { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ - { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ - { BASE_REGNUM, BASE_REGNUM }} - -#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ - (OFFSET) = s390_initial_elimination_offset ((FROM), (TO)) - - -/* Stack arguments. */ - -/* We need current_function_outgoing_args to be valid. */ -#define ACCUMULATE_OUTGOING_ARGS 1 - - -/* Register arguments. */ - -typedef struct s390_arg_structure -{ - int gprs; /* gpr so far */ - int fprs; /* fpr so far */ -} -CUMULATIVE_ARGS; - -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, NN, N_NAMED_ARGS) \ - ((CUM).gprs=0, (CUM).fprs=0) - -/* Arguments can be placed in general registers 2 to 6, or in floating - point registers 0 and 2 for 31 bit and fprs 0, 2, 4 and 6 for 64 - bit. */ -#define FUNCTION_ARG_REGNO_P(N) (((N) >=2 && (N) <7) || \ - (N) == 16 || (N) == 17 || (TARGET_64BIT && ((N) == 18 || (N) == 19))) - - -/* Only gpr 2 and fpr 0 are ever used as return registers. */ -#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16) - - -/* Function entry and exit. */ - -/* When returning from a function, the stack pointer does not matter. */ -#define EXIT_IGNORE_STACK 1 - - -/* Profiling. */ - -#define FUNCTION_PROFILER(FILE, LABELNO) \ - s390_function_profiler ((FILE), ((LABELNO))) - -#define PROFILE_BEFORE_PROLOGUE 1 - - -/* Trampolines for nested functions. */ - -#define TRAMPOLINE_SIZE (TARGET_64BIT ? 32 : 16) -#define TRAMPOLINE_ALIGNMENT BITS_PER_WORD - -/* Addressing modes, and classification of registers for them. */ - -/* Recognize any constant value that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) 0 - -/* Maximum number of registers that can appear in a valid memory address. */ -#define MAX_REGS_PER_ADDRESS 2 - -/* This definition replaces the formerly used 'm' constraint with a - different constraint letter in order to avoid changing semantics of - the 'm' constraint when accepting new address formats in - TARGET_LEGITIMATE_ADDRESS_P. The constraint letter defined here - must not be used in insn definitions or inline assemblies. */ -#define TARGET_MEM_CONSTRAINT 'e' - -/* Try a machine-dependent way of reloading an illegitimate address - operand. If we find one, push the reload and jump to WIN. This - macro is used in only one place: `find_reloads_address' in reload.c. */ -#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \ -do { \ - rtx new_rtx = legitimize_reload_address (AD, MODE, OPNUM, (int)(TYPE)); \ - if (new_rtx) \ - { \ - (AD) = new_rtx; \ - goto WIN; \ - } \ -} while (0) - -/* Helper macro for s390.c and s390.md to check for symbolic constants. */ -#define SYMBOLIC_CONST(X) \ -(GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X))) - -#define TLS_SYMBOLIC_CONST(X) \ -((GET_CODE (X) == SYMBOL_REF && tls_symbolic_operand (X)) \ - || (GET_CODE (X) == CONST && tls_symbolic_reference_mentioned_p (X))) - - -/* Condition codes. */ - -/* 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)) - -/* Canonicalize a comparison from one we don't have to one we do have. */ -#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \ - s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1)) - -/* Relative costs of operations. */ - -/* A C expression for the cost of a branch instruction. A value of 1 - is the default; other values are interpreted relative to that. */ -#define BRANCH_COST(speed_p, predictable_p) s390_branch_cost - -/* Nonzero if access to memory by bytes is slow and undesirable. */ -#define SLOW_BYTE_ACCESS 1 - -/* An integer expression for the size in bits of the largest integer machine - mode that should actually be used. We allow pairs of registers. */ -#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (TARGET_64BIT ? TImode : DImode) - -/* The maximum number of bytes that a single instruction can move quickly - between memory and registers or between two memory locations. */ -#define MOVE_MAX (TARGET_ZARCH ? 16 : 8) -#define MOVE_MAX_PIECES (TARGET_ZARCH ? 8 : 4) -#define MAX_MOVE_MAX 16 - -/* Determine whether to use move_by_pieces or block move insn. */ -#define MOVE_BY_PIECES_P(SIZE, ALIGN) \ - ( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 \ - || (TARGET_ZARCH && (SIZE) == 8) ) - -/* Determine whether to use clear_by_pieces or block clear insn. */ -#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \ - ( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 \ - || (TARGET_ZARCH && (SIZE) == 8) ) - -/* This macro is used to determine whether store_by_pieces should be - called to "memcpy" storage when the source is a constant string. */ -#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN) - -/* Likewise to decide whether to "memset" storage with byte values - other than zero. */ -#define SET_BY_PIECES_P(SIZE, ALIGN) STORE_BY_PIECES_P (SIZE, ALIGN) - -/* Don't perform CSE on function addresses. */ -#define NO_FUNCTION_CSE - -/* This value is used in tree-sra to decide whether it might benefical - to split a struct move into several word-size moves. For S/390 - only small values make sense here since struct moves are relatively - cheap thanks to mvc so the small default value choosen for archs - with memmove patterns should be ok. But this value is multiplied - in tree-sra with UNITS_PER_WORD to make a decision so we adjust it - here to compensate for that factor since mvc costs exactly the same - on 31 and 64 bit. */ -#define MOVE_RATIO(speed) (TARGET_64BIT? 2 : 4) - - -/* Sections. */ - -/* Output before read-only data. */ -#define TEXT_SECTION_ASM_OP ".text" - -/* Output before writable (initialized) data. */ -#define DATA_SECTION_ASM_OP ".data" - -/* Output before writable (uninitialized) data. */ -#define BSS_SECTION_ASM_OP ".bss" - -/* S/390 constant pool breaks the devices in crtstuff.c to control section - in where code resides. We have to write it as asm code. */ -#ifndef __s390x__ -#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ - asm (SECTION_OP "\n\ - bras\t%r2,1f\n\ -0: .long\t" USER_LABEL_PREFIX #FUNC " - 0b\n\ -1: l\t%r3,0(%r2)\n\ - bas\t%r14,0(%r3,%r2)\n\ - .previous"); -#endif - - -/* Position independent code. */ - -#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 12 : INVALID_REGNUM) - -#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X) - - -/* Assembler file format. */ - -/* Character to start a comment. */ -#define ASM_COMMENT_START "#" - -/* Declare an uninitialized external linkage data object. */ -#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ - asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) - -/* Globalizing directive for a label. */ -#define GLOBAL_ASM_OP ".globl " - -/* Advance the location counter to a multiple of 2**LOG bytes. */ -#define ASM_OUTPUT_ALIGN(FILE, LOG) \ - if ((LOG)) fprintf ((FILE), "\t.align\t%d\n", 1 << (LOG)) - -/* Advance the location counter by SIZE bytes. */ -#define ASM_OUTPUT_SKIP(FILE, SIZE) \ - 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 "." - -#define LABEL_ALIGN(LABEL) \ - s390_label_align (LABEL) - -/* How to refer to registers in assembler output. This sequence is - indexed by compiler's hard-register-number (see above). */ -#define REGISTER_NAMES \ -{ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \ - "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", \ - "%f0", "%f2", "%f4", "%f6", "%f1", "%f3", "%f5", "%f7", \ - "%f8", "%f10", "%f12", "%f14", "%f9", "%f11", "%f13", "%f15", \ - "%ap", "%cc", "%fp", "%rp", "%a0", "%a1" \ -} - -/* 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) - -/* Output an element of a case-vector that is absolute. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ -do { \ - char buf[32]; \ - fputs (integer_asm_op (UNITS_PER_LONG, TRUE), (FILE)); \ - ASM_GENERATE_INTERNAL_LABEL (buf, "L", (VALUE)); \ - assemble_name ((FILE), buf); \ - fputc ('\n', (FILE)); \ -} while (0) - -/* Output an element of a case-vector that is relative. */ -#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ -do { \ - char buf[32]; \ - fputs (integer_asm_op (UNITS_PER_LONG, TRUE), (FILE)); \ - ASM_GENERATE_INTERNAL_LABEL (buf, "L", (VALUE)); \ - assemble_name ((FILE), buf); \ - fputc ('-', (FILE)); \ - ASM_GENERATE_INTERNAL_LABEL (buf, "L", (REL)); \ - assemble_name ((FILE), buf); \ - fputc ('\n', (FILE)); \ -} while (0) - - -/* Miscellaneous parameters. */ - -/* Specify the machine mode that this machine uses for the index in the - tablejump instruction. */ -#define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode) - -/* 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 - -/* Specify the machine mode that pointers have. - After generation of rtl, the compiler makes no further distinction - 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 - -/* Specify the value which is used when clz operand is zero. */ -#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 64, 1) - -/* Machine-specific symbol_ref flags. */ -#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0) -#define SYMBOL_REF_ALIGN1_P(X) \ - ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_ALIGN1)) -#define SYMBOL_FLAG_NOT_NATURALLY_ALIGNED (SYMBOL_FLAG_MACH_DEP << 1) -#define SYMBOL_REF_NOT_NATURALLY_ALIGNED_P(X) \ - ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_NOT_NATURALLY_ALIGNED)) - -/* Check whether integer displacement is in range. */ -#define DISP_IN_RANGE(d) \ - (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \ - : ((d) >= 0 && (d) <= 4095)) - -/* Reads can reuse write prefetches, used by tree-ssa-prefetch-loops.c. */ -#define READ_CAN_USE_WRITE_PREFETCH 1 - -extern const int processor_flags_table[]; -#endif diff --git a/gcc-4.7/gcc/config/s390/s390.md b/gcc-4.7/gcc/config/s390/s390.md deleted file mode 100644 index a875eec7b..000000000 --- a/gcc-4.7/gcc/config/s390/s390.md +++ /dev/null @@ -1,9416 +0,0 @@ -;;- Machine description for GNU compiler -- S/390 / zSeries version. -;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, -;; 2009, 2010 Free Software Foundation, Inc. -;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and -;; Ulrich Weigand (uweigand@de.ibm.com) and -;; Andreas Krebbel (Andreas.Krebbel@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 3, or (at your option) any later -;; version. - -;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -;; WARRANTY; without even the implied warranty of MERCHANTABILITY or -;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -;; for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -;; -;; See constraints.md for a description of constraints specific to s390. -;; - -;; Special formats used for outputting 390 instructions. -;; -;; %C: print opcode suffix for branch condition. -;; %D: print opcode suffix for inverse branch condition. -;; %J: print tls_load/tls_gdcall/tls_ldcall suffix -;; %G: print the size of the operand in bytes. -;; %O: print only the displacement of a memory reference. -;; %R: print only the base register of a memory reference. -;; %S: print S-type memory reference (base+displacement). -;; %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. -;; %c: print integer X as if it's an signed byte. -;; %x: print integer X as if it's an unsigned halfword. -;; %h: print integer X as if it's a signed halfword. -;; %i: print the first nonzero HImode part of X. -;; %j: print the first HImode part unequal to -1 of X. -;; %k: print the first nonzero SImode part of X. -;; %m: print the first SImode part unequal to -1 of X. -;; %o: print integer X as if it's an unsigned 32bit word. -;; -;; We have a special constraint for pattern matching. -;; -;; s_operand -- Matches a valid S operand in a RS, SI or SS type instruction. -;; - -;; -;; UNSPEC usage -;; - -(define_c_enum "unspec" [ - ; Miscellaneous - UNSPEC_ROUND - UNSPEC_CCU_TO_INT - UNSPEC_CCZ_TO_INT - UNSPEC_ICM - UNSPEC_TIE - - ; GOT/PLT and lt-relative accesses - UNSPEC_LTREL_OFFSET - UNSPEC_LTREL_BASE - UNSPEC_POOL_OFFSET - UNSPEC_GOTENT - UNSPEC_GOT - UNSPEC_GOTOFF - UNSPEC_PLT - UNSPEC_PLTOFF - - ; Literal pool - UNSPEC_RELOAD_BASE - UNSPEC_MAIN_BASE - UNSPEC_LTREF - UNSPEC_INSN - UNSPEC_EXECUTE - - ; Atomic Support - UNSPEC_MB - - ; TLS relocation specifiers - UNSPEC_TLSGD - UNSPEC_TLSLDM - UNSPEC_NTPOFF - UNSPEC_DTPOFF - UNSPEC_GOTNTPOFF - UNSPEC_INDNTPOFF - - ; TLS support - UNSPEC_TLSLDM_NTPOFF - UNSPEC_TLS_LOAD - - ; String Functions - UNSPEC_SRST - UNSPEC_MVST - - ; Stack Smashing Protector - UNSPEC_SP_SET - UNSPEC_SP_TEST - - ; Test Data Class (TDC) - UNSPEC_TDC_INSN - - ; Population Count - UNSPEC_POPCNT - UNSPEC_COPYSIGN - ]) - -;; -;; UNSPEC_VOLATILE usage -;; - -(define_c_enum "unspecv" [ - ; Blockage - UNSPECV_BLOCKAGE - - ; TPF Support - UNSPECV_TPF_PROLOGUE - UNSPECV_TPF_EPILOGUE - - ; Literal pool - UNSPECV_POOL - UNSPECV_POOL_SECTION - UNSPECV_POOL_ALIGN - UNSPECV_POOL_ENTRY - UNSPECV_MAIN_POOL - - ; TLS support - UNSPECV_SET_TP - - ; Atomic Support - UNSPECV_CAS - UNSPECV_ATOMIC_OP - ]) - -;; -;; Registers -;; - -; Registers with special meaning - -(define_constants - [ - ; Sibling call register. - (SIBCALL_REGNUM 1) - ; Literal pool base register. - (BASE_REGNUM 13) - ; Return address register. - (RETURN_REGNUM 14) - ; Condition code register. - (CC_REGNUM 33) - ; Thread local storage pointer register. - (TP_REGNUM 36) - ]) - -; Hardware register names - -(define_constants - [ - ; General purpose registers - (GPR0_REGNUM 0) - ; Floating point registers. - (FPR0_REGNUM 16) - (FPR2_REGNUM 18) - ]) - -;; -;; PFPO GPR0 argument format -;; - -(define_constants - [ - ; PFPO operation type - (PFPO_CONVERT 0x1000000) - ; PFPO operand types - (PFPO_OP_TYPE_SF 0x5) - (PFPO_OP_TYPE_DF 0x6) - (PFPO_OP_TYPE_TF 0x7) - (PFPO_OP_TYPE_SD 0x8) - (PFPO_OP_TYPE_DD 0x9) - (PFPO_OP_TYPE_TD 0xa) - ; Bitposition of operand types - (PFPO_OP0_TYPE_SHIFT 16) - (PFPO_OP1_TYPE_SHIFT 8) - ]) - - -;; Instruction operand type as used in the Principles of Operation. -;; Used to determine defaults for length and other attribute values. - -(define_attr "op_type" - "NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE,RXY,RSY,SIY,RRF,RRR,SIL,RRS,RIS" - (const_string "NN")) - -;; Instruction type attribute used for scheduling. - -(define_attr "type" "none,integer,load,lr,la,larl,lm,stm, - cs,vs,store,sem,idiv, - imulhi,imulsi,imuldi, - branch,jsr,fsimptf,fsimpdf,fsimpsf,fhex, - floadtf,floaddf,floadsf,fstoredf,fstoresf, - fmultf,fmuldf,fmulsf,fdivtf,fdivdf,fdivsf, - ftoi,fsqrttf,fsqrtdf,fsqrtsf, - fmadddf,fmaddsf, - ftrunctf,ftruncdf, ftruncsd, ftruncdd, - itoftf, itofdf, itofsf, itofdd, itoftd, - fdivdd, fdivtd, floaddd, floadsd, fmuldd, fmultd, - fsimpdd, fsimpsd, fsimptd, fstoredd, fstoresd, - ftoidfp, other" - (cond [(eq_attr "op_type" "NN") (const_string "other") - (eq_attr "op_type" "SS") (const_string "cs")] - (const_string "integer"))) - -;; Another attribute used for scheduling purposes: -;; agen: Instruction uses the address generation unit -;; reg: Instruction does not use the agen unit - -(define_attr "atype" "agen,reg" - (if_then_else (eq_attr "op_type" "E,RR,RI,RRE,RSI,RIL,RIE,RRF,RRR") - (const_string "reg") - (const_string "agen"))) - -;; Properties concerning Z10 execution grouping and value forwarding. -;; z10_super: instruction is superscalar. -;; z10_super_c: instruction is superscalar and meets the condition of z10_c. -;; z10_fwd: The instruction reads the value of an operand and stores it into a -;; target register. It can forward this value to a second instruction that reads -;; the same register if that second instruction is issued in the same group. -;; z10_rec: The instruction is in the T pipeline and reads a register. If the -;; instruction in the S pipe writes to the register, then the T instruction -;; can immediately read the new value. -;; z10_fr: union of Z10_fwd and z10_rec. -;; z10_c: second operand of instruction is a register and read with complemented bits. -;; -;; An additional suffix A1, A3, or E1 indicates the respective AGI bypass. - - -(define_attr "z10prop" "none, - z10_super, z10_super_E1, z10_super_A1, z10_super_c, z10_super_c_E1, - z10_fwd, z10_fwd_A1, z10_fwd_A3, z10_fwd_E1, - z10_rec, - z10_fr, z10_fr_A3, z10_fr_E1, - z10_c" - (const_string "none")) - -;; Properties concerning Z196 decoding -;; z196_alone: must group alone -;; z196_end: ends a group -;; z196_cracked: instruction is cracked or expanded -(define_attr "z196prop" "none, - z196_alone, z196_ends, - z196_cracked" - (const_string "none")) - -;; Length in bytes. - -(define_attr "length" "" - (cond [(eq_attr "op_type" "E,RR") (const_int 2) - (eq_attr "op_type" "RX,RI,RRE,RS,RSI,S,SI,RRF,RRR") (const_int 4)] - (const_int 6))) - - -;; Processor type. This attribute must exactly match the processor_type -;; enumeration in s390.h. The current machine description does not -;; distinguish between g5 and g6, but there are differences between the two -;; CPUs could in theory be modeled. - -(define_attr "cpu" "g5,g6,z900,z990,z9_109,z9_ec,z10,z196" - (const (symbol_ref "s390_tune_attr"))) - -(define_attr "cpu_facility" "standard,ieee,zarch,longdisp,extimm,dfp,z10,z196" - (const_string "standard")) - -(define_attr "enabled" "" - (cond [(eq_attr "cpu_facility" "standard") - (const_int 1) - - (and (eq_attr "cpu_facility" "ieee") - (match_test "TARGET_CPU_IEEE_FLOAT")) - (const_int 1) - - (and (eq_attr "cpu_facility" "zarch") - (match_test "TARGET_ZARCH")) - (const_int 1) - - (and (eq_attr "cpu_facility" "longdisp") - (match_test "TARGET_LONG_DISPLACEMENT")) - (const_int 1) - - (and (eq_attr "cpu_facility" "extimm") - (match_test "TARGET_EXTIMM")) - (const_int 1) - - (and (eq_attr "cpu_facility" "dfp") - (match_test "TARGET_DFP")) - (const_int 1) - - (and (eq_attr "cpu_facility" "z10") - (match_test "TARGET_Z10")) - (const_int 1) - - (and (eq_attr "cpu_facility" "z196") - (match_test "TARGET_Z196")) - (const_int 1)] - (const_int 0))) - -;; Pipeline description for z900. For lack of anything better, -;; this description is also used for the g5 and g6. -(include "2064.md") - -;; Pipeline description for z990, z9-109 and z9-ec. -(include "2084.md") - -;; Pipeline description for z10 -(include "2097.md") - -;; Pipeline description for z196 -(include "2817.md") - -;; Predicates -(include "predicates.md") - -;; Constraint definitions -(include "constraints.md") - -;; Other includes -(include "tpf.md") - -;; Iterators - -;; These mode iterators allow floating point patterns to be generated from the -;; same template. -(define_mode_iterator FP_ALL [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP") - (SD "TARGET_HARD_DFP")]) -(define_mode_iterator FP [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")]) -(define_mode_iterator FPALL [TF DF SF TD DD SD]) -(define_mode_iterator BFP [TF DF SF]) -(define_mode_iterator DFP [TD DD]) -(define_mode_iterator DFP_ALL [TD DD SD]) -(define_mode_iterator DSF [DF SF]) -(define_mode_iterator SD_SF [SF SD]) -(define_mode_iterator DD_DF [DF DD]) -(define_mode_iterator TD_TF [TF TD]) - -;; This mode iterator allows 31-bit and 64-bit TDSI patterns to be generated -;; from the same template. -(define_mode_iterator TDSI [(TI "TARGET_64BIT") DI SI]) - -;; These mode iterators allow 31-bit and 64-bit GPR patterns to be generated -;; from the same template. -(define_mode_iterator GPR [(DI "TARGET_ZARCH") SI]) -(define_mode_iterator DSI [DI SI]) - -;; These mode iterators allow :P to be used for patterns that operate on -;; pointer-sized quantities. Exactly one of the two alternatives will match. -(define_mode_iterator P [(DI "TARGET_64BIT") (SI "!TARGET_64BIT")]) - -;; These macros refer to the actual word_mode of the configuration. This is equal -;; to Pmode except on 31-bit machines in zarch mode. -(define_mode_iterator DW [(TI "TARGET_ZARCH") (DI "!TARGET_ZARCH")]) -(define_mode_iterator W [(DI "TARGET_ZARCH") (SI "!TARGET_ZARCH")]) - -;; Used by the umul pattern to express modes having half the size. -(define_mode_attr DWH [(TI "DI") (DI "SI")]) -(define_mode_attr dwh [(TI "di") (DI "si")]) - -;; This mode iterator allows the QI and HI patterns to be defined from -;; the same template. -(define_mode_iterator HQI [HI QI]) - -;; This mode iterator allows the integer patterns to be defined from the -;; same template. -(define_mode_iterator INT [(DI "TARGET_ZARCH") SI HI QI]) -(define_mode_iterator INTALL [TI DI SI HI QI]) - -;; This iterator allows some 'ashift' and 'lshiftrt' pattern to be defined from -;; the same template. -(define_code_iterator SHIFT [ashift lshiftrt]) - -;; This iterator and attribute allow to combine most atomic operations. -(define_code_iterator ATOMIC [and ior xor plus minus mult]) -(define_code_iterator ATOMIC_Z196 [and ior xor plus]) -(define_code_attr atomic [(and "and") (ior "ior") (xor "xor") - (plus "add") (minus "sub") (mult "nand")]) -(define_code_attr noxa [(and "n") (ior "o") (xor "x") (plus "a")]) - -;; In FP templates, a string like "lt<de>br" will expand to "ltxbr" in -;; TF/TDmode, "ltdbr" in DF/DDmode, and "ltebr" in SF/SDmode. -(define_mode_attr xde [(TF "x") (DF "d") (SF "e") (TD "x") (DD "d") (SD "e")]) - -;; In FP templates, a <dee> in "m<dee><bt>r" will expand to "mx<bt>r" in -;; TF/TDmode, "md<bt>r" in DF/DDmode, "mee<bt>r" in SFmode and "me<bt>r in -;; SDmode. -(define_mode_attr xdee [(TF "x") (DF "d") (SF "ee") (TD "x") (DD "d") (SD "e")]) - -;; In FP templates, "<RRe>" will expand to "RRE" in TFmode and "RR" otherwise. -;; Likewise for "<RXe>". -(define_mode_attr RRe [(TF "RRE") (DF "RR") (SF "RR")]) -(define_mode_attr RXe [(TF "RXE") (DF "RX") (SF "RX")]) - -;; The decimal floating point variants of add, sub, div and mul support 3 -;; fp register operands. The following attributes allow to merge the bfp and -;; dfp variants in a single insn definition. - -;; This attribute is used to set op_type accordingly. -(define_mode_attr RRer [(TF "RRE") (DF "RRE") (SF "RRE") (TD "RRR") - (DD "RRR") (SD "RRR")]) - -;; This attribute is used in the operand constraint list in order to have the -;; first and the second operand match for bfp modes. -(define_mode_attr f0 [(TF "0") (DF "0") (SF "0") (TD "f") (DD "f") (DD "f")]) - -;; This attribute is used in the operand list of the instruction to have an -;; additional operand for the dfp instructions. -(define_mode_attr op1 [(TF "") (DF "") (SF "") - (TD "%1,") (DD "%1,") (SD "%1,")]) - - -;; This attribute is used in the operand constraint list -;; for instructions dealing with the sign bit of 32 or 64bit fp values. -;; TFmode values are represented by a fp register pair. Since the -;; sign bit instructions only handle single source and target fp registers -;; these instructions can only be used for TFmode values if the source and -;; target operand uses the same fp register. -(define_mode_attr fT0 [(TF "0") (DF "f") (SF "f")]) - -;; In FP templates, "<Rf>" will expand to "f" in TFmode and "R" otherwise. -;; This is used to disable the memory alternative in TFmode patterns. -(define_mode_attr Rf [(TF "f") (DF "R") (SF "R") (TD "f") (DD "f") (SD "f")]) - -;; This attribute adds b for bfp instructions and t for dfp instructions and is used -;; within instruction mnemonics. -(define_mode_attr bt [(TF "b") (DF "b") (SF "b") (TD "t") (DD "t") (SD "t")]) - -;; This attribute is used within instruction mnemonics. It evaluates to d for dfp -;; modes and to an empty string for bfp modes. -(define_mode_attr _d [(TF "") (DF "") (SF "") (TD "d") (DD "d") (SD "d")]) - -;; In GPR and P templates, a constraint like "<d0>" will expand to "d" in DImode -;; and "0" in SImode. This allows to combine instructions of which the 31bit -;; version only operates on one register. -(define_mode_attr d0 [(DI "d") (SI "0")]) - -;; In combination with d0 this allows to combine instructions of which the 31bit -;; version only operates on one register. The DImode version needs an additional -;; register for the assembler output. -(define_mode_attr 1 [(DI "%1,") (SI "")]) - -;; In SHIFT templates, a string like "s<lr>dl" will expand to "sldl" in -;; 'ashift' and "srdl" in 'lshiftrt'. -(define_code_attr lr [(ashift "l") (lshiftrt "r")]) - -;; In SHIFT templates, this attribute holds the correct standard name for the -;; pattern itself and the corresponding function calls. -(define_code_attr shift [(ashift "ashl") (lshiftrt "lshr")]) - -;; This attribute handles differences in the instruction 'type' and will result -;; in "RRE" for DImode and "RR" for SImode. -(define_mode_attr E [(DI "E") (SI "")]) - -;; This attribute handles differences in the instruction 'type' and makes RX<Y> -;; to result in "RXY" for DImode and "RX" for SImode. -(define_mode_attr Y [(DI "Y") (SI "")]) - -;; This attribute handles differences in the instruction 'type' and will result -;; in "RSE" for TImode and "RS" for DImode. -(define_mode_attr TE [(TI "E") (DI "")]) - -;; In GPR templates, a string like "lc<g>r" will expand to "lcgr" in DImode -;; and "lcr" in SImode. -(define_mode_attr g [(DI "g") (SI "")]) - -;; In GPR templates, a string like "sl<y>" will expand to "slg" in DImode -;; and "sly" in SImode. This is useful because on 64bit the ..g instructions -;; were enhanced with long displacements whereas 31bit instructions got a ..y -;; variant for long displacements. -(define_mode_attr y [(DI "g") (SI "y")]) - -;; In DW templates, a string like "cds<g>" will expand to "cdsg" in TImode -;; and "cds" in DImode. -(define_mode_attr tg [(TI "g") (DI "")]) - -;; In GPR templates, a string like "c<gf>dbr" will expand to "cgdbr" in DImode -;; and "cfdbr" in SImode. -(define_mode_attr gf [(DI "g") (SI "f")]) - -;; In GPR templates, a string like sll<gk> will expand to sllg for DI -;; and sllk for SI. This way it is possible to merge the new z196 SI -;; 3 operands shift instructions into the existing patterns. -(define_mode_attr gk [(DI "g") (SI "k")]) - -;; ICM mask required to load MODE value into the lowest subreg -;; of a SImode register. -(define_mode_attr icm_lo [(HI "3") (QI "1")]) - -;; In HQI templates, a string like "llg<hc>" will expand to "llgh" in -;; HImode and "llgc" in QImode. -(define_mode_attr hc [(HI "h") (QI "c")]) - -;; In P templates, the mode <DBL> will expand to "TI" in DImode and "DI" -;; in SImode. -(define_mode_attr DBL [(DI "TI") (SI "DI")]) - -;; This attribute expands to DF for TFmode and to DD for TDmode . It is -;; used for Txmode splitters splitting a Txmode copy into 2 Dxmode copies. -(define_mode_attr HALF_TMODE [(TF "DF") (TD "DD")]) - -;; Maximum unsigned integer that fits in MODE. -(define_mode_attr max_uint [(HI "65535") (QI "255")]) - -;; -;;- Compare instructions. -;; - -; Test-under-Mask instructions - -(define_insn "*tmqi_mem" - [(set (reg CC_REGNUM) - (compare (and:QI (match_operand:QI 0 "memory_operand" "Q,S") - (match_operand:QI 1 "immediate_operand" "n,n")) - (match_operand:QI 2 "immediate_operand" "n,n")))] - "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], false))" - "@ - tm\t%S0,%b1 - tmy\t%S0,%b1" - [(set_attr "op_type" "SI,SIY") - (set_attr "z10prop" "z10_super,z10_super")]) - -(define_insn "*tmdi_reg" - [(set (reg CC_REGNUM) - (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_ZARCH - && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], true)) - && 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") - (set_attr "z10prop" "z10_super,z10_super,z10_super,z10_super")]) - -(define_insn "*tmsi_reg" - [(set (reg CC_REGNUM) - (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], true)) - && s390_single_part (operands[1], SImode, HImode, 0) >= 0" - "@ - tmh\t%0,%i1 - tml\t%0,%i1" - [(set_attr "op_type" "RI") - (set_attr "z10prop" "z10_super,z10_super")]) - -(define_insn "*tm<mode>_full" - [(set (reg CC_REGNUM) - (compare (match_operand:HQI 0 "register_operand" "d") - (match_operand:HQI 1 "immediate_operand" "n")))] - "s390_match_ccmode (insn, s390_tm_ccmode (constm1_rtx, operands[1], true))" - "tml\t%0,<max_uint>" - [(set_attr "op_type" "RI") - (set_attr "z10prop" "z10_super")]) - - -; -; Load-and-Test instructions -; - -; tst(di|si) instruction pattern(s). - -(define_insn "*tstdi_sign" - [(set (reg CC_REGNUM) - (compare - (ashiftrt:DI - (ashift:DI - (subreg:DI (match_operand:SI 0 "nonimmediate_operand" "d,RT") 0) - (const_int 32)) (const_int 32)) - (match_operand:DI 1 "const0_operand" ""))) - (set (match_operand:DI 2 "register_operand" "=d,d") - (sign_extend:DI (match_dup 0)))] - "s390_match_ccmode(insn, CCSmode) && TARGET_ZARCH" - "ltgfr\t%2,%0 - ltgf\t%2,%0" - [(set_attr "op_type" "RRE,RXY") - (set_attr "cpu_facility" "*,z10") - (set_attr "z10prop" "z10_super_E1,z10_super_E1") ]) - -; ltr, lt, ltgr, ltg -(define_insn "*tst<mode>_extimm" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 0 "nonimmediate_operand" "d,RT") - (match_operand:GPR 1 "const0_operand" ""))) - (set (match_operand:GPR 2 "register_operand" "=d,d") - (match_dup 0))] - "s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM" - "@ - lt<g>r\t%2,%0 - lt<g>\t%2,%0" - [(set_attr "op_type" "RR<E>,RXY") - (set_attr "z10prop" "z10_fr_E1,z10_fwd_A3") ]) - -; ltr, lt, ltgr, ltg -(define_insn "*tst<mode>_cconly_extimm" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 0 "nonimmediate_operand" "d,RT") - (match_operand:GPR 1 "const0_operand" ""))) - (clobber (match_scratch:GPR 2 "=X,d"))] - "s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM" - "@ - lt<g>r\t%0,%0 - lt<g>\t%2,%0" - [(set_attr "op_type" "RR<E>,RXY") - (set_attr "z10prop" "z10_fr_E1,z10_fwd_A3")]) - -(define_insn "*tstdi" - [(set (reg CC_REGNUM) - (compare (match_operand:DI 0 "register_operand" "d") - (match_operand:DI 1 "const0_operand" ""))) - (set (match_operand:DI 2 "register_operand" "=d") - (match_dup 0))] - "s390_match_ccmode(insn, CCSmode) && TARGET_ZARCH && !TARGET_EXTIMM" - "ltgr\t%2,%0" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_fr_E1")]) - -(define_insn "*tstsi" - [(set (reg CC_REGNUM) - (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,d") - (match_dup 0))] - "s390_match_ccmode(insn, CCSmode) && !TARGET_EXTIMM" - "@ - ltr\t%2,%0 - icm\t%2,15,%S0 - icmy\t%2,15,%S0" - [(set_attr "op_type" "RR,RS,RSY") - (set_attr "z10prop" "z10_fr_E1,z10_super_E1,z10_super_E1")]) - -(define_insn "*tstsi_cconly" - [(set (reg CC_REGNUM) - (compare (match_operand:SI 0 "nonimmediate_operand" "d,Q,S") - (match_operand:SI 1 "const0_operand" ""))) - (clobber (match_scratch:SI 2 "=X,d,d"))] - "s390_match_ccmode(insn, CCSmode)" - "@ - ltr\t%0,%0 - icm\t%2,15,%S0 - icmy\t%2,15,%S0" - [(set_attr "op_type" "RR,RS,RSY") - (set_attr "z10prop" "z10_fr_E1,z10_super_E1,z10_super_E1")]) - -(define_insn "*tstdi_cconly_31" - [(set (reg CC_REGNUM) - (compare (match_operand:DI 0 "register_operand" "d") - (match_operand:DI 1 "const0_operand" "")))] - "s390_match_ccmode(insn, CCSmode) && !TARGET_ZARCH" - "srda\t%0,0" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -; ltr, ltgr -(define_insn "*tst<mode>_cconly2" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 0 "register_operand" "d") - (match_operand:GPR 1 "const0_operand" "")))] - "s390_match_ccmode(insn, CCSmode)" - "lt<g>r\t%0,%0" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_fr_E1")]) - -; tst(hi|qi) instruction pattern(s). - -(define_insn "*tst<mode>CCT" - [(set (reg CC_REGNUM) - (compare (match_operand:HQI 0 "nonimmediate_operand" "?Q,?S,d") - (match_operand:HQI 1 "const0_operand" ""))) - (set (match_operand:HQI 2 "register_operand" "=d,d,0") - (match_dup 0))] - "s390_match_ccmode(insn, CCTmode)" - "@ - icm\t%2,<icm_lo>,%S0 - icmy\t%2,<icm_lo>,%S0 - tml\t%0,<max_uint>" - [(set_attr "op_type" "RS,RSY,RI") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super")]) - -(define_insn "*tsthiCCT_cconly" - [(set (reg CC_REGNUM) - (compare (match_operand:HI 0 "nonimmediate_operand" "Q,S,d") - (match_operand:HI 1 "const0_operand" ""))) - (clobber (match_scratch:HI 2 "=d,d,X"))] - "s390_match_ccmode(insn, CCTmode)" - "@ - icm\t%2,3,%S0 - icmy\t%2,3,%S0 - tml\t%0,65535" - [(set_attr "op_type" "RS,RSY,RI") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super")]) - -(define_insn "*tstqiCCT_cconly" - [(set (reg CC_REGNUM) - (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,?S,d") - (match_operand:QI 1 "const0_operand" "")))] - "s390_match_ccmode(insn, CCTmode)" - "@ - cli\t%S0,0 - cliy\t%S0,0 - tml\t%0,255" - [(set_attr "op_type" "SI,SIY,RI") - (set_attr "z10prop" "z10_super,z10_super,z10_super")]) - -(define_insn "*tst<mode>" - [(set (reg CC_REGNUM) - (compare (match_operand:HQI 0 "s_operand" "Q,S") - (match_operand:HQI 1 "const0_operand" ""))) - (set (match_operand:HQI 2 "register_operand" "=d,d") - (match_dup 0))] - "s390_match_ccmode(insn, CCSmode)" - "@ - icm\t%2,<icm_lo>,%S0 - icmy\t%2,<icm_lo>,%S0" - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_insn "*tst<mode>_cconly" - [(set (reg CC_REGNUM) - (compare (match_operand:HQI 0 "s_operand" "Q,S") - (match_operand:HQI 1 "const0_operand" ""))) - (clobber (match_scratch:HQI 2 "=d,d"))] - "s390_match_ccmode(insn, CCSmode)" - "@ - icm\t%2,<icm_lo>,%S0 - icmy\t%2,<icm_lo>,%S0" - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - - -; Compare (equality) instructions - -(define_insn "*cmpdi_cct" - [(set (reg CC_REGNUM) - (compare (match_operand:DI 0 "nonimmediate_operand" "%d,d,d,d,Q") - (match_operand:DI 1 "general_operand" "d,K,Os,RT,BQ")))] - "s390_match_ccmode (insn, CCTmode) && TARGET_ZARCH" - "@ - cgr\t%0,%1 - cghi\t%0,%h1 - cgfi\t%0,%1 - cg\t%0,%1 - #" - [(set_attr "op_type" "RRE,RI,RIL,RXY,SS") - (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,*")]) - -(define_insn "*cmpsi_cct" - [(set (reg CC_REGNUM) - (compare (match_operand:SI 0 "nonimmediate_operand" "%d,d,d,d,d,Q") - (match_operand:SI 1 "general_operand" "d,K,Os,R,T,BQ")))] - "s390_match_ccmode (insn, CCTmode)" - "@ - cr\t%0,%1 - chi\t%0,%h1 - cfi\t%0,%1 - c\t%0,%1 - cy\t%0,%1 - #" - [(set_attr "op_type" "RR,RI,RIL,RX,RXY,SS") - (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,*")]) - -; Compare (signed) instructions - -(define_insn "*cmpdi_ccs_sign" - [(set (reg CC_REGNUM) - (compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" - "d,RT,b")) - (match_operand:DI 0 "register_operand" "d, d,d")))] - "s390_match_ccmode(insn, CCSRmode) && TARGET_ZARCH" - "@ - cgfr\t%0,%1 - cgf\t%0,%1 - cgfrl\t%0,%1" - [(set_attr "op_type" "RRE,RXY,RIL") - (set_attr "z10prop" "z10_c,*,*") - (set_attr "type" "*,*,larl")]) - - - -(define_insn "*cmpsi_ccs_sign" - [(set (reg CC_REGNUM) - (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T,b")) - (match_operand:SI 0 "register_operand" "d,d,d")))] - "s390_match_ccmode(insn, CCSRmode)" - "@ - ch\t%0,%1 - chy\t%0,%1 - chrl\t%0,%1" - [(set_attr "op_type" "RX,RXY,RIL") - (set_attr "cpu_facility" "*,*,z10") - (set_attr "type" "*,*,larl") - (set_attr "z196prop" "z196_cracked,z196_cracked,z196_cracked")]) - -(define_insn "*cmphi_ccs_z10" - [(set (reg CC_REGNUM) - (compare (match_operand:HI 0 "s_operand" "Q") - (match_operand:HI 1 "immediate_operand" "K")))] - "s390_match_ccmode(insn, CCSmode) && TARGET_Z10" - "chhsi\t%0,%1" - [(set_attr "op_type" "SIL") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "*cmpdi_ccs_signhi_rl" - [(set (reg CC_REGNUM) - (compare (sign_extend:DI (match_operand:HI 1 "memory_operand" "RT,b")) - (match_operand:GPR 0 "register_operand" "d,d")))] - "s390_match_ccmode(insn, CCSRmode) && TARGET_Z10" - "@ - cgh\t%0,%1 - cghrl\t%0,%1" - [(set_attr "op_type" "RXY,RIL") - (set_attr "type" "*,larl")]) - -; cr, chi, cfi, c, cy, cgr, cghi, cgfi, cg, chsi, cghsi, crl, cgrl -(define_insn "*cmp<mode>_ccs" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 0 "nonimmediate_operand" - "d,d,Q, d,d,d,d") - (match_operand:GPR 1 "general_operand" - "d,K,K,Os,R,T,b")))] - "s390_match_ccmode(insn, CCSmode)" - "@ - c<g>r\t%0,%1 - c<g>hi\t%0,%h1 - c<g>hsi\t%0,%h1 - c<g>fi\t%0,%1 - c<g>\t%0,%1 - c<y>\t%0,%1 - c<g>rl\t%0,%1" - [(set_attr "op_type" "RR<E>,RI,SIL,RIL,RX<Y>,RXY,RIL") - (set_attr "cpu_facility" "*,*,z10,extimm,*,*,z10") - (set_attr "type" "*,*,*,*,*,*,larl") - (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,z10_super")]) - - -; Compare (unsigned) instructions - -(define_insn "*cmpsi_ccu_zerohi_rlsi" - [(set (reg CC_REGNUM) - (compare (zero_extend:SI (mem:HI (match_operand:SI 1 - "larl_operand" "X"))) - (match_operand:SI 0 "register_operand" "d")))] - "s390_match_ccmode(insn, CCURmode) && TARGET_Z10" - "clhrl\t%0,%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "larl") - (set_attr "z10prop" "z10_super")]) - -; clhrl, clghrl -(define_insn "*cmp<GPR:mode>_ccu_zerohi_rldi" - [(set (reg CC_REGNUM) - (compare (zero_extend:GPR (mem:HI (match_operand:DI 1 - "larl_operand" "X"))) - (match_operand:GPR 0 "register_operand" "d")))] - "s390_match_ccmode(insn, CCURmode) && TARGET_Z10" - "cl<g>hrl\t%0,%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "larl") - (set_attr "z10prop" "z10_super")]) - -(define_insn "*cmpdi_ccu_zero" - [(set (reg CC_REGNUM) - (compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" - "d,RT,b")) - (match_operand:DI 0 "register_operand" "d, d,d")))] - "s390_match_ccmode (insn, CCURmode) && TARGET_ZARCH" - "@ - clgfr\t%0,%1 - clgf\t%0,%1 - clgfrl\t%0,%1" - [(set_attr "op_type" "RRE,RXY,RIL") - (set_attr "cpu_facility" "*,*,z10") - (set_attr "type" "*,*,larl") - (set_attr "z10prop" "z10_super_c,z10_super_E1,z10_super")]) - -(define_insn "*cmpdi_ccu" - [(set (reg CC_REGNUM) - (compare (match_operand:DI 0 "nonimmediate_operand" - "d, d,d,Q, d, Q,BQ") - (match_operand:DI 1 "general_operand" - "d,Op,b,D,RT,BQ,Q")))] - "s390_match_ccmode (insn, CCUmode) && TARGET_ZARCH" - "@ - clgr\t%0,%1 - clgfi\t%0,%1 - clgrl\t%0,%1 - clghsi\t%0,%x1 - clg\t%0,%1 - # - #" - [(set_attr "op_type" "RRE,RIL,RIL,SIL,RXY,SS,SS") - (set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*") - (set_attr "type" "*,*,larl,*,*,*,*") - (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,*,*")]) - -(define_insn "*cmpsi_ccu" - [(set (reg CC_REGNUM) - (compare (match_operand:SI 0 "nonimmediate_operand" "d, d,d,Q,d,d, Q,BQ") - (match_operand:SI 1 "general_operand" "d,Os,b,D,R,T,BQ, Q")))] - "s390_match_ccmode (insn, CCUmode)" - "@ - clr\t%0,%1 - clfi\t%0,%o1 - clrl\t%0,%1 - clfhsi\t%0,%x1 - cl\t%0,%1 - cly\t%0,%1 - # - #" - [(set_attr "op_type" "RR,RIL,RIL,SIL,RX,RXY,SS,SS") - (set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*,*") - (set_attr "type" "*,*,larl,*,*,*,*,*") - (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,z10_super,*,*")]) - -(define_insn "*cmphi_ccu" - [(set (reg CC_REGNUM) - (compare (match_operand:HI 0 "nonimmediate_operand" "d,d,Q,Q,BQ") - (match_operand:HI 1 "general_operand" "Q,S,D,BQ,Q")))] - "s390_match_ccmode (insn, CCUmode) - && !register_operand (operands[1], HImode)" - "@ - clm\t%0,3,%S1 - clmy\t%0,3,%S1 - clhhsi\t%0,%1 - # - #" - [(set_attr "op_type" "RS,RSY,SIL,SS,SS") - (set_attr "cpu_facility" "*,*,z10,*,*") - (set_attr "z10prop" "*,*,z10_super,*,*")]) - -(define_insn "*cmpqi_ccu" - [(set (reg CC_REGNUM) - (compare (match_operand:QI 0 "nonimmediate_operand" "d,d,Q,S,Q,BQ") - (match_operand:QI 1 "general_operand" "Q,S,n,n,BQ,Q")))] - "s390_match_ccmode (insn, CCUmode) - && !register_operand (operands[1], QImode)" - "@ - clm\t%0,1,%S1 - clmy\t%0,1,%S1 - cli\t%S0,%b1 - cliy\t%S0,%b1 - # - #" - [(set_attr "op_type" "RS,RSY,SI,SIY,SS,SS") - (set_attr "z10prop" "*,*,z10_super,z10_super,*,*")]) - - -; Block compare (CLC) instruction patterns. - -(define_insn "*clc" - [(set (reg CC_REGNUM) - (compare (match_operand:BLK 0 "memory_operand" "Q") - (match_operand:BLK 1 "memory_operand" "Q"))) - (use (match_operand 2 "const_int_operand" "n"))] - "s390_match_ccmode (insn, CCUmode) - && INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256" - "clc\t%O0(%2,%R0),%S1" - [(set_attr "op_type" "SS")]) - -(define_split - [(set (reg CC_REGNUM) - (compare (match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "")))] - "reload_completed - && s390_match_ccmode (insn, CCUmode) - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) > 0" - [(parallel - [(set (match_dup 0) (match_dup 1)) - (use (match_dup 2))])] -{ - operands[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))); - operands[0] = adjust_address (operands[0], BLKmode, 0); - operands[1] = adjust_address (operands[1], BLKmode, 0); - - operands[1] = gen_rtx_COMPARE (GET_MODE (SET_DEST (PATTERN (curr_insn))), - operands[0], operands[1]); - operands[0] = SET_DEST (PATTERN (curr_insn)); -}) - - -; (TF|DF|SF|TD|DD|SD) instructions - -; ltxbr, ltdbr, ltebr, ltxtr, ltdtr -(define_insn "*cmp<mode>_ccs_0" - [(set (reg CC_REGNUM) - (compare (match_operand:FP 0 "register_operand" "f") - (match_operand:FP 1 "const0_operand" "")))] - "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT" - "lt<xde><bt>r\t%0,%0" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; cxtr, cxbr, cdtr, cdbr, cebr, cdb, ceb -(define_insn "*cmp<mode>_ccs" - [(set (reg CC_REGNUM) - (compare (match_operand:FP 0 "register_operand" "f,f") - (match_operand:FP 1 "general_operand" "f,<Rf>")))] - "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT" - "@ - c<xde><bt>r\t%0,%1 - c<xde>b\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fsimp<mode>")]) - - -; Compare and Branch instructions - -; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr -; The following instructions do a complementary access of their second -; operand (z01 only): crj_c, cgrjc, cr, cgr -(define_insn "*cmp_and_br_signed_<mode>" - [(set (pc) - (if_then_else (match_operator 0 "s390_signed_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,C")]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH" -{ - if (get_attr_length (insn) == 6) - return which_alternative ? - "c<g>ij%C0\t%1,%c2,%l3" : "c<g>rj%C0\t%1,%2,%l3"; - else - return which_alternative ? - "c<g>fi\t%1,%c2\;jg%C0\t%l3" : "c<g>r\t%1,%2\;jg%C0\t%l3"; -} - [(set_attr "op_type" "RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) - (const_int 6) (const_int 12)))]) ; 8 byte for cr/jg - ; 10 byte for cgr/jg - -; clij, clgij, clrj, clgrj, clfi, clgfi, clr, clgr -; The following instructions do a complementary access of their second -; operand (z10 only): clrj, clgrj, clr, clgr -(define_insn "*cmp_and_br_unsigned_<mode>" - [(set (pc) - (if_then_else (match_operator 0 "s390_unsigned_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,I")]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH" -{ - if (get_attr_length (insn) == 6) - return which_alternative ? - "cl<g>ij%C0\t%1,%b2,%l3" : "cl<g>rj%C0\t%1,%2,%l3"; - else - return which_alternative ? - "cl<g>fi\t%1,%b2\;jg%C0\t%l3" : "cl<g>r\t%1,%2\;jg%C0\t%l3"; -} - [(set_attr "op_type" "RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) - (const_int 6) (const_int 12)))]) ; 8 byte for clr/jg - ; 10 byte for clgr/jg - -; And now the same two patterns as above but with a negated CC mask. - -; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr -; The following instructions do a complementary access of their second -; operand (z01 only): crj_c, cgrjc, cr, cgr -(define_insn "*icmp_and_br_signed_<mode>" - [(set (pc) - (if_then_else (match_operator 0 "s390_signed_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,C")]) - (pc) - (label_ref (match_operand 3 "" "")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH" -{ - if (get_attr_length (insn) == 6) - return which_alternative ? - "c<g>ij%D0\t%1,%c2,%l3" : "c<g>rj%D0\t%1,%2,%l3"; - else - return which_alternative ? - "c<g>fi\t%1,%c2\;jg%D0\t%l3" : "c<g>r\t%1,%2\;jg%D0\t%l3"; -} - [(set_attr "op_type" "RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) - (const_int 6) (const_int 12)))]) ; 8 byte for cr/jg - ; 10 byte for cgr/jg - -; clij, clgij, clrj, clgrj, clfi, clgfi, clr, clgr -; The following instructions do a complementary access of their second -; operand (z10 only): clrj, clgrj, clr, clgr -(define_insn "*icmp_and_br_unsigned_<mode>" - [(set (pc) - (if_then_else (match_operator 0 "s390_unsigned_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,I")]) - (pc) - (label_ref (match_operand 3 "" "")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 && !TARGET_AVOID_CMP_AND_BRANCH" -{ - if (get_attr_length (insn) == 6) - return which_alternative ? - "cl<g>ij%D0\t%1,%b2,%l3" : "cl<g>rj%D0\t%1,%2,%l3"; - else - return which_alternative ? - "cl<g>fi\t%1,%b2\;jg%D0\t%l3" : "cl<g>r\t%1,%2\;jg%D0\t%l3"; -} - [(set_attr "op_type" "RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) - (const_int 6) (const_int 12)))]) ; 8 byte for clr/jg - ; 10 byte for clgr/jg - -;; -;;- Move instructions. -;; - -; -; movti instruction pattern(s). -; - -(define_insn "movti" - [(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o") - (match_operand:TI 1 "general_operand" "QS,d,dPRT,d"))] - "TARGET_ZARCH" - "@ - lmg\t%0,%N0,%S1 - stmg\t%1,%N1,%S0 - # - #" - [(set_attr "op_type" "RSY,RSY,*,*") - (set_attr "type" "lm,stm,*,*")]) - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "general_operand" ""))] - "TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], TImode, 0)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 0, 0, TImode); - operands[3] = operand_subword (operands[0], 1, 0, TImode); - operands[4] = operand_subword (operands[1], 0, 0, TImode); - operands[5] = operand_subword (operands[1], 1, 0, TImode); -}) - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "general_operand" ""))] - "TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], TImode, 1)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 1, 0, TImode); - operands[3] = operand_subword (operands[0], 0, 0, TImode); - operands[4] = operand_subword (operands[1], 1, 0, TImode); - operands[5] = operand_subword (operands[1], 0, 0, TImode); -}) - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (match_operand:TI 1 "memory_operand" ""))] - "TARGET_ZARCH && reload_completed - && !s_operand (operands[1], VOIDmode)" - [(set (match_dup 0) (match_dup 1))] -{ - rtx addr = operand_subword (operands[0], 1, 0, TImode); - addr = gen_lowpart (Pmode, addr); - s390_load_address (addr, XEXP (operands[1], 0)); - operands[1] = replace_equiv_address (operands[1], addr); -}) - - -; -; Patterns used for secondary reloads -; - -; z10 provides move instructions accepting larl memory operands. -; Unfortunately there is no such variant for QI, TI and FP mode moves. -; These patterns are also used for unaligned SI and DI accesses. - -(define_expand "reload<INTALL:mode><P:mode>_tomem_z10" - [(parallel [(match_operand:INTALL 0 "memory_operand" "") - (match_operand:INTALL 1 "register_operand" "=d") - (match_operand:P 2 "register_operand" "=&a")])] - "TARGET_Z10" -{ - s390_reload_symref_address (operands[1], operands[0], operands[2], 1); - DONE; -}) - -(define_expand "reload<INTALL:mode><P:mode>_toreg_z10" - [(parallel [(match_operand:INTALL 0 "register_operand" "=d") - (match_operand:INTALL 1 "memory_operand" "") - (match_operand:P 2 "register_operand" "=a")])] - "TARGET_Z10" -{ - s390_reload_symref_address (operands[0], operands[1], operands[2], 0); - DONE; -}) - -(define_expand "reload<FPALL:mode><P:mode>_tomem_z10" - [(parallel [(match_operand:FPALL 0 "memory_operand" "") - (match_operand:FPALL 1 "register_operand" "=d") - (match_operand:P 2 "register_operand" "=&a")])] - "TARGET_Z10" -{ - s390_reload_symref_address (operands[1], operands[0], operands[2], 1); - DONE; -}) - -(define_expand "reload<FPALL:mode><P:mode>_toreg_z10" - [(parallel [(match_operand:FPALL 0 "register_operand" "=d") - (match_operand:FPALL 1 "memory_operand" "") - (match_operand:P 2 "register_operand" "=a")])] - "TARGET_Z10" -{ - s390_reload_symref_address (operands[0], operands[1], operands[2], 0); - DONE; -}) - -(define_expand "reload<P:mode>_larl_odd_addend_z10" - [(parallel [(match_operand:P 0 "register_operand" "=d") - (match_operand:P 1 "larl_operand" "") - (match_operand:P 2 "register_operand" "=a")])] - "TARGET_Z10" -{ - s390_reload_larl_operand (operands[0], operands[1], operands[2]); - DONE; -}) - -; Handles loading a PLUS (load address) expression - -(define_expand "reload<mode>_plus" - [(parallel [(match_operand:P 0 "register_operand" "=a") - (match_operand:P 1 "s390_plus_operand" "") - (match_operand:P 2 "register_operand" "=&a")])] - "" -{ - s390_expand_plus_operand (operands[0], operands[1], operands[2]); - DONE; -}) - -; Handles assessing a non-offsetable memory address - -(define_expand "reload<mode>_nonoffmem_in" - [(parallel [(match_operand 0 "register_operand" "") - (match_operand 1 "" "") - (match_operand:P 2 "register_operand" "=&a")])] - "" -{ - gcc_assert (MEM_P (operands[1])); - s390_load_address (operands[2], find_replacement (&XEXP (operands[1], 0))); - operands[1] = replace_equiv_address (operands[1], operands[2]); - emit_move_insn (operands[0], operands[1]); - DONE; -}) - -(define_expand "reload<mode>_nonoffmem_out" - [(parallel [(match_operand 0 "" "") - (match_operand 1 "register_operand" "") - (match_operand:P 2 "register_operand" "=&a")])] - "" -{ - gcc_assert (MEM_P (operands[0])); - s390_load_address (operands[2], find_replacement (&XEXP (operands[0], 0))); - operands[0] = replace_equiv_address (operands[0], operands[2]); - emit_move_insn (operands[0], operands[1]); - DONE; -}) - -(define_expand "reload<mode>_PIC_addr" - [(parallel [(match_operand 0 "register_operand" "=d") - (match_operand 1 "larl_operand" "") - (match_operand:P 2 "register_operand" "=a")])] - "" -{ - rtx new_rtx = legitimize_pic_address (operands[1], operands[2]); - emit_move_insn (operands[0], new_rtx); -}) - -; -; movdi instruction pattern(s). -; - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" -{ - /* Handle symbolic constants. */ - if (TARGET_64BIT - && (SYMBOLIC_CONST (operands[1]) - || (GET_CODE (operands[1]) == PLUS - && XEXP (operands[1], 0) == pic_offset_table_rtx - && SYMBOLIC_CONST (XEXP (operands[1], 1))))) - emit_symbolic_move (operands); -}) - -(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" - [(set_attr "op_type" "RIL") - (set_attr "type" "larl") - (set_attr "z10prop" "z10_super_A1")]) - -(define_insn "*movdi_64" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=d,d,d,d,d,d,d,d,f,d,d,d,d,d, - RT,!*f,!*f,!*f,!R,!T,b,Q,d,t,Q,t") - (match_operand:DI 1 "general_operand" - "K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,d,f,L,b,d,RT, - d,*f,R,T,*f,*f,d,K,t,d,t,Q"))] - "TARGET_ZARCH" - "@ - lghi\t%0,%h1 - llihh\t%0,%i1 - llihl\t%0,%i1 - llilh\t%0,%i1 - llill\t%0,%i1 - lgfi\t%0,%1 - llihf\t%0,%k1 - llilf\t%0,%k1 - ldgr\t%0,%1 - lgdr\t%0,%1 - lay\t%0,%a1 - lgrl\t%0,%1 - 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 - stgrl\t%1,%0 - mvghi\t%0,%1 - # - # - stam\t%1,%N1,%S0 - lam\t%0,%N0,%S1" - [(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RXY,RIL,RRE,RXY, - RXY,RR,RX,RXY,RX,RXY,RIL,SIL,*,*,RS,RS") - (set_attr "type" "*,*,*,*,*,*,*,*,floaddf,floaddf,la,larl,lr,load,store, - floaddf,floaddf,floaddf,fstoredf,fstoredf,larl,*,*,*, - *,*") - (set_attr "cpu_facility" "*,*,*,*,*,extimm,extimm,extimm,dfp,dfp,longdisp, - z10,*,*,*,*,*,longdisp,*,longdisp, - z10,z10,*,*,*,*") - (set_attr "z10prop" "z10_fwd_A1, - z10_fwd_E1, - z10_fwd_E1, - z10_fwd_E1, - z10_fwd_E1, - z10_fwd_A1, - z10_fwd_E1, - z10_fwd_E1, - *, - *, - z10_fwd_A1, - z10_fwd_A3, - z10_fr_E1, - z10_fwd_A3, - z10_rec, - *, - *, - *, - *, - *, - z10_rec, - z10_super, - *, - *, - *, - *") -]) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "register_operand" ""))] - "TARGET_ZARCH && ACCESS_REG_P (operands[1])" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32))) - (set (strict_low_part (match_dup 2)) (match_dup 4))] - "operands[2] = gen_lowpart (SImode, operands[0]); - s390_split_access_reg (operands[1], &operands[4], &operands[3]);") - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "register_operand" ""))] - "TARGET_ZARCH && ACCESS_REG_P (operands[0]) - && dead_or_set_p (insn, operands[1])" - [(set (match_dup 3) (match_dup 2)) - (set (match_dup 1) (lshiftrt:DI (match_dup 1) (const_int 32))) - (set (match_dup 4) (match_dup 2))] - "operands[2] = gen_lowpart (SImode, operands[1]); - s390_split_access_reg (operands[0], &operands[3], &operands[4]);") - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "register_operand" ""))] - "TARGET_ZARCH && ACCESS_REG_P (operands[0]) - && !dead_or_set_p (insn, operands[1])" - [(set (match_dup 3) (match_dup 2)) - (set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32))) - (set (match_dup 4) (match_dup 2)) - (set (match_dup 1) (rotate:DI (match_dup 1) (const_int 32)))] - "operands[2] = gen_lowpart (SImode, operands[1]); - s390_split_access_reg (operands[0], &operands[3], &operands[4]);") - -(define_insn "*movdi_31" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=d,d,Q,S,d ,o,!*f,!*f,!*f,!R,!T,d") - (match_operand:DI 1 "general_operand" - " Q,S,d,d,dPRT,d, *f, R, T,*f,*f,b"))] - "!TARGET_ZARCH" - "@ - lm\t%0,%N0,%S1 - lmy\t%0,%N0,%S1 - stm\t%1,%N1,%S0 - stmy\t%1,%N1,%S0 - # - # - ldr\t%0,%1 - ld\t%0,%1 - ldy\t%0,%1 - std\t%1,%0 - stdy\t%1,%0 - #" - [(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RX,RXY,*") - (set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fstoredf,fstoredf,*") - (set_attr "cpu_facility" "*,*,*,*,*,*,*,*,*,*,*,z10")]) - -; For a load from a symbol ref we can use one of the target registers -; together with larl to load the address. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "memory_operand" ""))] - "!TARGET_ZARCH && reload_completed && TARGET_Z10 - && larl_operand (XEXP (operands[1], 0), SImode)" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (match_dup 1))] -{ - operands[2] = operand_subword (operands[0], 1, 0, DImode); - operands[3] = XEXP (operands[1], 0); - operands[1] = replace_equiv_address (operands[1], operands[2]); -}) - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "!TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], DImode, 0)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 0, 0, DImode); - operands[3] = operand_subword (operands[0], 1, 0, DImode); - operands[4] = operand_subword (operands[1], 0, 0, DImode); - operands[5] = operand_subword (operands[1], 1, 0, DImode); -}) - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "!TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], DImode, 1)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 1, 0, DImode); - operands[3] = operand_subword (operands[0], 0, 0, DImode); - operands[4] = operand_subword (operands[1], 1, 0, DImode); - operands[5] = operand_subword (operands[1], 0, 0, DImode); -}) - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "memory_operand" ""))] - "!TARGET_ZARCH && reload_completed - && !FP_REG_P (operands[0]) - && !s_operand (operands[1], VOIDmode)" - [(set (match_dup 0) (match_dup 1))] -{ - rtx addr = operand_subword (operands[0], 1, 0, DImode); - s390_load_address (addr, XEXP (operands[1], 0)); - operands[1] = replace_equiv_address (operands[1], addr); -}) - -(define_peephole2 - [(set (match_operand:DI 0 "register_operand" "") - (mem:DI (match_operand 1 "address_operand" "")))] - "TARGET_ZARCH - && !FP_REG_P (operands[0]) - && GET_CODE (operands[1]) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (operands[1]) - && get_pool_mode (operands[1]) == DImode - && legitimate_reload_constant_p (get_pool_constant (operands[1]))" - [(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" "ZQZR,ZSZT"))] - "TARGET_64BIT" - "@ - la\t%0,%a1 - lay\t%0,%a1" - [(set_attr "op_type" "RX,RXY") - (set_attr "type" "la") - (set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")]) - -(define_peephole2 - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (match_operand:QI 1 "address_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_64BIT - && preferred_la_operand_p (operands[1], const0_rtx)" - [(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 CC_REGNUM))])] - "TARGET_64BIT - && !reg_overlap_mentioned_p (operands[0], operands[2]) - && preferred_la_operand_p (operands[1], operands[2])" - [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))] - "") - -; -; movsi instruction pattern(s). -; - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" -{ - /* Handle symbolic constants. */ - if (!TARGET_64BIT - && (SYMBOLIC_CONST (operands[1]) - || (GET_CODE (operands[1]) == PLUS - && XEXP (operands[1], 0) == pic_offset_table_rtx - && SYMBOLIC_CONST (XEXP(operands[1], 1))))) - emit_symbolic_move (operands); -}) - -(define_insn "*movsi_larl" - [(set (match_operand:SI 0 "register_operand" "=d") - (match_operand:SI 1 "larl_operand" "X"))] - "!TARGET_64BIT && TARGET_CPU_ZARCH - && !FP_REG_P (operands[0])" - "larl\t%0,%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "larl") - (set_attr "z10prop" "z10_fwd_A1")]) - -(define_insn "*movsi_zarch" - [(set (match_operand:SI 0 "nonimmediate_operand" - "=d,d,d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,b,Q,t") - (match_operand:SI 1 "general_operand" - "K,N0HS0,N1HS0,Os,L,b,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,d,K,Q"))] - "TARGET_ZARCH" - "@ - lhi\t%0,%h1 - llilh\t%0,%i1 - llill\t%0,%i1 - iilf\t%0,%o1 - lay\t%0,%a1 - lrl\t%0,%1 - 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 - ear\t%0,%1 - sar\t%0,%1 - stam\t%1,%1,%S0 - strl\t%1,%0 - mvhi\t%0,%1 - lam\t%0,%0,%S1" - [(set_attr "op_type" "RI,RI,RI,RIL,RXY,RIL,RR,RX,RXY,RX,RXY, - RR,RX,RXY,RX,RXY,RRE,RRE,RS,RIL,SIL,RS") - (set_attr "type" "*, - *, - *, - *, - la, - larl, - lr, - load, - load, - store, - store, - floadsf, - floadsf, - floadsf, - fstoresf, - fstoresf, - *, - *, - *, - larl, - *, - *") - (set_attr "cpu_facility" "*,*,*,extimm,longdisp,z10,*,*,longdisp,*,longdisp, - *,*,longdisp,*,longdisp,*,*,*,z10,z10,*") - (set_attr "z10prop" "z10_fwd_A1, - z10_fwd_E1, - z10_fwd_E1, - z10_fwd_A1, - z10_fwd_A1, - z10_fwd_A3, - z10_fr_E1, - z10_fwd_A3, - z10_fwd_A3, - z10_rec, - z10_rec, - *, - *, - *, - *, - *, - z10_super_E1, - z10_super, - *, - z10_rec, - z10_super, - *")]) - -(define_insn "*movsi_esa" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,d,t,Q,t") - (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,t,d,t,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 - ear\t%0,%1 - sar\t%0,%1 - stam\t%1,%1,%S0 - lam\t%0,%0,%S1" - [(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,RRE,RRE,RS,RS") - (set_attr "type" "*,lr,load,store,floadsf,floadsf,fstoresf,*,*,*,*") - (set_attr "z10prop" "z10_fwd_A1, - z10_fr_E1, - z10_fwd_A3, - z10_rec, - *, - *, - *, - z10_super_E1, - z10_super, - *, - *") -]) - -(define_peephole2 - [(set (match_operand:SI 0 "register_operand" "") - (mem:SI (match_operand 1 "address_operand" "")))] - "!FP_REG_P (operands[0]) - && GET_CODE (operands[1]) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (operands[1]) - && get_pool_mode (operands[1]) == SImode - && legitimate_reload_constant_p (get_pool_constant (operands[1]))" - [(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" "ZQZR,ZSZT"))] - "!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") - (set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")]) - -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:QI 1 "address_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "!TARGET_64BIT - && preferred_la_operand_p (operands[1], const0_rtx)" - [(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 CC_REGNUM))])] - "!TARGET_64BIT - && !reg_overlap_mentioned_p (operands[0], operands[2]) - && preferred_la_operand_p (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" "ZQZR,ZSZT") - (const_int 2147483647)))] - "!TARGET_64BIT" - "@ - la\t%0,%a1 - lay\t%0,%a1" - [(set_attr "op_type" "RX,RXY") - (set_attr "type" "la") - (set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")]) - -(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 CC_REGNUM))] - "!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" "ZQZR,ZSZT")) - (use (const_int 0))] - "!TARGET_64BIT" - "@ - la\t%0,%a1 - lay\t%0,%a1" - [(set_attr "op_type" "RX") - (set_attr "type" "la") - (set_attr "z10prop" "z10_fwd_A1,z10_fwd_A1")]) - -; -; movhi instruction pattern(s). -; - -(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 && can_create_pseudo_p () - && register_operand (operands[0], VOIDmode) - && GET_CODE (operands[1]) == MEM) - { - 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,d,R,T,b,Q") - (match_operand:HI 1 "general_operand" " d,n,R,T,b,d,d,d,K"))] - "" - "@ - lr\t%0,%1 - lhi\t%0,%h1 - lh\t%0,%1 - lhy\t%0,%1 - lhrl\t%0,%1 - sth\t%1,%0 - sthy\t%1,%0 - sthrl\t%1,%0 - mvhhi\t%0,%1" - [(set_attr "op_type" "RR,RI,RX,RXY,RIL,RX,RXY,RIL,SIL") - (set_attr "type" "lr,*,*,*,larl,store,store,store,*") - (set_attr "cpu_facility" "*,*,*,*,z10,*,*,z10,z10") - (set_attr "z10prop" "z10_fr_E1, - z10_fwd_A1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_rec, - z10_rec, - z10_rec, - z10_super")]) - -(define_peephole2 - [(set (match_operand:HI 0 "register_operand" "") - (mem:HI (match_operand 1 "address_operand" "")))] - "GET_CODE (operands[1]) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (operands[1]) - && get_pool_mode (operands[1]) == HImode - && GET_CODE (get_pool_constant (operands[1])) == CONST_INT" - [(set (match_dup 0) (match_dup 2))] - "operands[2] = get_pool_constant (operands[1]);") - -; -; movqi instruction pattern(s). -; - -(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 && can_create_pseudo_p () - && register_operand (operands[0], VOIDmode) - && GET_CODE (operands[1]) == MEM) - { - rtx tmp = gen_reg_rtx (DImode); - rtx ext = gen_rtx_ZERO_EXTEND (DImode, 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,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 - icy\t%0,%1 - stc\t%1,%0 - stcy\t%1,%0 - mvi\t%S0,%b1 - mviy\t%S0,%b1 - #" - [(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SI,SIY,SS") - (set_attr "type" "lr,*,*,*,store,store,store,store,*") - (set_attr "z10prop" "z10_fr_E1, - z10_fwd_A1, - z10_super_E1, - z10_super_E1, - z10_rec, - z10_rec, - z10_super, - z10_super, - *")]) - -(define_peephole2 - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (mem:QI (match_operand 1 "address_operand" "")))] - "GET_CODE (operands[1]) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (operands[1]) - && get_pool_mode (operands[1]) == QImode - && GET_CODE (get_pool_constant (operands[1])) == CONST_INT" - [(set (match_dup 0) (match_dup 2))] - "operands[2] = get_pool_constant (operands[1]);") - -; -; movstrictqi instruction pattern(s). -; - -(define_insn "*movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d,d")) - (match_operand:QI 1 "memory_operand" "R,T"))] - "" - "@ - ic\t%0,%1 - icy\t%0,%1" - [(set_attr "op_type" "RX,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -; -; movstricthi instruction pattern(s). -; - -(define_insn "*movstricthi" - [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d,d")) - (match_operand:HI 1 "memory_operand" "Q,S")) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - icm\t%0,3,%S1 - icmy\t%0,3,%S1" - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -; -; movstrictsi instruction pattern(s). -; - -(define_insn "movstrictsi" - [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d,d")) - (match_operand:SI 1 "general_operand" "d,R,T,t"))] - "TARGET_ZARCH" - "@ - lr\t%0,%1 - l\t%0,%1 - ly\t%0,%1 - ear\t%0,%1" - [(set_attr "op_type" "RR,RX,RXY,RRE") - (set_attr "type" "lr,load,load,*") - (set_attr "z10prop" "z10_fr_E1,z10_fwd_A3,z10_fwd_A3,z10_super_E1")]) - -; -; mov(tf|td) instruction pattern(s). -; - -(define_expand "mov<mode>" - [(set (match_operand:TD_TF 0 "nonimmediate_operand" "") - (match_operand:TD_TF 1 "general_operand" ""))] - "" - "") - -(define_insn "*mov<mode>_64" - [(set (match_operand:TD_TF 0 "nonimmediate_operand" "=f,f,f,o, d,QS, d,o") - (match_operand:TD_TF 1 "general_operand" " G,f,o,f,QS, d,dRT,d"))] - "TARGET_ZARCH" - "@ - lzxr\t%0 - lxr\t%0,%1 - # - # - lmg\t%0,%N0,%S1 - stmg\t%1,%N1,%S0 - # - #" - [(set_attr "op_type" "RRE,RRE,*,*,RSY,RSY,*,*") - (set_attr "type" "fsimptf,fsimptf,*,*,lm,stm,*,*") - (set_attr "cpu_facility" "z196,*,*,*,*,*,*,*")]) - -(define_insn "*mov<mode>_31" - [(set (match_operand:TD_TF 0 "nonimmediate_operand" "=f,f,f,o") - (match_operand:TD_TF 1 "general_operand" " G,f,o,f"))] - "!TARGET_ZARCH" - "@ - lzxr\t%0 - lxr\t%0,%1 - # - #" - [(set_attr "op_type" "RRE,RRE,*,*") - (set_attr "type" "fsimptf,fsimptf,*,*") - (set_attr "cpu_facility" "z196,*,*,*")]) - -; TFmode in GPRs splitters - -(define_split - [(set (match_operand:TD_TF 0 "nonimmediate_operand" "") - (match_operand:TD_TF 1 "general_operand" ""))] - "TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], <MODE>mode, 0)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 0, 0, <MODE>mode); - operands[3] = operand_subword (operands[0], 1, 0, <MODE>mode); - operands[4] = operand_subword (operands[1], 0, 0, <MODE>mode); - operands[5] = operand_subword (operands[1], 1, 0, <MODE>mode); -}) - -(define_split - [(set (match_operand:TD_TF 0 "nonimmediate_operand" "") - (match_operand:TD_TF 1 "general_operand" ""))] - "TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], <MODE>mode, 1)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 1, 0, <MODE>mode); - operands[3] = operand_subword (operands[0], 0, 0, <MODE>mode); - operands[4] = operand_subword (operands[1], 1, 0, <MODE>mode); - operands[5] = operand_subword (operands[1], 0, 0, <MODE>mode); -}) - -(define_split - [(set (match_operand:TD_TF 0 "register_operand" "") - (match_operand:TD_TF 1 "memory_operand" ""))] - "TARGET_ZARCH && reload_completed - && !FP_REG_P (operands[0]) - && !s_operand (operands[1], VOIDmode)" - [(set (match_dup 0) (match_dup 1))] -{ - rtx addr = operand_subword (operands[0], 1, 0, <MODE>mode); - addr = gen_lowpart (Pmode, addr); - s390_load_address (addr, XEXP (operands[1], 0)); - operands[1] = replace_equiv_address (operands[1], addr); -}) - -; TFmode in BFPs splitters - -(define_split - [(set (match_operand:TD_TF 0 "register_operand" "") - (match_operand:TD_TF 1 "memory_operand" ""))] - "reload_completed && offsettable_memref_p (operands[1]) - && FP_REG_P (operands[0])" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = simplify_gen_subreg (<HALF_TMODE>mode, operands[0], - <MODE>mode, 0); - operands[3] = simplify_gen_subreg (<HALF_TMODE>mode, operands[0], - <MODE>mode, 8); - operands[4] = adjust_address_nv (operands[1], <HALF_TMODE>mode, 0); - operands[5] = adjust_address_nv (operands[1], <HALF_TMODE>mode, 8); -}) - -(define_split - [(set (match_operand:TD_TF 0 "memory_operand" "") - (match_operand:TD_TF 1 "register_operand" ""))] - "reload_completed && offsettable_memref_p (operands[0]) - && FP_REG_P (operands[1])" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = adjust_address_nv (operands[0], <HALF_TMODE>mode, 0); - operands[3] = adjust_address_nv (operands[0], <HALF_TMODE>mode, 8); - operands[4] = simplify_gen_subreg (<HALF_TMODE>mode, operands[1], - <MODE>mode, 0); - operands[5] = simplify_gen_subreg (<HALF_TMODE>mode, operands[1], - <MODE>mode, 8); -}) - -; -; mov(df|dd) instruction pattern(s). -; - -(define_expand "mov<mode>" - [(set (match_operand:DD_DF 0 "nonimmediate_operand" "") - (match_operand:DD_DF 1 "general_operand" ""))] - "" - "") - -(define_insn "*mov<mode>_64dfp" - [(set (match_operand:DD_DF 0 "nonimmediate_operand" - "=f,f,f,d,f,f,R,T,d,d, d,RT") - (match_operand:DD_DF 1 "general_operand" - " G,f,d,f,R,T,f,f,G,d,RT, d"))] - "TARGET_DFP" - "@ - lzdr\t%0 - ldr\t%0,%1 - ldgr\t%0,%1 - lgdr\t%0,%1 - ld\t%0,%1 - ldy\t%0,%1 - std\t%1,%0 - stdy\t%1,%0 - lghi\t%0,0 - lgr\t%0,%1 - lg\t%0,%1 - stg\t%1,%0" - [(set_attr "op_type" "RRE,RR,RRE,RRE,RX,RXY,RX,RXY,RI,RRE,RXY,RXY") - (set_attr "type" "fsimpdf,floaddf,floaddf,floaddf,floaddf,floaddf, - fstoredf,fstoredf,*,lr,load,store") - (set_attr "z10prop" "*,*,*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_rec") - (set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")]) - -(define_insn "*mov<mode>_64" - [(set (match_operand:DD_DF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d, d,RT") - (match_operand:DD_DF 1 "general_operand" " G,f,R,T,f,f,G,d,RT, d"))] - "TARGET_ZARCH" - "@ - lzdr\t%0 - ldr\t%0,%1 - ld\t%0,%1 - ldy\t%0,%1 - std\t%1,%0 - stdy\t%1,%0 - lghi\t%0,0 - lgr\t%0,%1 - lg\t%0,%1 - stg\t%1,%0" - [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RI,RRE,RXY,RXY") - (set_attr "type" "fsimpdf,fload<mode>,fload<mode>,fload<mode>, - fstore<mode>,fstore<mode>,*,lr,load,store") - (set_attr "z10prop" "*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_rec") - (set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*")]) - -(define_insn "*mov<mode>_31" - [(set (match_operand:DD_DF 0 "nonimmediate_operand" - "=f,f,f,f,R,T,d,d,Q,S, d,o") - (match_operand:DD_DF 1 "general_operand" - " G,f,R,T,f,f,Q,S,d,d,dPRT,d"))] - "!TARGET_ZARCH" - "@ - lzdr\t%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,%S1 - lmy\t%0,%N0,%S1 - stm\t%1,%N1,%S0 - stmy\t%1,%N1,%S0 - # - #" - [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RS,RSY,RS,RSY,*,*") - (set_attr "type" "fsimpdf,fload<mode>,fload<mode>,fload<mode>, - fstore<mode>,fstore<mode>,lm,lm,stm,stm,*,*") - (set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")]) - -(define_split - [(set (match_operand:DD_DF 0 "nonimmediate_operand" "") - (match_operand:DD_DF 1 "general_operand" ""))] - "!TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], <MODE>mode, 0)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 0, 0, <MODE>mode); - operands[3] = operand_subword (operands[0], 1, 0, <MODE>mode); - operands[4] = operand_subword (operands[1], 0, 0, <MODE>mode); - operands[5] = operand_subword (operands[1], 1, 0, <MODE>mode); -}) - -(define_split - [(set (match_operand:DD_DF 0 "nonimmediate_operand" "") - (match_operand:DD_DF 1 "general_operand" ""))] - "!TARGET_ZARCH && reload_completed - && s390_split_ok_p (operands[0], operands[1], <MODE>mode, 1)" - [(set (match_dup 2) (match_dup 4)) - (set (match_dup 3) (match_dup 5))] -{ - operands[2] = operand_subword (operands[0], 1, 0, <MODE>mode); - operands[3] = operand_subword (operands[0], 0, 0, <MODE>mode); - operands[4] = operand_subword (operands[1], 1, 0, <MODE>mode); - operands[5] = operand_subword (operands[1], 0, 0, <MODE>mode); -}) - -(define_split - [(set (match_operand:DD_DF 0 "register_operand" "") - (match_operand:DD_DF 1 "memory_operand" ""))] - "!TARGET_ZARCH && reload_completed - && !FP_REG_P (operands[0]) - && !s_operand (operands[1], VOIDmode)" - [(set (match_dup 0) (match_dup 1))] -{ - rtx addr = operand_subword (operands[0], 1, 0, <MODE>mode); - s390_load_address (addr, XEXP (operands[1], 0)); - operands[1] = replace_equiv_address (operands[1], addr); -}) - -; -; mov(sf|sd) instruction pattern(s). -; - -(define_insn "mov<mode>" - [(set (match_operand:SD_SF 0 "nonimmediate_operand" - "=f,f,f,f,R,T,d,d,d,d,R,T") - (match_operand:SD_SF 1 "general_operand" - " G,f,R,T,f,f,G,d,R,T,d,d"))] - "" - "@ - lzer\t%0 - ler\t%0,%1 - le\t%0,%1 - ley\t%0,%1 - ste\t%1,%0 - stey\t%1,%0 - lhi\t%0,0 - lr\t%0,%1 - l\t%0,%1 - ly\t%0,%1 - st\t%1,%0 - sty\t%1,%0" - [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RI,RR,RX,RXY,RX,RXY") - (set_attr "type" "fsimpsf,fload<mode>,fload<mode>,fload<mode>, - fstore<mode>,fstore<mode>,*,lr,load,load,store,store") - (set_attr "z10prop" "*,*,*,*,*,*,z10_fwd_A1,z10_fr_E1,z10_fwd_A3,z10_fwd_A3,z10_rec,z10_rec") - (set_attr "cpu_facility" "z196,*,*,*,*,*,*,*,*,*,*,*")]) - -; -; movcc instruction pattern -; - -(define_insn "movcc" - [(set (match_operand:CC 0 "nonimmediate_operand" "=d,c,d,d,d,R,T") - (match_operand:CC 1 "nonimmediate_operand" "d,d,c,R,T,d,d"))] - "" - "@ - lr\t%0,%1 - tmh\t%1,12288 - ipm\t%0 - st\t%0,%1 - sty\t%0,%1 - l\t%1,%0 - ly\t%1,%0" - [(set_attr "op_type" "RR,RI,RRE,RX,RXY,RX,RXY") - (set_attr "type" "lr,*,*,store,store,load,load") - (set_attr "z10prop" "z10_fr_E1,z10_super,*,z10_rec,z10_rec,z10_fwd_A3,z10_fwd_A3") - (set_attr "z196prop" "*,*,z196_ends,*,*,*,*")]) - -; -; Block move (MVC) patterns. -; - -(define_insn "*mvc" - [(set (match_operand:BLK 0 "memory_operand" "=Q") - (match_operand:BLK 1 "memory_operand" "Q")) - (use (match_operand 2 "const_int_operand" "n"))] - "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256" - "mvc\t%O0(%2,%R0),%S1" - [(set_attr "op_type" "SS")]) - -; This splitter converts a QI to QI mode copy into a BLK mode copy in -; order to have it implemented with mvc. - -(define_split - [(set (match_operand:QI 0 "memory_operand" "") - (match_operand:QI 1 "memory_operand" ""))] - "reload_completed" - [(parallel - [(set (match_dup 0) (match_dup 1)) - (use (const_int 1))])] -{ - operands[0] = adjust_address (operands[0], BLKmode, 0); - operands[1] = adjust_address (operands[1], BLKmode, 0); -}) - - -(define_peephole2 - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "const_int_operand" ""))]) - (parallel - [(set (match_operand:BLK 3 "memory_operand" "") - (match_operand:BLK 4 "memory_operand" "")) - (use (match_operand 5 "const_int_operand" ""))])] - "s390_offset_p (operands[0], operands[3], operands[2]) - && s390_offset_p (operands[1], operands[4], operands[2]) - && !s390_overlap_p (operands[0], operands[1], - INTVAL (operands[2]) + INTVAL (operands[5])) - && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256" - [(parallel - [(set (match_dup 6) (match_dup 7)) - (use (match_dup 8))])] - "operands[6] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0)); - operands[7] = gen_rtx_MEM (BLKmode, XEXP (operands[1], 0)); - operands[8] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[5]));") - - -; -; 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; - int i, off; - - /* Support only loading a constant number of fixed-point registers from - memory and only bother with this if more than two */ - if (GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) < 2 - || INTVAL (operands[2]) > 16 - || GET_CODE (operands[1]) != MEM - || GET_CODE (operands[0]) != REG - || REGNO (operands[0]) >= 16) - FAIL; - - count = INTVAL (operands[2]); - regno = REGNO (operands[0]); - mode = GET_MODE (operands[0]); - if (mode != SImode && (!TARGET_ZARCH || mode != DImode)) - FAIL; - - operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); - if (!can_create_pseudo_p ()) - { - if (GET_CODE (XEXP (operands[1], 0)) == REG) - { - from = XEXP (operands[1], 0); - off = 0; - } - else if (GET_CODE (XEXP (operands[1], 0)) == PLUS - && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == REG - && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT) - { - from = XEXP (XEXP (operands[1], 0), 0); - off = INTVAL (XEXP (XEXP (operands[1], 0), 1)); - } - else - FAIL; - } - else - { - from = force_reg (Pmode, XEXP (operands[1], 0)); - off = 0; - } - - for (i = 0; i < count; i++) - XVECEXP (operands[3], 0, i) - = 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" "QS"))])] - "reload_completed && TARGET_ZARCH" -{ - int words = XVECLEN (operands[0], 0); - operands[0] = gen_rtx_REG (DImode, REGNO (operands[1]) + words - 1); - return "lmg\t%1,%0,%S2"; -} - [(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,r") - (match_operand:SI 2 "s_operand" "Q,S"))])] - "reload_completed" -{ - int words = XVECLEN (operands[0], 0); - operands[0] = gen_rtx_REG (SImode, REGNO (operands[1]) + words - 1); - return which_alternative == 0 ? "lm\t%1,%0,%S2" : "lmy\t%1,%0,%S2"; -} - [(set_attr "op_type" "RS,RSY") - (set_attr "type" "lm")]) - -; -; 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; - int i, off; - - /* Support only storing a constant number of fixed-point registers to - memory and only bother with this if more than two. */ - if (GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) < 2 - || INTVAL (operands[2]) > 16 - || GET_CODE (operands[0]) != MEM - || GET_CODE (operands[1]) != REG - || REGNO (operands[1]) >= 16) - FAIL; - - count = INTVAL (operands[2]); - regno = REGNO (operands[1]); - mode = GET_MODE (operands[1]); - if (mode != SImode && (!TARGET_ZARCH || mode != DImode)) - FAIL; - - operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); - - if (!can_create_pseudo_p ()) - { - if (GET_CODE (XEXP (operands[0], 0)) == REG) - { - to = XEXP (operands[0], 0); - off = 0; - } - else if (GET_CODE (XEXP (operands[0], 0)) == PLUS - && GET_CODE (XEXP (XEXP (operands[0], 0), 0)) == REG - && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT) - { - to = XEXP (XEXP (operands[0], 0), 0); - off = INTVAL (XEXP (XEXP (operands[0], 0), 1)); - } - else - FAIL; - } - else - { - to = force_reg (Pmode, XEXP (operands[0], 0)); - off = 0; - } - - for (i = 0; i < count; i++) - XVECEXP (operands[3], 0, i) - = gen_rtx_SET (VOIDmode, - 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" "=QS") - (match_operand:DI 2 "register_operand" "r"))])] - "reload_completed && TARGET_ZARCH" -{ - int words = XVECLEN (operands[0], 0); - operands[0] = gen_rtx_REG (DImode, REGNO (operands[2]) + words - 1); - return "stmg\t%2,%0,%S1"; -} - [(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,S") - (match_operand:SI 2 "register_operand" "r,r"))])] - "reload_completed" -{ - int words = XVECLEN (operands[0], 0); - operands[0] = gen_rtx_REG (SImode, REGNO (operands[2]) + words - 1); - return which_alternative == 0 ? "stm\t%2,%0,%S1" : "stmy\t%2,%0,%S1"; -} - [(set_attr "op_type" "RS,RSY") - (set_attr "type" "stm")]) - -;; -;; String instructions. -;; - -(define_insn "*execute_rl" - [(match_parallel 0 "" - [(unspec [(match_operand 1 "register_operand" "a") - (match_operand 2 "" "") - (match_operand:SI 3 "larl_operand" "X")] UNSPEC_EXECUTE)])] - "TARGET_Z10 && GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT - && GET_MODE_SIZE (GET_MODE (operands[1])) <= UNITS_PER_WORD" - "exrl\t%1,%3" - [(set_attr "op_type" "RIL") - (set_attr "type" "cs")]) - -(define_insn "*execute" - [(match_parallel 0 "" - [(unspec [(match_operand 1 "register_operand" "a") - (match_operand:BLK 2 "memory_operand" "R") - (match_operand 3 "" "")] UNSPEC_EXECUTE)])] - "GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT - && GET_MODE_SIZE (GET_MODE (operands[1])) <= UNITS_PER_WORD" - "ex\t%1,%2" - [(set_attr "op_type" "RX") - (set_attr "type" "cs")]) - - -; -; strlenM instruction pattern(s). -; - -(define_expand "strlen<mode>" - [(set (reg:SI 0) (match_operand:SI 2 "immediate_operand" "")) - (parallel - [(set (match_dup 4) - (unspec:P [(const_int 0) - (match_operand:BLK 1 "memory_operand" "") - (reg:SI 0) - (match_operand 3 "immediate_operand" "")] UNSPEC_SRST)) - (clobber (scratch:P)) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_operand:P 0 "register_operand" "") - (minus:P (match_dup 4) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))])] - "" -{ - operands[4] = gen_reg_rtx (Pmode); - operands[5] = gen_reg_rtx (Pmode); - emit_move_insn (operands[5], force_operand (XEXP (operands[1], 0), NULL_RTX)); - operands[1] = replace_equiv_address (operands[1], operands[5]); -}) - -(define_insn "*strlen<mode>" - [(set (match_operand:P 0 "register_operand" "=a") - (unspec:P [(match_operand:P 2 "general_operand" "0") - (mem:BLK (match_operand:P 3 "register_operand" "1")) - (reg:SI 0) - (match_operand 4 "immediate_operand" "")] UNSPEC_SRST)) - (clobber (match_scratch:P 1 "=a")) - (clobber (reg:CC CC_REGNUM))] - "" - "srst\t%0,%1\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -; -; cmpstrM instruction pattern(s). -; - -(define_expand "cmpstrsi" - [(set (reg:SI 0) (const_int 0)) - (parallel - [(clobber (match_operand 3 "" "")) - (clobber (match_dup 4)) - (set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 1 "memory_operand" "") - (match_operand:BLK 2 "memory_operand" ""))) - (use (reg:SI 0))]) - (parallel - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CCU_TO_INT)) - (clobber (reg:CC CC_REGNUM))])] - "" -{ - /* As the result of CMPINT is inverted compared to what we need, - we have to swap the operands. */ - rtx op1 = operands[2]; - rtx op2 = operands[1]; - rtx addr1 = gen_reg_rtx (Pmode); - rtx addr2 = gen_reg_rtx (Pmode); - - emit_move_insn (addr1, force_operand (XEXP (op1, 0), NULL_RTX)); - emit_move_insn (addr2, force_operand (XEXP (op2, 0), NULL_RTX)); - operands[1] = replace_equiv_address_nv (op1, addr1); - operands[2] = replace_equiv_address_nv (op2, addr2); - operands[3] = addr1; - operands[4] = addr2; -}) - -(define_insn "*cmpstr<mode>" - [(clobber (match_operand:P 0 "register_operand" "=d")) - (clobber (match_operand:P 1 "register_operand" "=d")) - (set (reg:CCU CC_REGNUM) - (compare:CCU (mem:BLK (match_operand:P 2 "register_operand" "0")) - (mem:BLK (match_operand:P 3 "register_operand" "1")))) - (use (reg:SI 0))] - "" - "clst\t%0,%1\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -; -; movstr instruction pattern. -; - -(define_expand "movstr" - [(set (reg:SI 0) (const_int 0)) - (parallel - [(clobber (match_dup 3)) - (set (match_operand:BLK 1 "memory_operand" "") - (match_operand:BLK 2 "memory_operand" "")) - (set (match_operand 0 "register_operand" "") - (unspec [(match_dup 1) - (match_dup 2) - (reg:SI 0)] UNSPEC_MVST)) - (clobber (reg:CC CC_REGNUM))])] - "" -{ - rtx addr1 = gen_reg_rtx (Pmode); - rtx addr2 = gen_reg_rtx (Pmode); - - emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); - emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX)); - operands[1] = replace_equiv_address_nv (operands[1], addr1); - operands[2] = replace_equiv_address_nv (operands[2], addr2); - operands[3] = addr2; -}) - -(define_insn "*movstr" - [(clobber (match_operand:P 2 "register_operand" "=d")) - (set (mem:BLK (match_operand:P 1 "register_operand" "0")) - (mem:BLK (match_operand:P 3 "register_operand" "2"))) - (set (match_operand:P 0 "register_operand" "=d") - (unspec [(mem:BLK (match_dup 1)) - (mem:BLK (match_dup 3)) - (reg:SI 0)] UNSPEC_MVST)) - (clobber (reg:CC CC_REGNUM))] - "" - "mvst\t%1,%2\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - - -; -; movmemM instruction pattern(s). -; - -(define_expand "movmem<mode>" - [(set (match_operand:BLK 0 "memory_operand" "") ; destination - (match_operand:BLK 1 "memory_operand" "")) ; source - (use (match_operand:GPR 2 "general_operand" "")) ; count - (match_operand 3 "" "")] - "" - "s390_expand_movmem (operands[0], operands[1], operands[2]); DONE;") - -; Move a block that is up to 256 bytes in length. -; The block length is taken as (operands[2] % 256) + 1. - -(define_expand "movmem_short" - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "nonmemory_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_dup 3))])] - "" - "operands[3] = gen_rtx_SCRATCH (Pmode);") - -(define_insn "*movmem_short" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q")) - (use (match_operand 2 "nonmemory_operand" "n,a,a,a")) - (use (match_operand 3 "immediate_operand" "X,R,X,X")) - (clobber (match_scratch 4 "=X,X,X,&a"))] - "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) - && GET_MODE (operands[4]) == Pmode" - "#" - [(set_attr "type" "cs") - (set_attr "cpu_facility" "*,*,z10,*")]) - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "const_int_operand" "")) - (use (match_operand 3 "immediate_operand" "")) - (clobber (scratch))] - "reload_completed" - [(parallel - [(set (match_dup 0) (match_dup 1)) - (use (match_dup 2))])] - "operands[2] = GEN_INT ((INTVAL (operands[2]) & 0xff) + 1);") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "register_operand" "")) - (use (match_operand 3 "memory_operand" "")) - (clobber (scratch))] - "reload_completed" - [(parallel - [(unspec [(match_dup 2) (match_dup 3) - (const_int 0)] UNSPEC_EXECUTE) - (set (match_dup 0) (match_dup 1)) - (use (const_int 1))])] - "") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch))] - "TARGET_Z10 && reload_completed" - [(parallel - [(unspec [(match_dup 2) (const_int 0) - (label_ref (match_dup 3))] UNSPEC_EXECUTE) - (set (match_dup 0) (match_dup 1)) - (use (const_int 1))])] - "operands[3] = gen_label_rtx ();") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand 2 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_operand 3 "register_operand" ""))] - "reload_completed && TARGET_CPU_ZARCH" - [(set (match_dup 3) (label_ref (match_dup 4))) - (parallel - [(unspec [(match_dup 2) (mem:BLK (match_dup 3)) - (label_ref (match_dup 4))] UNSPEC_EXECUTE) - (set (match_dup 0) (match_dup 1)) - (use (const_int 1))])] - "operands[4] = gen_label_rtx ();") - -; Move a block of arbitrary length. - -(define_expand "movmem_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 CC_REGNUM))])] - "" -{ - enum machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode; - enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode; - rtx reg0 = gen_reg_rtx (dreg_mode); - rtx reg1 = gen_reg_rtx (dreg_mode); - rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0)); - rtx addr1 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg1)); - rtx len0 = gen_lowpart (Pmode, reg0); - rtx len1 = gen_lowpart (Pmode, reg1); - - emit_clobber (reg0); - emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); - emit_move_insn (len0, operands[2]); - - emit_clobber (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 "*movmem_long" - [(clobber (match_operand:<DBL> 0 "register_operand" "=d")) - (clobber (match_operand:<DBL> 1 "register_operand" "=d")) - (set (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0)) - (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "1") 0))) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_64BIT || !TARGET_ZARCH" - "mvcle\t%0,%1,0\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -(define_insn "*movmem_long_31z" - [(clobber (match_operand:TI 0 "register_operand" "=d")) - (clobber (match_operand:TI 1 "register_operand" "=d")) - (set (mem:BLK (subreg:SI (match_operand:TI 2 "register_operand" "0") 4)) - (mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "1") 4))) - (use (match_dup 2)) - (use (match_dup 3)) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_64BIT && TARGET_ZARCH" - "mvcle\t%0,%1,0\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - - -; -; Test data class. -; - -(define_expand "signbit<mode>2" - [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f") - (match_dup 2)] - UNSPEC_TDC_INSN)) - (set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))] - "TARGET_HARD_FLOAT" -{ - operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET); -}) - -(define_expand "isinf<mode>2" - [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f") - (match_dup 2)] - UNSPEC_TDC_INSN)) - (set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))] - "TARGET_HARD_FLOAT" -{ - operands[2] = GEN_INT (S390_TDC_INFINITY); -}) - -; This insn is used to generate all variants of the Test Data Class -; instruction, namely tcxb, tcdb, and tceb. The insn's first operand -; is the register to be tested and the second one is the bit mask -; specifying the required test(s). -; -; tcxb, tcdb, tceb, tdcxt, tdcdt, tdcet -(define_insn "*TDC_insn_<mode>" - [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:FP_ALL 0 "register_operand" "f") - (match_operand:SI 1 "const_int_operand")] UNSPEC_TDC_INSN))] - "TARGET_HARD_FLOAT" - "t<_d>c<xde><bt>\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "type" "fsimp<mode>")]) - -(define_insn_and_split "*ccz_to_int" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:CCZ 1 "register_operand" "0")] - UNSPEC_CCZ_TO_INT))] - "" - "#" - "reload_completed" - [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))]) - - -; -; setmemM instruction pattern(s). -; - -(define_expand "setmem<mode>" - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:QI 2 "general_operand" "")) - (use (match_operand:GPR 1 "general_operand" "")) - (match_operand 3 "" "")] - "" - "s390_expand_setmem (operands[0], operands[1], operands[2]); DONE;") - -; Clear a block that is up to 256 bytes in length. -; The block length is taken as (operands[1] % 256) + 1. - -(define_expand "clrmem_short" - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "nonmemory_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_dup 2)) - (clobber (reg:CC CC_REGNUM))])] - "" - "operands[2] = gen_rtx_SCRATCH (Pmode);") - -(define_insn "*clrmem_short" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q") - (const_int 0)) - (use (match_operand 1 "nonmemory_operand" "n,a,a,a")) - (use (match_operand 2 "immediate_operand" "X,R,X,X")) - (clobber (match_scratch 3 "=X,X,X,&a")) - (clobber (reg:CC CC_REGNUM))] - "(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode) - && GET_MODE (operands[3]) == Pmode" - "#" - [(set_attr "type" "cs") - (set_attr "cpu_facility" "*,*,z10,*")]) - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "const_int_operand" "")) - (use (match_operand 2 "immediate_operand" "")) - (clobber (scratch)) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (const_int 0)) - (use (match_dup 1)) - (clobber (reg:CC CC_REGNUM))])] - "operands[1] = GEN_INT ((INTVAL (operands[1]) & 0xff) + 1);") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "register_operand" "")) - (use (match_operand 2 "memory_operand" "")) - (clobber (scratch)) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(unspec [(match_dup 1) (match_dup 2) - (const_int 0)] UNSPEC_EXECUTE) - (set (match_dup 0) (const_int 0)) - (use (const_int 1)) - (clobber (reg:CC CC_REGNUM))])] - "") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 && reload_completed" - [(parallel - [(unspec [(match_dup 1) (const_int 0) - (label_ref (match_dup 3))] UNSPEC_EXECUTE) - (set (match_dup 0) (const_int 0)) - (use (const_int 1)) - (clobber (reg:CC CC_REGNUM))])] - "operands[3] = gen_label_rtx ();") - -(define_split - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_operand 2 "register_operand" "")) - (clobber (reg:CC CC_REGNUM))] - "reload_completed && TARGET_CPU_ZARCH" - [(set (match_dup 2) (label_ref (match_dup 3))) - (parallel - [(unspec [(match_dup 1) (mem:BLK (match_dup 2)) - (label_ref (match_dup 3))] UNSPEC_EXECUTE) - (set (match_dup 0) (const_int 0)) - (use (const_int 1)) - (clobber (reg:CC CC_REGNUM))])] - "operands[3] = gen_label_rtx ();") - -; Initialize a block of arbitrary length with (operands[2] % 256). - -(define_expand "setmem_long" - [(parallel - [(clobber (match_dup 1)) - (set (match_operand:BLK 0 "memory_operand" "") - (match_operand 2 "shift_count_or_setmem_operand" "")) - (use (match_operand 1 "general_operand" "")) - (use (match_dup 3)) - (clobber (reg:CC CC_REGNUM))])] - "" -{ - enum machine_mode sreg_mode = TARGET_ZARCH ? DImode : SImode; - enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode; - rtx reg0 = gen_reg_rtx (dreg_mode); - rtx reg1 = gen_reg_rtx (dreg_mode); - rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0)); - rtx len0 = gen_lowpart (Pmode, reg0); - - emit_clobber (reg0); - emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); - emit_move_insn (len0, operands[1]); - - emit_move_insn (reg1, const0_rtx); - - operands[0] = replace_equiv_address_nv (operands[0], addr0); - operands[1] = reg0; - operands[3] = reg1; -}) - -(define_insn "*setmem_long" - [(clobber (match_operand:<DBL> 0 "register_operand" "=d")) - (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0)) - (match_operand 2 "shift_count_or_setmem_operand" "Y")) - (use (match_dup 3)) - (use (match_operand:<DBL> 1 "register_operand" "d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_64BIT || !TARGET_ZARCH" - "mvcle\t%0,%1,%Y2\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -(define_insn "*setmem_long_and" - [(clobber (match_operand:<DBL> 0 "register_operand" "=d")) - (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0)) - (and (match_operand 2 "shift_count_or_setmem_operand" "Y") - (match_operand 4 "const_int_operand" "n"))) - (use (match_dup 3)) - (use (match_operand:<DBL> 1 "register_operand" "d")) - (clobber (reg:CC CC_REGNUM))] - "(TARGET_64BIT || !TARGET_ZARCH) && - (INTVAL (operands[4]) & 255) == 255" - "mvcle\t%0,%1,%Y2\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -(define_insn "*setmem_long_31z" - [(clobber (match_operand:TI 0 "register_operand" "=d")) - (set (mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "0") 4)) - (match_operand 2 "shift_count_or_setmem_operand" "Y")) - (use (match_dup 3)) - (use (match_operand:TI 1 "register_operand" "d")) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_64BIT && TARGET_ZARCH" - "mvcle\t%0,%1,%Y2\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -; -; cmpmemM instruction pattern(s). -; - -(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_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_expand "cmpmem_short" - [(parallel - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "nonmemory_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_dup 3))])] - "" - "operands[3] = gen_rtx_SCRATCH (Pmode);") - -(define_insn "*cmpmem_short" - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q"))) - (use (match_operand 2 "nonmemory_operand" "n,a,a,a")) - (use (match_operand 3 "immediate_operand" "X,R,X,X")) - (clobber (match_scratch 4 "=X,X,X,&a"))] - "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) - && GET_MODE (operands[4]) == Pmode" - "#" - [(set_attr "type" "cs") - (set_attr "cpu_facility" "*,*,z10,*")]) - -(define_split - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "const_int_operand" "")) - (use (match_operand 3 "immediate_operand" "")) - (clobber (scratch))] - "reload_completed" - [(parallel - [(set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) - (use (match_dup 2))])] - "operands[2] = GEN_INT ((INTVAL (operands[2]) & 0xff) + 1);") - -(define_split - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "register_operand" "")) - (use (match_operand 3 "memory_operand" "")) - (clobber (scratch))] - "reload_completed" - [(parallel - [(unspec [(match_dup 2) (match_dup 3) - (const_int 0)] UNSPEC_EXECUTE) - (set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) - (use (const_int 1))])] - "") - -(define_split - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (scratch))] - "TARGET_Z10 && reload_completed" - [(parallel - [(unspec [(match_dup 2) (const_int 0) - (label_ref (match_dup 4))] UNSPEC_EXECUTE) - (set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) - (use (const_int 1))])] - "operands[4] = gen_label_rtx ();") - -(define_split - [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "register_operand" "")) - (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) - (clobber (match_operand 3 "register_operand" ""))] - "reload_completed && TARGET_CPU_ZARCH" - [(set (match_dup 3) (label_ref (match_dup 4))) - (parallel - [(unspec [(match_dup 2) (mem:BLK (match_dup 3)) - (label_ref (match_dup 4))] UNSPEC_EXECUTE) - (set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) - (use (const_int 1))])] - "operands[4] = gen_label_rtx ();") - -; Compare a block of arbitrary length. - -(define_expand "cmpmem_long" - [(parallel - [(clobber (match_dup 2)) - (clobber (match_dup 3)) - (set (reg:CCU CC_REGNUM) - (compare:CCU (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 sreg_mode = TARGET_ZARCH ? DImode : SImode; - enum machine_mode dreg_mode = TARGET_ZARCH ? TImode : DImode; - rtx reg0 = gen_reg_rtx (dreg_mode); - rtx reg1 = gen_reg_rtx (dreg_mode); - rtx addr0 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg0)); - rtx addr1 = gen_lowpart (Pmode, gen_highpart (sreg_mode, reg1)); - rtx len0 = gen_lowpart (Pmode, reg0); - rtx len1 = gen_lowpart (Pmode, reg1); - - emit_clobber (reg0); - emit_move_insn (addr0, force_operand (XEXP (operands[0], 0), NULL_RTX)); - emit_move_insn (len0, operands[2]); - - emit_clobber (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" - [(clobber (match_operand:<DBL> 0 "register_operand" "=d")) - (clobber (match_operand:<DBL> 1 "register_operand" "=d")) - (set (reg:CCU CC_REGNUM) - (compare:CCU (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0)) - (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "1") 0)))) - (use (match_dup 2)) - (use (match_dup 3))] - "TARGET_64BIT || !TARGET_ZARCH" - "clcle\t%0,%1,0\;jo\t.-4" - [(set_attr "length" "8") - (set_attr "type" "vs")]) - -(define_insn "*cmpmem_long_31z" - [(clobber (match_operand:TI 0 "register_operand" "=d")) - (clobber (match_operand:TI 1 "register_operand" "=d")) - (set (reg:CCU CC_REGNUM) - (compare:CCU (mem:BLK (subreg:SI (match_operand:TI 2 "register_operand" "0") 4)) - (mem:BLK (subreg:SI (match_operand:TI 3 "register_operand" "1") 4)))) - (use (match_dup 2)) - (use (match_dup 3))] - "!TARGET_64BIT && TARGET_ZARCH" - "clcle\t%0,%1,0\;jo\t.-4" - [(set_attr "op_type" "NN") - (set_attr "type" "vs") - (set_attr "length" "8")]) - -; Convert CCUmode condition code to integer. -; Result is zero if EQ, positive if LTU, negative if GTU. - -(define_insn_and_split "cmpint" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_operand:CCU 1 "register_operand" "0")] - UNSPEC_CCU_TO_INT)) - (clobber (reg:CC CC_REGNUM))] - "" - "#" - "reload_completed" - [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 2))) - (parallel - [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 30))) - (clobber (reg:CC CC_REGNUM))])]) - -(define_insn_and_split "*cmpint_cc" - [(set (reg CC_REGNUM) - (compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")] - UNSPEC_CCU_TO_INT) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT))] - "s390_match_ccmode (insn, CCSmode)" - "#" - "&& reload_completed" - [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 2))) - (parallel - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 30)))])] -{ - rtx result = gen_rtx_ASHIFTRT (SImode, operands[0], GEN_INT (30)); - operands[2] = SET_DEST (XVECEXP (PATTERN (curr_insn), 0, 0)); - operands[3] = gen_rtx_COMPARE (GET_MODE (operands[2]), result, const0_rtx); -}) - -(define_insn_and_split "*cmpint_sign" - [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")] - UNSPEC_CCU_TO_INT))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 34))) - (parallel - [(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 62))) - (clobber (reg:CC CC_REGNUM))])]) - -(define_insn_and_split "*cmpint_sign_cc" - [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (ashift:DI (subreg:DI - (unspec:SI [(match_operand:CCU 1 "register_operand" "0")] - UNSPEC_CCU_TO_INT) 0) - (const_int 32)) (const_int 32)) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT)))] - "s390_match_ccmode (insn, CCSmode) && TARGET_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) (ashift:DI (match_dup 0) (const_int 34))) - (parallel - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 62)))])] -{ - rtx result = gen_rtx_ASHIFTRT (DImode, operands[0], GEN_INT (62)); - operands[2] = SET_DEST (XVECEXP (PATTERN (curr_insn), 0, 0)); - operands[3] = gen_rtx_COMPARE (GET_MODE (operands[2]), result, const0_rtx); -}) - - -;; -;;- Conversion instructions. -;; - -(define_insn "*sethighpartsi" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (unspec:SI [(match_operand:BLK 1 "s_operand" "Q,S") - (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - icm\t%0,%2,%S1 - icmy\t%0,%2,%S1" - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_insn "*sethighpartdi_64" - [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:BLK 1 "s_operand" "QS") - (match_operand 2 "const_int_operand" "n")] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "icmh\t%0,%2,%S1" - [(set_attr "op_type" "RSY") - (set_attr "z10prop" "z10_super")]) - -(define_insn "*sethighpartdi_31" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (unspec:DI [(match_operand:BLK 1 "s_operand" "Q,S") - (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH" - "@ - icm\t%0,%2,%S1 - icmy\t%0,%2,%S1" - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - - -(define_insn_and_split "*extzv<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extract:GPR (match_operand:QI 1 "s_operand" "QS") - (match_operand 2 "const_int_operand" "n") - (const_int 0))) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))] -{ - int bitsize = INTVAL (operands[2]); - int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */ - int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size); - - operands[1] = adjust_address (operands[1], BLKmode, 0); - set_mem_size (operands[1], size); - operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize); - operands[3] = GEN_INT (mask); -}) - -(define_insn_and_split "*extv<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (sign_extract:GPR (match_operand:QI 1 "s_operand" "QS") - (match_operand 2 "const_int_operand" "n") - (const_int 0))) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))])] -{ - int bitsize = INTVAL (operands[2]); - int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */ - int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size); - - operands[1] = adjust_address (operands[1], BLKmode, 0); - set_mem_size (operands[1], size); - operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize); - operands[3] = GEN_INT (mask); -}) - -; -; insv instruction patterns -; - -(define_expand "insv" - [(set (zero_extract (match_operand 0 "nonimmediate_operand" "") - (match_operand 1 "const_int_operand" "") - (match_operand 2 "const_int_operand" "")) - (match_operand 3 "general_operand" ""))] - "" -{ - if (s390_expand_insv (operands[0], operands[1], operands[2], operands[3])) - DONE; - FAIL; -}) - -(define_insn "*insv<mode>_z10" - [(set (zero_extract:GPR (match_operand:GPR 0 "nonimmediate_operand" "+d") - (match_operand 1 "const_int_operand" "I") - (match_operand 2 "const_int_operand" "I")) - (match_operand:GPR 3 "nonimmediate_operand" "d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 - && (INTVAL (operands[1]) + INTVAL (operands[2])) <= - GET_MODE_BITSIZE (<MODE>mode)" -{ - int start = INTVAL (operands[2]); - int size = INTVAL (operands[1]); - int offset = 64 - GET_MODE_BITSIZE (<MODE>mode); - - operands[2] = GEN_INT (offset + start); /* start bit position */ - operands[1] = GEN_INT (offset + start + size - 1); /* end bit position */ - operands[4] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - - start - size); /* left shift count */ - - return "risbg\t%0,%3,%b2,%b1,%b4"; -} - [(set_attr "op_type" "RIE") - (set_attr "z10prop" "z10_super_E1")]) - -; and op1 with a mask being 1 for the selected bits and 0 for the rest -; and op3=op0 with a mask being 0 for the selected bits and 1 for the rest -(define_insn "*insv<mode>_z10_noshift" - [(set (match_operand:GPR 0 "nonimmediate_operand" "=d") - (ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d") - (match_operand 2 "const_int_operand" "n")) - (and:GPR (match_operand:GPR 3 "nonimmediate_operand" "0") - (match_operand 4 "const_int_operand" "n")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 - && s390_contiguous_bitmask_p (INTVAL (operands[2]), - GET_MODE_BITSIZE (<MODE>mode), NULL, NULL) - && INTVAL (operands[2]) == ~(INTVAL (operands[4]))" - -{ - int start; - int size; - - s390_contiguous_bitmask_p (INTVAL (operands[2]), - GET_MODE_BITSIZE (<MODE>mode), &start, &size); - - operands[5] = GEN_INT (64 - start - size); /* start bit position */ - operands[6] = GEN_INT (64 - 1 - start); /* end bit position */ - operands[7] = const0_rtx; /* left shift count */ - - return "risbg\t%0,%1,%b5,%b6,%b7"; -} - [(set_attr "op_type" "RIE") - (set_attr "z10prop" "z10_super_E1")]) - -; and op1 with a mask being 1 for the selected bits and 0 for the rest -(define_insn "*insv<mode>_or_z10_noshift" - [(set (match_operand:GPR 0 "nonimmediate_operand" "=d") - (ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d") - (match_operand 2 "const_int_operand" "n")) - (match_operand:GPR 3 "nonimmediate_operand" "0"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z10 - && s390_contiguous_bitmask_p (INTVAL (operands[2]), - GET_MODE_BITSIZE (<MODE>mode), NULL, NULL)" -{ - int start; - int size; - - s390_contiguous_bitmask_p (INTVAL (operands[2]), - GET_MODE_BITSIZE (<MODE>mode), &start, &size); - - operands[4] = GEN_INT (64 - start - size); /* start bit position */ - operands[5] = GEN_INT (64 - 1 - start); /* end bit position */ - operands[6] = const0_rtx; /* left shift count */ - - return "rosbg\t%0,%1,%b4,%b5,%b6"; -} - [(set_attr "op_type" "RIE")]) - -(define_insn "*insv<mode>_mem_reg" - [(set (zero_extract:W (match_operand:QI 0 "memory_operand" "+Q,S") - (match_operand 1 "const_int_operand" "n,n") - (const_int 0)) - (match_operand:W 2 "register_operand" "d,d"))] - "INTVAL (operands[1]) > 0 - && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode) - && INTVAL (operands[1]) % BITS_PER_UNIT == 0" -{ - int size = INTVAL (operands[1]) / BITS_PER_UNIT; - - operands[1] = GEN_INT ((1ul << size) - 1); - return (which_alternative == 0) ? "stcm\t%2,%1,%S0" - : "stcmy\t%2,%1,%S0"; -} - [(set_attr "op_type" "RS,RSY") - (set_attr "z10prop" "z10_super,z10_super")]) - -(define_insn "*insvdi_mem_reghigh" - [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "+QS") - (match_operand 1 "const_int_operand" "n") - (const_int 0)) - (lshiftrt:DI (match_operand:DI 2 "register_operand" "d") - (const_int 32)))] - "TARGET_ZARCH - && INTVAL (operands[1]) > 0 - && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode) - && INTVAL (operands[1]) % BITS_PER_UNIT == 0" -{ - int size = INTVAL (operands[1]) / BITS_PER_UNIT; - - operands[1] = GEN_INT ((1ul << size) - 1); - return "stcmh\t%2,%1,%S0"; -} -[(set_attr "op_type" "RSY") - (set_attr "z10prop" "z10_super")]) - -(define_insn "*insvdi_reg_imm" - [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+d") - (const_int 16) - (match_operand 1 "const_int_operand" "n")) - (match_operand:DI 2 "const_int_operand" "n"))] - "TARGET_ZARCH - && INTVAL (operands[1]) >= 0 - && INTVAL (operands[1]) < BITS_PER_WORD - && INTVAL (operands[1]) % 16 == 0" -{ - switch (BITS_PER_WORD - INTVAL (operands[1])) - { - case 64: return "iihh\t%0,%x2"; break; - case 48: return "iihl\t%0,%x2"; break; - case 32: return "iilh\t%0,%x2"; break; - case 16: return "iill\t%0,%x2"; break; - default: gcc_unreachable(); - } -} - [(set_attr "op_type" "RI") - (set_attr "z10prop" "z10_super_E1")]) - -; Update the left-most 32 bit of a DI. -(define_insn "*insv_h_di_reg_extimm" - [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+d") - (const_int 32) - (const_int 0)) - (match_operand:DI 1 "const_int_operand" "n"))] - "TARGET_EXTIMM" - "iihf\t%0,%o1" - [(set_attr "op_type" "RIL") - (set_attr "z10prop" "z10_fwd_E1")]) - -; Update the right-most 32 bit of a DI, or the whole of a SI. -(define_insn "*insv_l<mode>_reg_extimm" - [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d") - (const_int 32) - (match_operand 1 "const_int_operand" "n")) - (match_operand:P 2 "const_int_operand" "n"))] - "TARGET_EXTIMM - && BITS_PER_WORD - INTVAL (operands[1]) == 32" - "iilf\t%0,%o2" - [(set_attr "op_type" "RIL") - (set_attr "z10prop" "z10_fwd_A1")]) - -; -; extendsidi2 instruction pattern(s). -; - -(define_expand "extendsidi2" - [(set (match_operand:DI 0 "register_operand" "") - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] - "" -{ - if (!TARGET_ZARCH) - { - emit_clobber (operands[0]); - emit_move_insn (gen_highpart (SImode, operands[0]), operands[1]); - emit_move_insn (gen_lowpart (SImode, operands[0]), const0_rtx); - emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32))); - DONE; - } -}) - -(define_insn "*extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))] - "TARGET_ZARCH" - "@ - lgfr\t%0,%1 - lgf\t%0,%1 - lgfrl\t%0,%1" - [(set_attr "op_type" "RRE,RXY,RIL") - (set_attr "type" "*,*,larl") - (set_attr "cpu_facility" "*,*,z10") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1")]) - -; -; extend(hi|qi)(si|di)2 instruction pattern(s). -; - -(define_expand "extend<HQI:mode><DSI:mode>2" - [(set (match_operand:DSI 0 "register_operand" "") - (sign_extend:DSI (match_operand:HQI 1 "nonimmediate_operand" "")))] - "" -{ - if (<DSI:MODE>mode == DImode && !TARGET_ZARCH) - { - rtx tmp = gen_reg_rtx (SImode); - emit_insn (gen_extend<HQI:mode>si2 (tmp, operands[1])); - emit_insn (gen_extendsidi2 (operands[0], tmp)); - DONE; - } - else if (!TARGET_EXTIMM) - { - rtx bitcount = GEN_INT (GET_MODE_BITSIZE (<DSI:MODE>mode) - - GET_MODE_BITSIZE (<HQI:MODE>mode)); - - operands[1] = gen_lowpart (<DSI:MODE>mode, operands[1]); - emit_insn (gen_ashl<DSI:mode>3 (operands[0], operands[1], bitcount)); - emit_insn (gen_ashr<DSI:mode>3 (operands[0], operands[0], bitcount)); - DONE; - } -}) - -; -; extendhidi2 instruction pattern(s). -; - -(define_insn "*extendhidi2_extimm" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (sign_extend:DI (match_operand:HI 1 "general_operand" "d,RT,b")))] - "TARGET_ZARCH && TARGET_EXTIMM" - "@ - lghr\t%0,%1 - lgh\t%0,%1 - lghrl\t%0,%1" - [(set_attr "op_type" "RRE,RXY,RIL") - (set_attr "type" "*,*,larl") - (set_attr "cpu_facility" "extimm,extimm,z10") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1")]) - -(define_insn "*extendhidi2" - [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI (match_operand:HI 1 "memory_operand" "RT")))] - "TARGET_ZARCH" - "lgh\t%0,%1" - [(set_attr "op_type" "RXY") - (set_attr "z10prop" "z10_super_E1")]) - -; -; extendhisi2 instruction pattern(s). -; - -(define_insn "*extendhisi2_extimm" - [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" " d,R,T,b")))] - "TARGET_EXTIMM" - "@ - lhr\t%0,%1 - lh\t%0,%1 - lhy\t%0,%1 - lhrl\t%0,%1" - [(set_attr "op_type" "RRE,RX,RXY,RIL") - (set_attr "type" "*,*,*,larl") - (set_attr "cpu_facility" "extimm,extimm,extimm,z10") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1,z10_super_E1")]) - -(define_insn "*extendhisi2" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T")))] - "!TARGET_EXTIMM" - "@ - lh\t%0,%1 - lhy\t%0,%1" - [(set_attr "op_type" "RX,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -; -; extendqi(si|di)2 instruction pattern(s). -; - -; lbr, lgbr, lb, lgb -(define_insn "*extendqi<mode>2_extimm" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (sign_extend:GPR (match_operand:QI 1 "nonimmediate_operand" "d,RT")))] - "TARGET_EXTIMM" - "@ - l<g>br\t%0,%1 - l<g>b\t%0,%1" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -; lb, lgb -(define_insn "*extendqi<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (sign_extend:GPR (match_operand:QI 1 "memory_operand" "RT")))] - "!TARGET_EXTIMM && TARGET_LONG_DISPLACEMENT" - "l<g>b\t%0,%1" - [(set_attr "op_type" "RXY") - (set_attr "z10prop" "z10_super_E1")]) - -(define_insn_and_split "*extendqi<mode>2_short_displ" - [(set (match_operand:GPR 0 "register_operand" "=d") - (sign_extend:GPR (match_operand:QI 1 "s_operand" "Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_EXTIMM && !TARGET_LONG_DISPLACEMENT" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 0) (unspec:GPR [(match_dup 1) (const_int 8)] UNSPEC_ICM)) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))])] -{ - operands[1] = adjust_address (operands[1], BLKmode, 0); - set_mem_size (operands[1], GET_MODE_SIZE (QImode)); - operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - - GET_MODE_BITSIZE (QImode)); -}) - -; -; zero_extendsidi2 instruction pattern(s). -; - -(define_expand "zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand" "") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] - "" -{ - if (!TARGET_ZARCH) - { - emit_clobber (operands[0]); - emit_move_insn (gen_lowpart (SImode, operands[0]), operands[1]); - emit_move_insn (gen_highpart (SImode, operands[0]), const0_rtx); - DONE; - } -}) - -(define_insn "*zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))] - "TARGET_ZARCH" - "@ - llgfr\t%0,%1 - llgf\t%0,%1 - llgfrl\t%0,%1" - [(set_attr "op_type" "RRE,RXY,RIL") - (set_attr "type" "*,*,larl") - (set_attr "cpu_facility" "*,*,z10") - (set_attr "z10prop" "z10_fwd_E1,z10_fwd_A3,z10_fwd_A3")]) - -; -; LLGT-type instructions (zero-extend from 31 bit to 64 bit). -; - -(define_insn "*llgt_sidi" - [(set (match_operand:DI 0 "register_operand" "=d") - (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "RT") 0) - (const_int 2147483647)))] - "TARGET_ZARCH" - "llgt\t%0,%1" - [(set_attr "op_type" "RXE") - (set_attr "z10prop" "z10_super_E1")]) - -(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" "RT") 0) - (const_int 2147483647))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) - (and:DI (subreg:DI (match_dup 1) 0) - (const_int 2147483647)))] - "") - -(define_insn "*llgt_sisi" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (and:SI (match_operand:SI 1 "nonimmediate_operand" "d,RT") - (const_int 2147483647)))] - "TARGET_ZARCH" - "@ - llgtr\t%0,%1 - llgt\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(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_ZARCH" - "@ - llgtr\t%0,%1 - llgt\t%0,%N1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_split - [(set (match_operand:DSI 0 "register_operand" "") - (and:DSI (match_operand:DSI 1 "nonimmediate_operand" "") - (const_int 2147483647))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && reload_completed" - [(set (match_dup 0) - (and:DSI (match_dup 1) - (const_int 2147483647)))] - "") - -; -; zero_extend(hi|qi)(si|di)2 instruction pattern(s). -; - -(define_expand "zero_extend<mode>di2" - [(set (match_operand:DI 0 "register_operand" "") - (zero_extend:DI (match_operand:HQI 1 "nonimmediate_operand" "")))] - "" -{ - if (!TARGET_ZARCH) - { - rtx tmp = gen_reg_rtx (SImode); - emit_insn (gen_zero_extend<mode>si2 (tmp, operands[1])); - emit_insn (gen_zero_extendsidi2 (operands[0], tmp)); - DONE; - } - else if (!TARGET_EXTIMM) - { - rtx bitcount = GEN_INT (GET_MODE_BITSIZE(DImode) - - GET_MODE_BITSIZE(<MODE>mode)); - operands[1] = gen_lowpart (DImode, operands[1]); - emit_insn (gen_ashldi3 (operands[0], operands[1], bitcount)); - emit_insn (gen_lshrdi3 (operands[0], operands[0], bitcount)); - DONE; - } -}) - -(define_expand "zero_extend<mode>si2" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:HQI 1 "nonimmediate_operand" "")))] - "" -{ - if (!TARGET_EXTIMM) - { - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_andsi3 (operands[0], operands[1], - GEN_INT ((1 << GET_MODE_BITSIZE(<MODE>mode)) - 1))); - DONE; - } -}) - -; llhrl, llghrl -(define_insn "*zero_extendhi<mode>2_z10" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d") - (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "d,RT,b")))] - "TARGET_Z10" - "@ - ll<g>hr\t%0,%1 - ll<g>h\t%0,%1 - ll<g>hrl\t%0,%1" - [(set_attr "op_type" "RXY,RRE,RIL") - (set_attr "type" "*,*,larl") - (set_attr "cpu_facility" "*,*,z10") - (set_attr "z10prop" "z10_super_E1,z10_fwd_A3,z10_fwd_A3")]) - -; llhr, llcr, llghr, llgcr, llh, llc, llgh, llgc -(define_insn "*zero_extend<HQI:mode><GPR:mode>2_extimm" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (zero_extend:GPR (match_operand:HQI 1 "nonimmediate_operand" "d,RT")))] - "TARGET_EXTIMM" - "@ - ll<g><hc>r\t%0,%1 - ll<g><hc>\t%0,%1" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_E1,z10_fwd_A3")]) - -; llgh, llgc -(define_insn "*zero_extend<HQI:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extend:GPR (match_operand:HQI 1 "memory_operand" "RT")))] - "TARGET_ZARCH && !TARGET_EXTIMM" - "llg<hc>\t%0,%1" - [(set_attr "op_type" "RXY") - (set_attr "z10prop" "z10_fwd_A3")]) - -(define_insn_and_split "*zero_extendhisi2_31" - [(set (match_operand:SI 0 "register_operand" "=&d") - (zero_extend:SI (match_operand:HI 1 "s_operand" "QS"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) (const_int 0)) - (parallel - [(set (strict_low_part (match_dup 2)) (match_dup 1)) - (clobber (reg:CC CC_REGNUM))])] - "operands[2] = gen_lowpart (HImode, operands[0]);") - -(define_insn_and_split "*zero_extendqisi2_31" - [(set (match_operand:SI 0 "register_operand" "=&d") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "RT")))] - "!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]);") - -; -; zero_extendqihi2 instruction pattern(s). -; - -(define_expand "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "register_operand" "")))] - "TARGET_ZARCH && !TARGET_EXTIMM" -{ - operands[1] = gen_lowpart (HImode, operands[1]); - emit_insn (gen_andhi3 (operands[0], operands[1], GEN_INT (0xff))); - DONE; -}) - -(define_insn "*zero_extendqihi2_64" - [(set (match_operand:HI 0 "register_operand" "=d") - (zero_extend:HI (match_operand:QI 1 "memory_operand" "RT")))] - "TARGET_ZARCH && !TARGET_EXTIMM" - "llgc\t%0,%1" - [(set_attr "op_type" "RXY") - (set_attr "z10prop" "z10_fwd_A3")]) - -(define_insn_and_split "*zero_extendqihi2_31" - [(set (match_operand:HI 0 "register_operand" "=&d") - (zero_extend:HI (match_operand:QI 1 "memory_operand" "RT")))] - "!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]);") - -; -; fixuns_trunc(dd|td)di2 instruction pattern(s). -; - -(define_expand "fixuns_truncdddi2" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (unsigned_fix:DI (match_operand:DD 1 "register_operand" ""))) - (unspec:DI [(const_int 5)] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))])] - - "TARGET_HARD_DFP" -{ - if (!TARGET_Z196) - { - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx temp = gen_reg_rtx (TDmode); - REAL_VALUE_TYPE cmp, sub; - - decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */ - decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */ - - /* 2^63 can't be represented as 64bit DFP number with full precision. The - solution is doing the check and the subtraction in TD mode and using a - TD -> DI convert afterwards. */ - emit_insn (gen_extendddtd2 (temp, operands[1])); - temp = force_reg (TDmode, temp); - emit_cmp_and_jump_insns (temp, - CONST_DOUBLE_FROM_REAL_VALUE (cmp, TDmode), - LT, NULL_RTX, VOIDmode, 0, label1); - emit_insn (gen_subtd3 (temp, temp, - CONST_DOUBLE_FROM_REAL_VALUE (sub, TDmode))); - emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp, GEN_INT (11))); - emit_jump (label2); - - emit_label (label1); - emit_insn (gen_fix_truncdddi2_dfp (operands[0], operands[1], GEN_INT (9))); - emit_label (label2); - DONE; - } -}) - -(define_expand "fixuns_trunctddi2" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (unsigned_fix:DI (match_operand:TD 1 "register_operand" ""))) - (unspec:DI [(const_int 5)] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))])] - - "TARGET_HARD_DFP" -{ - if (!TARGET_Z196) - { - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx temp = gen_reg_rtx (TDmode); - REAL_VALUE_TYPE cmp, sub; - - operands[1] = force_reg (TDmode, operands[1]); - decimal_real_from_string (&cmp, "9223372036854775808.0"); /* 2^63 */ - decimal_real_from_string (&sub, "18446744073709551616.0"); /* 2^64 */ - - emit_cmp_and_jump_insns (operands[1], - CONST_DOUBLE_FROM_REAL_VALUE (cmp, TDmode), - LT, NULL_RTX, VOIDmode, 0, label1); - emit_insn (gen_subtd3 (temp, operands[1], - CONST_DOUBLE_FROM_REAL_VALUE (sub, TDmode))); - emit_insn (gen_fix_trunctddi2_dfp (operands[0], temp, GEN_INT (11))); - emit_jump (label2); - - emit_label (label1); - emit_insn (gen_fix_trunctddi2_dfp (operands[0], operands[1], GEN_INT (9))); - emit_label (label2); - DONE; - } -}) - -; -; fixuns_trunc(sf|df|tf)(si|di)2 and fix_trunc(sf|df|tf)(si|di)2 -; instruction pattern(s). -; - -(define_expand "fixuns_trunc<BFP:mode><GPR:mode>2" - [(parallel - [(set (match_operand:GPR 0 "register_operand" "") - (unsigned_fix:GPR (match_operand:BFP 1 "register_operand" ""))) - (unspec:GPR [(const_int 5)] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_HARD_FLOAT" -{ - if (!TARGET_Z196) - { - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx temp = gen_reg_rtx (<BFP:MODE>mode); - REAL_VALUE_TYPE cmp, sub; - - operands[1] = force_reg (<BFP:MODE>mode, operands[1]); - real_2expN (&cmp, GET_MODE_BITSIZE(<GPR:MODE>mode) - 1, <BFP:MODE>mode); - real_2expN (&sub, GET_MODE_BITSIZE(<GPR:MODE>mode), <BFP:MODE>mode); - - emit_cmp_and_jump_insns (operands[1], - CONST_DOUBLE_FROM_REAL_VALUE (cmp, <BFP:MODE>mode), - LT, NULL_RTX, VOIDmode, 0, label1); - emit_insn (gen_sub<BFP:mode>3 (temp, operands[1], - CONST_DOUBLE_FROM_REAL_VALUE (sub, <BFP:MODE>mode))); - emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0], temp, - GEN_INT (7))); - emit_jump (label2); - - emit_label (label1); - emit_insn (gen_fix_trunc<BFP:mode><GPR:mode>2_bfp (operands[0], - operands[1], GEN_INT (5))); - emit_label (label2); - DONE; - } -}) - -; fixuns_trunc(td|dd)si2 expander -(define_expand "fixuns_trunc<mode>si2" - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (unsigned_fix:SI (match_operand:DFP 1 "register_operand" ""))) - (unspec:SI [(const_int 5)] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_Z196 && TARGET_HARD_DFP" - "") - -; fixuns_trunc(tf|df|sf|td|dd)(di|si)2 instruction patterns. - -; clfebr, clfdbr, clfxbr, clgebr, clgdbr, clgxbr -; clfdtr, clfxtr, clgdtr, clgxtr -(define_insn "*fixuns_trunc<FP:mode><GPR:mode>2_z196" - [(set (match_operand:GPR 0 "register_operand" "=r") - (unsigned_fix:GPR (match_operand:FP 1 "register_operand" "f"))) - (unspec:GPR [(match_operand:GPR 2 "immediate_operand" "K")] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z196" - "cl<GPR:gf><FP:xde><FP:bt>r\t%0,%h2,%1,0" - [(set_attr "op_type" "RRF") - (set_attr "type" "ftoi")]) - -(define_expand "fix_trunc<DSF:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand" "") - (fix:GPR (match_operand:DSF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT" -{ - emit_insn (gen_fix_trunc<DSF:mode><GPR:mode>2_bfp (operands[0], operands[1], - GEN_INT (5))); - DONE; -}) - -; cgxbr, cgdbr, cgebr, cfxbr, cfdbr, cfebr -(define_insn "fix_trunc<BFP:mode><GPR:mode>2_bfp" - [(set (match_operand:GPR 0 "register_operand" "=d") - (fix:GPR (match_operand:BFP 1 "register_operand" "f"))) - (unspec:GPR [(match_operand:GPR 2 "immediate_operand" "K")] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "c<GPR:gf><BFP:xde>br\t%0,%h2,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "ftoi")]) - - -; -; fix_trunc(td|dd)di2 instruction pattern(s). -; - -(define_expand "fix_trunc<mode>di2" - [(set (match_operand:DI 0 "register_operand" "") - (fix:DI (match_operand:DFP 1 "nonimmediate_operand" "")))] - "TARGET_ZARCH && TARGET_HARD_DFP" -{ - operands[1] = force_reg (<MODE>mode, operands[1]); - emit_insn (gen_fix_trunc<mode>di2_dfp (operands[0], operands[1], - GEN_INT (9))); - DONE; -}) - -; cgxtr, cgdtr -(define_insn "fix_trunc<DFP:mode>di2_dfp" - [(set (match_operand:DI 0 "register_operand" "=d") - (fix:DI (match_operand:DFP 1 "register_operand" "f"))) - (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && TARGET_HARD_DFP" - "cg<DFP:xde>tr\t%0,%h2,%1" - [(set_attr "op_type" "RRF") - (set_attr "type" "ftoidfp")]) - - -; -; fix_trunctf(si|di)2 instruction pattern(s). -; - -(define_expand "fix_trunctf<mode>2" - [(parallel [(set (match_operand:GPR 0 "register_operand" "") - (fix:GPR (match_operand:TF 1 "register_operand" ""))) - (unspec:GPR [(const_int 5)] UNSPEC_ROUND) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_HARD_FLOAT" - "") - - -; -; float(si|di)(tf|df|sf|td|dd)2 instruction pattern(s). -; - -; cxgbr, cdgbr, cegbr, cxgtr, cdgtr -(define_insn "floatdi<mode>2" - [(set (match_operand:FP 0 "register_operand" "=f") - (float:FP (match_operand:DI 1 "register_operand" "d")))] - "TARGET_ZARCH && TARGET_HARD_FLOAT" - "c<xde>g<bt>r\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "itof<mode>" )]) - -; cxfbr, cdfbr, cefbr -(define_insn "floatsi<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f") - (float:BFP (match_operand:SI 1 "register_operand" "d")))] - "TARGET_HARD_FLOAT" - "c<xde>fbr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "itof<mode>" )]) - -; cxftr, cdftr -(define_insn "floatsi<mode>2" - [(set (match_operand:DFP 0 "register_operand" "=f") - (float:DFP (match_operand:SI 1 "register_operand" "d")))] - "TARGET_Z196 && TARGET_HARD_FLOAT" - "c<xde>ftr\t%0,0,%1,0" - [(set_attr "op_type" "RRE") - (set_attr "type" "itof<mode>" )]) - -; -; floatuns(si|di)(tf|df|sf|td|dd)2 instruction pattern(s). -; - -; cxlgbr, cdlgbr, celgbr, cxlgtr, cdlgtr -; cxlfbr, cdlfbr, celfbr, cxlftr, cdlftr -(define_insn "floatuns<GPR:mode><FP:mode>2" - [(set (match_operand:FP 0 "register_operand" "=f") - (unsigned_float:FP (match_operand:GPR 1 "register_operand" "d")))] - "TARGET_Z196 && TARGET_HARD_FLOAT" - "c<FP:xde>l<GPR:gf><FP:bt>r\t%0,0,%1,0" - [(set_attr "op_type" "RRE") - (set_attr "type" "itof<FP:mode>" )]) - -; -; truncdfsf2 instruction pattern(s). -; - -(define_insn "truncdfsf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "ledbr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "ftruncdf")]) - -; -; trunctf(df|sf)2 instruction pattern(s). -; - -; ldxbr, lexbr -(define_insn "trunctf<mode>2" - [(set (match_operand:DSF 0 "register_operand" "=f") - (float_truncate:DSF (match_operand:TF 1 "register_operand" "f"))) - (clobber (match_scratch:TF 2 "=f"))] - "TARGET_HARD_FLOAT" - "l<xde>xbr\t%2,%1\;l<xde>r\t%0,%2" - [(set_attr "length" "6") - (set_attr "type" "ftrunctf")]) - -; -; trunctddd2 and truncddsd2 instruction pattern(s). -; - -(define_insn "trunctddd2" - [(set (match_operand:DD 0 "register_operand" "=f") - (float_truncate:DD (match_operand:TD 1 "register_operand" "f"))) - (clobber (match_scratch:TD 2 "=f"))] - "TARGET_HARD_DFP" - "ldxtr\t%2,0,%1,0\;ldr\t%0,%2" - [(set_attr "length" "6") - (set_attr "type" "ftruncdd")]) - -(define_insn "truncddsd2" - [(set (match_operand:SD 0 "register_operand" "=f") - (float_truncate:SD (match_operand:DD 1 "register_operand" "f")))] - "TARGET_HARD_DFP" - "ledtr\t%0,0,%1,0" - [(set_attr "op_type" "RRF") - (set_attr "type" "ftruncsd")]) - -; -; extend(sf|df)(df|tf)2 instruction pattern(s). -; - -; ldebr, ldeb, lxdbr, lxdb, lxebr, lxeb -(define_insn "extend<DSF:mode><BFP:mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f,f") - (float_extend:BFP (match_operand:DSF 1 "nonimmediate_operand" "f,R")))] - "TARGET_HARD_FLOAT - && GET_MODE_SIZE (<BFP:MODE>mode) > GET_MODE_SIZE (<DSF:MODE>mode)" - "@ - l<BFP:xde><DSF:xde>br\t%0,%1 - l<BFP:xde><DSF:xde>b\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fsimp<BFP:mode>, fload<BFP:mode>")]) - -; -; extendddtd2 and extendsddd2 instruction pattern(s). -; - -(define_insn "extendddtd2" - [(set (match_operand:TD 0 "register_operand" "=f") - (float_extend:TD (match_operand:DD 1 "register_operand" "f")))] - "TARGET_HARD_DFP" - "lxdtr\t%0,%1,0" - [(set_attr "op_type" "RRF") - (set_attr "type" "fsimptf")]) - -(define_insn "extendsddd2" - [(set (match_operand:DD 0 "register_operand" "=f") - (float_extend:DD (match_operand:SD 1 "register_operand" "f")))] - "TARGET_HARD_DFP" - "ldetr\t%0,%1,0" - [(set_attr "op_type" "RRF") - (set_attr "type" "fsimptf")]) - -; Binary <-> Decimal floating point trunc patterns -; - -(define_insn "*trunc<BFP:mode><DFP_ALL:mode>2" - [(set (reg:DFP_ALL FPR0_REGNUM) - (float_truncate:DFP_ALL (reg:BFP FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_DFP" - "pfpo") - -(define_insn "*trunc<DFP_ALL:mode><BFP:mode>2" - [(set (reg:BFP FPR0_REGNUM) - (float_truncate:BFP (reg:DFP_ALL FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_DFP" - "pfpo") - -(define_expand "trunc<BFP:mode><DFP_ALL:mode>2" - [(set (reg:BFP FPR2_REGNUM) (match_operand:BFP 1 "nonimmediate_operand" "")) - (set (reg:SI GPR0_REGNUM) (match_dup 2)) - (parallel - [(set (reg:DFP_ALL FPR0_REGNUM) - (float_truncate:DFP_ALL (reg:BFP FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:DFP_ALL 0 "nonimmediate_operand" "") - (reg:DFP_ALL FPR0_REGNUM))] - "TARGET_HARD_DFP - && GET_MODE_SIZE (<BFP:MODE>mode) > GET_MODE_SIZE (<DFP_ALL:MODE>mode)" -{ - HOST_WIDE_INT flags; - - flags = (PFPO_CONVERT | - PFPO_OP_TYPE_<DFP_ALL:MODE> << PFPO_OP0_TYPE_SHIFT | - PFPO_OP_TYPE_<BFP:MODE> << PFPO_OP1_TYPE_SHIFT); - - operands[2] = GEN_INT (flags); -}) - -(define_expand "trunc<DFP_ALL:mode><BFP:mode>2" - [(set (reg:DFP_ALL FPR2_REGNUM) - (match_operand:DFP_ALL 1 "nonimmediate_operand" "")) - (set (reg:SI GPR0_REGNUM) (match_dup 2)) - (parallel - [(set (reg:BFP FPR0_REGNUM) (float_truncate:BFP (reg:DFP_ALL FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:BFP 0 "nonimmediate_operand" "") (reg:BFP FPR0_REGNUM))] - "TARGET_HARD_DFP - && GET_MODE_SIZE (<DFP_ALL:MODE>mode) >= GET_MODE_SIZE (<BFP:MODE>mode)" -{ - HOST_WIDE_INT flags; - - flags = (PFPO_CONVERT | - PFPO_OP_TYPE_<BFP:MODE> << PFPO_OP0_TYPE_SHIFT | - PFPO_OP_TYPE_<DFP_ALL:MODE> << PFPO_OP1_TYPE_SHIFT); - - operands[2] = GEN_INT (flags); -}) - -; -; Binary <-> Decimal floating point extend patterns -; - -(define_insn "*extend<BFP:mode><DFP_ALL:mode>2" - [(set (reg:DFP_ALL FPR0_REGNUM) (float_extend:DFP_ALL (reg:BFP FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_DFP" - "pfpo") - -(define_insn "*extend<DFP_ALL:mode><BFP:mode>2" - [(set (reg:BFP FPR0_REGNUM) (float_extend:BFP (reg:DFP_ALL FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_DFP" - "pfpo") - -(define_expand "extend<BFP:mode><DFP_ALL:mode>2" - [(set (reg:BFP FPR2_REGNUM) (match_operand:BFP 1 "nonimmediate_operand" "")) - (set (reg:SI GPR0_REGNUM) (match_dup 2)) - (parallel - [(set (reg:DFP_ALL FPR0_REGNUM) - (float_extend:DFP_ALL (reg:BFP FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:DFP_ALL 0 "nonimmediate_operand" "") - (reg:DFP_ALL FPR0_REGNUM))] - "TARGET_HARD_DFP - && GET_MODE_SIZE (<BFP:MODE>mode) <= GET_MODE_SIZE (<DFP_ALL:MODE>mode)" -{ - HOST_WIDE_INT flags; - - flags = (PFPO_CONVERT | - PFPO_OP_TYPE_<DFP_ALL:MODE> << PFPO_OP0_TYPE_SHIFT | - PFPO_OP_TYPE_<BFP:MODE> << PFPO_OP1_TYPE_SHIFT); - - operands[2] = GEN_INT (flags); -}) - -(define_expand "extend<DFP_ALL:mode><BFP:mode>2" - [(set (reg:DFP_ALL FPR2_REGNUM) - (match_operand:DFP_ALL 1 "nonimmediate_operand" "")) - (set (reg:SI GPR0_REGNUM) (match_dup 2)) - (parallel - [(set (reg:BFP FPR0_REGNUM) (float_extend:BFP (reg:DFP_ALL FPR2_REGNUM))) - (use (reg:SI GPR0_REGNUM)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:BFP 0 "nonimmediate_operand" "") (reg:BFP FPR0_REGNUM))] - "TARGET_HARD_DFP - && GET_MODE_SIZE (<DFP_ALL:MODE>mode) < GET_MODE_SIZE (<BFP:MODE>mode)" -{ - HOST_WIDE_INT flags; - - flags = (PFPO_CONVERT | - PFPO_OP_TYPE_<BFP:MODE> << PFPO_OP0_TYPE_SHIFT | - PFPO_OP_TYPE_<DFP_ALL:MODE> << PFPO_OP1_TYPE_SHIFT); - - operands[2] = GEN_INT (flags); -}) - - -;; -;; ARITHMETIC OPERATIONS -;; -; 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 - -;; -;;- Add instructions. -;; - -; -; addti3 instruction pattern(s). -; - -(define_insn_and_split "addti3" - [(set (match_operand:TI 0 "register_operand" "=&d") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "%0") - (match_operand:TI 2 "general_operand" "do") ) ) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (reg:CCL1 CC_REGNUM) - (compare:CCL1 (plus:DI (match_dup 7) (match_dup 8)) - (match_dup 7))) - (set (match_dup 6) (plus:DI (match_dup 7) (match_dup 8)))]) - (parallel - [(set (match_dup 3) (plus:DI - (plus:DI (ltu:DI (reg:CCL1 CC_REGNUM) (const_int 0)) - (match_dup 4)) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))])] - "operands[3] = operand_subword (operands[0], 0, 0, TImode); - operands[4] = operand_subword (operands[1], 0, 0, TImode); - operands[5] = operand_subword (operands[2], 0, 0, TImode); - operands[6] = operand_subword (operands[0], 1, 0, TImode); - operands[7] = operand_subword (operands[1], 1, 0, TImode); - operands[8] = operand_subword (operands[2], 1, 0, TImode);") - -; -; adddi3 instruction pattern(s). -; - -(define_expand "adddi3" - [(parallel - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*adddi3_sign" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (plus:DI (sign_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) - (match_operand:DI 1 "register_operand" "0,0"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "@ - agfr\t%0,%2 - agf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z196prop" "z196_cracked,z196_cracked")]) - -(define_insn "*adddi3_zero_cc" - [(set (reg CC_REGNUM) - (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) - (match_operand:DI 1 "register_operand" "0,0")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d") - (plus:DI (zero_extend:DI (match_dup 2)) (match_dup 1)))] - "s390_match_ccmode (insn, CCLmode) && TARGET_ZARCH" - "@ - algfr\t%0,%2 - algf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_insn "*adddi3_zero_cconly" - [(set (reg CC_REGNUM) - (compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) - (match_operand:DI 1 "register_operand" "0,0")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d"))] - "s390_match_ccmode (insn, CCLmode) && TARGET_ZARCH" - "@ - algfr\t%0,%2 - algf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_insn "*adddi3_zero" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) - (match_operand:DI 1 "register_operand" "0,0"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "@ - algfr\t%0,%2 - algf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_E1,z10_super_E1")]) - -(define_insn_and_split "*adddi3_31z" - [(set (match_operand:DI 0 "nonimmediate_operand" "=&d") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") - (match_operand:DI 2 "general_operand" "do") ) ) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (reg:CCL1 CC_REGNUM) - (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 (ltu:SI (reg:CCL1 CC_REGNUM) (const_int 0)) - (match_dup 4)) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))])] - "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);") - -(define_insn_and_split "*adddi3_31" - [(set (match_operand:DI 0 "nonimmediate_operand" "=&d") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") - (match_operand:DI 2 "general_operand" "do") ) ) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 3) (plus:SI (match_dup 4) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (reg:CCL1 CC_REGNUM) - (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)))]) - (set (pc) - (if_then_else (ltu (reg:CCL1 CC_REGNUM) (const_int 0)) - (pc) - (label_ref (match_dup 9)))) - (parallel - [(set (match_dup 3) (plus:SI (match_dup 3) (const_int 1))) - (clobber (reg:CC CC_REGNUM))]) - (match_dup 9)] - "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); - operands[9] = gen_label_rtx ();") - -; -; addsi3 instruction pattern(s). -; - -(define_expand "addsi3" - [(parallel - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*addsi3_sign" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (plus:SI (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T")) - (match_operand:SI 1 "register_operand" "0,0"))) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - ah\t%0,%2 - ahy\t%0,%2" - [(set_attr "op_type" "RX,RXY") - (set_attr "z196prop" "z196_cracked,z196_cracked")]) - -; -; add(di|si)3 instruction pattern(s). -; - -; ark, agrk, ar, ahi, ahik, aghik, alfi, slfi, a, ay, agr, aghi, algfi, slgfi, ag, asi, agsi -(define_insn "*add<mode>3" - [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d, d, d,d,d,QS") - (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,d, 0, 0,0,0, 0") - (match_operand:GPR 2 "general_operand" " d,d,K,K,Op,On,R,T, C") ) ) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - a<g>r\t%0,%2 - a<g>rk\t%0,%1,%2 - a<g>hi\t%0,%h2 - a<g>hik\t%0,%1,%h2 - al<g>fi\t%0,%2 - sl<g>fi\t%0,%n2 - a<g>\t%0,%2 - a<y>\t%0,%2 - a<g>si\t%0,%c2" - [(set_attr "op_type" "RR<E>,RRF,RI,RIE,RIL,RIL,RX<Y>,RXY,SIY") - (set_attr "cpu_facility" "*,z196,*,z196,extimm,extimm,*,*,z10") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,*,z10_super_E1,z10_super_E1, - z10_super_E1,z10_super_E1,z10_super_E1")]) - -; alr, alfi, slfi, al, aly, alrk, alhsik, algr, algfi, slgfi, alg, alsi, algsi, algrk, alghsik -(define_insn "*add<mode>3_carry1_cc" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d, 0, 0,d,0,0,0") - (match_operand:GPR 2 "general_operand" " d,d,Op,On,K,R,T,C")) - (match_dup 1))) - (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d, d, d,d,d,d,d") - (plus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>fi\t%0,%2 - sl<g>fi\t%0,%n2 - al<g>hsik\t%0,%1,%h2 - al<g>\t%0,%2 - al<y>\t%0,%2 - al<g>si\t%0,%c2" - [(set_attr "op_type" "RR<E>,RRF,RIL,RIL,RIE,RX<Y>,RXY,SIY") - (set_attr "cpu_facility" "*,z196,extimm,extimm,z196,*,*,z10") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1,z10_super_E1")]) - -; alr, al, aly, algr, alg, alrk, algrk -(define_insn "*add<mode>3_carry1_cconly" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (match_dup 1))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCL1mode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>\t%0,%2 - al<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg, alsi, algsi, alrk, algrk, alhsik, alghsik -(define_insn "*add<mode>3_carry2_cc" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d, 0, 0,d,0,0, 0") - (match_operand:GPR 2 "general_operand" " d,d,Op,On,K,R,T, C")) - (match_dup 2))) - (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d, d, d,d,d,d,RS") - (plus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>fi\t%0,%2 - sl<g>fi\t%0,%n2 - al<g>hsik\t%0,%1,%h2 - al<g>\t%0,%2 - al<y>\t%0,%2 - al<g>si\t%0,%c2" - [(set_attr "op_type" "RR<E>,RRF,RIL,RIL,RIE,RX<Y>,RXY,SIY") - (set_attr "cpu_facility" "*,z196,extimm,extimm,z196,*,*,z10") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1,z10_super_E1")]) - -; alr, al, aly, algr, alg, alrk, algrk -(define_insn "*add<mode>3_carry2_cconly" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (match_dup 2))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCL1mode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>\t%0,%2 - al<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg, alsi, algsi, alrk, algrk, alhsik, alghsik -(define_insn "*add<mode>3_cc" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d, 0, 0,d,0,0, 0") - (match_operand:GPR 2 "general_operand" " d,d,Op,On,K,R,T, C")) - (const_int 0))) - (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d, d, d,d,d,d,RS") - (plus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCLmode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>fi\t%0,%2 - sl<g>fi\t%0,%n2 - al<g>hsik\t%0,%1,%h2 - al<g>\t%0,%2 - al<y>\t%0,%2 - al<g>si\t%0,%c2" - [(set_attr "op_type" "RR<E>,RRF,RIL,RIL,RIE,RX<Y>,RXY,SIY") - (set_attr "cpu_facility" "*,z196,extimm,extimm,z196,*,*,z10") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1, - *,z10_super_E1,z10_super_E1,z10_super_E1")]) - -; alr, al, aly, algr, alg, alrk, algrk -(define_insn "*add<mode>3_cconly" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCLmode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>\t%0,%2 - al<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -; alr, al, aly, algr, alg, alrk, algrk -(define_insn "*add<mode>3_cconly2" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 1 "nonimmediate_operand" "%0,d,0,0") - (neg:GPR (match_operand:GPR 2 "general_operand" "d,d,R,T")))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode(insn, CCLmode)" - "@ - al<g>r\t%0,%2 - al<g>rk\t%0,%1,%2 - al<g>\t%0,%2 - al<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -; ahi, afi, aghi, agfi, asi, agsi -(define_insn "*add<mode>3_imm_cc" - [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" " 0, d,0, 0") - (match_operand:GPR 2 "const_int_operand" " K, K,Os, C")) - (const_int 0))) - (set (match_operand:GPR 0 "nonimmediate_operand" "=d, d,d,QS") - (plus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCAmode) - && (CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\") - || CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'O', \"Os\") - || CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'C', \"C\")) - && INTVAL (operands[2]) != -((HOST_WIDE_INT)1 << (GET_MODE_BITSIZE(<MODE>mode) - 1))" - "@ - a<g>hi\t%0,%h2 - a<g>hik\t%0,%1,%h2 - a<g>fi\t%0,%2 - a<g>si\t%0,%c2" - [(set_attr "op_type" "RI,RIE,RIL,SIY") - (set_attr "cpu_facility" "*,z196,extimm,z10") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -; -; add(tf|df|sf|td|dd)3 instruction pattern(s). -; - -; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr -(define_insn "add<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f, f") - (plus:FP (match_operand:FP 1 "nonimmediate_operand" "%<f0>,0") - (match_operand:FP 2 "general_operand" " f,<Rf>"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "@ - a<xde><bt>r\t%0,<op1>%2 - a<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - -; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr -(define_insn "*add<mode>3_cc" - [(set (reg CC_REGNUM) - (compare (plus:FP (match_operand:FP 1 "nonimmediate_operand" "%<f0>,0") - (match_operand:FP 2 "general_operand" " f,<Rf>")) - (match_operand:FP 3 "const0_operand" ""))) - (set (match_operand:FP 0 "register_operand" "=f,f") - (plus:FP (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "@ - a<xde><bt>r\t%0,<op1>%2 - a<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - -; axbr, adbr, aebr, axb, adb, aeb, adtr, axtr -(define_insn "*add<mode>3_cconly" - [(set (reg CC_REGNUM) - (compare (plus:FP (match_operand:FP 1 "nonimmediate_operand" "%<f0>,0") - (match_operand:FP 2 "general_operand" " f,<Rf>")) - (match_operand:FP 3 "const0_operand" ""))) - (clobber (match_scratch:FP 0 "=f,f"))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "@ - a<xde><bt>r\t%0,<op1>%2 - a<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - - -;; -;;- Subtract instructions. -;; - -; -; subti3 instruction pattern(s). -; - -(define_insn_and_split "subti3" - [(set (match_operand:TI 0 "register_operand" "=&d") - (minus:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:TI 2 "general_operand" "do") ) ) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (reg:CCL2 CC_REGNUM) - (compare:CCL2 (minus:DI (match_dup 7) (match_dup 8)) - (match_dup 7))) - (set (match_dup 6) (minus:DI (match_dup 7) (match_dup 8)))]) - (parallel - [(set (match_dup 3) (minus:DI (minus:DI (match_dup 4) (match_dup 5)) - (gtu:DI (reg:CCL2 CC_REGNUM) (const_int 0)))) - (clobber (reg:CC CC_REGNUM))])] - "operands[3] = operand_subword (operands[0], 0, 0, TImode); - operands[4] = operand_subword (operands[1], 0, 0, TImode); - operands[5] = operand_subword (operands[2], 0, 0, TImode); - operands[6] = operand_subword (operands[0], 1, 0, TImode); - operands[7] = operand_subword (operands[1], 1, 0, TImode); - operands[8] = operand_subword (operands[2], 1, 0, TImode);") - -; -; subdi3 instruction pattern(s). -; - -(define_expand "subdi3" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (minus:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*subdi3_sign" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (sign_extend:DI (match_operand:SI 2 "general_operand" "d,RT")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "@ - sgfr\t%0,%2 - sgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_c,*") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "*subdi3_zero_cc" - [(set (reg CC_REGNUM) - (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT"))) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d") - (minus:DI (match_dup 1) (zero_extend:DI (match_dup 2))))] - "s390_match_ccmode (insn, CCLmode) && TARGET_ZARCH" - "@ - slgfr\t%0,%2 - slgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_c_E1,z10_super_E1")]) - -(define_insn "*subdi3_zero_cconly" - [(set (reg CC_REGNUM) - (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT"))) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d"))] - "s390_match_ccmode (insn, CCLmode) && TARGET_ZARCH" - "@ - slgfr\t%0,%2 - slgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_c_E1,z10_super_E1")]) - -(define_insn "*subdi3_zero" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (minus:DI (match_operand:DI 1 "register_operand" "0,0") - (zero_extend:DI (match_operand:SI 2 "general_operand" "d,RT")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "@ - slgfr\t%0,%2 - slgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super_c_E1,z10_super_E1")]) - -(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 CC_REGNUM))] - "!TARGET_ZARCH && TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (reg:CCL2 CC_REGNUM) - (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 CC_REGNUM) (const_int 0)))) - (clobber (reg:CC CC_REGNUM))])] - "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);") - -(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 CC_REGNUM))] - "!TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 3) (minus:SI (match_dup 4) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (reg:CCL2 CC_REGNUM) - (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)))]) - (set (pc) - (if_then_else (gtu (reg:CCL2 CC_REGNUM) (const_int 0)) - (pc) - (label_ref (match_dup 9)))) - (parallel - [(set (match_dup 3) (plus:SI (match_dup 3) (const_int -1))) - (clobber (reg:CC CC_REGNUM))]) - (match_dup 9)] - "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); - operands[9] = gen_label_rtx ();") - -; -; subsi3 instruction pattern(s). -; - -(define_expand "subsi3" - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*subsi3_sign" - [(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 CC_REGNUM))] - "" - "@ - sh\t%0,%2 - shy\t%0,%2" - [(set_attr "op_type" "RX,RXY") - (set_attr "z196prop" "z196_cracked,z196_cracked")]) - -; -; sub(di|si)3 instruction pattern(s). -; - -; sr, s, sy, sgr, sg, srk, sgrk -(define_insn "*sub<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d") - (minus:GPR (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T") ) ) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - s<g>r\t%0,%2 - s<g>rk\t%0,%1,%2 - s<g>\t%0,%2 - s<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_borrow_cc" - [(set (reg CC_REGNUM) - (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (match_dup 1))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d") - (minus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL2mode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_borrow_cconly" - [(set (reg CC_REGNUM) - (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (match_dup 1))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCL2mode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_cc" - [(set (reg CC_REGNUM) - (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d") - (minus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCLmode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_cc2" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T"))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d") - (minus:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCL3mode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_cconly" - [(set (reg CC_REGNUM) - (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T")) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCLmode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - - -; slr, sl, sly, slgr, slg, slrk, slgrk -(define_insn "*sub<mode>3_cconly2" - [(set (reg CC_REGNUM) - (compare (match_operand:GPR 1 "register_operand" "0,d,0,0") - (match_operand:GPR 2 "general_operand" "d,d,R,T"))) - (clobber (match_scratch:GPR 0 "=d,d,d,d"))] - "s390_match_ccmode (insn, CCL3mode)" - "@ - sl<g>r\t%0,%2 - sl<g>rk\t%0,%1,%2 - sl<g>\t%0,%2 - sl<y>\t%0,%2" - [(set_attr "op_type" "RR<E>,RRF,RX<Y>,RXY") - (set_attr "cpu_facility" "*,z196,*,*") - (set_attr "z10prop" "z10_super_c_E1,*,z10_super_E1,z10_super_E1")]) - - -; -; sub(tf|df|sf|td|dd)3 instruction pattern(s). -; - -; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr -(define_insn "sub<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f, f") - (minus:FP (match_operand:FP 1 "register_operand" "<f0>,0") - (match_operand:FP 2 "general_operand" "f,<Rf>"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "@ - s<xde><bt>r\t%0,<op1>%2 - s<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - -; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr -(define_insn "*sub<mode>3_cc" - [(set (reg CC_REGNUM) - (compare (minus:FP (match_operand:FP 1 "nonimmediate_operand" "<f0>,0") - (match_operand:FP 2 "general_operand" "f,<Rf>")) - (match_operand:FP 3 "const0_operand" ""))) - (set (match_operand:FP 0 "register_operand" "=f,f") - (minus:FP (match_dup 1) (match_dup 2)))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "@ - s<xde><bt>r\t%0,<op1>%2 - s<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - -; sxbr, sdbr, sebr, sdb, seb, sxtr, sdtr -(define_insn "*sub<mode>3_cconly" - [(set (reg CC_REGNUM) - (compare (minus:FP (match_operand:FP 1 "nonimmediate_operand" "<f0>,0") - (match_operand:FP 2 "general_operand" "f,<Rf>")) - (match_operand:FP 3 "const0_operand" ""))) - (clobber (match_scratch:FP 0 "=f,f"))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "@ - s<xde><bt>r\t%0,<op1>%2 - s<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fsimp<mode>")]) - - -;; -;;- Conditional add/subtract instructions. -;; - -; -; add(di|si)cc instruction pattern(s). -; - -; the following 4 patterns are used when the result of an add with -; carry is checked for an overflow condition - -; op1 + op2 + c < op1 - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc_carry1_cc" - [(set (reg CC_REGNUM) - (compare - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_dup 1))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (plus:GPR (plus:GPR (match_dup 3) (match_dup 1)) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode) && TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z196prop" "z196_alone,z196_alone")]) - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc_carry1_cconly" - [(set (reg CC_REGNUM) - (compare - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_dup 1))) - (clobber (match_scratch:GPR 0 "=d,d"))] - "s390_match_ccmode (insn, CCL1mode) && TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z196prop" "z196_alone,z196_alone")]) - -; op1 + op2 + c < op2 - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc_carry2_cc" - [(set (reg CC_REGNUM) - (compare - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_dup 2))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (plus:GPR (plus:GPR (match_dup 3) (match_dup 1)) (match_dup 2)))] - "s390_match_ccmode (insn, CCL1mode) && TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY")]) - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc_carry2_cconly" - [(set (reg CC_REGNUM) - (compare - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_dup 2))) - (clobber (match_scratch:GPR 0 "=d,d"))] - "s390_match_ccmode (insn, CCL1mode) && TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY")]) - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc_cc" - [(set (reg CC_REGNUM) - (compare - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (plus:GPR (plus:GPR (match_dup 3) (match_dup 1)) (match_dup 2)))] - "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY")]) - -; alcr, alc, alcgr, alcg -(define_insn "*add<mode>3_alc" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (plus:GPR (plus:GPR (match_operand:GPR 3 "s390_alc_comparison" "") - (match_operand:GPR 1 "nonimmediate_operand" "%0,0")) - (match_operand:GPR 2 "general_operand" "d,RT"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_CPU_ZARCH" - "@ - alc<g>r\t%0,%2 - alc<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY")]) - -; slbr, slb, slbgr, slbg -(define_insn "*sub<mode>3_slb_cc" - [(set (reg CC_REGNUM) - (compare - (minus:GPR (minus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0") - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_operand:GPR 3 "s390_slb_comparison" "")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (minus:GPR (minus:GPR (match_dup 1) (match_dup 2)) (match_dup 3)))] - "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH" - "@ - slb<g>r\t%0,%2 - slb<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_c,*")]) - -; slbr, slb, slbgr, slbg -(define_insn "*sub<mode>3_slb" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (minus:GPR (minus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0") - (match_operand:GPR 2 "general_operand" "d,RT")) - (match_operand:GPR 3 "s390_slb_comparison" ""))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_CPU_ZARCH" - "@ - slb<g>r\t%0,%2 - slb<g>\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_c,*")]) - -(define_expand "add<mode>cc" - [(match_operand:GPR 0 "register_operand" "") - (match_operand 1 "comparison_operator" "") - (match_operand:GPR 2 "register_operand" "") - (match_operand:GPR 3 "const_int_operand" "")] - "TARGET_CPU_ZARCH" - "if (!s390_expand_addcc (GET_CODE (operands[1]), - XEXP (operands[1], 0), XEXP (operands[1], 1), - operands[0], operands[2], - operands[3])) FAIL; DONE;") - -; -; scond instruction pattern(s). -; - -(define_insn_and_split "*scond<mode>" - [(set (match_operand:GPR 0 "register_operand" "=&d") - (match_operand:GPR 1 "s390_alc_comparison" "")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) (const_int 0)) - (parallel - [(set (match_dup 0) (plus:GPR (plus:GPR (match_dup 1) (match_dup 0)) - (match_dup 0))) - (clobber (reg:CC CC_REGNUM))])] - "") - -(define_insn_and_split "*scond<mode>_neg" - [(set (match_operand:GPR 0 "register_operand" "=&d") - (match_operand:GPR 1 "s390_slb_comparison" "")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_CPU_ZARCH" - "#" - "&& reload_completed" - [(set (match_dup 0) (const_int 0)) - (parallel - [(set (match_dup 0) (minus:GPR (minus:GPR (match_dup 0) (match_dup 0)) - (match_dup 1))) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_dup 0) (neg:GPR (match_dup 0))) - (clobber (reg:CC CC_REGNUM))])] - "") - - -(define_expand "cstore<mode>4" - [(set (match_operand:SI 0 "register_operand" "") - (match_operator:SI 1 "s390_scond_operator" - [(match_operand:GPR 2 "register_operand" "") - (match_operand:GPR 3 "general_operand" "")]))] - "TARGET_CPU_ZARCH" - "if (!s390_expand_addcc (GET_CODE (operands[1]), operands[2], operands[3], - operands[0], const0_rtx, const1_rtx)) FAIL; DONE;") - -(define_expand "cstorecc4" - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (match_operator:SI 1 "s390_eqne_operator" - [(match_operand:CCZ1 2 "register_operand") - (match_operand 3 "const0_operand")])) - (clobber (reg:CC CC_REGNUM))])] - "" - "emit_insn (gen_sne (operands[0], operands[2])); - if (GET_CODE (operands[1]) == EQ) - emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); - DONE;") - -(define_insn_and_split "sne" - [(set (match_operand:SI 0 "register_operand" "=d") - (ne:SI (match_operand:CCZ1 1 "register_operand" "0") - (const_int 0))) - (clobber (reg:CC CC_REGNUM))] - "" - "#" - "reload_completed" - [(parallel - [(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 28))) - (clobber (reg:CC CC_REGNUM))])]) - - -;; -;; - Conditional move instructions (introduced with z196) -;; - -(define_expand "mov<mode>cc" - [(set (match_operand:GPR 0 "nonimmediate_operand" "") - (if_then_else:GPR (match_operand 1 "comparison_operator" "") - (match_operand:GPR 2 "nonimmediate_operand" "") - (match_operand:GPR 3 "nonimmediate_operand" "")))] - "TARGET_Z196" - "operands[1] = s390_emit_compare (GET_CODE (operands[1]), - XEXP (operands[1], 0), XEXP (operands[1], 1));") - -; locr, loc, stoc, locgr, locg, stocg -(define_insn_and_split "*mov<mode>cc" - [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,d, d, d,QS,QS,&d") - (if_then_else:GPR - (match_operator 1 "s390_comparison" - [(match_operand 2 "cc_reg_operand" " c,c, c, c, c, c, c") - (const_int 0)]) - (match_operand:GPR 3 "nonimmediate_operand" " d,0,QS, 0, d, 0,QS") - (match_operand:GPR 4 "nonimmediate_operand" " 0,d, 0,QS, 0, d,QS")))] - "TARGET_Z196" - "@ - loc<g>r%C1\t%0,%3 - loc<g>r%D1\t%0,%4 - loc<g>%C1\t%0,%3 - loc<g>%D1\t%0,%4 - stoc<g>%C1\t%3,%0 - stoc<g>%D1\t%4,%0 - #" - "&& reload_completed - && MEM_P (operands[3]) && MEM_P (operands[4])" - [(set (match_dup 0) - (if_then_else:GPR - (match_op_dup 1 [(match_dup 2) (const_int 0)]) - (match_dup 3) - (match_dup 0))) - (set (match_dup 0) - (if_then_else:GPR - (match_op_dup 1 [(match_dup 2) (const_int 0)]) - (match_dup 0) - (match_dup 4)))] - "" - [(set_attr "op_type" "RRF,RRF,RSY,RSY,RSY,RSY,*")]) - -;; -;;- Multiply instructions. -;; - -; -; muldi3 instruction pattern(s). -; - -(define_insn "*muldi3_sign" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (mult:DI (sign_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) - (match_operand:DI 1 "register_operand" "0,0")))] - "TARGET_ZARCH" - "@ - msgfr\t%0,%2 - msgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "type" "imuldi")]) - -(define_insn "muldi3" - [(set (match_operand:DI 0 "register_operand" "=d,d,d,d") - (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,0") - (match_operand:DI 2 "general_operand" "d,K,RT,Os")))] - "TARGET_ZARCH" - "@ - msgr\t%0,%2 - mghi\t%0,%h2 - msg\t%0,%2 - msgfi\t%0,%2" - [(set_attr "op_type" "RRE,RI,RXY,RIL") - (set_attr "type" "imuldi") - (set_attr "cpu_facility" "*,*,*,z10")]) - -; -; mulsi3 instruction pattern(s). -; - -(define_insn "*mulsi3_sign" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (mult:SI (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T")) - (match_operand:SI 1 "register_operand" "0,0")))] - "" - "@ - mh\t%0,%2 - mhy\t%0,%2" - [(set_attr "op_type" "RX,RXY") - (set_attr "type" "imulhi") - (set_attr "cpu_facility" "*,z10")]) - -(define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") - (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0") - (match_operand:SI 2 "general_operand" "d,K,R,T,Os")))] - "" - "@ - msr\t%0,%2 - mhi\t%0,%h2 - ms\t%0,%2 - msy\t%0,%2 - msfi\t%0,%2" - [(set_attr "op_type" "RRE,RI,RX,RXY,RIL") - (set_attr "type" "imulsi,imulhi,imulsi,imulsi,imulsi") - (set_attr "cpu_facility" "*,*,*,*,z10")]) - -; -; mulsidi3 instruction pattern(s). -; - -(define_insn "mulsidi3" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (mult:DI (sign_extend:DI - (match_operand:SI 1 "register_operand" "%0,0,0")) - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,R,T"))))] - "!TARGET_ZARCH" - "@ - mr\t%0,%2 - m\t%0,%2 - mfy\t%0,%2" - [(set_attr "op_type" "RR,RX,RXY") - (set_attr "type" "imulsi") - (set_attr "cpu_facility" "*,*,z10")]) - -; -; umul instruction pattern(s). -; - -; mlr, ml, mlgr, mlg -(define_insn "umul<dwh><mode>3" - [(set (match_operand:DW 0 "register_operand" "=d, d") - (mult:DW (zero_extend:DW - (match_operand:<DWH> 1 "register_operand" "%0, 0")) - (zero_extend:DW - (match_operand:<DWH> 2 "nonimmediate_operand" " d,RT"))))] - "TARGET_CPU_ZARCH" - "@ - ml<tg>r\t%0,%2 - ml<tg>\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "type" "imul<dwh>")]) - -; -; mul(tf|df|sf|td|dd)3 instruction pattern(s). -; - -; mxbr, mdbr, meebr, mxb, mxb, meeb, mdtr, mxtr -(define_insn "mul<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f") - (mult:FP (match_operand:FP 1 "nonimmediate_operand" "%<f0>,0") - (match_operand:FP 2 "general_operand" "f,<Rf>")))] - "TARGET_HARD_FLOAT" - "@ - m<xdee><bt>r\t%0,<op1>%2 - m<xdee>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fmul<mode>")]) - -; madbr, maebr, maxb, madb, maeb -(define_insn "fma<mode>4" - [(set (match_operand:DSF 0 "register_operand" "=f,f") - (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f") - (match_operand:DSF 2 "nonimmediate_operand" "f,R") - (match_operand:DSF 3 "register_operand" "0,0")))] - "TARGET_HARD_FLOAT" - "@ - ma<xde>br\t%0,%1,%2 - ma<xde>b\t%0,%1,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fmadd<mode>")]) - -; msxbr, msdbr, msebr, msxb, msdb, mseb -(define_insn "fms<mode>4" - [(set (match_operand:DSF 0 "register_operand" "=f,f") - (fma:DSF (match_operand:DSF 1 "nonimmediate_operand" "%f,f") - (match_operand:DSF 2 "nonimmediate_operand" "f,R") - (neg:DSF (match_operand:DSF 3 "register_operand" "0,0"))))] - "TARGET_HARD_FLOAT" - "@ - ms<xde>br\t%0,%1,%2 - ms<xde>b\t%0,%1,%2" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fmadd<mode>")]) - -;; -;;- Divide and modulo instructions. -;; - -; -; divmoddi4 instruction pattern(s). -; - -(define_expand "divmoddi4" - [(parallel [(set (match_operand:DI 0 "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_ZARCH" -{ - 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]); - - operands[4] = gen_reg_rtx(TImode); - emit_insn (gen_divmodtidi3 (operands[4], operands[1], operands[2])); - - insn = emit_move_insn (operands[0], gen_lowpart (DImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, div_equal); - - insn = emit_move_insn (operands[3], gen_highpart (DImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, mod_equal); - - DONE; -}) - -(define_insn "divmodtidi3" - [(set (match_operand:TI 0 "register_operand" "=d,d") - (ior:TI - (ashift:TI - (zero_extend:TI - (mod:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:DI 2 "general_operand" "d,RT"))) - (const_int 64)) - (zero_extend:TI (div:DI (match_dup 1) (match_dup 2)))))] - "TARGET_ZARCH" - "@ - 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 - (ashift:TI - (zero_extend:TI - (mod:DI (match_operand:DI 1 "register_operand" "0,0") - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,RT")))) - (const_int 64)) - (zero_extend:TI - (div:DI (match_dup 1) (sign_extend:DI (match_dup 2))))))] - "TARGET_ZARCH" - "@ - dsgfr\t%0,%2 - dsgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "type" "idiv")]) - -; -; udivmoddi4 instruction pattern(s). -; - -(define_expand "udivmoddi4" - [(parallel [(set (match_operand:DI 0 "general_operand" "") - (udiv:DI (match_operand:DI 1 "general_operand" "") - (match_operand:DI 2 "nonimmediate_operand" ""))) - (set (match_operand:DI 3 "general_operand" "") - (umod:DI (match_dup 1) (match_dup 2)))]) - (clobber (match_dup 4))] - "TARGET_ZARCH" -{ - rtx insn, div_equal, mod_equal, equal; - - div_equal = gen_rtx_UDIV (DImode, operands[1], operands[2]); - mod_equal = gen_rtx_UMOD (DImode, operands[1], operands[2]); - equal = gen_rtx_IOR (TImode, - gen_rtx_ASHIFT (TImode, - gen_rtx_ZERO_EXTEND (TImode, mod_equal), - GEN_INT (64)), - gen_rtx_ZERO_EXTEND (TImode, div_equal)); - - operands[4] = gen_reg_rtx(TImode); - emit_clobber (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_udivmodtidi3 (operands[4], operands[4], operands[2])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], gen_lowpart (DImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, div_equal); - - insn = emit_move_insn (operands[3], gen_highpart (DImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, mod_equal); - - DONE; -}) - -(define_insn "udivmodtidi3" - [(set (match_operand:TI 0 "register_operand" "=d,d") - (ior:TI - (ashift:TI - (zero_extend:TI - (truncate:DI - (umod:TI (match_operand:TI 1 "register_operand" "0,0") - (zero_extend:TI - (match_operand:DI 2 "nonimmediate_operand" "d,RT"))))) - (const_int 64)) - (zero_extend:TI - (truncate:DI - (udiv:TI (match_dup 1) (zero_extend:TI (match_dup 2)))))))] - "TARGET_ZARCH" - "@ - dlgr\t%0,%2 - dlg\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "type" "idiv")]) - -; -; divmodsi4 instruction pattern(s). -; - -(define_expand "divmodsi4" - [(parallel [(set (match_operand:SI 0 "general_operand" "") - (div:SI (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "nonimmediate_operand" ""))) - (set (match_operand:SI 3 "general_operand" "") - (mod:SI (match_dup 1) (match_dup 2)))]) - (clobber (match_dup 4))] - "!TARGET_ZARCH" -{ - rtx insn, div_equal, mod_equal, equal; - - div_equal = gen_rtx_DIV (SImode, operands[1], operands[2]); - mod_equal = gen_rtx_MOD (SImode, operands[1], operands[2]); - equal = gen_rtx_IOR (DImode, - gen_rtx_ASHIFT (DImode, - gen_rtx_ZERO_EXTEND (DImode, mod_equal), - GEN_INT (32)), - gen_rtx_ZERO_EXTEND (DImode, div_equal)); - - operands[4] = gen_reg_rtx(DImode); - emit_insn (gen_extendsidi2 (operands[4], operands[1])); - - insn = emit_insn (gen_divmoddisi3 (operands[4], operands[4], operands[2])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], gen_lowpart (SImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, div_equal); - - insn = emit_move_insn (operands[3], gen_highpart (SImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, mod_equal); - - DONE; -}) - -(define_insn "divmoddisi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ior:DI - (ashift:DI - (zero_extend:DI - (truncate:SI - (mod:DI (match_operand:DI 1 "register_operand" "0,0") - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,R"))))) - (const_int 32)) - (zero_extend:DI - (truncate:SI - (div:DI (match_dup 1) (sign_extend:DI (match_dup 2)))))))] - "!TARGET_ZARCH" - "@ - dr\t%0,%2 - d\t%0,%2" - [(set_attr "op_type" "RR,RX") - (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_ZARCH && 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_ASHIFT (DImode, - gen_rtx_ZERO_EXTEND (DImode, mod_equal), - GEN_INT (32)), - gen_rtx_ZERO_EXTEND (DImode, div_equal)); - - operands[4] = gen_reg_rtx(DImode); - emit_clobber (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])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], gen_lowpart (SImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, div_equal); - - insn = emit_move_insn (operands[3], gen_highpart (SImode, operands[4])); - set_unique_reg_note (insn, REG_EQUAL, mod_equal); - - DONE; -}) - -(define_insn "udivmoddisi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ior:DI - (ashift:DI - (zero_extend:DI - (truncate:SI - (umod:DI (match_operand:DI 1 "register_operand" "0,0") - (zero_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,RT"))))) - (const_int 32)) - (zero_extend:DI - (truncate:SI - (udiv:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))))] - "!TARGET_ZARCH && 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_ZARCH && !TARGET_CPU_ZARCH" -{ - rtx insn, udiv_equal, umod_equal, equal; - - udiv_equal = gen_rtx_UDIV (SImode, operands[1], operands[2]); - umod_equal = gen_rtx_UMOD (SImode, operands[1], operands[2]); - equal = gen_rtx_IOR (DImode, - gen_rtx_ASHIFT (DImode, - gen_rtx_ZERO_EXTEND (DImode, umod_equal), - GEN_INT (32)), - gen_rtx_ZERO_EXTEND (DImode, udiv_equal)); - - operands[3] = gen_reg_rtx (DImode); - - if (CONSTANT_P (operands[2])) - { - if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) - { - rtx label1 = gen_label_rtx (); - - operands[1] = make_safe_from (operands[1], operands[0]); - emit_move_insn (operands[0], const0_rtx); - emit_cmp_and_jump_insns (operands[1], operands[2], LT, NULL_RTX, - SImode, 1, label1); - emit_move_insn (operands[0], const1_rtx); - emit_label (label1); - } - else - { - 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])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], - gen_lowpart (SImode, operands[3])); - set_unique_reg_note (insn, REG_EQUAL, udiv_equal); - } - } - 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]); - - emit_move_insn (operands[0], const0_rtx); - emit_cmp_and_jump_insns (operands[2], operands[1], GT, NULL_RTX, - SImode, 1, label3); - emit_cmp_and_jump_insns (operands[2], const0_rtx, LT, NULL_RTX, - SImode, 0, label2); - emit_cmp_and_jump_insns (operands[2], const1_rtx, EQ, NULL_RTX, - SImode, 0, label1); - emit_insn (gen_zero_extendsidi2 (operands[3], operands[1])); - insn = emit_insn (gen_divmoddisi3 (operands[3], operands[3], - operands[2])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], - gen_lowpart (SImode, operands[3])); - set_unique_reg_note (insn, REG_EQUAL, udiv_equal); - - emit_jump (label3); - emit_label (label1); - emit_move_insn (operands[0], operands[1]); - emit_jump (label3); - emit_label (label2); - emit_move_insn (operands[0], const1_rtx); - emit_label (label3); - } - 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_ZARCH && !TARGET_CPU_ZARCH" -{ - rtx insn, udiv_equal, umod_equal, equal; - - udiv_equal = gen_rtx_UDIV (SImode, operands[1], operands[2]); - umod_equal = gen_rtx_UMOD (SImode, operands[1], operands[2]); - equal = gen_rtx_IOR (DImode, - gen_rtx_ASHIFT (DImode, - gen_rtx_ZERO_EXTEND (DImode, umod_equal), - GEN_INT (32)), - gen_rtx_ZERO_EXTEND (DImode, udiv_equal)); - - operands[3] = gen_reg_rtx (DImode); - - if (CONSTANT_P (operands[2])) - { - if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) <= 0) - { - rtx label1 = gen_label_rtx (); - - operands[1] = make_safe_from (operands[1], operands[0]); - emit_move_insn (operands[0], operands[1]); - emit_cmp_and_jump_insns (operands[0], operands[2], LT, NULL_RTX, - SImode, 1, label1); - emit_insn (gen_abssi2 (operands[0], operands[2])); - emit_insn (gen_addsi3 (operands[0], operands[0], operands[1])); - emit_label (label1); - } - else - { - 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])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], - gen_highpart (SImode, operands[3])); - set_unique_reg_note (insn, REG_EQUAL, umod_equal); - } - } - 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]); - - emit_move_insn(operands[0], operands[1]); - emit_cmp_and_jump_insns (operands[2], operands[1], GT, NULL_RTX, - SImode, 1, label3); - emit_cmp_and_jump_insns (operands[2], const0_rtx, LT, NULL_RTX, - SImode, 0, label2); - emit_cmp_and_jump_insns (operands[2], const1_rtx, EQ, NULL_RTX, - SImode, 0, label1); - emit_insn (gen_zero_extendsidi2 (operands[3], operands[1])); - insn = emit_insn (gen_divmoddisi3 (operands[3], operands[3], - operands[2])); - set_unique_reg_note (insn, REG_EQUAL, equal); - - insn = emit_move_insn (operands[0], - gen_highpart (SImode, operands[3])); - set_unique_reg_note (insn, REG_EQUAL, umod_equal); - - emit_jump (label3); - emit_label (label1); - emit_move_insn (operands[0], const0_rtx); - emit_jump (label3); - emit_label (label2); - emit_insn (gen_subsi3 (operands[0], operands[0], operands[2])); - emit_label (label3); - } - DONE; -}) - -; -; div(df|sf)3 instruction pattern(s). -; - -; dxbr, ddbr, debr, dxb, ddb, deb, ddtr, dxtr -(define_insn "div<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f,f") - (div:FP (match_operand:FP 1 "register_operand" "<f0>,0") - (match_operand:FP 2 "general_operand" "f,<Rf>")))] - "TARGET_HARD_FLOAT" - "@ - d<xde><bt>r\t%0,<op1>%2 - d<xde>b\t%0,%2" - [(set_attr "op_type" "<RRer>,RXE") - (set_attr "type" "fdiv<mode>")]) - - -;; -;;- And instructions. -;; - -(define_expand "and<mode>3" - [(set (match_operand:INT 0 "nonimmediate_operand" "") - (and:INT (match_operand:INT 1 "nonimmediate_operand" "") - (match_operand:INT 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "" - "s390_expand_logical_operator (AND, <MODE>mode, operands); DONE;") - -; -; anddi3 instruction pattern(s). -; - -(define_insn "*anddi3_cc" - [(set (reg CC_REGNUM) - (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d, 0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d, d") - (and:DI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH" - "@ - ngr\t%0,%2 - ngrk\t%0,%1,%2 - ng\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*anddi3_cconly" - [(set (reg CC_REGNUM) - (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d, 0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d, d"))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH - /* Do not steal TM patterns. */ - && s390_single_part (operands[2], DImode, HImode, 0) < 0" - "@ - ngr\t%0,%2 - ngrk\t%0,%1,%2 - ng\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*anddi3" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=d,d, d, d, d, d, d, d,d,d, d, AQ,Q") - (and:DI (match_operand:DI 1 "nonimmediate_operand" - "%d,o, 0, 0, 0, 0, 0, 0,0,d, 0, 0,0") - (match_operand:DI 2 "general_operand" - "M, M,N0HDF,N1HDF,N2HDF,N3HDF,N0SDF,N1SDF,d,d,RT,NxQDF,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - # - # - nihh\t%0,%j2 - nihl\t%0,%j2 - nilh\t%0,%j2 - nill\t%0,%j2 - nihf\t%0,%m2 - nilf\t%0,%m2 - ngr\t%0,%2 - ngrk\t%0,%1,%2 - ng\t%0,%2 - # - #" - [(set_attr "op_type" "RRE,RXE,RI,RI,RI,RI,RIL,RIL,RRE,RRF,RXY,SI,SS") - (set_attr "cpu_facility" "*,*,*,*,*,*,extimm,extimm,*,z196,*,*,*") - (set_attr "z10prop" "*, - *, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - *, - z10_super_E1, - *, - *")]) - -(define_split - [(set (match_operand:DI 0 "s_operand" "") - (and:DI (match_dup 0) (match_operand:DI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (AND, &operands[0], &operands[1]);") - - -; -; andsi3 instruction pattern(s). -; - -(define_insn "*andsi3_cc" - [(set (reg CC_REGNUM) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") - (and:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode)" - "@ - nilf\t%0,%o2 - nr\t%0,%2 - nrk\t%0,%1,%2 - n\t%0,%2 - ny\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -(define_insn "*andsi3_cconly" - [(set (reg CC_REGNUM) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d,d,d,d"))] - "s390_match_ccmode(insn, CCTmode) - /* Do not steal TM patterns. */ - && s390_single_part (operands[2], SImode, HImode, 0) < 0" - "@ - nilf\t%0,%o2 - nr\t%0,%2 - nrk\t%0,%1,%2 - n\t%0,%2 - ny\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1")]) - -(define_insn "*andsi3_zarch" - [(set (match_operand:SI 0 "nonimmediate_operand" - "=d,d, d, d, d,d,d,d,d, AQ,Q") - (and:SI (match_operand:SI 1 "nonimmediate_operand" - "%d,o, 0, 0, 0,0,d,0,0, 0,0") - (match_operand:SI 2 "general_operand" - " M,M,N0HSF,N1HSF,Os,d,d,R,T,NxQSF,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - # - # - nilh\t%0,%j2 - nill\t%0,%j2 - nilf\t%0,%o2 - nr\t%0,%2 - nrk\t%0,%1,%2 - n\t%0,%2 - ny\t%0,%2 - # - #" - [(set_attr "op_type" "RRE,RXE,RI,RI,RIL,RR,RRF,RX,RXY,SI,SS") - (set_attr "cpu_facility" "*,*,*,*,*,*,z196,*,*,*,*") - (set_attr "z10prop" "*, - *, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - *, - z10_super_E1, - z10_super_E1, - *, - *")]) - -(define_insn "*andsi3_esa" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d, AQ,Q") - (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0, 0,0") - (match_operand:SI 2 "general_operand" " d,R,NxQSF,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - nr\t%0,%2 - n\t%0,%2 - # - #" - [(set_attr "op_type" "RR,RX,SI,SS") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,*")]) - - -(define_split - [(set (match_operand:SI 0 "s_operand" "") - (and:SI (match_dup 0) (match_operand:SI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (AND, &operands[0], &operands[1]);") - -; -; andhi3 instruction pattern(s). -; - -(define_insn "*andhi3_zarch" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d, AQ,Q") - (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,d,0, 0,0") - (match_operand:HI 2 "general_operand" " d,d,n,NxQHF,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - nr\t%0,%2 - nrk\t%0,%1,%2 - nill\t%0,%x2 - # - #" - [(set_attr "op_type" "RR,RRF,RI,SI,SS") - (set_attr "cpu_facility" "*,z196,*,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,*,*") -]) - -(define_insn "*andhi3_esa" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,AQ,Q") - (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:HI 2 "general_operand" "d,NxQHF,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - nr\t%0,%2 - # - #" - [(set_attr "op_type" "RR,SI,SS") - (set_attr "z10prop" "z10_super_E1,*,*") -]) - -(define_split - [(set (match_operand:HI 0 "s_operand" "") - (and:HI (match_dup 0) (match_operand:HI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (AND, &operands[0], &operands[1]);") - -; -; andqi3 instruction pattern(s). -; - -(define_insn "*andqi3_zarch" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,Q,S,Q") - (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,d,0,0,0,0") - (match_operand:QI 2 "general_operand" " d,d,n,n,n,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - nr\t%0,%2 - nrk\t%0,%1,%2 - nill\t%0,%b2 - ni\t%S0,%b2 - niy\t%S0,%b2 - #" - [(set_attr "op_type" "RR,RRF,RI,SI,SIY,SS") - (set_attr "cpu_facility" "*,z196,*,*,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,z10_super,z10_super,*")]) - -(define_insn "*andqi3_esa" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,Q,Q") - (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "d,n,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - nr\t%0,%2 - ni\t%S0,%b2 - #" - [(set_attr "op_type" "RR,SI,SS") - (set_attr "z10prop" "z10_super_E1,z10_super,*")]) - -; -; Block and (NC) patterns. -; - -(define_insn "*nc" - [(set (match_operand:BLK 0 "memory_operand" "=Q") - (and:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" "Q"))) - (use (match_operand 2 "const_int_operand" "n")) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256" - "nc\t%O0(%2,%R0),%S1" - [(set_attr "op_type" "SS") - (set_attr "z196prop" "z196_cracked")]) - -(define_split - [(set (match_operand 0 "memory_operand" "") - (and (match_dup 0) - (match_operand 1 "memory_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) > 0" - [(parallel - [(set (match_dup 0) (and:BLK (match_dup 0) (match_dup 1))) - (use (match_dup 2)) - (clobber (reg:CC CC_REGNUM))])] -{ - operands[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))); - operands[0] = adjust_address (operands[0], BLKmode, 0); - operands[1] = adjust_address (operands[1], BLKmode, 0); -}) - -(define_peephole2 - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (and:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_operand:BLK 3 "memory_operand" "") - (and:BLK (match_dup 3) - (match_operand:BLK 4 "memory_operand" ""))) - (use (match_operand 5 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "s390_offset_p (operands[0], operands[3], operands[2]) - && s390_offset_p (operands[1], operands[4], operands[2]) - && !s390_overlap_p (operands[0], operands[1], - INTVAL (operands[2]) + INTVAL (operands[5])) - && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256" - [(parallel - [(set (match_dup 6) (and:BLK (match_dup 6) (match_dup 7))) - (use (match_dup 8)) - (clobber (reg:CC CC_REGNUM))])] - "operands[6] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0)); - operands[7] = gen_rtx_MEM (BLKmode, XEXP (operands[1], 0)); - operands[8] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[5]));") - - -;; -;;- Bit set (inclusive or) instructions. -;; - -(define_expand "ior<mode>3" - [(set (match_operand:INT 0 "nonimmediate_operand" "") - (ior:INT (match_operand:INT 1 "nonimmediate_operand" "") - (match_operand:INT 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "" - "s390_expand_logical_operator (IOR, <MODE>mode, operands); DONE;") - -; -; iordi3 instruction pattern(s). -; - -(define_insn "*iordi3_cc" - [(set (reg CC_REGNUM) - (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d, 0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d, d") - (ior:DI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH" - "@ - ogr\t%0,%2 - ogrk\t%0,%1,%2 - og\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*iordi3_cconly" - [(set (reg CC_REGNUM) - (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d,0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d,d"))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH" - "@ - ogr\t%0,%2 - ogrk\t%0,%1,%2 - og\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*iordi3" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=d, d, d, d, d, d,d,d, d, AQ,Q") - (ior:DI (match_operand:DI 1 "nonimmediate_operand" - " %0, 0, 0, 0, 0, 0,0,d, 0, 0,0") - (match_operand:DI 2 "general_operand" - "N0HD0,N1HD0,N2HD0,N3HD0,N0SD0,N1SD0,d,d,RT,NxQD0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - oihh\t%0,%i2 - oihl\t%0,%i2 - oilh\t%0,%i2 - oill\t%0,%i2 - oihf\t%0,%k2 - oilf\t%0,%k2 - ogr\t%0,%2 - ogrk\t%0,%1,%2 - og\t%0,%2 - # - #" - [(set_attr "op_type" "RI,RI,RI,RI,RIL,RIL,RRE,RRF,RXY,SI,SS") - (set_attr "cpu_facility" "*,*,*,*,extimm,extimm,*,z196,*,*,*") - (set_attr "z10prop" "z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - *, - z10_super_E1, - *, - *")]) - -(define_split - [(set (match_operand:DI 0 "s_operand" "") - (ior:DI (match_dup 0) (match_operand:DI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (ior:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (IOR, &operands[0], &operands[1]);") - -; -; iorsi3 instruction pattern(s). -; - -(define_insn "*iorsi3_cc" - [(set (reg CC_REGNUM) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") - (ior:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode)" - "@ - oilf\t%0,%o2 - or\t%0,%2 - ork\t%0,%1,%2 - o\t%0,%2 - oy\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -(define_insn "*iorsi3_cconly" - [(set (reg CC_REGNUM) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d,d,d,d"))] - "s390_match_ccmode(insn, CCTmode)" - "@ - oilf\t%0,%o2 - or\t%0,%2 - ork\t%0,%1,%2 - o\t%0,%2 - oy\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,z10_super_E1,z10_super_E1")]) - -(define_insn "*iorsi3_zarch" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d, d, d,d,d,d,d, AQ,Q") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0, 0, 0,0,d,0,0, 0,0") - (match_operand:SI 2 "general_operand" "N0HS0,N1HS0,Os,d,d,R,T,NxQS0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - oilh\t%0,%i2 - oill\t%0,%i2 - oilf\t%0,%o2 - or\t%0,%2 - ork\t%0,%1,%2 - o\t%0,%2 - oy\t%0,%2 - # - #" - [(set_attr "op_type" "RI,RI,RIL,RR,RRF,RX,RXY,SI,SS") - (set_attr "cpu_facility" "*,*,*,*,z196,*,*,*,*") - (set_attr "z10prop" "z10_super_E1, - z10_super_E1, - z10_super_E1, - z10_super_E1, - *, - z10_super_E1, - z10_super_E1, - *, - *")]) - -(define_insn "*iorsi3_esa" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,AQ,Q") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0") - (match_operand:SI 2 "general_operand" "d,R,NxQS0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - or\t%0,%2 - o\t%0,%2 - # - #" - [(set_attr "op_type" "RR,RX,SI,SS") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,*")]) - -(define_split - [(set (match_operand:SI 0 "s_operand" "") - (ior:SI (match_dup 0) (match_operand:SI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (ior:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (IOR, &operands[0], &operands[1]);") - -; -; iorhi3 instruction pattern(s). -; - -(define_insn "*iorhi3_zarch" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d, AQ,Q") - (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,d,0, 0,0") - (match_operand:HI 2 "general_operand" " d,d,n,NxQH0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - or\t%0,%2 - ork\t%0,%1,%2 - oill\t%0,%x2 - # - #" - [(set_attr "op_type" "RR,RRF,RI,SI,SS") - (set_attr "cpu_facility" "*,z196,*,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1,*,*")]) - -(define_insn "*iorhi3_esa" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,AQ,Q") - (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:HI 2 "general_operand" "d,NxQH0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - or\t%0,%2 - # - #" - [(set_attr "op_type" "RR,SI,SS") - (set_attr "z10prop" "z10_super_E1,*,*")]) - -(define_split - [(set (match_operand:HI 0 "s_operand" "") - (ior:HI (match_dup 0) (match_operand:HI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (ior:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (IOR, &operands[0], &operands[1]);") - -; -; iorqi3 instruction pattern(s). -; - -(define_insn "*iorqi3_zarch" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,Q,S,Q") - (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,d,0,0,0,0") - (match_operand:QI 2 "general_operand" " d,d,n,n,n,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - or\t%0,%2 - ork\t%0,%1,%2 - oill\t%0,%b2 - oi\t%S0,%b2 - oiy\t%S0,%b2 - #" - [(set_attr "op_type" "RR,RRF,RI,SI,SIY,SS") - (set_attr "cpu_facility" "*,z196,*,*,*,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1, - z10_super,z10_super,*")]) - -(define_insn "*iorqi3_esa" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,Q,Q") - (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "d,n,Q"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - or\t%0,%2 - oi\t%S0,%b2 - #" - [(set_attr "op_type" "RR,SI,SS") - (set_attr "z10prop" "z10_super_E1,z10_super,*")]) - -; -; Block inclusive or (OC) patterns. -; - -(define_insn "*oc" - [(set (match_operand:BLK 0 "memory_operand" "=Q") - (ior:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" "Q"))) - (use (match_operand 2 "const_int_operand" "n")) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256" - "oc\t%O0(%2,%R0),%S1" - [(set_attr "op_type" "SS") - (set_attr "z196prop" "z196_cracked")]) - -(define_split - [(set (match_operand 0 "memory_operand" "") - (ior (match_dup 0) - (match_operand 1 "memory_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) > 0" - [(parallel - [(set (match_dup 0) (ior:BLK (match_dup 0) (match_dup 1))) - (use (match_dup 2)) - (clobber (reg:CC CC_REGNUM))])] -{ - operands[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))); - operands[0] = adjust_address (operands[0], BLKmode, 0); - operands[1] = adjust_address (operands[1], BLKmode, 0); -}) - -(define_peephole2 - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (ior:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_operand:BLK 3 "memory_operand" "") - (ior:BLK (match_dup 3) - (match_operand:BLK 4 "memory_operand" ""))) - (use (match_operand 5 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "s390_offset_p (operands[0], operands[3], operands[2]) - && s390_offset_p (operands[1], operands[4], operands[2]) - && !s390_overlap_p (operands[0], operands[1], - INTVAL (operands[2]) + INTVAL (operands[5])) - && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256" - [(parallel - [(set (match_dup 6) (ior:BLK (match_dup 6) (match_dup 7))) - (use (match_dup 8)) - (clobber (reg:CC CC_REGNUM))])] - "operands[6] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0)); - operands[7] = gen_rtx_MEM (BLKmode, XEXP (operands[1], 0)); - operands[8] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[5]));") - - -;; -;;- Xor instructions. -;; - -(define_expand "xor<mode>3" - [(set (match_operand:INT 0 "nonimmediate_operand" "") - (xor:INT (match_operand:INT 1 "nonimmediate_operand" "") - (match_operand:INT 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "" - "s390_expand_logical_operator (XOR, <MODE>mode, operands); DONE;") - -; -; xordi3 instruction pattern(s). -; - -(define_insn "*xordi3_cc" - [(set (reg CC_REGNUM) - (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d, 0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d,d, d") - (xor:DI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH" - "@ - xgr\t%0,%2 - xgrk\t%0,%1,%2 - xg\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*xordi3_cconly" - [(set (reg CC_REGNUM) - (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,d, 0") - (match_operand:DI 2 "general_operand" " d,d,RT")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d,d, d"))] - "s390_match_ccmode(insn, CCTmode) && TARGET_ZARCH" - "@ - xgr\t%0,%2 - xgrk\t%0,%1,%2 - xg\t%0,%2" - [(set_attr "op_type" "RRE,RRF,RXY") - (set_attr "cpu_facility" "*,z196,*") - (set_attr "z10prop" "z10_super_E1,*,z10_super_E1")]) - -(define_insn "*xordi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d, d,d,d, d, AQ,Q") - (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0, 0,0,d, 0, 0,0") - (match_operand:DI 2 "general_operand" "N0SD0,N1SD0,d,d,RT,NxQD0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH && s390_logical_operator_ok_p (operands)" - "@ - xihf\t%0,%k2 - xilf\t%0,%k2 - xgr\t%0,%2 - xgrk\t%0,%1,%2 - xg\t%0,%2 - # - #" - [(set_attr "op_type" "RIL,RIL,RRE,RRF,RXY,SI,SS") - (set_attr "cpu_facility" "extimm,extimm,*,z196,*,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,z10_super_E1, - *,z10_super_E1,*,*")]) - -(define_split - [(set (match_operand:DI 0 "s_operand" "") - (xor:DI (match_dup 0) (match_operand:DI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (XOR, &operands[0], &operands[1]);") - -; -; xorsi3 instruction pattern(s). -; - -(define_insn "*xorsi3_cc" - [(set (reg CC_REGNUM) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") - (xor:SI (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCTmode)" - "@ - xilf\t%0,%o2 - xr\t%0,%2 - xrk\t%0,%1,%2 - x\t%0,%2 - xy\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1")]) - -(define_insn "*xorsi3_cconly" - [(set (reg CC_REGNUM) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=d,d,d,d,d"))] - "s390_match_ccmode(insn, CCTmode)" - "@ - xilf\t%0,%o2 - xr\t%0,%2 - xrk\t%0,%1,%2 - x\t%0,%2 - xy\t%0,%2" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1")]) - -(define_insn "*xorsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d, AQ,Q") - (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,d,0,0, 0,0") - (match_operand:SI 2 "general_operand" "Os,d,d,R,T,NxQS0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "s390_logical_operator_ok_p (operands)" - "@ - xilf\t%0,%o2 - xr\t%0,%2 - xrk\t%0,%1,%2 - x\t%0,%2 - xy\t%0,%2 - # - #" - [(set_attr "op_type" "RIL,RR,RRF,RX,RXY,SI,SS") - (set_attr "cpu_facility" "*,*,z196,*,*,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*, - z10_super_E1,z10_super_E1,*,*")]) - -(define_split - [(set (match_operand:SI 0 "s_operand" "") - (xor:SI (match_dup 0) (match_operand:SI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (XOR, &operands[0], &operands[1]);") - -; -; xorhi3 instruction pattern(s). -; - -(define_insn "*xorhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d, AQ,Q") - (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,d, 0,0") - (match_operand:HI 2 "general_operand" "Os,d,d,NxQH0,Q"))) - (clobber (reg:CC CC_REGNUM))] - "s390_logical_operator_ok_p (operands)" - "@ - xilf\t%0,%x2 - xr\t%0,%2 - xrk\t%0,%1,%2 - # - #" - [(set_attr "op_type" "RIL,RR,RRF,SI,SS") - (set_attr "cpu_facility" "*,*,z196,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,*,*")]) - -(define_split - [(set (match_operand:HI 0 "s_operand" "") - (xor:HI (match_dup 0) (match_operand:HI 1 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed" - [(parallel - [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1))) - (clobber (reg:CC CC_REGNUM))])] - "s390_narrow_logical_operator (XOR, &operands[0], &operands[1]);") - -; -; xorqi3 instruction pattern(s). -; - -(define_insn "*xorqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,Q,S,Q") - (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,d,0,0,0") - (match_operand:QI 2 "general_operand" "Os,d,d,n,n,Q"))) - (clobber (reg:CC CC_REGNUM))] - "s390_logical_operator_ok_p (operands)" - "@ - xilf\t%0,%b2 - xr\t%0,%2 - xrk\t%0,%1,%2 - xi\t%S0,%b2 - xiy\t%S0,%b2 - #" - [(set_attr "op_type" "RIL,RR,RRF,SI,SIY,SS") - (set_attr "cpu_facility" "*,*,z196,*,*,*") - (set_attr "z10prop" "z10_super_E1,z10_super_E1,*,z10_super,z10_super,*")]) - - -; -; Block exclusive or (XC) patterns. -; - -(define_insn "*xc" - [(set (match_operand:BLK 0 "memory_operand" "=Q") - (xor:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" "Q"))) - (use (match_operand 2 "const_int_operand" "n")) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 256" - "xc\t%O0(%2,%R0),%S1" - [(set_attr "op_type" "SS")]) - -(define_split - [(set (match_operand 0 "memory_operand" "") - (xor (match_dup 0) - (match_operand 1 "memory_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "reload_completed - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) > 0" - [(parallel - [(set (match_dup 0) (xor:BLK (match_dup 0) (match_dup 1))) - (use (match_dup 2)) - (clobber (reg:CC CC_REGNUM))])] -{ - operands[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))); - operands[0] = adjust_address (operands[0], BLKmode, 0); - operands[1] = adjust_address (operands[1], BLKmode, 0); -}) - -(define_peephole2 - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (xor:BLK (match_dup 0) - (match_operand:BLK 1 "memory_operand" ""))) - (use (match_operand 2 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_operand:BLK 3 "memory_operand" "") - (xor:BLK (match_dup 3) - (match_operand:BLK 4 "memory_operand" ""))) - (use (match_operand 5 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "s390_offset_p (operands[0], operands[3], operands[2]) - && s390_offset_p (operands[1], operands[4], operands[2]) - && !s390_overlap_p (operands[0], operands[1], - INTVAL (operands[2]) + INTVAL (operands[5])) - && INTVAL (operands[2]) + INTVAL (operands[5]) <= 256" - [(parallel - [(set (match_dup 6) (xor:BLK (match_dup 6) (match_dup 7))) - (use (match_dup 8)) - (clobber (reg:CC CC_REGNUM))])] - "operands[6] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0)); - operands[7] = gen_rtx_MEM (BLKmode, XEXP (operands[1], 0)); - operands[8] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[5]));") - -; -; Block xor (XC) patterns with src == dest. -; - -(define_insn "*xc_zero" - [(set (match_operand:BLK 0 "memory_operand" "=Q") - (const_int 0)) - (use (match_operand 1 "const_int_operand" "n")) - (clobber (reg:CC CC_REGNUM))] - "INTVAL (operands[1]) >= 1 && INTVAL (operands[1]) <= 256" - "xc\t%O0(%1,%R0),%S0" - [(set_attr "op_type" "SS") - (set_attr "z196prop" "z196_cracked")]) - -(define_peephole2 - [(parallel - [(set (match_operand:BLK 0 "memory_operand" "") - (const_int 0)) - (use (match_operand 1 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (match_operand:BLK 2 "memory_operand" "") - (const_int 0)) - (use (match_operand 3 "const_int_operand" "")) - (clobber (reg:CC CC_REGNUM))])] - "s390_offset_p (operands[0], operands[2], operands[1]) - && INTVAL (operands[1]) + INTVAL (operands[3]) <= 256" - [(parallel - [(set (match_dup 4) (const_int 0)) - (use (match_dup 5)) - (clobber (reg:CC CC_REGNUM))])] - "operands[4] = gen_rtx_MEM (BLKmode, XEXP (operands[0], 0)); - operands[5] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[3]));") - - -;; -;;- Negate instructions. -;; - -; -; neg(di|si)2 instruction pattern(s). -; - -(define_expand "neg<mode>2" - [(parallel - [(set (match_operand:DSI 0 "register_operand" "=d") - (neg:DSI (match_operand:DSI 1 "register_operand" "d"))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*negdi2_sign_cc" - [(set (reg CC_REGNUM) - (compare (neg:DI (ashiftrt:DI (ashift:DI (subreg:DI - (match_operand:SI 1 "register_operand" "d") 0) - (const_int 32)) (const_int 32))) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (sign_extend:DI (match_dup 1))))] - "TARGET_ZARCH && s390_match_ccmode (insn, CCAmode)" - "lcgfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -(define_insn "*negdi2_sign" - [(set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "lcgfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -; lcr, lcgr -(define_insn "*neg<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (neg:GPR (match_operand:GPR 1 "register_operand" "d")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d") - (neg:GPR (match_dup 1)))] - "s390_match_ccmode (insn, CCAmode)" - "lc<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_super_c_E1")]) - -; lcr, lcgr -(define_insn "*neg<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (neg:GPR (match_operand:GPR 1 "register_operand" "d")) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d"))] - "s390_match_ccmode (insn, CCAmode)" - "lc<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_super_c_E1")]) - -; lcr, lcgr -(define_insn "*neg<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (neg:GPR (match_operand:GPR 1 "register_operand" "d"))) - (clobber (reg:CC CC_REGNUM))] - "" - "lc<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_super_c_E1")]) - -(define_insn_and_split "*negdi2_31" - [(set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (match_operand:DI 1 "register_operand" "d"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH" - "#" - "&& reload_completed" - [(parallel - [(set (match_dup 2) (neg:SI (match_dup 3))) - (clobber (reg:CC CC_REGNUM))]) - (parallel - [(set (reg:CCAP CC_REGNUM) - (compare:CCAP (neg:SI (match_dup 5)) (const_int 0))) - (set (match_dup 4) (neg:SI (match_dup 5)))]) - (set (pc) - (if_then_else (ne (reg:CCAP CC_REGNUM) (const_int 0)) - (pc) - (label_ref (match_dup 6)))) - (parallel - [(set (match_dup 2) (plus:SI (match_dup 2) (const_int -1))) - (clobber (reg:CC CC_REGNUM))]) - (match_dup 6)] - "operands[2] = operand_subword (operands[0], 0, 0, DImode); - operands[3] = operand_subword (operands[1], 0, 0, DImode); - operands[4] = operand_subword (operands[0], 1, 0, DImode); - operands[5] = operand_subword (operands[1], 1, 0, DImode); - operands[6] = gen_label_rtx ();") - -; -; neg(df|sf)2 instruction pattern(s). -; - -(define_expand "neg<mode>2" - [(parallel - [(set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (match_operand:BFP 1 "register_operand" "f"))) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_HARD_FLOAT" - "") - -; lcxbr, lcdbr, lcebr -(define_insn "*neg<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (neg:BFP (match_operand:BFP 1 "register_operand" "f")) - (match_operand:BFP 2 "const0_operand" ""))) - (set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (match_dup 1)))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "lc<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lcxbr, lcdbr, lcebr -(define_insn "*neg<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (neg:BFP (match_operand:BFP 1 "register_operand" "f")) - (match_operand:BFP 2 "const0_operand" ""))) - (clobber (match_scratch:BFP 0 "=f"))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "lc<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lcdfr -(define_insn "*neg<mode>2_nocc" - [(set (match_operand:FP 0 "register_operand" "=f") - (neg:FP (match_operand:FP 1 "register_operand" "<fT0>")))] - "TARGET_DFP" - "lcdfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lcxbr, lcdbr, lcebr -(define_insn "*neg<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (match_operand:BFP 1 "register_operand" "f"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "lc<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - - -;; -;;- Absolute value instructions. -;; - -; -; abs(di|si)2 instruction pattern(s). -; - -(define_insn "*absdi2_sign_cc" - [(set (reg CC_REGNUM) - (compare (abs:DI (ashiftrt:DI (ashift:DI (subreg:DI - (match_operand:SI 1 "register_operand" "d") 0) - (const_int 32)) (const_int 32))) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (abs:DI (sign_extend:DI (match_dup 1))))] - "TARGET_ZARCH && s390_match_ccmode (insn, CCAmode)" - "lpgfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -(define_insn "*absdi2_sign" - [(set (match_operand:DI 0 "register_operand" "=d") - (abs:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "lpgfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -; lpr, lpgr -(define_insn "*abs<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (abs:GPR (match_operand:DI 1 "register_operand" "d")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d") - (abs:GPR (match_dup 1)))] - "s390_match_ccmode (insn, CCAmode)" - "lp<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; lpr, lpgr -(define_insn "*abs<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (abs:GPR (match_operand:GPR 1 "register_operand" "d")) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d"))] - "s390_match_ccmode (insn, CCAmode)" - "lp<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; lpr, lpgr -(define_insn "abs<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (abs:GPR (match_operand:GPR 1 "register_operand" "d"))) - (clobber (reg:CC CC_REGNUM))] - "" - "lp<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; -; abs(df|sf)2 instruction pattern(s). -; - -(define_expand "abs<mode>2" - [(parallel - [(set (match_operand:BFP 0 "register_operand" "=f") - (abs:BFP (match_operand:BFP 1 "register_operand" "f"))) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_HARD_FLOAT" - "") - -; lpxbr, lpdbr, lpebr -(define_insn "*abs<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (abs:BFP (match_operand:BFP 1 "register_operand" "f")) - (match_operand:BFP 2 "const0_operand" ""))) - (set (match_operand:BFP 0 "register_operand" "=f") - (abs:BFP (match_dup 1)))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "lp<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lpxbr, lpdbr, lpebr -(define_insn "*abs<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (abs:BFP (match_operand:BFP 1 "register_operand" "f")) - (match_operand:BFP 2 "const0_operand" ""))) - (clobber (match_scratch:BFP 0 "=f"))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "lp<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lpdfr -(define_insn "*abs<mode>2_nocc" - [(set (match_operand:FP 0 "register_operand" "=f") - (abs:FP (match_operand:FP 1 "register_operand" "<fT0>")))] - "TARGET_DFP" - "lpdfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lpxbr, lpdbr, lpebr -(define_insn "*abs<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f") - (abs:BFP (match_operand:BFP 1 "register_operand" "f"))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "lp<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - - -;; -;;- Negated absolute value instructions -;; - -; -; Integer -; - -(define_insn "*negabsdi2_sign_cc" - [(set (reg CC_REGNUM) - (compare (neg:DI (abs:DI (ashiftrt:DI (ashift:DI (subreg:DI - (match_operand:SI 1 "register_operand" "d") 0) - (const_int 32)) (const_int 32)))) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (abs:DI (sign_extend:DI (match_dup 1)))))] - "TARGET_ZARCH && s390_match_ccmode (insn, CCAmode)" - "lngfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -(define_insn "*negabsdi2_sign" - [(set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (abs:DI (sign_extend:DI - (match_operand:SI 1 "register_operand" "d"))))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" - "lngfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "z10prop" "z10_c")]) - -; lnr, lngr -(define_insn "*negabs<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (neg:GPR (abs:GPR (match_operand:GPR 1 "register_operand" "d"))) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d") - (neg:GPR (abs:GPR (match_dup 1))))] - "s390_match_ccmode (insn, CCAmode)" - "ln<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; lnr, lngr -(define_insn "*negabs<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (neg:GPR (abs:GPR (match_operand:GPR 1 "register_operand" "d"))) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d"))] - "s390_match_ccmode (insn, CCAmode)" - "ln<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; lnr, lngr -(define_insn "*negabs<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (neg:GPR (abs:GPR (match_operand:GPR 1 "register_operand" "d")))) - (clobber (reg:CC CC_REGNUM))] - "" - "ln<g>r\t%0,%1" - [(set_attr "op_type" "RR<E>") - (set_attr "z10prop" "z10_c")]) - -; -; Floating point -; - -; lnxbr, lndbr, lnebr -(define_insn "*negabs<mode>2_cc" - [(set (reg CC_REGNUM) - (compare (neg:BFP (abs:BFP (match_operand:BFP 1 "register_operand" "f"))) - (match_operand:BFP 2 "const0_operand" ""))) - (set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (abs:BFP (match_dup 1))))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "ln<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lnxbr, lndbr, lnebr -(define_insn "*negabs<mode>2_cconly" - [(set (reg CC_REGNUM) - (compare (neg:BFP (abs:BFP (match_operand:BFP 1 "register_operand" "f"))) - (match_operand:BFP 2 "const0_operand" ""))) - (clobber (match_scratch:BFP 0 "=f"))] - "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT" - "ln<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lndfr -(define_insn "*negabs<mode>2_nocc" - [(set (match_operand:FP 0 "register_operand" "=f") - (neg:FP (abs:FP (match_operand:BFP 1 "register_operand" "<fT0>"))))] - "TARGET_DFP" - "lndfr\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -; lnxbr, lndbr, lnebr -(define_insn "*negabs<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f") - (neg:BFP (abs:BFP (match_operand:BFP 1 "register_operand" "f")))) - (clobber (reg:CC CC_REGNUM))] - "TARGET_HARD_FLOAT" - "ln<xde>br\t%0,%1" - [(set_attr "op_type" "RRE") - (set_attr "type" "fsimp<mode>")]) - -;; -;;- Square root instructions. -;; - -; -; sqrt(df|sf)2 instruction pattern(s). -; - -; sqxbr, sqdbr, sqebr, sqdb, sqeb -(define_insn "sqrt<mode>2" - [(set (match_operand:BFP 0 "register_operand" "=f,f") - (sqrt:BFP (match_operand:BFP 1 "general_operand" "f,<Rf>")))] - "TARGET_HARD_FLOAT" - "@ - sq<xde>br\t%0,%1 - sq<xde>b\t%0,%1" - [(set_attr "op_type" "RRE,RXE") - (set_attr "type" "fsqrt<mode>")]) - - -;; -;;- One complement instructions. -;; - -; -; one_cmpl(di|si|hi|qi)2 instruction pattern(s). -; - -(define_expand "one_cmpl<mode>2" - [(parallel - [(set (match_operand:INT 0 "register_operand" "") - (xor:INT (match_operand:INT 1 "register_operand" "") - (const_int -1))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - - -;; -;; Find leftmost bit instructions. -;; - -(define_expand "clzdi2" - [(set (match_operand:DI 0 "register_operand" "=d") - (clz:DI (match_operand:DI 1 "register_operand" "d")))] - "TARGET_EXTIMM && TARGET_ZARCH" -{ - rtx insn, clz_equal; - rtx wide_reg = gen_reg_rtx (TImode); - rtx msb = gen_rtx_CONST_INT (DImode, (unsigned HOST_WIDE_INT) 1 << 63); - - clz_equal = gen_rtx_CLZ (DImode, operands[1]); - - emit_insn (gen_clztidi2 (wide_reg, operands[1], msb)); - - insn = emit_move_insn (operands[0], gen_highpart (DImode, wide_reg)); - set_unique_reg_note (insn, REG_EQUAL, clz_equal); - - DONE; -}) - -(define_insn "clztidi2" - [(set (match_operand:TI 0 "register_operand" "=d") - (ior:TI - (ashift:TI - (zero_extend:TI - (xor:DI (match_operand:DI 1 "register_operand" "d") - (lshiftrt (match_operand:DI 2 "const_int_operand" "") - (subreg:SI (clz:DI (match_dup 1)) 4)))) - - (const_int 64)) - (zero_extend:TI (clz:DI (match_dup 1))))) - (clobber (reg:CC CC_REGNUM))] - "(unsigned HOST_WIDE_INT) INTVAL (operands[2]) - == (unsigned HOST_WIDE_INT) 1 << 63 - && TARGET_EXTIMM && TARGET_ZARCH" - "flogr\t%0,%1" - [(set_attr "op_type" "RRE")]) - - -;; -;;- Rotate instructions. -;; - -; -; rotl(di|si)3 instruction pattern(s). -; - -; rll, rllg -(define_insn "rotl<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d") - (rotate:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))] - "TARGET_CPU_ZARCH" - "rll<g>\t%0,%1,%Y2" - [(set_attr "op_type" "RSE") - (set_attr "atype" "reg") - (set_attr "z10prop" "z10_super_E1")]) - -; rll, rllg -(define_insn "*rotl<mode>3_and" - [(set (match_operand:GPR 0 "register_operand" "=d") - (rotate:GPR (match_operand:GPR 1 "register_operand" "d") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y") - (match_operand:SI 3 "const_int_operand" "n"))))] - "TARGET_CPU_ZARCH && (INTVAL (operands[3]) & 63) == 63" - "rll<g>\t%0,%1,%Y2" - [(set_attr "op_type" "RSE") - (set_attr "atype" "reg") - (set_attr "z10prop" "z10_super_E1")]) - - -;; -;;- Shift instructions. -;; - -; -; (ashl|lshr)(di|si)3 instruction pattern(s). -; Left shifts and logical right shifts - -(define_expand "<shift><mode>3" - [(set (match_operand:DSI 0 "register_operand" "") - (SHIFT:DSI (match_operand:DSI 1 "register_operand" "") - (match_operand:SI 2 "shift_count_or_setmem_operand" "")))] - "" - "") - -; sldl, srdl -(define_insn "*<shift>di3_31" - [(set (match_operand:DI 0 "register_operand" "=d") - (SHIFT:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))] - "!TARGET_ZARCH" - "s<lr>dl\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg") - (set_attr "z196prop" "z196_cracked")]) - -; sll, srl, sllg, srlg, sllk, srlk -(define_insn "*<shift><mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (SHIFT:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y")))] - "" - "@ - s<lr>l<g>\t%0,<1>%Y2 - s<lr>l<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; sldl, srdl -(define_insn "*<shift>di3_31_and" - [(set (match_operand:DI 0 "register_operand" "=d") - (SHIFT:DI (match_operand:DI 1 "register_operand" "0") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y") - (match_operand:SI 3 "const_int_operand" "n"))))] - "!TARGET_ZARCH && (INTVAL (operands[3]) & 63) == 63" - "s<lr>dl\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -; sll, srl, sllg, srlg, sllk, srlk -(define_insn "*<shift><mode>3_and" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (SHIFT:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y") - (match_operand:SI 3 "const_int_operand" "n,n"))))] - "(INTVAL (operands[3]) & 63) == 63" - "@ - s<lr>l<g>\t%0,<1>%Y2 - s<lr>l<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; -; ashr(di|si)3 instruction pattern(s). -; Arithmetic right shifts - -(define_expand "ashr<mode>3" - [(parallel - [(set (match_operand:DSI 0 "register_operand" "") - (ashiftrt:DSI (match_operand:DSI 1 "register_operand" "") - (match_operand:SI 2 "shift_count_or_setmem_operand" ""))) - (clobber (reg:CC CC_REGNUM))])] - "" - "") - -(define_insn "*ashrdi3_cc_31" - [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (ashiftrt:DI (match_dup 1) (match_dup 2)))] - "!TARGET_ZARCH && s390_match_ccmode(insn, CCSmode)" - "srda\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -(define_insn "*ashrdi3_cconly_31" - [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d"))] - "!TARGET_ZARCH && s390_match_ccmode(insn, CCSmode)" - "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") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH" - "srda\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -; sra, srag, srak -(define_insn "*ashr<mode>3_cc" - [(set (reg CC_REGNUM) - (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y")) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (ashiftrt:GPR (match_dup 1) (match_dup 2)))] - "s390_match_ccmode(insn, CCSmode)" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; sra, srag, srak -(define_insn "*ashr<mode>3_cconly" - [(set (reg CC_REGNUM) - (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y")) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d,d"))] - "s390_match_ccmode(insn, CCSmode)" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; sra, srag -(define_insn "*ashr<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y"))) - (clobber (reg:CC CC_REGNUM))] - "" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - - -; shift pattern with implicit ANDs - -(define_insn "*ashrdi3_cc_31_and" - [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y") - (match_operand:SI 3 "const_int_operand" "n"))) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=d") - (ashiftrt:DI (match_dup 1) (and:SI (match_dup 2) (match_dup 3))))] - "!TARGET_ZARCH && s390_match_ccmode(insn, CCSmode) - && (INTVAL (operands[3]) & 63) == 63" - "srda\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -(define_insn "*ashrdi3_cconly_31_and" - [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y") - (match_operand:SI 3 "const_int_operand" "n"))) - (const_int 0))) - (clobber (match_scratch:DI 0 "=d"))] - "!TARGET_ZARCH && s390_match_ccmode(insn, CCSmode) - && (INTVAL (operands[3]) & 63) == 63" - "srda\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -(define_insn "*ashrdi3_31_and" - [(set (match_operand:DI 0 "register_operand" "=d") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y") - (match_operand:SI 3 "const_int_operand" "n")))) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && (INTVAL (operands[3]) & 63) == 63" - "srda\t%0,%Y2" - [(set_attr "op_type" "RS") - (set_attr "atype" "reg")]) - -; sra, srag, srak -(define_insn "*ashr<mode>3_cc_and" - [(set (reg CC_REGNUM) - (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y") - (match_operand:SI 3 "const_int_operand" "n,n"))) - (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d") - (ashiftrt:GPR (match_dup 1) (and:SI (match_dup 2) (match_dup 3))))] - "s390_match_ccmode(insn, CCSmode) && (INTVAL (operands[3]) & 63) == 63" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; sra, srag, srak -(define_insn "*ashr<mode>3_cconly_and" - [(set (reg CC_REGNUM) - (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y") - (match_operand:SI 3 "const_int_operand" "n,n"))) - (const_int 0))) - (clobber (match_scratch:GPR 0 "=d,d"))] - "s390_match_ccmode(insn, CCSmode) && (INTVAL (operands[3]) & 63) == 63" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - -; sra, srag, srak -(define_insn "*ashr<mode>3_and" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>,d") - (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y,Y") - (match_operand:SI 3 "const_int_operand" "n,n")))) - (clobber (reg:CC CC_REGNUM))] - "(INTVAL (operands[3]) & 63) == 63" - "@ - sra<g>\t%0,<1>%Y2 - sra<gk>\t%0,%1,%Y2" - [(set_attr "op_type" "RS<E>,RSY") - (set_attr "atype" "reg,reg") - (set_attr "cpu_facility" "*,z196") - (set_attr "z10prop" "z10_super_E1,*")]) - - -;; -;; Branch instruction patterns. -;; - -(define_expand "cbranch<mode>4" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:GPR 1 "register_operand" "") - (match_operand:GPR 2 "general_operand" "")]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - "s390_emit_jump (operands[3], - s390_emit_compare (GET_CODE (operands[0]), operands[1], operands[2])); - DONE;") - -(define_expand "cbranch<mode>4" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:FP 1 "register_operand" "") - (match_operand:FP 2 "general_operand" "")]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" - "s390_emit_jump (operands[3], - s390_emit_compare (GET_CODE (operands[0]), operands[1], operands[2])); - DONE;") - -(define_expand "cbranchcc4" - [(set (pc) - (if_then_else (match_operator 0 "s390_eqne_operator" - [(match_operand 1 "cc_reg_operand" "") - (match_operand 2 "const0_operand" "")]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" - "s390_emit_jump (operands[3], - s390_emit_compare (GET_CODE (operands[0]), operands[1], operands[2])); - DONE;") - - - -;; -;;- Conditional jump instructions. -;; - -(define_insn "*cjump_64" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_CPU_ZARCH" -{ - if (get_attr_length (insn) == 4) - return "j%C1\t%l0"; - else - return "jg%C1\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 6)))]) - -(define_insn "*cjump_31" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "!TARGET_CPU_ZARCH" -{ - gcc_assert (get_attr_length (insn) == 4); - return "j%C1\t%l0"; -} - [(set_attr "op_type" "RI") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (not (match_test "flag_pic")) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 6)) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 8))))]) - -(define_insn "*cjump_long" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (match_operand 0 "address_operand" "ZQZR") - (pc)))] - "" -{ - if (get_attr_op_type (insn) == OP_TYPE_RR) - return "b%C1r\t%0"; - else - 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 "type" "branch") - (set_attr "atype" "agen")]) - - -;; -;;- Negated conditional jump instructions. -;; - -(define_insn "*icjump_64" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_CPU_ZARCH" -{ - if (get_attr_length (insn) == 4) - return "j%D1\t%l0"; - else - return "jg%D1\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 6)))]) - -(define_insn "*icjump_31" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "!TARGET_CPU_ZARCH" -{ - gcc_assert (get_attr_length (insn) == 4); - return "j%D1\t%l0"; -} - [(set_attr "op_type" "RI") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (not (match_test "flag_pic")) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 6)) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 8))))]) - -(define_insn "*icjump_long" - [(set (pc) - (if_then_else - (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)]) - (pc) - (match_operand 0 "address_operand" "ZQZR")))] - "" -{ - if (get_attr_op_type (insn) == OP_TYPE_RR) - return "b%D1r\t%0"; - else - 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 "type" "branch") - (set_attr "atype" "agen")]) - -;; -;;- Trap instructions. -;; - -(define_insn "trap" - [(trap_if (const_int 1) (const_int 0))] - "" - "j\t.+2" - [(set_attr "op_type" "RI") - (set_attr "type" "branch")]) - -(define_expand "ctrap<mode>4" - [(trap_if (match_operator 0 "comparison_operator" - [(match_operand:GPR 1 "register_operand" "") - (match_operand:GPR 2 "general_operand" "")]) - (match_operand 3 "const0_operand" ""))] - "" - { - rtx cond = s390_emit_compare (GET_CODE (operands[0]), - operands[1], operands[2]); - emit_insn (gen_condtrap (cond, XEXP (cond, 0))); - DONE; - }) - -(define_expand "ctrap<mode>4" - [(trap_if (match_operator 0 "comparison_operator" - [(match_operand:FP 1 "register_operand" "") - (match_operand:FP 2 "general_operand" "")]) - (match_operand 3 "const0_operand" ""))] - "" - { - rtx cond = s390_emit_compare (GET_CODE (operands[0]), - operands[1], operands[2]); - emit_insn (gen_condtrap (cond, XEXP (cond, 0))); - DONE; - }) - -(define_insn "condtrap" - [(trap_if (match_operator 0 "s390_comparison" - [(match_operand 1 "cc_reg_operand" "c") - (const_int 0)]) - (const_int 0))] - "" - "j%C0\t.+2"; - [(set_attr "op_type" "RI") - (set_attr "type" "branch")]) - -; crt, cgrt, cit, cgit -(define_insn "*cmp_and_trap_signed_int<mode>" - [(trap_if (match_operator 0 "s390_signed_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,K")]) - (const_int 0))] - "TARGET_Z10" - "@ - c<g>rt%C0\t%1,%2 - c<g>it%C0\t%1,%h2" - [(set_attr "op_type" "RRF,RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super")]) - -; clrt, clgrt, clfit, clgit -(define_insn "*cmp_and_trap_unsigned_int<mode>" - [(trap_if (match_operator 0 "s390_unsigned_integer_comparison" - [(match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "nonmemory_operand" "d,D")]) - (const_int 0))] - "TARGET_Z10" - "@ - cl<g>rt%C0\t%1,%2 - cl<gf>it%C0\t%1,%x2" - [(set_attr "op_type" "RRF,RIE") - (set_attr "type" "branch") - (set_attr "z10prop" "z10_super_c,z10_super")]) - -;; -;;- Loop instructions. -;; -;; This is all complicated by the fact that since this is a jump insn -;; we must handle our own output reloads. - -;; branch on index - -; This splitter will be matched by combine and has to add the 2 moves -; necessary to load the compare and the increment values into a -; register pair as needed by brxle. - -(define_insn_and_split "*brx_stage1_<GPR:mode>" - [(set (pc) - (if_then_else - (match_operator 6 "s390_brx_operator" - [(plus:GPR (match_operand:GPR 1 "register_operand" "") - (match_operand:GPR 2 "general_operand" "")) - (match_operand:GPR 3 "register_operand" "")]) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:GPR 4 "nonimmediate_operand" "") - (plus:GPR (match_dup 1) (match_dup 2))) - (clobber (match_scratch:GPR 5 ""))] - "TARGET_CPU_ZARCH" - "#" - "!reload_completed && !reload_in_progress" - [(set (match_dup 7) (match_dup 2)) ; the increment - (set (match_dup 8) (match_dup 3)) ; the comparison value - (parallel [(set (pc) - (if_then_else - (match_op_dup 6 - [(plus:GPR (match_dup 1) (match_dup 7)) - (match_dup 8)]) - (label_ref (match_dup 0)) - (pc))) - (set (match_dup 4) - (plus:GPR (match_dup 1) (match_dup 7))) - (clobber (match_dup 5)) - (clobber (reg:CC CC_REGNUM))])] - { - rtx dreg = gen_reg_rtx (word_mode == DImode ? TImode : DImode); - operands[7] = gen_lowpart (<GPR:MODE>mode, - gen_highpart (word_mode, dreg)); - operands[8] = gen_lowpart (<GPR:MODE>mode, - gen_lowpart (word_mode, dreg)); - }) - -; brxlg, brxhg - -(define_insn_and_split "*brxg_64bit" - [(set (pc) - (if_then_else - (match_operator 5 "s390_brx_operator" - [(plus:DI (match_operand:DI 1 "register_operand" "d,d,d") - (subreg:DI (match_operand:TI 2 "register_operand" "d,d,d") 0)) - (subreg:DI (match_dup 2) 8)]) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:DI 3 "nonimmediate_operand" "=1,?X,?X") - (plus:DI (match_dup 1) - (subreg:DI (match_dup 2) 0))) - (clobber (match_scratch:DI 4 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 6) - return "brx%E5g\t%1,%2,%l0"; - else - return "agr\t%1,%2\;cgr\t%1,%M2\;jg%C5\t%l0"; -} - "&& reload_completed - && (!REG_P (operands[3]) - || !rtx_equal_p (operands[1], operands[3]))" - [(set (match_dup 4) (match_dup 1)) - (parallel [(set (match_dup 4) (plus:DI (match_dup 4) (subreg:DI (match_dup 2) 0))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:DI (match_dup 2) 8))) - (set (match_dup 3) (match_dup 4)) - (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RIE") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 6) (const_int 16)))]) - -; brxle, brxh - -(define_insn_and_split "*brx_64bit" - [(set (pc) - (if_then_else - (match_operator 5 "s390_brx_operator" - [(plus:SI (match_operand:SI 1 "register_operand" "d,d,d") - (subreg:SI (match_operand:TI 2 "register_operand" "d,d,d") 4)) - (subreg:SI (match_dup 2) 12)]) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:SI 3 "nonimmediate_operand" "=1,?X,?X") - (plus:SI (match_dup 1) - (subreg:SI (match_dup 2) 4))) - (clobber (match_scratch:SI 4 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 6) - return "brx%C5\t%1,%2,%l0"; - else - return "ar\t%1,%2\;cr\t%1,%M2\;jg%C5\t%l0"; -} - "&& reload_completed - && (!REG_P (operands[3]) - || !rtx_equal_p (operands[1], operands[3]))" - [(set (match_dup 4) (match_dup 1)) - (parallel [(set (match_dup 4) (plus:SI (match_dup 4) (subreg:SI (match_dup 2) 4))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:SI (match_dup 2) 12))) - (set (match_dup 3) (match_dup 4)) - (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RSI") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 6) (const_int 14)))]) - -; brxle, brxh - -(define_insn_and_split "*brx_31bit" - [(set (pc) - (if_then_else - (match_operator 5 "s390_brx_operator" - [(plus:SI (match_operand:SI 1 "register_operand" "d,d,d") - (subreg:SI (match_operand:DI 2 "register_operand" "d,d,d") 0)) - (subreg:SI (match_dup 2) 4)]) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:SI 3 "nonimmediate_operand" "=1,?X,?X") - (plus:SI (match_dup 1) - (subreg:SI (match_dup 2) 0))) - (clobber (match_scratch:SI 4 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_ZARCH && TARGET_CPU_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 6) - return "brx%C5\t%1,%2,%l0"; - else - return "ar\t%1,%2\;cr\t%1,%M2\;jg%C5\t%l0"; -} - "&& reload_completed - && (!REG_P (operands[3]) - || !rtx_equal_p (operands[1], operands[3]))" - [(set (match_dup 4) (match_dup 1)) - (parallel [(set (match_dup 4) (plus:SI (match_dup 4) (subreg:SI (match_dup 2) 0))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:SI (match_dup 2) 4))) - (set (match_dup 3) (match_dup 4)) - (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RSI") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 6) (const_int 14)))]) - - -;; branch on count - -(define_expand "doloop_end" - [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" ""))] ; label - "" -{ - if (GET_MODE (operands[0]) == SImode && !TARGET_CPU_ZARCH) - emit_jump_insn (gen_doloop_si31 (operands[4], operands[0], operands[0])); - else if (GET_MODE (operands[0]) == SImode && TARGET_CPU_ZARCH) - emit_jump_insn (gen_doloop_si64 (operands[4], operands[0], operands[0])); - else if (GET_MODE (operands[0]) == DImode && TARGET_ZARCH) - emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0])); - else - FAIL; - - DONE; -}) - -(define_insn_and_split "doloop_si64" - [(set (pc) - (if_then_else - (ne (match_operand:SI 1 "register_operand" "d,d,d") - (const_int 1)) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:SI 2 "nonimmediate_operand" "=1,?X,?X") - (plus:SI (match_dup 1) (const_int -1))) - (clobber (match_scratch:SI 3 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_CPU_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 4) - return "brct\t%1,%l0"; - else - return "ahi\t%1,-1\;jgne\t%l0"; -} - "&& reload_completed - && (! REG_P (operands[2]) - || ! rtx_equal_p (operands[1], operands[2]))" - [(set (match_dup 3) (match_dup 1)) - (parallel [(set (reg:CCAN CC_REGNUM) - (compare:CCAN (plus:SI (match_dup 3) (const_int -1)) - (const_int 0))) - (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))]) - (set (match_dup 2) (match_dup 3)) - (set (pc) (if_then_else (ne (reg:CCAN CC_REGNUM) (const_int 0)) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RI") - ; Strictly speaking, the z10 properties are valid for brct only, however, it does not - ; hurt us in the (rare) case of ahi. - (set_attr "z10prop" "z10_super_E1") - (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 10)))]) - -(define_insn_and_split "doloop_si31" - [(set (pc) - (if_then_else - (ne (match_operand:SI 1 "register_operand" "d,d,d") - (const_int 1)) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:SI 2 "nonimmediate_operand" "=1,?X,?X") - (plus:SI (match_dup 1) (const_int -1))) - (clobber (match_scratch:SI 3 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_CPU_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 4) - return "brct\t%1,%l0"; - else - gcc_unreachable (); -} - "&& reload_completed - && (! REG_P (operands[2]) - || ! rtx_equal_p (operands[1], operands[2]))" - [(set (match_dup 3) (match_dup 1)) - (parallel [(set (reg:CCAN CC_REGNUM) - (compare:CCAN (plus:SI (match_dup 3) (const_int -1)) - (const_int 0))) - (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))]) - (set (match_dup 2) (match_dup 3)) - (set (pc) (if_then_else (ne (reg:CCAN CC_REGNUM) (const_int 0)) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RI") - ; Strictly speaking, the z10 properties are valid for brct only, however, it does not - ; hurt us in the (rare) case of ahi. - (set_attr "z10prop" "z10_super_E1") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (not (match_test "flag_pic")) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 6)) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 8))))]) - -(define_insn "*doloop_si_long" - [(set (pc) - (if_then_else - (ne (match_operand:SI 1 "register_operand" "d") - (const_int 1)) - (match_operand 0 "address_operand" "ZQZR") - (pc))) - (set (match_operand:SI 2 "register_operand" "=1") - (plus:SI (match_dup 1) (const_int -1))) - (clobber (match_scratch:SI 3 "=X")) - (clobber (reg:CC CC_REGNUM))] - "!TARGET_CPU_ZARCH" -{ - if (get_attr_op_type (insn) == OP_TYPE_RR) - return "bctr\t%1,%0"; - else - 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 "type" "branch") - (set_attr "atype" "agen") - (set_attr "z10prop" "z10_c") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn_and_split "doloop_di" - [(set (pc) - (if_then_else - (ne (match_operand:DI 1 "register_operand" "d,d,d") - (const_int 1)) - (label_ref (match_operand 0 "" "")) - (pc))) - (set (match_operand:DI 2 "nonimmediate_operand" "=1,?X,?X") - (plus:DI (match_dup 1) (const_int -1))) - (clobber (match_scratch:DI 3 "=X,&1,&?d")) - (clobber (reg:CC CC_REGNUM))] - "TARGET_ZARCH" -{ - if (which_alternative != 0) - return "#"; - else if (get_attr_length (insn) == 4) - return "brctg\t%1,%l0"; - else - return "aghi\t%1,-1\;jgne\t%l0"; -} - "&& reload_completed - && (! REG_P (operands[2]) - || ! rtx_equal_p (operands[1], operands[2]))" - [(set (match_dup 3) (match_dup 1)) - (parallel [(set (reg:CCAN CC_REGNUM) - (compare:CCAN (plus:DI (match_dup 3) (const_int -1)) - (const_int 0))) - (set (match_dup 3) (plus:DI (match_dup 3) (const_int -1)))]) - (set (match_dup 2) (match_dup 3)) - (set (pc) (if_then_else (ne (reg:CCAN CC_REGNUM) (const_int 0)) - (label_ref (match_dup 0)) - (pc)))] - "" - [(set_attr "op_type" "RI") - ; Strictly speaking, the z10 properties are valid for brct only, however, it does not - ; hurt us in the (rare) case of ahi. - (set_attr "z10prop" "z10_super_E1") - (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 10)))]) - -;; -;;- Unconditional jump instructions. -;; - -; -; jump instruction pattern(s). -; - -(define_expand "jump" - [(match_operand 0 "" "")] - "" - "s390_emit_jump (operands[0], NULL_RTX); DONE;") - -(define_insn "*jump64" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "TARGET_CPU_ZARCH" -{ - if (get_attr_length (insn) == 4) - return "j\t%l0"; - else - return "jg\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 6)))]) - -(define_insn "*jump31" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "!TARGET_CPU_ZARCH" -{ - gcc_assert (get_attr_length (insn) == 4); - return "j\t%l0"; -} - [(set_attr "op_type" "RI") - (set_attr "type" "branch") - (set (attr "length") - (if_then_else (not (match_test "flag_pic")) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 6)) - (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000)) - (const_int 4) (const_int 8))))]) - -; -; indirect-jump instruction pattern(s). -; - -(define_insn "indirect_jump" - [(set (pc) (match_operand 0 "address_operand" "ZQZR"))] - "" -{ - if (get_attr_op_type (insn) == OP_TYPE_RR) - return "br\t%0"; - else - return "b\t%a0"; -} - [(set (attr "op_type") - (if_then_else (match_operand 0 "register_operand" "") - (const_string "RR") (const_string "RX"))) - (set_attr "type" "branch") - (set_attr "atype" "agen")]) - -; -; casesi instruction pattern(s). -; - -(define_insn "casesi_jump" - [(set (pc) (match_operand 0 "address_operand" "ZQZR")) - (use (label_ref (match_operand 1 "" "")))] - "" -{ - if (get_attr_op_type (insn) == OP_TYPE_RR) - return "br\t%0"; - else - return "b\t%a0"; -} - [(set (attr "op_type") - (if_then_else (match_operand 0 "register_operand" "") - (const_string "RR") (const_string "RX"))) - (set_attr "type" "branch") - (set_attr "atype" "agen")]) - -(define_expand "casesi" - [(match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" "") - (match_operand:SI 2 "general_operand" "") - (label_ref (match_operand 3 "" "")) - (label_ref (match_operand 4 "" ""))] - "" -{ - rtx index = gen_reg_rtx (SImode); - rtx base = gen_reg_rtx (Pmode); - rtx target = gen_reg_rtx (Pmode); - - emit_move_insn (index, operands[0]); - emit_insn (gen_subsi3 (index, index, operands[1])); - emit_cmp_and_jump_insns (index, operands[2], GTU, NULL_RTX, SImode, 1, - operands[4]); - - if (Pmode != SImode) - index = convert_to_mode (Pmode, index, 1); - if (GET_CODE (index) != REG) - index = copy_to_mode_reg (Pmode, index); - - if (TARGET_64BIT) - emit_insn (gen_ashldi3 (index, index, GEN_INT (3))); - else - emit_insn (gen_ashlsi3 (index, index, const2_rtx)); - - emit_move_insn (base, gen_rtx_LABEL_REF (Pmode, operands[3])); - - index = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, base, index)); - emit_move_insn (target, index); - - if (flag_pic) - target = gen_rtx_PLUS (Pmode, base, target); - emit_jump_insn (gen_casesi_jump (target, operands[3])); - - DONE; -}) - - -;; -;;- Jump to subroutine. -;; -;; - -; -; untyped call instruction pattern(s). -; - -;; Call subroutine returning any type. -(define_expand "untyped_call" - [(parallel [(call (match_operand 0 "" "") - (const_int 0)) - (match_operand 1 "" "") - (match_operand 2 "" "")])] - "" -{ - int i; - - emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx)); - - for (i = 0; i < XVECLEN (operands[2], 0); i++) - { - rtx set = XVECEXP (operands[2], 0, i); - emit_move_insn (SET_DEST (set), SET_SRC (set)); - } - - /* The optimizer does not know that the call sets the function value - registers we stored in the result block. We avoid problems by - claiming that all hard registers are used and clobbered at this - point. */ - emit_insn (gen_blockage ()); - - DONE; -}) - -;; 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)] UNSPECV_BLOCKAGE)] - "" - "" - [(set_attr "type" "none") - (set_attr "length" "0")]) - -; -; sibcall patterns -; - -(define_expand "sibcall" - [(call (match_operand 0 "" "") - (match_operand 1 "" ""))] - "" -{ - s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, NULL_RTX); - DONE; -}) - -(define_insn "*sibcall_br" - [(call (mem:QI (reg SIBCALL_REGNUM)) - (match_operand 0 "const_int_operand" "n"))] - "SIBLING_CALL_P (insn) - && GET_MODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == Pmode" - "br\t%%r1" - [(set_attr "op_type" "RR") - (set_attr "type" "branch") - (set_attr "atype" "agen")]) - -(define_insn "*sibcall_brc" - [(call (mem:QI (match_operand 0 "bras_sym_operand" "X")) - (match_operand 1 "const_int_operand" "n"))] - "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC" - "j\t%0" - [(set_attr "op_type" "RI") - (set_attr "type" "branch")]) - -(define_insn "*sibcall_brcl" - [(call (mem:QI (match_operand 0 "bras_sym_operand" "X")) - (match_operand 1 "const_int_operand" "n"))] - "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH" - "jg\t%0" - [(set_attr "op_type" "RIL") - (set_attr "type" "branch")]) - -; -; sibcall_value patterns -; - -(define_expand "sibcall_value" - [(set (match_operand 0 "" "") - (call (match_operand 1 "" "") - (match_operand 2 "" "")))] - "" -{ - s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], NULL_RTX); - DONE; -}) - -(define_insn "*sibcall_value_br" - [(set (match_operand 0 "" "") - (call (mem:QI (reg SIBCALL_REGNUM)) - (match_operand 1 "const_int_operand" "n")))] - "SIBLING_CALL_P (insn) - && GET_MODE (XEXP (XEXP (XEXP (PATTERN (insn), 1), 0), 0)) == Pmode" - "br\t%%r1" - [(set_attr "op_type" "RR") - (set_attr "type" "branch") - (set_attr "atype" "agen")]) - -(define_insn "*sibcall_value_brc" - [(set (match_operand 0 "" "") - (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) - (match_operand 2 "const_int_operand" "n")))] - "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC" - "j\t%1" - [(set_attr "op_type" "RI") - (set_attr "type" "branch")]) - -(define_insn "*sibcall_value_brcl" - [(set (match_operand 0 "" "") - (call (mem:QI (match_operand 1 "bras_sym_operand" "X")) - (match_operand 2 "const_int_operand" "n")))] - "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH" - "jg\t%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "branch")]) - - -; -; call instruction pattern(s). -; - -(define_expand "call" - [(call (match_operand 0 "" "") - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))] - "" -{ - s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, - gen_rtx_REG (Pmode, RETURN_REGNUM)); - DONE; -}) - -(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"))] - "!SIBLING_CALL_P (insn) - && TARGET_SMALL_EXEC - && GET_MODE (operands[2]) == Pmode" - "bras\t%2,%0" - [(set_attr "op_type" "RI") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(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"))] - "!SIBLING_CALL_P (insn) - && TARGET_CPU_ZARCH - && GET_MODE (operands[2]) == Pmode" - "brasl\t%2,%0" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "*basr" - [(call (mem:QI (match_operand 0 "address_operand" "ZQZR")) - (match_operand 1 "const_int_operand" "n")) - (clobber (match_operand 2 "register_operand" "=r"))] - "!SIBLING_CALL_P (insn) && 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") - (set_attr "z196prop" "z196_cracked")]) - -; -; call_value instruction pattern(s). -; - -(define_expand "call_value" - [(set (match_operand 0 "" "") - (call (match_operand 1 "" "") - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))] - "" -{ - s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], - gen_rtx_REG (Pmode, RETURN_REGNUM)); - DONE; -}) - -(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 3 "register_operand" "=r"))] - "!SIBLING_CALL_P (insn) - && TARGET_SMALL_EXEC - && GET_MODE (operands[3]) == Pmode" - "bras\t%3,%1" - [(set_attr "op_type" "RI") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(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"))] - "!SIBLING_CALL_P (insn) - && TARGET_CPU_ZARCH - && GET_MODE (operands[3]) == Pmode" - "brasl\t%3,%1" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "*basr_r" - [(set (match_operand 0 "" "") - (call (mem:QI (match_operand 1 "address_operand" "ZQZR")) - (match_operand 2 "const_int_operand" "n"))) - (clobber (match_operand 3 "register_operand" "=r"))] - "!SIBLING_CALL_P (insn) && 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") - (set_attr "z196prop" "z196_cracked")]) - -;; -;;- Thread-local storage support. -;; - -(define_expand "get_tp_64" - [(set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI TP_REGNUM))] - "TARGET_64BIT" - "") - -(define_expand "get_tp_31" - [(set (match_operand:SI 0 "nonimmediate_operand" "") (reg:SI TP_REGNUM))] - "!TARGET_64BIT" - "") - -(define_expand "set_tp_64" - [(set (reg:DI TP_REGNUM) (match_operand:DI 0 "nonimmediate_operand" "")) - (set (reg:DI TP_REGNUM) (unspec_volatile:DI [(reg:DI TP_REGNUM)] UNSPECV_SET_TP))] - "TARGET_64BIT" - "") - -(define_expand "set_tp_31" - [(set (reg:SI TP_REGNUM) (match_operand:SI 0 "nonimmediate_operand" "")) - (set (reg:SI TP_REGNUM) (unspec_volatile:SI [(reg:SI TP_REGNUM)] UNSPECV_SET_TP))] - "!TARGET_64BIT" - "") - -(define_insn "*set_tp" - [(set (reg TP_REGNUM) (unspec_volatile [(reg TP_REGNUM)] UNSPECV_SET_TP))] - "" - "" - [(set_attr "type" "none") - (set_attr "length" "0")]) - -(define_insn "*tls_load_64" - [(set (match_operand:DI 0 "register_operand" "=d") - (unspec:DI [(match_operand:DI 1 "memory_operand" "RT") - (match_operand:DI 2 "" "")] - UNSPEC_TLS_LOAD))] - "TARGET_64BIT" - "lg\t%0,%1%J2" - [(set_attr "op_type" "RXE") - (set_attr "z10prop" "z10_fwd_A3")]) - -(define_insn "*tls_load_31" - [(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 - ly\t%0,%1%J2" - [(set_attr "op_type" "RX,RXY") - (set_attr "type" "load") - (set_attr "z10prop" "z10_fwd_A3,z10_fwd_A3")]) - -(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 "" ""))] - "!SIBLING_CALL_P (insn) - && TARGET_SMALL_EXEC - && GET_MODE (operands[3]) == Pmode" - "bras\t%3,%1%J4" - [(set_attr "op_type" "RI") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(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 "" ""))] - "!SIBLING_CALL_P (insn) - && TARGET_CPU_ZARCH - && GET_MODE (operands[3]) == Pmode" - "brasl\t%3,%1%J4" - [(set_attr "op_type" "RIL") - (set_attr "type" "jsr") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "*basr_tls" - [(set (match_operand 0 "" "") - (call (mem:QI (match_operand 1 "address_operand" "ZQZR")) - (match_operand 2 "const_int_operand" "n"))) - (clobber (match_operand 3 "register_operand" "=r")) - (use (match_operand 4 "" ""))] - "!SIBLING_CALL_P (insn) && 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") - (set_attr "z196prop" "z196_cracked")]) - -;; -;;- Atomic operations -;; - -; -; memory barrier pattern. -; - -(define_expand "memory_barrier" - [(set (match_dup 0) - (unspec:BLK [(match_dup 0)] UNSPEC_MB))] - "" -{ - operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); - MEM_VOLATILE_P (operands[0]) = 1; -}) - -(define_insn "*memory_barrier" - [(set (match_operand:BLK 0 "" "") - (unspec:BLK [(match_dup 0)] UNSPEC_MB))] - "" - "bcr\t15,0" - [(set_attr "op_type" "RR")]) - -; Although bcr is superscalar on Z10, this variant will never become part of -; an execution group. - -; -; compare and swap patterns. -; - -(define_expand "sync_compare_and_swap<mode>" - [(parallel - [(set (match_operand:TDSI 0 "register_operand" "") - (match_operand:TDSI 1 "memory_operand" "")) - (set (match_dup 1) - (unspec_volatile:TDSI - [(match_dup 1) - (match_operand:TDSI 2 "register_operand" "") - (match_operand:TDSI 3 "register_operand" "")] - UNSPECV_CAS)) - (set (reg:CCZ1 CC_REGNUM) - (compare:CCZ1 (match_dup 1) (match_dup 2)))])] - "") - -(define_expand "sync_compare_and_swap<mode>" - [(parallel - [(set (match_operand:HQI 0 "register_operand" "") - (match_operand:HQI 1 "memory_operand" "")) - (set (match_dup 1) - (unspec_volatile:HQI - [(match_dup 1) - (match_operand:HQI 2 "general_operand" "") - (match_operand:HQI 3 "general_operand" "")] - UNSPECV_CAS)) - (clobber (reg:CC CC_REGNUM))])] - "" - "s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1], - operands[2], operands[3]); DONE;") - -; cds, cdsg -(define_insn "*sync_compare_and_swap<mode>" - [(set (match_operand:DW 0 "register_operand" "=r") - (match_operand:DW 1 "memory_operand" "+Q")) - (set (match_dup 1) - (unspec_volatile:DW - [(match_dup 1) - (match_operand:DW 2 "register_operand" "0") - (match_operand:DW 3 "register_operand" "r")] - UNSPECV_CAS)) - (set (reg:CCZ1 CC_REGNUM) - (compare:CCZ1 (match_dup 1) (match_dup 2)))] - "" - "cds<tg>\t%0,%3,%S1" - [(set_attr "op_type" "RS<TE>") - (set_attr "type" "sem")]) - -; cs, csg -(define_insn "*sync_compare_and_swap<mode>" - [(set (match_operand:GPR 0 "register_operand" "=r") - (match_operand:GPR 1 "memory_operand" "+Q")) - (set (match_dup 1) - (unspec_volatile:GPR - [(match_dup 1) - (match_operand:GPR 2 "register_operand" "0") - (match_operand:GPR 3 "register_operand" "r")] - UNSPECV_CAS)) - (set (reg:CCZ1 CC_REGNUM) - (compare:CCZ1 (match_dup 1) (match_dup 2)))] - "" - "cs<g>\t%0,%3,%S1" - [(set_attr "op_type" "RS<E>") - (set_attr "type" "sem")]) - - -; -; Other atomic instruction patterns. -; - -(define_expand "sync_lock_test_and_set<mode>" - [(match_operand:HQI 0 "register_operand") - (match_operand:HQI 1 "memory_operand") - (match_operand:HQI 2 "general_operand")] - "" - "s390_expand_atomic (<MODE>mode, SET, operands[0], operands[1], - operands[2], false); DONE;") - -; z196 load and add, xor, or and and instructions - -; lan, lang, lao, laog, lax, laxg, laa, laag -(define_insn "sync_<atomic><mode>" - [(parallel - [(set (match_operand:GPR 0 "memory_operand" "+QS") - (unspec_volatile:GPR - [(ATOMIC_Z196:GPR (match_dup 0) - (match_operand:GPR 1 "general_operand" "d"))] - UNSPECV_ATOMIC_OP)) - (clobber (match_scratch:GPR 2 "=d")) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_Z196" - "la<noxa><g>\t%2,%1,%0") - -; lan, lang, lao, laog, lax, laxg, laa, laag -(define_insn "sync_old_<atomic><mode>" - [(parallel - [(set (match_operand:GPR 0 "register_operand" "=d") - (match_operand:GPR 1 "memory_operand" "+QS")) - (set (match_dup 1) - (unspec_volatile:GPR - [(ATOMIC_Z196:GPR (match_dup 1) - (match_operand:GPR 2 "general_operand" "d"))] - UNSPECV_ATOMIC_OP)) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_Z196" - "la<noxa><g>\t%0,%2,%1") - - -(define_expand "sync_<atomic><mode>" - [(set (match_operand:HQI 0 "memory_operand") - (ATOMIC:HQI (match_dup 0) - (match_operand:HQI 1 "general_operand")))] - "" - "s390_expand_atomic (<MODE>mode, <CODE>, NULL_RTX, operands[0], - operands[1], false); DONE;") - -(define_expand "sync_old_<atomic><mode>" - [(set (match_operand:HQI 0 "register_operand") - (match_operand:HQI 1 "memory_operand")) - (set (match_dup 1) - (ATOMIC:HQI (match_dup 1) - (match_operand:HQI 2 "general_operand")))] - "" - "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], - operands[2], false); DONE;") - -(define_expand "sync_new_<atomic><mode>" - [(set (match_operand:HQI 0 "register_operand") - (ATOMIC:HQI (match_operand:HQI 1 "memory_operand") - (match_operand:HQI 2 "general_operand"))) - (set (match_dup 1) (ATOMIC:HQI (match_dup 1) (match_dup 2)))] - "" - "s390_expand_atomic (<MODE>mode, <CODE>, operands[0], operands[1], - operands[2], true); DONE;") - -;; -;;- Miscellaneous instructions. -;; - -; -; allocate stack instruction pattern(s). -; - -(define_expand "allocate_stack" - [(match_operand 0 "general_operand" "") - (match_operand 1 "general_operand" "")] - "TARGET_BACKCHAIN" -{ - rtx temp = gen_reg_rtx (Pmode); - - emit_move_insn (temp, s390_back_chain_rtx ()); - anti_adjust_stack (operands[1]); - emit_move_insn (s390_back_chain_rtx (), temp); - - emit_move_insn (operands[0], virtual_stack_dynamic_rtx); - DONE; -}) - - -; -; setjmp instruction pattern. -; - -(define_expand "builtin_setjmp_receiver" - [(match_operand 0 "" "")] - "flag_pic" -{ - emit_insn (s390_load_got ()); - emit_use (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 -;; preserve the backchain. At block level, we have to restore the backchain -;; when we restore the stack pointer. -;; -;; For nonlocal gotos, we must save both the stack pointer and its -;; backchain and restore both. Note that in the nonlocal case, the -;; save area is a memory location. - -(define_expand "save_stack_function" - [(match_operand 0 "general_operand" "") - (match_operand 1 "general_operand" "")] - "" - "DONE;") - -(define_expand "restore_stack_function" - [(match_operand 0 "general_operand" "") - (match_operand 1 "general_operand" "")] - "" - "DONE;") - -(define_expand "restore_stack_block" - [(match_operand 0 "register_operand" "") - (match_operand 1 "register_operand" "")] - "TARGET_BACKCHAIN" -{ - rtx temp = gen_reg_rtx (Pmode); - - emit_move_insn (temp, s390_back_chain_rtx ()); - emit_move_insn (operands[0], operands[1]); - emit_move_insn (s390_back_chain_rtx (), temp); - - DONE; -}) - -(define_expand "save_stack_nonlocal" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "register_operand" "")] - "" -{ - rtx base = gen_rtx_REG (Pmode, BASE_REGNUM); - - /* Copy the backchain to the first word, sp to the second and the - literal pool base to the third. */ - - rtx save_bc = adjust_address (operands[0], Pmode, 0); - rtx save_sp = adjust_address (operands[0], Pmode, GET_MODE_SIZE (Pmode)); - rtx save_bp = adjust_address (operands[0], Pmode, 2 * GET_MODE_SIZE (Pmode)); - - if (TARGET_BACKCHAIN) - emit_move_insn (save_bc, force_reg (Pmode, s390_back_chain_rtx ())); - - emit_move_insn (save_sp, operands[1]); - emit_move_insn (save_bp, base); - - DONE; -}) - -(define_expand "restore_stack_nonlocal" - [(match_operand 0 "register_operand" "") - (match_operand 1 "memory_operand" "")] - "" -{ - rtx base = gen_rtx_REG (Pmode, BASE_REGNUM); - rtx temp = NULL_RTX; - - /* Restore the backchain from the first word, sp from the second and the - literal pool base from the third. */ - - rtx save_bc = adjust_address (operands[1], Pmode, 0); - rtx save_sp = adjust_address (operands[1], Pmode, GET_MODE_SIZE (Pmode)); - rtx save_bp = adjust_address (operands[1], Pmode, 2 * GET_MODE_SIZE (Pmode)); - - if (TARGET_BACKCHAIN) - temp = force_reg (Pmode, save_bc); - - emit_move_insn (base, save_bp); - emit_move_insn (operands[0], save_sp); - - if (temp) - emit_move_insn (s390_back_chain_rtx (), temp); - - emit_use (base); - DONE; -}) - -(define_expand "exception_receiver" - [(const_int 0)] - "" -{ - s390_set_has_landing_pad_p (true); - DONE; -}) - -; -; nop instruction pattern(s). -; - -(define_insn "nop" - [(const_int 0)] - "" - "lr\t0,0" - [(set_attr "op_type" "RR") - (set_attr "z10prop" "z10_fr_E1")]) - -(define_insn "nop1" - [(const_int 1)] - "" - "lr\t1,1" - [(set_attr "op_type" "RR")]) - - -; -; Special literal pool access instruction pattern(s). -; - -(define_insn "*pool_entry" - [(unspec_volatile [(match_operand 0 "consttable_operand" "X")] - UNSPECV_POOL_ENTRY)] - "" -{ - enum machine_mode mode = GET_MODE (PATTERN (insn)); - unsigned int align = GET_MODE_BITSIZE (mode); - s390_output_pool_entry (operands[0], mode, align); - return ""; -} - [(set (attr "length") - (symbol_ref "GET_MODE_SIZE (GET_MODE (PATTERN (insn)))"))]) - -(define_insn "pool_align" - [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] - UNSPECV_POOL_ALIGN)] - "" - ".align\t%0" - [(set (attr "length") (symbol_ref "INTVAL (operands[0])"))]) - -(define_insn "pool_section_start" - [(unspec_volatile [(const_int 1)] UNSPECV_POOL_SECTION)] - "" - ".section\t.rodata" - [(set_attr "length" "0")]) - -(define_insn "pool_section_end" - [(unspec_volatile [(const_int 0)] UNSPECV_POOL_SECTION)] - "" - ".previous" - [(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") - (set_attr "z196prop" "z196_cracked")]) - -(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") - (set_attr "z196prop" "z196_cracked")]) - -(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") - (set_attr "z10prop" "z10_fwd_A1")]) - -(define_insn "main_pool" - [(set (match_operand 0 "register_operand" "=a") - (unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL))] - "GET_MODE (operands[0]) == Pmode" -{ - gcc_unreachable (); -} - [(set (attr "type") - (if_then_else (match_test "TARGET_CPU_ZARCH") - (const_string "larl") (const_string "la")))]) - -(define_insn "reload_base_31" - [(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 "length" "6") - (set_attr "type" "la") - (set_attr "z196prop" "z196_cracked")]) - -(define_insn "reload_base_64" - [(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" "larl") - (set_attr "z10prop" "z10_fwd_A1")]) - -(define_insn "pool" - [(unspec_volatile [(match_operand 0 "const_int_operand" "n")] UNSPECV_POOL)] - "" -{ - gcc_unreachable (); -} - [(set (attr "length") (symbol_ref "INTVAL (operands[0])"))]) - -;; -;; Insns related to generating the function prologue and epilogue. -;; - - -(define_expand "prologue" - [(use (const_int 0))] - "" - "s390_emit_prologue (); DONE;") - -(define_expand "epilogue" - [(use (const_int 1))] - "" - "s390_emit_epilogue (false); DONE;") - -(define_expand "sibcall_epilogue" - [(use (const_int 0))] - "" - "s390_emit_epilogue (true); DONE;") - -(define_insn "*return" - [(return) - (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" "agen")]) - - -;; Instruction definition to extend a 31-bit pointer into a 64-bit -;; pointer. This is used for compatibility. - -(define_expand "ptr_extend" - [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:SI 1 "register_operand" "r"))] - "TARGET_64BIT" -{ - emit_insn (gen_anddi3 (operands[0], - gen_lowpart (DImode, operands[1]), - GEN_INT (0x7fffffff))); - DONE; -}) - -;; Instruction definition to expand eh_return macro to support -;; swapping in special linkage return addresses. - -(define_expand "eh_return" - [(use (match_operand 0 "register_operand" ""))] - "TARGET_TPF" -{ - s390_emit_tpf_eh_return (operands[0]); - DONE; -}) - -; -; Stack Protector Patterns -; - -(define_expand "stack_protect_set" - [(set (match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" ""))] - "" -{ -#ifdef TARGET_THREAD_SSP_OFFSET - operands[1] - = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), - GEN_INT (TARGET_THREAD_SSP_OFFSET))); -#endif - if (TARGET_64BIT) - emit_insn (gen_stack_protect_setdi (operands[0], operands[1])); - else - emit_insn (gen_stack_protect_setsi (operands[0], operands[1])); - - DONE; -}) - -(define_insn "stack_protect_set<mode>" - [(set (match_operand:DSI 0 "memory_operand" "=Q") - (unspec:DSI [(match_operand:DSI 1 "memory_operand" "Q")] UNSPEC_SP_SET))] - "" - "mvc\t%O0(%G0,%R0),%S1" - [(set_attr "op_type" "SS")]) - -(define_expand "stack_protect_test" - [(set (reg:CC CC_REGNUM) - (compare (match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" ""))) - (match_operand 2 "" "")] - "" -{ - rtx cc_reg, test; -#ifdef TARGET_THREAD_SSP_OFFSET - operands[1] - = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), - GEN_INT (TARGET_THREAD_SSP_OFFSET))); -#endif - if (TARGET_64BIT) - emit_insn (gen_stack_protect_testdi (operands[0], operands[1])); - else - emit_insn (gen_stack_protect_testsi (operands[0], operands[1])); - - cc_reg = gen_rtx_REG (CCZmode, CC_REGNUM); - test = gen_rtx_EQ (VOIDmode, cc_reg, const0_rtx); - emit_jump_insn (gen_cbranchcc4 (test, cc_reg, const0_rtx, operands[2])); - DONE; -}) - -(define_insn "stack_protect_test<mode>" - [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:DSI 0 "memory_operand" "Q") - (match_operand:DSI 1 "memory_operand" "Q")] UNSPEC_SP_TEST))] - "" - "clc\t%O0(%G0,%R0),%S1" - [(set_attr "op_type" "SS")]) - -; This is used in s390_emit_prologue in order to prevent insns -; adjusting the stack pointer to be moved over insns writing stack -; slots using a copy of the stack pointer in a different register. -(define_insn "stack_tie" - [(set (match_operand:BLK 0 "memory_operand" "+m") - (unspec:BLK [(match_dup 0)] UNSPEC_TIE))] - "" - "" - [(set_attr "length" "0")]) - - -; -; Data prefetch patterns -; - -(define_insn "prefetch" - [(prefetch (match_operand 0 "address_operand" "ZQZRZSZT,X") - (match_operand:SI 1 "const_int_operand" " n,n") - (match_operand:SI 2 "const_int_operand" " n,n"))] - "TARGET_Z10" -{ - switch (which_alternative) - { - case 0: - return INTVAL (operands[1]) == 1 ? "pfd\t2,%a0" : "pfd\t1,%a0"; - case 1: - if (larl_operand (operands[0], Pmode)) - return INTVAL (operands[1]) == 1 ? "pfdrl\t2,%a0" : "pfdrl\t1,%a0"; - default: - - /* This might be reached for symbolic operands with an odd - addend. We simply omit the prefetch for such rare cases. */ - - return ""; - } -} - [(set_attr "type" "load,larl") - (set_attr "op_type" "RXY,RIL") - (set_attr "z10prop" "z10_super") - (set_attr "z196prop" "z196_alone")]) - - -; -; Byte swap instructions -; - -(define_insn "bswap<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d, d") - (bswap:GPR (match_operand:GPR 1 "nonimmediate_operand" " d,RT")))] - "TARGET_CPU_ZARCH" - "@ - lrv<g>r\t%0,%1 - lrv<g>\t%0,%1" - [(set_attr "type" "*,load") - (set_attr "op_type" "RRE,RXY") - (set_attr "z10prop" "z10_super")]) - - -; -; Population count instruction -; - -; The S/390 popcount instruction counts the bits of op1 in 8 byte -; portions and stores the result in the corresponding bytes in op0. -(define_insn "*popcount<mode>" - [(set (match_operand:INT 0 "register_operand" "=d") - (unspec:INT [(match_operand:INT 1 "register_operand" "d")] UNSPEC_POPCNT)) - (clobber (reg:CC CC_REGNUM))] - "TARGET_Z196" - "popcnt\t%0,%1" - [(set_attr "op_type" "RRE")]) - -(define_expand "popcountdi2" - [; popcnt op0, op1 - (parallel [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:DI 1 "register_operand")] - UNSPEC_POPCNT)) - (clobber (reg:CC CC_REGNUM))]) - ; sllg op2, op0, 32 - (set (match_dup 2) (ashift:DI (match_dup 0) (const_int 32))) - ; agr op0, op2 - (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; sllg op2, op0, 16 - (set (match_dup 2) - (ashift:DI (match_dup 0) (const_int 16))) - ; agr op0, op2 - (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; sllg op2, op0, 8 - (set (match_dup 2) (ashift:DI (match_dup 0) (const_int 8))) - ; agr op0, op2 - (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; srlg op0, op0, 56 - (set (match_dup 0) (lshiftrt:DI (match_dup 0) (const_int 56)))] - "TARGET_Z196 && TARGET_64BIT" - "operands[2] = gen_reg_rtx (DImode);") - -(define_expand "popcountsi2" - [; popcnt op0, op1 - (parallel [(set (match_operand:SI 0 "register_operand" "") - (unspec:SI [(match_operand:SI 1 "register_operand")] - UNSPEC_POPCNT)) - (clobber (reg:CC CC_REGNUM))]) - ; sllk op2, op0, 16 - (set (match_dup 2) - (ashift:SI (match_dup 0) (const_int 16))) - ; ar op0, op2 - (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; sllk op2, op0, 8 - (set (match_dup 2) (ashift:SI (match_dup 0) (const_int 8))) - ; ar op0, op2 - (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; srl op0, op0, 24 - (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 24)))] - "TARGET_Z196" - "operands[2] = gen_reg_rtx (SImode);") - -(define_expand "popcounthi2" - [; popcnt op0, op1 - (parallel [(set (match_operand:HI 0 "register_operand" "") - (unspec:HI [(match_operand:HI 1 "register_operand")] - UNSPEC_POPCNT)) - (clobber (reg:CC CC_REGNUM))]) - ; sllk op2, op0, 8 - (set (match_dup 2) - (ashift:SI (match_dup 0) (const_int 8))) - ; ar op0, op2 - (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2))) - (clobber (reg:CC CC_REGNUM))]) - ; srl op0, op0, 8 - (set (match_dup 0) (lshiftrt:HI (match_dup 0) (const_int 8)))] - "TARGET_Z196" - "operands[2] = gen_reg_rtx (SImode);") - -(define_expand "popcountqi2" - [; popcnt op0, op1 - (parallel [(set (match_operand:QI 0 "register_operand" "") - (unspec:QI [(match_operand:QI 1 "register_operand")] - UNSPEC_POPCNT)) - (clobber (reg:CC CC_REGNUM))])] - "TARGET_Z196" - "") - -;; -;;- Copy sign instructions -;; - -(define_insn "copysign<mode>3" - [(set (match_operand:FP 0 "register_operand" "=f") - (unspec:FP [(match_operand:FP 1 "register_operand" "<fT0>") - (match_operand:FP 2 "register_operand" "f")] - UNSPEC_COPYSIGN))] - "TARGET_Z196" - "cpsdr\t%0,%2,%1" - [(set_attr "op_type" "RRF") - (set_attr "type" "fsimp<mode>")]) diff --git a/gcc-4.7/gcc/config/s390/s390.opt b/gcc-4.7/gcc/config/s390/s390.opt deleted file mode 100644 index 51b395ee9..000000000 --- a/gcc-4.7/gcc/config/s390/s390.opt +++ /dev/null @@ -1,148 +0,0 @@ -; Options for the S/390 / zSeries port of the compiler. - -; Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC is free software; you can redistribute it and/or modify it under -; the terms of the GNU General Public License as published by the Free -; Software Foundation; either version 3, or (at your option) any later -; version. -; -; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -; WARRANTY; without even the implied warranty of MERCHANTABILITY or -; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -; for more details. -; -; You should have received a copy of the GNU General Public License -; along with GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -HeaderInclude -config/s390/s390-opts.h - -; The architecture name to use in diagnostics. -Variable -const char *s390_arch_string - -Variable -int s390_tune_flags - -Variable -int s390_arch_flags - -Variable -HOST_WIDE_INT s390_warn_framesize = 0 - -m31 -Target Report RejectNegative Negative(m64) InverseMask(64BIT) -31 bit ABI - -m64 -Target Report RejectNegative Negative(m31) Mask(64BIT) -64 bit ABI - -march= -Target RejectNegative Joined Enum(processor_type) Var(s390_arch) Init(PROCESSOR_max) -Generate code for given CPU - -Enum -Name(processor_type) Type(enum processor_type) - -EnumValue -Enum(processor_type) String(g5) Value(PROCESSOR_9672_G5) - -EnumValue -Enum(processor_type) String(g6) Value(PROCESSOR_9672_G6) - -EnumValue -Enum(processor_type) String(z900) Value(PROCESSOR_2064_Z900) - -EnumValue -Enum(processor_type) String(z990) Value(PROCESSOR_2084_Z990) - -EnumValue -Enum(processor_type) String(z9-109) Value(PROCESSOR_2094_Z9_109) - -EnumValue -Enum(processor_type) String(z9-ec) Value(PROCESSOR_2094_Z9_EC) - -EnumValue -Enum(processor_type) String(z10) Value(PROCESSOR_2097_Z10) - -EnumValue -Enum(processor_type) String(z196) Value(PROCESSOR_2817_Z196) - -mbackchain -Target Report Mask(BACKCHAIN) -Maintain backchain pointer - -mdebug -Target Report Mask(DEBUG_ARG) -Additional debug prints - -mesa -Target Report RejectNegative Negative(mzarch) InverseMask(ZARCH) -ESA/390 architecture - -mhard-dfp -Target Report Mask(HARD_DFP) -Enable decimal floating point hardware support - -mhard-float -Target Report RejectNegative Negative(msoft-float) InverseMask(SOFT_FLOAT, HARD_FLOAT) -Enable hardware floating point - -mlong-double-128 -Target Report RejectNegative Negative(mlong-double-64) Mask(LONG_DOUBLE_128) -Use 128-bit long double - -mlong-double-64 -Target Report RejectNegative Negative(mlong-double-128) InverseMask(LONG_DOUBLE_128) -Use 64-bit long double - -mpacked-stack -Target Report Mask(PACKED_STACK) -Use packed stack layout - -msmall-exec -Target Report Mask(SMALL_EXEC) -Use bras for executable < 64k - -msoft-float -Target Report RejectNegative Negative(mhard-float) Mask(SOFT_FLOAT) -Disable hardware floating point - -mstack-guard= -Target RejectNegative Joined UInteger Var(s390_stack_guard) -Set the max. number of bytes which has to be left to stack size before a trap instruction is triggered - -mstack-size= -Target RejectNegative Joined UInteger Var(s390_stack_size) -Emit extra code in the function prologue in order to trap if the stack size exceeds the given limit - -mtune= -Target RejectNegative Joined Enum(processor_type) Var(s390_tune) Init(PROCESSOR_max) -Schedule code for given CPU - -mmvcle -Target Report Mask(MVCLE) -mvcle use - -mwarn-dynamicstack -Target RejectNegative Var(s390_warn_dynamicstack_p) -Warn if a function uses alloca or creates an array with dynamic size - -mwarn-framesize= -Target RejectNegative Joined -Warn if a single function's framesize exceeds the given framesize - -mzarch -Target Report RejectNegative Negative(mesa) Mask(ZARCH) -z/Architecture - -mbranch-cost= -Target Report Joined RejectNegative UInteger Var(s390_branch_cost) Init(1) -Set the branch costs for conditional branch instructions. Reasonable -values are small, non-negative integers. The default branch cost is -1. diff --git a/gcc-4.7/gcc/config/s390/s390x.h b/gcc-4.7/gcc/config/s390/s390x.h deleted file mode 100644 index 3712eb156..000000000 --- a/gcc-4.7/gcc/config/s390/s390x.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Definitions of target machine for IBM zSeries 64-bit - Copyright (C) 2002, 2007 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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef _S390X_H -#define _S390X_H - -#define DEFAULT_TARGET_64BIT - -#endif diff --git a/gcc-4.7/gcc/config/s390/t-linux64 b/gcc-4.7/gcc/config/s390/t-linux64 deleted file mode 100644 index ede76a2cb..000000000 --- a/gcc-4.7/gcc/config/s390/t-linux64 +++ /dev/null @@ -1,10 +0,0 @@ -# On Debian, Ubuntu and other derivative distributions, the 32bit libraries -# are found in /lib32 and /usr/lib32, /lib64 and /usr/lib64 are symlinks to -# /lib and /usr/lib, while other distributions install libraries into /lib64 -# and /usr/lib64. The LSB does not enforce the use of /lib64 and /usr/lib64, -# it doesn't tell anything about the 32bit libraries on those systems. Set -# MULTILIB_OSDIRNAMES according to what is found on the target. - -MULTILIB_OPTIONS = m64/m31 -MULTILIB_DIRNAMES = 64 32 -MULTILIB_OSDIRNAMES = ../lib64 $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib) diff --git a/gcc-4.7/gcc/config/s390/tpf.h b/gcc-4.7/gcc/config/s390/tpf.h deleted file mode 100644 index e4a1b50b6..000000000 --- a/gcc-4.7/gcc/config/s390/tpf.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Definitions for target OS TPF for GNU compiler, for IBM S/390 hardware - Copyright (C) 2003, 2004, 2005, 2007, 2009, - 2010, 2011 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 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef _TPF_H -#define _TPF_H - -/* TPF wants the following macros defined/undefined as follows. */ -#undef TARGET_TPF -#define TARGET_TPF 1 -#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_POSIX_IO - -#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 - - -/* TPF OS specific stack-pointer offset. */ -#undef STACK_POINTER_OFFSET -#define STACK_POINTER_OFFSET 448 - -/* When building for TPF, set a generic default target that is 64 bits. Also - enable TPF profiling support and the standard backchain by default. */ -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (MASK_TPF_PROFILING | MASK_64BIT | MASK_ZARCH \ - | MASK_HARD_DFP | MASK_BACKCHAIN) - -/* Exception handling. */ - -/* Select a format to encode pointers in exception handling data. */ -#undef ASM_PREFERRED_EH_DATA_FORMAT -#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) DW_EH_PE_absptr - -/* 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__"); \ - } \ - while (0) - - -#define EXTRA_SPECS \ - { "entry_spec", ENTRY_SPEC } - -/* Make TPF specific spec file settings here. */ - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC \ - "%{mmain:crt0%O%s} crtbeginS%O%s crt3%O%s" - -#undef ENDFILE_SPEC -#define ENDFILE_SPEC "crtendS%O%s" - -#undef CC1_SPEC -#define CC1_SPEC "%{!fverbose-asm: -fverbose-asm}" - -/* The GNU C++ standard library requires that these macros be defined. */ -#undef CPLUSPLUS_CPP_SPEC -#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)" - -#undef ASM_SPEC -#define ASM_SPEC "%{m31&m64}%{mesa&mzarch}%{march=*} \ - -alshd=%b.lst" - -/* It would be nice to get the system linker script define the ones that it - needed. */ -#undef LIB_SPEC -#define LIB_SPEC "-lCTIS -lCISO -lCLBM -lCTAL -lCFVS -lCTBX -lCTXO \ - -lCJ00 -lCTDF -lCOMX -lCOMS -lCTHD -lCTAD -lTPFSTUB" - -#undef TARGET_C99_FUNCTIONS -#define TARGET_C99_FUNCTIONS 1 - -#define ENTRY_SPEC "%{mmain:-entry=_start} \ - %{!mmain:-entry=0}" - -/* All linking is done shared on TPF-OS. */ -/* FIXME: When binutils patch for new emulation is committed - then change emulation to elf64_s390_tpf. */ -#undef LINK_SPEC -#define LINK_SPEC \ - "-m elf64_s390 \ - %{static:%estatic is not supported on TPF-OS} \ - %{shared: -shared} \ - %{!shared:-shared} \ - %(entry_spec)" - -/* IBM copies these libraries over with these names. */ -#define MATH_LIBRARY "CLBM" -#define LIBSTDCXX "CPP1" -#endif /* ! _TPF_H */ diff --git a/gcc-4.7/gcc/config/s390/tpf.md b/gcc-4.7/gcc/config/s390/tpf.md deleted file mode 100644 index e1106a052..000000000 --- a/gcc-4.7/gcc/config/s390/tpf.md +++ /dev/null @@ -1,33 +0,0 @@ -;; S390 TPF-OS specific machine patterns -;; Copyright (C) 2005, 2007 Free Software Foundation, Inc. -;; -;; This file is part of GCC. -;; -;; GCC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -(define_insn "prologue_tpf" - [(unspec_volatile [(const_int 0)] UNSPECV_TPF_PROLOGUE) - (clobber (reg:DI 1))] - "TARGET_TPF_PROFILING" - "larl\t%%r1,.+14\;tm\t4065,255\;bnz\t4064" - [(set_attr "length" "14")]) - - -(define_insn "epilogue_tpf" - [(unspec_volatile [(const_int 0)] UNSPECV_TPF_EPILOGUE) - (clobber (reg:DI 1))] - "TARGET_TPF_PROFILING" - "larl\t%%r1,.+14\;tm\t4071,255\;bnz\t4070" - [(set_attr "length" "14")]) diff --git a/gcc-4.7/gcc/config/s390/tpf.opt b/gcc-4.7/gcc/config/s390/tpf.opt deleted file mode 100644 index c3cde22b6..000000000 --- a/gcc-4.7/gcc/config/s390/tpf.opt +++ /dev/null @@ -1,27 +0,0 @@ -; Options for the TPF-OS port of the compiler. - -; Copyright (C) 2005, 2007 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC is free software; you can redistribute it and/or modify it under -; the terms of the GNU General Public License as published by the Free -; Software Foundation; either version 3, or (at your option) any later -; version. -; -; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -; WARRANTY; without even the implied warranty of MERCHANTABILITY or -; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -; for more details. -; -; You should have received a copy of the GNU General Public License -; along with GCC; see the file COPYING3. If not see -; <http://www.gnu.org/licenses/>. - -mtpf-trace -Target Report Mask(TPF_PROFILING) -Enable TPF-OS tracing code - -mmain -Target Report -Specify main object for TPF-OS |